From 22094368c2865dcfb6daf8366425212b721a4657 Mon Sep 17 00:00:00 2001
From: matthew_swift <matthew_swift@localhost>
Date: Thu, 05 Feb 2009 17:42:14 +0000
Subject: [PATCH] Merge ASN1 branch to trunk

---
 opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/ldap/LDAPv2TestCase.java                                |  176 
 opends/tests/unit-tests-testng/src/server/org/opends/server/replication/plugin/HistoricalTest.java                            |    8 
 opends/src/server/org/opends/server/schema/PrintableStringSyntax.java                                                         |    7 
 opends/src/server/org/opends/server/schema/CaseIgnoreIA5SubstringMatchingRule.java                                            |  173 
 opends/src/server/org/opends/server/types/AbstractOperation.java                                                              |   32 
 opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendCompareOperation.java                            |   82 
 opends/src/server/org/opends/server/schema/DoubleMetaphoneApproximateMatchingRule.java                                        |   34 
 opends/src/server/org/opends/server/core/ModifyOperationBasis.java                                                            |    3 
 opends/src/server/org/opends/server/protocols/jmx/RmiAuthenticator.java                                                       |   16 
 opends/src/server/org/opends/server/types/SearchFilter.java                                                                   |  110 
 opends/tests/unit-tests-testng/src/server/org/opends/server/plugins/DelayPreOpPlugin.java                                     |  212 
 opends/src/server/org/opends/server/api/DirectoryThread.java                                                                  |    3 
 opends/src/server/org/opends/server/protocols/ldap/SearchResultReferenceProtocolOp.java                                       |   91 
 opends/src/server/org/opends/server/tools/LDAPReader.java                                                                     |  109 
 opends/tests/staf-tests/functional-tests/testcases/aci/aci_targetattr.xml                                                     |    2 
 opends/tests/unit-tests-testng/src/server/org/opends/server/controls/PasswordPolicyControlTestCase.java                       |  466 
 opends/src/server/org/opends/server/protocols/ldap/LDAPControl.java                                                           |  388 
 opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/UniqueCharactersPasswordValidatorTestCase.java         |   13 
 opends/src/server/org/opends/server/backends/jeb/VLVKeyComparator.java                                                        |   11 
 opends/tests/unit-tests-testng/src/server/org/opends/server/plugins/UniqueAttributePluginTestCase.java                        |   12 
 opends/tests/unit-tests-testng/src/server/org/opends/server/schema/EqualityMatchingRuleTest.java                              |   11 
 opends/src/server/org/opends/server/types/operation/PreOperationBindOperation.java                                            |    5 
 opends/src/server/org/opends/server/schema/BitStringSyntax.java                                                               |   13 
 opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/CancelExtendedOperationTestCase.java                   |  373 
 opends/tests/unit-tests-testng/src/server/org/opends/server/TestCaseUtils.java                                                |   18 
 opends/tests/unit-tests-testng/src/server/org/opends/server/core/RejectUnauthReqTests.java                                    |   26 
 opends/src/server/org/opends/server/replication/service/ReplicationDomain.java                                                |    2 
 opends/src/server/org/opends/server/plugins/profiler/ProfileViewer.java                                                       |   31 
 opends/src/server/org/opends/server/protocols/ldap/ExtendedRequestProtocolOp.java                                             |  159 
 opends/src/server/org/opends/server/tasks/AddSchemaFileTask.java                                                              |   22 
 opends/src/server/org/opends/server/extensions/CharacterSetPasswordValidator.java                                             |    9 
 opends/src/server/org/opends/server/core/OperationWrapper.java                                                                |   10 
 opends/src/server/org/opends/server/extensions/LengthBasedPasswordValidator.java                                              |    9 
 opends/src/server/org/opends/server/protocols/ldap/LDAPStatistics.java                                                        | 1064 
 opends/tests/unit-tests-testng/src/server/org/opends/server/backends/jeb/TestRebuildJob.java                                  |    2 
 opends/src/server/org/opends/server/plugins/ChangeNumberControlPlugin.java                                                    |   56 
 opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendDeleteOperation.java                             |  115 
 opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/internal/InternalLDAPSocketTestCase.java                |   48 
 opends/tests/unit-tests-testng/src/server/org/opends/server/core/AbandonOperationTestCase.java                                |  209 
 opends/src/server/org/opends/server/extensions/WhoAmIExtendedOperation.java                                                   |  167 
 opends/src/server/org/opends/server/types/DITContentRule.java                                                                 |    2 
 opends/src/guitools/org/opends/guitools/controlpanel/ui/AbstractBrowseEntriesPanel.java                                       |    9 
 opends/src/server/org/opends/server/types/RDN.java                                                                            |   65 
 opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/AttributeValuePasswordValidatorTestCase.java           |    3 
 opends/src/server/org/opends/server/extensions/SubschemaSubentryVirtualAttributeProvider.java                                 |   12 
 opends/src/server/org/opends/server/extensions/ClearPasswordStorageScheme.java                                                |   32 
 opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/asn1/ASN1ByteSequenceReaderTestCase.java                |   18 
 opends/tests/unit-tests-testng/src/server/org/opends/server/controls/MatchedValuesControlTest.java                            |   78 
 opends/tests/unit-tests-testng/src/server/org/opends/server/plugins/LDAPADListPluginTestCase.java                             |    5 
 opends/tests/unit-tests-testng/src/server/org/opends/server/schema/UserPasswordEqualityMatchingRuleTest.java                  |    3 
 opends/src/server/org/opends/server/tools/makeldif/Branch.java                                                                |    4 
 opends/src/server/org/opends/server/schema/CaseIgnoreOrderingMatchingRule.java                                                |   71 
 opends/src/server/org/opends/server/types/operation/PostResponseModifyOperation.java                                          |    8 
 opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/VirtualStaticGroupTestCase.java                        |   33 
 opends/src/server/org/opends/server/backends/jeb/VerifyJob.java                                                               |   41 
 opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/ldap/TestModifyResponseProtocolOp.java                  |  142 
 opends/src/messages/messages/extension.properties                                                                             |   28 
 opends/src/server/org/opends/server/backends/jeb/IndexQueryFactoryImpl.java                                                   |  117 
 opends/src/server/org/opends/server/protocols/ldap/IntermediateResponseProtocolOp.java                                        |  205 
 opends/src/dsml/org/opends/dsml/protocol/DSMLExtendedOperation.java                                                           |    4 
 opends/src/server/org/opends/server/backends/jeb/IndexRebuildThread.java                                                      |   35 
 opends/src/server/org/opends/server/types/Schema.java                                                                         |  318 
 opends/src/server/org/opends/server/controls/SubtreeDeleteControl.java                                                        |   94 
 opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/ldap/TestModifyDNResponseProtocolOp.java                |  142 
 opends/src/server/org/opends/server/controls/LDAPPreReadResponseControl.java                                                  |  218 
 opends/src/server/org/opends/server/types/Operation.java                                                                      |   19 
 opends/tests/unit-tests-testng/src/server/org/opends/server/replication/plugin/AttrInfoTest.java                              |    7 
 opends/src/server/org/opends/server/extensions/ConfigFileHandler.java                                                         |    5 
 opends/src/server/org/opends/server/replication/protocol/ModifyCommonMsg.java                                                 |   23 
 opends/src/server/org/opends/server/protocols/internal/InternalClientConnection.java                                          |  200 
 opends/src/server/org/opends/server/api/CompressedSchema.java                                                                 |   52 
 opends/src/server/org/opends/server/extensions/AttributeValuePasswordValidator.java                                           |   15 
 opends/src/server/org/opends/server/types/operation/SubordinateModifyDNOperation.java                                         |    6 
 opends/src/server/org/opends/server/config/StringConfigAttribute.java                                                         |   27 
 opends/src/server/org/opends/server/schema/UniqueMemberEqualityMatchingRule.java                                              |   56 
 opends/src/server/org/opends/server/backends/jeb/ExportJob.java                                                               |    7 
 opends/src/server/org/opends/server/core/CompareOperationBasis.java                                                           |    3 
 opends/src/server/org/opends/server/config/MultiChoiceConfigAttribute.java                                                    |   35 
 opends/src/server/org/opends/server/controls/ServerSideSortResponseControl.java                                               |  182 
 opends/src/server/org/opends/server/tools/ConsoleDebugLogPublisher.java                                                       |  474 
 opends/tests/unit-tests-testng/src/server/org/opends/server/schema/SubstringMatchingRuleTest.java                             |   17 
 opends/src/server/org/opends/server/schema/GuideSyntax.java                                                                   |    7 
 opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/DigestMD5SASLMechanismHandlerTestCase.java             |   12 
 opends/tests/unit-tests-testng/src/server/org/opends/server/controls/ServerSideSortControlTestCase.java                       |   77 
 opends/src/server/org/opends/server/plugins/ReferentialIntegrityPlugin.java                                                   |   19 
 opends/src/server/org/opends/server/admin/server/ServerManagementContext.java                                                 |    6 
 opends/tests/unit-tests-testng/src/server/org/opends/server/types/ByteSequenceTest.java                                       |  209 
 opends/src/server/org/opends/server/schema/OtherMailboxSyntax.java                                                            |    7 
 opends/tests/unit-tests-testng/src/server/org/opends/server/controls/ProxiedAuthV1ControlTestCase.java                        |  182 
 opends/tests/unit-tests-testng/src/server/org/opends/server/plugins/EntryUUIDPluginTestCase.java                              |    9 
 opends/src/server/org/opends/server/extensions/CRAMMD5SASLMechanismHandler.java                                               |   15 
 opends/src/server/org/opends/server/types/RawModification.java                                                                |   92 
 opends/src/server/org/opends/server/core/PasswordPolicyState.java                                                             |  100 
 opends/src/server/org/opends/server/types/AttributeType.java                                                                  |   93 
 opends/src/server/org/opends/server/extensions/UserDefinedVirtualAttributeProvider.java                                       |   15 
 opends/src/server/org/opends/server/util/Base64.java                                                                          |   50 
 opends/src/server/org/opends/server/schema/CaseIgnoreSubstringMatchingRule.java                                               |  164 
 opends/src/server/org/opends/server/admin/ACIPropertyDefinition.java                                                          |    4 
 opends/src/server/org/opends/server/controls/PersistentSearchControl.java                                                     |  298 
 opends/src/server/org/opends/server/backends/jeb/JECompressedSchema.java                                                      |  379 
 opends/tests/unit-tests-testng/src/server/org/opends/server/core/BindOperationTestCase.java                                   |  561 
 opends/src/server/org/opends/server/extensions/IsMemberOfVirtualAttributeProvider.java                                        |   16 
 opends/src/server/org/opends/server/types/MatchingRuleUse.java                                                                |    3 
 opends/tests/unit-tests-testng/src/server/org/opends/server/admin/client/ldap/MockLDAPConnection.java                         |    2 
 opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/PasswordModifyExtendedOperationTestCase.java           |   71 
 opends/src/server/org/opends/server/schema/UUIDEqualityMatchingRule.java                                                      |   87 
 opends/src/server/org/opends/server/protocols/ldap/SearchResultEntryProtocolOp.java                                           |  155 
 opends/src/server/org/opends/server/protocols/asn1/ASN1OutputStreamWriter.java                                                |  591 
 opends/tests/unit-tests-testng/src/server/org/opends/server/replication/plugin/ModifyConflictTest.java                        |   40 
 opends/src/server/org/opends/server/schema/TelephoneNumberEqualityMatchingRule.java                                           |   40 
 opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/ldap/TestLDAPFilter.java                                |   77 
 opends/src/server/org/opends/server/tasks/ShutdownTask.java                                                                   |    4 
 opends/src/server/org/opends/server/schema/ProtocolInformationSyntax.java                                                     |    5 
 opends/src/server/org/opends/server/schema/OctetStringSubstringMatchingRule.java                                              |  137 
 opends/tests/unit-tests-testng/src/server/org/opends/server/controls/ProxiedAuthV2ControlTestCase.java                        |  149 
 opends/src/server/org/opends/server/core/AddOperationWrapper.java                                                             |    7 
 opends/src/server/org/opends/server/schema/RelativeSubtreeSpecificationSyntax.java                                            |   13 
 opends/tests/unit-tests-testng/src/server/org/opends/server/admin/TestCfg.java                                                |    5 
 opends/src/server/org/opends/server/schema/CountryStringSyntax.java                                                           |    7 
 opends/src/server/org/opends/server/schema/IntegerFirstComponentEqualityMatchingRule.java                                     |   60 
 opends/tests/unit-tests-testng/src/server/org/opends/server/replication/plugin/AssuredReplicationPluginTest.java              |   32 
 opends/src/server/org/opends/server/backends/jeb/OrderingIndexer.java                                                         |    4 
 opends/src/server/org/opends/server/extensions/RegularExpressionIdentityMapper.java                                           |   21 
 opends/src/guitools/org/opends/guitools/controlpanel/ui/TableViewEntryPanel.java                                              |   18 
 opends/src/server/org/opends/server/backends/jeb/ApproximateIndexer.java                                                      |    4 
 opends/src/server/org/opends/server/backends/task/TaskScheduler.java                                                          |    2 
 opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/asn1/ASN1OutputStreamWriterTestCase.java                |   66 
 opends/src/server/org/opends/server/replication/plugin/ReplicationRepairRequestControl.java                                   |   87 
 opends/src/server/org/opends/server/core/ModifyOperationWrapper.java                                                          |    7 
 opends/src/server/org/opends/server/plugins/profiler/ProfileStack.java                                                        |   81 
 opends/src/server/org/opends/server/tools/ManageAccount.java                                                                  |  503 
 opends/src/server/org/opends/server/protocols/ldap/LDAPConnectionHandler.java                                                 |  248 
 opends/src/server/org/opends/server/core/BindOperation.java                                                                   |   16 
 opends/src/quicksetup/org/opends/quicksetup/ui/UIFactory.java                                                                 |    6 
 opends/src/server/org/opends/server/extensions/SimilarityBasedPasswordValidator.java                                          |   14 
 opends/tests/unit-tests-testng/src/server/org/opends/server/schema/ApproximatematchingRule.java                               |    5 
 opends/src/server/org/opends/server/extensions/MD5PasswordStorageScheme.java                                                  |   50 
 opends/src/server/org/opends/server/schema/DITStructureRuleSyntax.java                                                        |   17 
 opends/src/server/org/opends/server/controls/PasswordExpiringControl.java                                                     |  163 
 opends/src/server/org/opends/server/core/AddOperationBasis.java                                                               |    7 
 opends/src/server/org/opends/server/schema/NumericStringSyntax.java                                                           |    7 
 opends/src/server/org/opends/server/types/operation/PreParseDeleteOperation.java                                              |    1 
 opends/src/server/org/opends/server/tools/LDAPToolUtils.java                                                                  |   10 
 opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/AnonymousSASLMechanismHandlerTestCase.java             |    6 
 opends/src/server/org/opends/server/protocols/asn1/ASN1ByteChannelReader.java                                                 |  456 
 opends/src/server/org/opends/server/api/SubstringMatchingRule.java                                                            |  112 
 opends/src/server/org/opends/server/replication/protocol/ModifyDNMsg.java                                                     |   27 
 opends/tests/unit-tests-testng/src/server/org/opends/server/replication/UpdateOperationTest.java                              |   32 
 opends/src/server/org/opends/server/replication/plugin/HistVal.java                                                           |    9 
 opends/src/server/org/opends/server/schema/DeliveryMethodSyntax.java                                                          |   11 
 opends/tests/unit-tests-testng/src/server/org/opends/server/replication/ReplicationTestCase.java                              |   22 
 opends/src/server/org/opends/server/extensions/VirtualStaticGroup.java                                                        |    2 
 opends/src/server/org/opends/server/schema/GeneralizedTimeSyntax.java                                                         |   17 
 opends/tests/unit-tests-testng/src/server/org/opends/server/admin/RelativeInheritedDefaultBehaviorProviderTest.java           |    4 
 opends/src/quicksetup/org/opends/quicksetup/installer/ui/SecurityOptionsDialog.java                                           |    5 
 opends/src/server/org/opends/server/controls/VLVResponseControl.java                                                          |  220 
 opends/src/server/org/opends/server/controls/LDAPPreReadRequestControl.java                                                   |  279 
 opends/src/server/org/opends/server/schema/DistinguishedNameSyntax.java                                                       |   14 
 opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendBindOperation.java                               |   18 
 opends/src/server/org/opends/server/protocols/ldap/DeleteRequestProtocolOp.java                                               |   79 
 opends/src/server/org/opends/server/extensions/SaltedSHA256PasswordStorageScheme.java                                         |   71 
 opends/src/server/org/opends/server/schema/BooleanSyntax.java                                                                 |   71 
 opends/src/server/org/opends/server/schema/ObjectClassSyntax.java                                                             |   18 
 opends/src/server/org/opends/server/types/operation/PostResponseSearchOperation.java                                          |    8 
 opends/src/server/org/opends/server/controls/AuthorizationIdentityResponseControl.java                                        |  257 
 opends/src/server/org/opends/server/extensions/SaltedSHA1PasswordStorageScheme.java                                           |   71 
 opends/src/server/org/opends/server/backends/jeb/IndexQuery.java                                                              |  305 
 opends/tests/unit-tests-testng/src/server/org/opends/server/schema/AuthPasswordEqualityMatchingRuleTest.java                  |    5 
 opends/src/server/org/opends/server/controls/VLVRequestControl.java                                                           |  367 
 opends/src/server/org/opends/server/core/ModifyDNOperationWrapper.java                                                        |    7 
 opends/src/server/org/opends/server/backends/jeb/SortValues.java                                                              |    2 
 opends/src/server/org/opends/server/tasks/DisconnectClientTask.java                                                           |    8 
 opends/src/server/org/opends/server/backends/RootDSEBackend.java                                                              |    5 
 opends/src/messages/messages/jeb.properties                                                                                   |    2 
 opends/src/server/org/opends/server/authorization/dseecompat/AciEffectiveRights.java                                          |    9 
 opends/src/quicksetup/org/opends/quicksetup/ui/CertificateDialog.java                                                         |    3 
 opends/src/server/org/opends/server/tools/LDAPCompare.java                                                                    |   20 
 opends/tests/unit-tests-testng/src/server/org/opends/server/schema/CollationMatchingRuleTest.java                             |   25 
 opends/src/server/org/opends/server/controls/PasswordExpiredControl.java                                                      |  109 
 opends/src/dsml/org/opends/dsml/protocol/DSMLSearchOperation.java                                                             |  539 
 opends/src/server/org/opends/server/extensions/RandomPasswordGenerator.java                                                   |   13 
 opends/src/server/org/opends/server/schema/OctetStringEqualityMatchingRule.java                                               |   36 
 opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/ldap/TestAbandonRequestProtocolOp.java                  |   34 
 opends/src/server/org/opends/server/backends/MemoryBackend.java                                                               |   15 
 opends/src/server/org/opends/server/schema/DistinguishedNameEqualityMatchingRule.java                                         |   72 
 opends/src/server/org/opends/server/protocols/ldap/SearchResultDoneProtocolOp.java                                            |  242 
 opends/src/server/org/opends/server/backends/jeb/EntryCachePreloader.java                                                     |    3 
 opends/src/server/org/opends/server/schema/BinarySyntax.java                                                                  |   14 
 opends/src/server/org/opends/server/schema/CaseIgnoreListSubstringMatchingRule.java                                           |  164 
 opends/src/server/org/opends/server/schema/CaseExactSubstringMatchingRule.java                                                |  154 
 opends/tests/unit-tests-testng/src/server/org/opends/server/schema/AttributeSyntaxTest.java                                   |    4 
 opends/src/server/org/opends/server/crypto/CryptoManagerSync.java                                                             |   13 
 opends/src/server/org/opends/server/replication/plugin/LDAPReplicationDomain.java                                             |   56 
 opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/ldap/TestCompareResponseProtocolOp.java                 |  142 
 opends/src/server/org/opends/server/tools/tasks/TaskEntry.java                                                                |    6 
 opends/src/server/org/opends/server/types/RecordingInputStream.java                                                           |  180 
 opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/LengthBasedPasswordValidatorTestCase.java              |    9 
 opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/jmx/JmxPrivilegeTestCase.java                           |   31 
 opends/src/server/org/opends/server/types/operation/PostOperationExtendedOperation.java                                       |    9 
 opends/src/dsml/org/opends/dsml/protocol/DSMLAddOperation.java                                                                |    8 
 opends/src/server/org/opends/server/protocols/ldap/AddRequestProtocolOp.java                                                  |  166 
 opends/tests/unit-tests-testng/src/server/org/opends/server/replication/GenerationIdTest.java                                 |    6 
 opends/src/server/org/opends/server/core/SearchOperation.java                                                                 |   13 
 opends/src/server/org/opends/server/core/ModifyDNOperationBasis.java                                                          |   14 
 opends/src/messages/src/org/opends/messages/MessageBuilder.java                                                               |   19 
 opends/src/server/org/opends/server/schema/TelephoneNumberSubstringMatchingRule.java                                          |  147 
 opends/src/server/org/opends/server/schema/UTCTimeSyntax.java                                                                 |   17 
 opends/src/server/org/opends/server/types/operation/PostResponseCompareOperation.java                                         |    6 
 opends/src/server/org/opends/server/tools/LDAPToolOptions.java                                                                |   10 
 opends/src/server/org/opends/server/extensions/UniqueCharactersPasswordValidator.java                                         |    8 
 opends/src/server/org/opends/server/loggers/TextAccessLogPublisher.java                                                       |   64 
 opends/src/server/org/opends/server/protocols/ldap/ModifyDNResponseProtocolOp.java                                            |  246 
 opends/src/server/org/opends/server/tools/ExportLDIF.java                                                                     |   67 
 opends/tests/unit-tests-testng/src/server/org/opends/server/plugins/ReferentialIntegrityPluginTestCase.java                   |    8 
 opends/src/server/org/opends/server/controls/PasswordPolicyRequestControl.java                                                |   92 
 opends/src/server/org/opends/server/core/ExtendedOperationBasis.java                                                          |   23 
 opends/src/server/org/opends/server/admin/server/ConfigAddListenerAdaptor.java                                                |    2 
 opends/src/server/org/opends/server/controls/AccountUsableResponseControl.java                                                |  578 
 opends/src/server/org/opends/server/extensions/CancelExtendedOperation.java                                                   |   11 
 opends/src/server/org/opends/server/types/operation/PostOperationBindOperation.java                                           |    7 
 opends/src/server/org/opends/server/extensions/SASLByteChannel.java                                                           |  329 
 opends/src/server/org/opends/server/controls/ProxiedAuthV1Control.java                                                        |  257 
 opends/src/server/org/opends/server/extensions/SaltedSHA512PasswordStorageScheme.java                                         |   71 
 opends/tests/staf-tests/functional-tests/testcases/replication/changelog/changelog.xml                                        |    2 
 opends/src/server/org/opends/server/types/Entry.java                                                                          | 1682 -
 opends/src/server/org/opends/server/extensions/SASLContext.java                                                               |   51 
 opends/src/server/org/opends/server/plugins/PasswordPolicyImportPlugin.java                                                   |   22 
 opends/src/server/org/opends/server/types/RawFilter.java                                                                      |  537 
 opends/src/server/org/opends/server/backends/jeb/SubstringIndexer.java                                                        |    4 
 opends/src/server/org/opends/server/api/PasswordGenerator.java                                                                |    6 
 opends/src/dsml/org/opends/dsml/protocol/DSMLCompareOperation.java                                                            |    8 
 opends/src/server/org/opends/server/types/operation/PreParseExtendedOperation.java                                            |    9 
 opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/PlainSASLMechanismHandlerTestCase.java                 |  155 
 opends/tests/unit-tests-testng/src/server/org/opends/server/core/SearchOperationTestCase.java                                 |  136 
 opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/ldap/TestAddRequestProtocolOp.java                      |  125 
 opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/ldap/TestBindResponseProtocolOp.java                    |  155 
 opends/src/server/org/opends/server/controls/AccountUsableRequestControl.java                                                 |  101 
 opends/src/server/org/opends/server/core/CompareOperation.java                                                                |    5 
 opends/src/server/org/opends/server/schema/CaseExactIA5EqualityMatchingRule.java                                              |   64 
 opends/src/server/org/opends/server/tools/LDAPAuthenticationHandler.java                                                      |  209 
 opends/src/server/org/opends/server/types/RecordingOutputStream.java                                                          |  144 
 opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/WhoAmIExtendedOperationTestCase.java                   |   70 
 opends/src/server/org/opends/server/replication/protocol/DeleteMsg.java                                                       |    6 
 opends/src/server/org/opends/server/controls/MatchedValuesControl.java                                                        |  235 
 opends/tests/unit-tests-testng/src/server/org/opends/server/controls/PersistentSearchControlTest.java                         |  139 
 opends/src/server/org/opends/server/protocols/internal/InternalLDAPInputStream.java                                           |  180 
 opends/src/server/org/opends/server/monitors/BackendMonitor.java                                                              |   17 
 opends/tests/unit-tests-testng/src/server/org/opends/server/core/AddOperationTestCase.java                                    |  462 
 opends/src/server/org/opends/server/config/IntegerConfigAttribute.java                                                        |   31 
 opends/src/server/org/opends/server/extensions/PasswordPolicyStateExtendedOperation.java                                      | 1522 
 opends/src/server/org/opends/server/controls/ServerSideSortRequestControl.java                                                |  614 
 opends/src/server/org/opends/server/extensions/HasSubordinatesVirtualAttributeProvider.java                                   |   19 
 opends/src/server/org/opends/server/protocols/ldap/ModifyRequestProtocolOp.java                                               |  152 
 opends/src/server/org/opends/server/api/AttributeSyntax.java                                                                  |    4 
 opends/tests/unit-tests-testng/src/server/org/opends/server/authorization/dseecompat/TargetTestCase.java                      |    6 
 opends/src/server/org/opends/server/plugins/profiler/ProfilerThread.java                                                      |   22 
 opends/src/server/org/opends/server/extensions/GSSAPISASLMechanismHandler.java                                                |  531 
 opends/src/server/org/opends/server/schema/CollationMatchingRuleFactory.java                                                  | 1309 
 opends/src/server/org/opends/server/types/DN.java                                                                             |  595 
 opends/src/server/org/opends/server/protocols/ldap/LDAPRequestHandler.java                                                    |    5 
 opends/src/server/org/opends/server/schema/UserPasswordExactEqualityMatchingRule.java                                         |  136 
 opends/tests/unit-tests-testng/src/server/org/opends/server/backends/jeb/TestImportJob.java                                   |    9 
 opends/src/server/org/opends/server/protocols/ldap/ExtendedResponseProtocolOp.java                                            |  331 
 opends/src/server/org/opends/server/types/operation/PreParseModifyOperation.java                                              |    1 
 opends/src/server/org/opends/server/types/operation/SearchReferenceSearchOperation.java                                       |    8 
 opends/src/guitools/org/opends/guitools/controlpanel/task/Task.java                                                           |    5 
 opends/src/server/org/opends/server/schema/AbsoluteSubtreeSpecificationSyntax.java                                            |   12 
 opends/src/guitools/org/opends/guitools/controlpanel/ui/nodes/BasicNode.java                                                  |    2 
 opends/src/server/org/opends/server/schema/AuthPasswordSyntax.java                                                            |   21 
 opends/src/server/org/opends/server/extensions/GetConnectionIDExtendedOperation.java                                          |   41 
 opends/src/server/org/opends/server/schema/NumericStringEqualityMatchingRule.java                                             |   55 
 opends/src/server/org/opends/server/authorization/dseecompat/AciContainer.java                                                |   29 
 opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/EntryDNVirtualAttributeProviderTestCase.java           |   51 
 opends/src/server/org/opends/server/controls/PagedResultsControl.java                                                         |  229 
 opends/src/server/org/opends/server/core/PluginConfigManager.java                                                             |    4 
 opends/src/server/org/opends/server/extensions/ExactMatchIdentityMapper.java                                                  |   21 
 opends/src/server/org/opends/server/types/operation/SearchEntrySearchOperation.java                                           |    8 
 opends/src/quicksetup/org/opends/quicksetup/util/InProcessServerController.java                                               |    8 
 opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendSearchOperation.java                             |  133 
 opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/NumSubordinatesVirtualAttributeProviderTestCase.java   |   13 
 opends/src/server/org/opends/server/backends/MonitorBackend.java                                                              |    5 
 opends/tests/unit-tests-testng/src/server/org/opends/server/types/ByteSequenceReaderTest.java                                 |  402 
 opends/src/server/org/opends/server/replication/plugin/HistoricalCsnOrderingMatchingRule.java                                 |   14 
 opends/src/server/org/opends/server/types/EntryEncodeConfig.java                                                              |   37 
 opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/HasSubordinatesVirtualAttributeProviderTestCase.java   |   13 
 opends/src/server/org/opends/server/schema/EnhancedGuideSyntax.java                                                           |    7 
 opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/asn1/ASN1ByteChannelReaderTestCase.java                 |  244 
 opends/src/server/org/opends/server/extensions/ExternalSASLMechanismHandler.java                                              |   71 
 opends/src/server/org/opends/server/schema/OctetStringOrderingMatchingRule.java                                               |   22 
 opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/asn1/ASN1ByteChannelWriterTestCase.java                 |   73 
 opends/tests/unit-tests-testng/src/server/org/opends/server/types/AttributeBuilderTest.java                                   |  112 
 opends/src/server/org/opends/server/protocols/ldap/CompareRequestProtocolOp.java                                              |  220 
 opends/src/server/org/opends/server/schema/SupportedAlgorithmSyntax.java                                                      |    5 
 opends/src/server/org/opends/server/protocols/asn1/ASN1Reader.java                                                            |  380 
 opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/SimilarityBasedPasswordValidatorTestCase.java          |    8 
 opends/src/server/org/opends/server/backends/jeb/importLDIF/Importer.java                                                     |    3 
 opends/src/server/org/opends/server/backends/LDIFBackend.java                                                                 |   19 
 opends/src/server/org/opends/server/extensions/RC4PasswordStorageScheme.java                                                  |   39 
 opends/tests/unit-tests-testng/src/server/org/opends/server/core/networkgroups/NetworkGroupTest.java                          |   15 
 opends/src/server/org/opends/server/util/ServerConstants.java                                                                 |   17 
 opends/src/server/org/opends/server/core/networkgroups/ResourceLimitsPolicyFactory.java                                       |    6 
 opends/tests/unit-tests-testng/src/server/org/opends/server/backends/jeb/TestVLVIndex.java                                    |  200 
 opends/src/server/org/opends/server/extensions/TLSCapableConnection.java                                                      |   21 
 opends/src/server/org/opends/server/replication/server/ReplicationBackend.java                                                |    2 
 opends/tests/unit-tests-testng/src/server/org/opends/server/core/CompareOperationTestCase.java                                |  135 
 opends/src/server/org/opends/server/types/CryptoManager.java                                                                  |   22 
 opends/tests/unit-tests-testng/src/server/org/opends/server/core/WorkflowConfigurationTest.java                               |   18 
 opends/src/server/org/opends/server/core/SearchOperationWrapper.java                                                          |   12 
 opends/src/server/org/opends/server/protocols/ldap/UnbindRequestProtocolOp.java                                               |   53 
 opends/src/server/org/opends/server/protocols/ldap/DeleteResponseProtocolOp.java                                              |  245 
 opends/src/server/org/opends/server/types/ByteSequenceReader.java                                                             |  509 
 opends/src/server/org/opends/server/types/operation/PostResponseExtendedOperation.java                                        |    7 
 opends/src/server/org/opends/server/protocols/jmx/JmxClientConnection.java                                                    |  123 
 opends/src/server/org/opends/server/authorization/dseecompat/AciList.java                                                     |    2 
 opends/tests/unit-tests-testng/src/server/org/opends/server/types/PrivilegeTestCase.java                                      |   11 
 opends/src/server/org/opends/server/api/ExtensibleMatchingRule.java                                                           |   64 
 opends/src/server/org/opends/server/replication/service/ReplicationMonitor.java                                               |   15 
 opends/src/server/org/opends/server/tools/tasks/TaskClient.java                                                               |  118 
 opends/tests/unit-tests-testng/src/server/org/opends/server/crypto/GetSymmetricKeyExtendedOperationTestCase.java              |    7 
 opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendModifyOperation.java                             |  206 
 opends/tests/unit-tests-testng/src/server/org/opends/server/core/OperationTestCase.java                                       |    3 
 opends/tests/unit-tests-testng/src/server/org/opends/server/schema/OrderingMatchingRuleTest.java                              |    9 
 opends/src/server/org/opends/server/extensions/BlowfishPasswordStorageScheme.java                                             |   39 
 opends/src/server/org/opends/server/controls/GetEffectiveRightsRequestControl.java                                            |  287 
 opends/src/server/org/opends/server/replication/plugin/PersistentServerState.java                                             |   21 
 opends/tests/unit-tests-testng/src/server/org/opends/server/tasks/DisconnectClientTaskTestCase.java                           |   41 
 opends/src/server/org/opends/server/schema/SubstringAssertionSyntax.java                                                      |    7 
 opends/src/messages/messages/protocol.properties                                                                              |  161 
 opends/src/server/org/opends/server/core/DeleteOperationBasis.java                                                            |    3 
 opends/src/server/org/opends/server/schema/NumericStringOrderingMatchingRule.java                                             |   71 
 opends/src/server/org/opends/server/extensions/AnonymousSASLMechanismHandler.java                                             |    2 
 opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/CRAMMD5SASLMechanismHandlerTestCase.java               |   20 
 opends/tests/unit-tests-testng/src/server/org/opends/server/types/TestAttributeType.java                                      |   82 
 opends/src/server/org/opends/server/core/ModifyOperation.java                                                                 |    7 
 opends/tests/unit-tests-testng/src/server/org/opends/server/types/ByteStringTest.java                                         |  149 
 opends/src/server/org/opends/server/core/BindOperationWrapper.java                                                            |   16 
 opends/src/server/org/opends/server/protocols/ldap/LDAPClientConnection.java                                                  | 2814 +-
 opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/TestPasswordValidator.java                             |    7 
 opends/src/server/org/opends/server/schema/NumericStringSubstringMatchingRule.java                                            |  165 
 opends/src/server/org/opends/server/controls/EntryChangeNotificationControl.java                                              |  423 
 opends/tests/unit-tests-testng/src/server/org/opends/server/util/TestStaticUtils.java                                         |   10 
 opends/src/server/org/opends/server/tools/LDAPWriter.java                                                                     |  103 
 opends/src/server/org/opends/server/extensions/NumSubordinatesVirtualAttributeProvider.java                                   |   18 
 opends/src/server/org/opends/server/tools/LDAPSearch.java                                                                     |  137 
 opends/tests/unit-tests-testng/src/server/org/opends/server/types/TestAttributeValue.java                                     |  111 
 opends/src/server/org/opends/server/plugins/LastModPlugin.java                                                                |   55 
 opends/src/server/org/opends/server/backends/jeb/EntryIDSetSorter.java                                                        |   16 
 opends/src/server/org/opends/server/monitors/VersionMonitorProvider.java                                                      |   24 
 opends/src/server/org/opends/server/protocols/ldap/LDAPReader.java                                                            | 2977 ++
 opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/ldap/TestDeleteResponseProtocolOp.java                  |  142 
 opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/SaltedSHA1PasswordStorageSchemeTestCase.java           |    5 
 opends/src/server/org/opends/server/authorization/dseecompat/GroupDN.java                                                     |    2 
 opends/src/server/org/opends/server/types/AccountStatusNotification.java                                                      |    4 
 opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/ldap/TestModifyDNRequestProtocolOp.java                 |  139 
 opends/tests/unit-tests-testng/src/server/org/opends/server/types/TestRDN.java                                                |    7 
 opends/tests/unit-tests-testng/src/server/org/opends/quicksetup/TestUtilities.java                                            |   13 
 opends/src/server/org/opends/server/authorization/dseecompat/AciListenerManager.java                                          |    6 
 opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/ldap/TestAddResponseProtocolOp.java                     |  138 
 opends/src/server/org/opends/server/protocols/internal/InternalLDAPOutputStream.java                                          |  533 
 opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendAddOperation.java                                |  153 
 opends/src/server/org/opends/server/controls/LDAPAssertionRequestControl.java                                                 |  198 
 opends/src/server/org/opends/server/plugins/EntryUUIDPlugin.java                                                              |   19 
 opends/src/server/org/opends/server/schema/IntegerEqualityMatchingRule.java                                                   |   61 
 opends/src/server/org/opends/server/tools/StopDS.java                                                                         |   53 
 opends/src/server/org/opends/server/extensions/SMTPAccountStatusNotificationHandler.java                                      |    4 
 opends/src/server/org/opends/server/admin/server/ConfigDeleteListenerAdaptor.java                                             |    2 
 opends/src/server/org/opends/server/extensions/StaticGroup.java                                                               |   11 
 opends/src/server/org/opends/server/backends/SchemaBackend.java                                                               |   68 
 opends/src/server/org/opends/server/replication/common/ServerState.java                                                       |    8 
 opends/src/server/org/opends/server/backends/jeb/JebFormat.java                                                               |  239 
 opends/src/guitools/org/opends/guitools/controlpanel/task/NewEntryTask.java                                                   |    2 
 opends/src/server/org/opends/server/schema/UserPasswordEqualityMatchingRule.java                                              |   65 
 opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/PasswordStorageSchemeTestCase.java                     |   63 
 opends/src/guitools/org/opends/guitools/controlpanel/ui/NewBaseDNPanel.java                                                   |    8 
 opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/asn1/ASN1InputStreamReaderTestCase.java                 |   17 
 opends/src/server/org/opends/server/config/ConfigAttribute.java                                                               |   10 
 opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/ldap/TestSearchProtocolOp.java                          |  334 
 opends/src/server/org/opends/server/config/DNConfigAttribute.java                                                             |   34 
 opends/src/server/org/opends/server/replication/protocol/AddMsg.java                                                          |  137 
 opends/tests/unit-tests-testng/src/server/org/opends/server/schema/AttributeTypeSyntaxTest.java                               |    4 
 opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/ldap/TestModifyRequestProtocolOp.java                   |  118 
 opends/src/server/org/opends/server/protocols/ldap/CompareResponseProtocolOp.java                                             |  245 
 opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/ExternalSASLMechanismHandlerTestCase.java              |   21 
 opends/src/server/org/opends/server/api/PasswordValidator.java                                                                |    5 
 opends/tests/unit-tests-testng/src/server/org/opends/server/types/TestEntry.java                                              |    5 
 opends/src/server/org/opends/server/core/ModifyDNOperation.java                                                               |    8 
 opends/src/server/org/opends/server/config/IntegerWithUnitConfigAttribute.java                                                |   19 
 opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/ldap/TestDeleteRequestProtocolOp.java                   |   53 
 opends/tests/unit-tests-testng/src/server/org/opends/server/replication/server/ReplicationServerTest.java                     |   22 
 opends/src/server/org/opends/server/crypto/GetSymmetricKeyExtendedOperation.java                                              |   55 
 opends/src/server/org/opends/server/backends/task/RecurringTask.java                                                          |   16 
 opends/src/server/org/opends/server/schema/IA5StringSyntax.java                                                               |   11 
 opends/tests/unit-tests-testng/src/server/org/opends/server/types/VirtualAttributeTestCase.java                               |   16 
 opends/src/guitools/org/opends/guitools/controlpanel/ui/SimplifiedViewEntryPanel.java                                         |   18 
 opends/src/server/org/opends/server/schema/CaseIgnoreListEqualityMatchingRule.java                                            |   55 
 opends/src/server/org/opends/server/types/operation/PreParseBindOperation.java                                                |    9 
 opends/src/server/org/opends/server/types/operation/PostResponseDeleteOperation.java                                          |    1 
 opends/src/server/org/opends/server/extensions/EntryUUIDVirtualAttributeProvider.java                                         |   18 
 opends/tests/unit-tests-testng/src/server/org/opends/server/schema/EqualLengthApproximateMatchingRule.java                    |   26 
 opends/src/server/org/opends/server/admin/AdministrationDataSync.java                                                         |  126 
 opends/tests/unit-tests-testng/src/server/org/opends/server/admin/server/DefaultBehaviorTest.java                             |    4 
 opends/src/server/org/opends/server/monitors/SystemInfoMonitorProvider.java                                                   |   25 
 opends/src/server/org/opends/server/schema/MatchingRuleSyntax.java                                                            |   30 
 opends/src/server/org/opends/server/config/ReadOnlyConfigAttribute.java                                                       |   15 
 opends/src/server/org/opends/server/schema/AuthPasswordExactEqualityMatchingRule.java                                         |   60 
 opends/src/server/org/opends/server/config/BooleanConfigAttribute.java                                                        |   21 
 opends/src/server/org/opends/server/extensions/DictionaryPasswordValidator.java                                               |   11 
 opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/ldap/LDAPBinaryOptionTestCase.java                      |   51 
 opends/tests/unit-tests-testng/src/server/org/opends/server/schema/BitStringSyntaxTest.java                                   |    6 
 opends/src/server/org/opends/server/loggers/debug/TextDebugLogPublisher.java                                                  |    6 
 opends/src/server/org/opends/server/types/operation/PreParseCompareOperation.java                                             |    1 
 opends/src/server/org/opends/server/authorization/dseecompat/UserDN.java                                                      |    2 
 opends/src/server/org/opends/server/types/Control.java                                                                        |  141 
 opends/tests/unit-tests-testng/src/server/org/opends/server/monitors/InternalSearchMonitorTestCase.java                       |   11 
 opends/src/server/org/opends/server/core/AddOperation.java                                                                    |    8 
 opends/src/server/org/opends/server/schema/PostalAddressSyntax.java                                                           |    5 
 opends/src/server/org/opends/server/extensions/RedirectingByteChannel.java                                                    |  114 
 opends/tests/unit-tests-testng/src/server/org/opends/server/schema/ConfigurableAttributeSyntaxTest.java                       |    5 
 opends/src/server/org/opends/server/schema/UserPasswordSyntax.java                                                            |   19 
 opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/SubschemaSubentryVirtualAttributeProviderTestCase.java |   70 
 opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/DictionaryPasswordValidatorTestCase.java               |    3 
 opends/src/server/org/opends/server/api/DebugLogPublisher.java                                                                |    7 
 opends/src/server/org/opends/server/backends/jeb/SortValuesSet.java                                                           |   49 
 opends/src/server/org/opends/server/schema/DirectoryStringSyntax.java                                                         |   12 
 opends/src/server/org/opends/server/backends/jeb/EqualityIndexer.java                                                         |    4 
 opends/src/server/org/opends/server/schema/FaxSyntax.java                                                                     |    5 
 opends/src/server/org/opends/server/tools/LDAPDelete.java                                                                     |   22 
 opends/src/server/org/opends/server/api/AccessControlHandler.java                                                             |  315 
 opends/src/server/org/opends/server/schema/CaseExactOrderingMatchingRule.java                                                 |   64 
 opends/src/server/org/opends/server/replication/protocol/ModifyMsg.java                                                       |   25 
 opends/src/server/org/opends/server/admin/ManagedObjectPath.java                                                              |   11 
 opends/src/server/org/opends/server/protocols/ldap/SearchRequestProtocolOp.java                                               |  417 
 opends/src/server/org/opends/server/schema/NameFormSyntax.java                                                                |   19 
 opends/src/server/org/opends/server/protocols/ldap/AddResponseProtocolOp.java                                                 |  245 
 opends/tests/unit-tests-testng/src/server/org/opends/server/backends/GenericBackendTestCase.java                              |   13 
 opends/src/server/org/opends/server/util/LDIFReader.java                                                                      |   70 
 opends/src/server/org/opends/server/core/DefaultCompressedSchema.java                                                         |  341 
 opends/src/server/org/opends/server/extensions/EntryDNVirtualAttributeProvider.java                                           |   25 
 opends/src/server/org/opends/server/schema/CaseExactEqualityMatchingRule.java                                                 |   54 
 opends/src/server/org/opends/server/schema/DirectoryStringFirstComponentEqualityMatchingRule.java                             |   50 
 opends/src/server/org/opends/server/extensions/TLSByteChannel.java                                                            |  400 
 opends/src/server/org/opends/server/backends/jeb/VLVIndex.java                                                                |   53 
 opends/src/server/org/opends/server/monitors/ConnectionHandlerMonitor.java                                                    |   14 
 opends/src/server/org/opends/server/api/IndexQueryFactory.java                                                                |  109 
 opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/RepeatedCharactersPasswordValidatorTestCase.java       |   13 
 opends/src/dsml/org/opends/dsml/protocol/DSMLModifyDNOperation.java                                                           |   25 
 opends/src/server/org/opends/server/extensions/DynamicGroup.java                                                              |    4 
 opends/src/server/org/opends/server/config/JMXMBean.java                                                                      |   32 
 opends/src/server/org/opends/server/protocols/ldap/AbandonRequestProtocolOp.java                                              |   70 
 opends/src/server/org/opends/server/controls/LDAPPostReadRequestControl.java                                                  |  259 
 opends/tests/staf-tests/functional-tests/testcases/aci/aci_targetfilter.xml                                                   |    2 
 opends/src/server/org/opends/server/authorization/dseecompat/Aci.java                                                         |    8 
 opends/tests/unit-tests-testng/src/server/org/opends/server/backends/SchemaTestMatchingRule.java                              |   24 
 opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/ldap/TestBindRequestProtocolOp.java                     |  146 
 opends/src/server/org/opends/server/schema/OIDSyntax.java                                                                     |    7 
 opends/src/server/org/opends/server/backends/task/Task.java                                                                   |   20 
 opends/src/server/org/opends/server/backends/NullBackend.java                                                                 |   84 
 opends/src/server/org/opends/server/protocols/asn1/ASN1Writer.java                                                            |  389 
 opends/src/server/org/opends/server/protocols/ldap/BindResponseProtocolOp.java                                                |  350 
 opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/EntryUUIDVirtualAttributeProviderTestCase.java         |   43 
 opends/src/server/org/opends/server/schema/JPEGSyntax.java                                                                    |    5 
 opends/tests/unit-tests-testng/src/server/org/opends/server/core/networkgroups/MockClientConnection.java                      |   32 
 opends/tests/unit-tests-testng/src/server/org/opends/server/tools/LDAPAuthenticationHandlerTestCase.java                      |  623 
 opends/src/server/org/opends/server/tools/LDIFModify.java                                                                     |    2 
 opends/src/server/org/opends/server/extensions/SHA1PasswordStorageScheme.java                                                 |   50 
 opends/src/server/org/opends/server/schema/PresentationAddressEqualityMatchingRule.java                                       |   47 
 opends/src/server/org/opends/server/api/ApproximateMatchingRule.java                                                          |   11 
 opends/src/server/org/opends/server/extensions/FingerprintCertificateMapper.java                                              |   16 
 opends/src/server/org/opends/server/schema/IntegerSyntax.java                                                                 |   13 
 opends/src/server/org/opends/server/tools/DBTest.java                                                                         |  114 
 opends/tests/unit-tests-testng/src/server/org/opends/server/plugins/ShortCircuitPlugin.java                                   |  212 
 opends/src/server/org/opends/server/schema/IntegerOrderingMatchingRule.java                                                   |  150 
 opends/src/server/org/opends/server/tools/EncodePassword.java                                                                 |   48 
 opends/src/server/org/opends/server/tools/LDAPConnection.java                                                                 |  130 
 opends/tests/unit-tests-testng/src/server/org/opends/server/controls/PasswordControlTest.java                                 |  199 
 opends/tests/unit-tests-testng/src/server/org/opends/server/plugins/DisconnectClientPlugin.java                               |  155 
 opends/src/server/org/opends/server/backends/jeb/DN2URI.java                                                                  |   23 
 opends/src/server/org/opends/server/extensions/SaltedSHA384PasswordStorageScheme.java                                         |   71 
 opends/src/server/org/opends/server/monitors/ClientConnectionMonitorProvider.java                                             |    9 
 opends/src/server/org/opends/server/schema/CertificateListSyntax.java                                                         |    5 
 opends/src/server/org/opends/server/extensions/SubjectDNToUserAttributeCertificateMapper.java                                 |   17 
 opends/src/server/org/opends/server/protocols/ldap/BindRequestProtocolOp.java                                                 |  315 
 opends/src/server/org/opends/server/schema/UUIDOrderingMatchingRule.java                                                      |  114 
 opends/src/server/org/opends/server/types/AttributeValues.java                                                                |  424 
 opends/src/server/org/opends/server/controls/PasswordPolicyResponseControl.java                                               |  332 
 opends/src/server/org/opends/server/tools/ImportLDIF.java                                                                     |   81 
 opends/src/server/org/opends/server/core/networkgroups/NetworkGroup.java                                                      |    2 
 opends/src/server/org/opends/server/protocols/ldap/LDAPFilter.java                                                            |  213 
 opends/src/server/org/opends/server/schema/GeneralizedTimeOrderingMatchingRule.java                                           |   40 
 opends/src/server/org/opends/server/schema/AuthPasswordEqualityMatchingRule.java                                              |   60 
 opends/src/server/org/opends/server/replication/protocol/MonitorMsg.java                                                      |  290 
 opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/internal/InternalClientConnectionTestCase.java          |  103 
 opends/src/server/org/opends/server/util/SizeLimitInputStream.java                                                            |  182 
 opends/src/server/org/opends/server/schema/WordEqualityMatchingRule.java                                                      |   45 
 opends/src/server/org/opends/server/tasks/TaskUtils.java                                                                      |   36 
 opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/asn1/ASN1ReaderTestCase.java                            |  804 
 opends/src/server/org/opends/server/extensions/FileSystemEntryCache.java                                                      |   48 
 opends/src/server/org/opends/server/tools/LDIFDiff.java                                                                       |   19 
 opends/src/server/org/opends/server/types/IntermediateResponse.java                                                           |   10 
 opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/ExactMatchIdentityMapperTestCase.java                  |   48 
 opends/tests/unit-tests-testng/src/server/org/opends/server/types/SearchFilterTests.java                                      |    9 
 opends/src/server/org/opends/server/types/RawAttribute.java                                                                   |  130 
 opends/src/server/org/opends/server/protocols/asn1/ASN1InputStreamReader.java                                                 |  793 
 opends/src/server/org/opends/server/schema/ProtocolInformationEqualityMatchingRule.java                                       |   47 
 opends/src/server/org/opends/server/authorization/dseecompat/AciHandler.java                                                  |   27 
 opends/src/server/org/opends/server/types/NameForm.java                                                                       |    3 
 opends/src/server/org/opends/server/protocols/ldap/ModifyResponseProtocolOp.java                                              |  248 
 opends/src/server/org/opends/server/types/ByteStringBuilder.java                                                              | 1155 +
 opends/src/server/org/opends/server/schema/AttributeTypeSyntax.java                                                           |    8 
 opends/src/server/org/opends/server/schema/NameAndOptionalUIDSyntax.java                                                      |    6 
 opends/src/server/org/opends/server/api/VirtualAttributeProvider.java                                                         |   12 
 opends/src/server/org/opends/server/replication/plugin/Historical.java                                                        |   28 
 opends/src/server/org/opends/server/backends/jeb/EntryContainer.java                                                          |  594 
 opends/src/server/org/opends/server/schema/BitStringEqualityMatchingRule.java                                                 |   65 
 opends/src/server/org/opends/server/authorization/dseecompat/PatternDN.java                                                   |   15 
 opends/src/server/org/opends/server/backends/TrustStoreBackend.java                                                           |   44 
 opends/src/server/org/opends/server/crypto/CryptoManagerImpl.java                                                             |   63 
 opends/src/server/org/opends/server/extensions/PlainSASLMechanismHandler.java                                                 |    5 
 opends/src/server/org/opends/server/plugins/UniqueAttributePlugin.java                                                        |   16 
 opends/src/server/org/opends/server/protocols/ldap/LDAPAttribute.java                                                         |   54 
 opends/src/server/org/opends/server/extensions/SaltedMD5PasswordStorageScheme.java                                            |   71 
 opends/src/server/org/opends/server/schema/TelexNumberSyntax.java                                                             |    7 
 opends/src/server/org/opends/server/schema/PresentationAddressSyntax.java                                                     |    5 
 opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/ldap/TestUnbindRequestProtocolOp.java                   |   13 
 opends/src/guitools/org/opends/guitools/controlpanel/task/ModifyEntryTask.java                                                |   21 
 opends/src/server/org/opends/server/authorization/dseecompat/PatternRDN.java                                                  |    7 
 opends/src/server/org/opends/server/types/operation/PreOperationExtendedOperation.java                                        |    7 
 opends/tests/unit-tests-testng/src/server/org/opends/server/backends/jeb/TestVerifyJob.java                                   |   12 
 opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/internal/InternalSearchOperationTestCase.java           |   25 
 opends/src/server/org/opends/server/protocols/asn1/ASN1ByteChannelWriter.java                                                 |  318 
 opends/tests/unit-tests-testng/src/server/org/opends/server/core/PluginConfigManagerTestCase.java                             |    2 
 opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/UserDefinedVirtualAttributeProviderTestCase.java       |   24 
 opends/src/server/org/opends/server/core/SearchOperationBasis.java                                                            |   11 
 opends/src/server/org/opends/server/schema/CertificatePairSyntax.java                                                         |    5 
 opends/src/server/org/opends/server/tools/LDAPPasswordModify.java                                                             |   77 
 opends/tests/unit-tests-testng/src/server/org/opends/server/controls/VLVControlTestCase.java                                  |  258 
 opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/CharacterSetPasswordValidatorTestCase.java             |    3 
 opends/tests/unit-tests-testng/src/server/org/opends/server/core/DeleteOperationTestCase.java                                 |  159 
 opends/src/server/org/opends/server/schema/CaseIgnoreIA5EqualityMatchingRule.java                                             |   64 
 opends/src/server/org/opends/server/api/EqualityMatchingRule.java                                                             |   54 
 opends/src/server/org/opends/server/core/GroupManager.java                                                                    |    3 
 opends/src/server/org/opends/server/extensions/AESPasswordStorageScheme.java                                                  |   39 
 opends/src/server/org/opends/server/extensions/UserAttributeNotificationMessageTemplateElement.java                           |    2 
 opends/tests/unit-tests-testng/src/server/org/opends/server/plugins/LastModPluginTestCase.java                                |    9 
 opends/src/server/org/opends/server/util/StaticUtils.java                                                                     |  512 
 opends/tests/unit-tests-testng/src/server/org/opends/server/replication/ProtocolWindowTest.java                               |   23 
 opends/src/server/org/opends/server/tools/LDAPModify.java                                                                     |  182 
 opends/tests/unit-tests-testng/src/server/org/opends/server/types/TestDN.java                                                 |    6 
 opends/tests/unit-tests-testng/src/server/org/opends/server/replication/plugin/HistoricalCsnOrderingTest.java                 |    9 
 opends/tests/unit-tests-testng/src/server/org/opends/server/core/ModifyOperationTestCase.java                                 |  655 
 opends/tests/unit-tests-testng/src/server/org/opends/server/util/TestLDIFReader.java                                          |   36 
 opends/src/server/org/opends/server/controls/ProxiedAuthV2Control.java                                                        |  237 
 opends/src/server/org/opends/server/extensions/Base64PasswordStorageScheme.java                                               |   36 
 opends/src/server/org/opends/server/protocols/ldap/ModifyDNRequestProtocolOp.java                                             |  249 
 opends/tests/staf-tests/functional-tests/testcases/dsml/dsml_test.xml                                                         |    2 
 opends/src/server/org/opends/server/protocols/ldap/ProtocolOp.java                                                            |  149 
 opends/src/server/org/opends/server/protocols/asn1/ByteSequenceOutputStream.java                                              |  115 
 opends/src/server/org/opends/server/loggers/TextAuditLogPublisher.java                                                        |   21 
 opends/tests/unit-tests-testng/src/server/org/opends/server/backends/jeb/TestJebFormat.java                                   |  305 
 opends/src/server/org/opends/server/types/ObjectClass.java                                                                    |    2 
 opends/src/server/org/opends/server/schema/UUIDSyntax.java                                                                    |    7 
 opends/tests/unit-tests-testng/src/server/org/opends/server/tasks/DummyTask.java                                              |    2 
 opends/src/server/org/opends/server/extensions/RepeatedCharactersPasswordValidator.java                                       |    8 
 opends/tests/unit-tests-testng/src/server/org/opends/server/backends/jeb/TestBackendImpl.java                                 |   26 
 opends/tests/staf-tests/functional-tests/testcases/aci/multiple_aci_tests.xml                                                 |    2 
 opends/src/guitools/org/opends/guitools/controlpanel/util/Utilities.java                                                      |   11 
 opends/tests/unit-tests-testng/src/server/org/opends/server/api/PasswordValidatorTestCase.java                                |  173 
 opends/src/server/org/opends/server/backends/jeb/ID2Entry.java                                                                |  276 
 opends/src/server/org/opends/server/types/AttributeValue.java                                                                 |  349 
 opends/src/server/org/opends/server/schema/DITContentRuleSyntax.java                                                          |   19 
 opends/src/server/org/opends/server/types/operation/PluginOperation.java                                                      |   19 
 opends/src/server/org/opends/server/extensions/CryptPasswordStorageScheme.java                                                |   42 
 opends/src/server/org/opends/server/types/CommonSchemaElements.java                                                           |   19 
 opends/src/server/org/opends/server/types/operation/PostResponseAddOperation.java                                             |    9 
 opends/tests/unit-tests-testng/src/server/org/opends/server/core/IdleTimeLimitTestCase.java                                   |   48 
 opends/src/server/org/opends/server/backends/jeb/JEExtensibleIndexer.java                                                     |    9 
 opends/src/guitools/org/opends/guitools/controlpanel/ui/NewVLVIndexPanel.java                                                 |   11 
 opends/src/server/org/opends/server/backends/jeb/AttributeIndex.java                                                          |   21 
 opends/src/server/org/opends/server/api/MatchingRule.java                                                                     |  154 
 opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/IsMemberOfVirtualAttributeProviderTestCase.java        |   79 
 opends/src/server/org/opends/server/extensions/ConnectionSecurityProvider.java                                                |   81 
 opends/tests/unit-tests-testng/src/server/org/opends/server/core/TestModifyDNOperation.java                                   |  208 
 opends/src/server/org/opends/server/core/SchemaConfigManager.java                                                             |   12 
 opends/src/server/org/opends/server/loggers/debug/TraceSettings.java                                                          |   55 
 opends/src/server/org/opends/server/schema/GeneralizedTimeEqualityMatchingRule.java                                           |   29 
 opends/src/dsml/org/opends/dsml/protocol/DSMLModifyOperation.java                                                             |    8 
 opends/src/server/org/opends/server/types/ByteSequence.java                                                                   |  353 
 opends/src/server/org/opends/server/schema/OctetStringSyntax.java                                                             |    5 
 opends/src/server/org/opends/server/types/operation/PostResponseModifyDNOperation.java                                        |    7 
 opends/src/server/org/opends/server/schema/ObjectIdentifierFirstComponentEqualityMatchingRule.java                            |   44 
 opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendModifyDNOperation.java                           |  135 
 opends/src/server/org/opends/server/admin/Reference.java                                                                      |    2 
 opends/src/server/org/opends/server/protocols/ldap/LDAPMessage.java                                                           |  172 
 opends/src/server/org/opends/server/tools/makeldif/TemplateEntry.java                                                         |   18 
 opends/tests/unit-tests-testng/src/server/org/opends/server/replication/plugin/ValueInfoTest.java                             |    9 
 opends/src/dsml/org/opends/dsml/protocol/DSMLDeleteOperation.java                                                             |    4 
 opends/src/server/org/opends/server/tools/BackUpDB.java                                                                       |   51 
 opends/src/server/org/opends/server/controls/LDAPPostReadResponseControl.java                                                 |  227 
 opends/src/server/org/opends/server/schema/CertificateSyntax.java                                                             |    5 
 opends/src/server/org/opends/server/schema/RFC3672SubtreeSpecificationSyntax.java                                             |   13 
 opends/src/server/org/opends/server/extensions/StartTLSExtendedOperation.java                                                 |   23 
 opends/tests/unit-tests-testng/src/server/org/opends/server/plugins/PasswordPolicyImportPluginTestCase.java                   |    6 
 opends/src/server/org/opends/server/backends/task/TaskBackend.java                                                            |    3 
 opends/src/server/org/opends/server/types/DITStructureRule.java                                                               |    2 
 opends/src/server/org/opends/server/types/operation/PreParseAddOperation.java                                                 |    1 
 opends/src/server/org/opends/server/extensions/MemberVirtualAttributeProvider.java                                            |    3 
 opends/src/server/org/opends/server/plugins/SevenBitCleanPlugin.java                                                          |   23 
 opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/asn1/ASN1WriterTestCase.java                            |  709 
 opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/ldap/LdapTestCase.java                                  |   49 
 opends/src/server/org/opends/server/extensions/TripleDESPasswordStorageScheme.java                                            |   39 
 opends/src/server/org/opends/server/schema/LDAPSyntaxDescriptionSyntax.java                                                   |   30 
 opends/src/server/org/opends/server/schema/TeletexTerminalIdentifierSyntax.java                                               |    7 
 opends/src/server/org/opends/server/schema/MatchingRuleUseSyntax.java                                                         |   17 
 opends/src/server/org/opends/server/core/UnbindOperationBasis.java                                                            |    4 
 opends/src/server/org/opends/server/api/OrderingMatchingRule.java                                                             |   13 
 opends/src/server/org/opends/server/admin/AdministrationConnector.java                                                        |  447 
 opends/src/server/org/opends/server/types/AttributeBuilder.java                                                               |   10 
 opends/src/server/org/opends/server/core/ExtendedOperation.java                                                               |    9 
 opends/src/server/org/opends/server/types/operation/PostResponseBindOperation.java                                            |    5 
 opends/src/server/org/opends/server/types/Attributes.java                                                                     |    2 
 opends/src/server/org/opends/server/core/PasswordPolicy.java                                                                  |    9 
 opends/src/guitools/org/opends/guitools/controlpanel/ui/JavaPropertiesPanel.java                                              |   30 
 opends/src/server/org/opends/server/controls/MatchedValuesFilter.java                                                         |  438 
 opends/src/server/org/opends/server/schema/TelephoneNumberSyntax.java                                                         |    6 
 opends/src/server/org/opends/server/loggers/debug/DebugTracer.java                                                            |   12 
 opends/src/server/org/opends/server/protocols/asn1/ASN1.java                                                                  |  302 
 opends/src/server/org/opends/server/schema/CaseExactIA5SubstringMatchingRule.java                                             |  164 
 opends/src/server/org/opends/server/monitors/StackTraceMonitorProvider.java                                                   |   11 
 opends/src/server/org/opends/server/controls/ControlDecoder.java                                                              |   68 
 opends/src/server/org/opends/server/types/operation/PreParseModifyDNOperation.java                                            |    1 
 opends/src/server/org/opends/server/api/ExtensibleIndexer.java                                                                |   72 
 opends/src/server/org/opends/server/backends/BackupBackend.java                                                               |   60 
 opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/ldap/TestSearchResultEntryProtocolOp.java               |   76 
 opends/src/server/org/opends/server/api/PasswordStorageScheme.java                                                            |   23 
 opends/src/server/org/opends/server/core/BindOperationBasis.java                                                              |   39 
 opends/src/server/org/opends/server/schema/BooleanEqualityMatchingRule.java                                                   |   63 
 opends/src/server/org/opends/server/tasks/BackupTask.java                                                                     |    3 
 opends/src/server/org/opends/server/schema/ObjectIdentifierEqualityMatchingRule.java                                          |   48 
 opends/src/server/org/opends/server/types/ByteString.java                                                                     |  748 
 opends/src/server/org/opends/server/tools/RestoreDB.java                                                                      |   24 
 opends/src/server/org/opends/server/schema/FaxNumberSyntax.java                                                               |    7 
 opends/src/server/org/opends/server/schema/AciSyntax.java                                                                     |    4 
 opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/ldap/TestCompareRequestProtocolOp.java                  |  112 
 opends/tests/unit-tests-testng/src/server/org/opends/server/types/ByteStringBuilderTest.java                                  |  246 
 opends/src/server/org/opends/server/core/DirectoryServer.java                                                                 |  133 
 opends/src/server/org/opends/server/extensions/PasswordModifyExtendedOperation.java                                           |   82 
 opends/src/server/org/opends/server/util/LDIFWriter.java                                                                      |   72 
 opends/src/server/org/opends/server/api/ClientConnection.java                                                                 |   48 
 /dev/null                                                                                                                     |  530 
 opends/src/server/org/opends/server/monitors/MemoryUsageMonitorProvider.java                                                  |   19 
 opends/src/server/org/opends/server/protocols/asn1/ASN1ByteSequenceReader.java                                                |  486 
 opends/src/guitools/org/opends/guitools/controlpanel/ui/NewIndexPanel.java                                                    |    4 
 opends/src/server/org/opends/server/schema/CaseIgnoreEqualityMatchingRule.java                                                |   83 
 opends/src/server/org/opends/server/authorization/dseecompat/UserAttr.java                                                    |    4 
 654 files changed, 36,378 insertions(+), 32,203 deletions(-)

diff --git a/opends/src/dsml/org/opends/dsml/protocol/DSMLAddOperation.java b/opends/src/dsml/org/opends/dsml/protocol/DSMLAddOperation.java
index bd69f7b..0f1e8ca 100644
--- a/opends/src/dsml/org/opends/dsml/protocol/DSMLAddOperation.java
+++ b/opends/src/dsml/org/opends/dsml/protocol/DSMLAddOperation.java
@@ -32,13 +32,13 @@
 
 import org.opends.messages.Message;
 import org.opends.server.protocols.asn1.ASN1Exception;
-import org.opends.server.protocols.asn1.ASN1OctetString;
 import org.opends.server.protocols.ldap.AddRequestProtocolOp;
 import org.opends.server.protocols.ldap.AddResponseProtocolOp;
 import org.opends.server.protocols.ldap.LDAPAttribute;
 import org.opends.server.protocols.ldap.LDAPMessage;
 import org.opends.server.protocols.ldap.ProtocolOp;
 import org.opends.server.tools.LDAPConnection;
+import org.opends.server.types.ByteString;
 import org.opends.server.types.LDAPException;
 import org.opends.server.types.RawAttribute;
 
@@ -86,17 +86,17 @@
     LDAPResult addResponse = objFactory.createLDAPResult();
     addResponse.setRequestID(addRequest.getRequestID());
 
-    ASN1OctetString dnStr = new ASN1OctetString(addRequest.getDn());
+    ByteString dnStr = ByteString.valueOf(addRequest.getDn());
     ArrayList<RawAttribute> attributes = new ArrayList<RawAttribute>();
 
     List<DsmlAttr> addList = addRequest.getAttr();
     for(DsmlAttr attr : addList)
     {
-      ArrayList<ASN1OctetString> values = new ArrayList<ASN1OctetString>();
+      ArrayList<ByteString> values = new ArrayList<ByteString>();
       List<String> vals = attr.getValue();
       for(String val : vals)
       {
-        values.add(new ASN1OctetString(val));
+        values.add(ByteString.valueOf(val));
       }
       LDAPAttribute ldapAttribute = new LDAPAttribute(attr.getName(), values);
       attributes.add(ldapAttribute);
diff --git a/opends/src/dsml/org/opends/dsml/protocol/DSMLCompareOperation.java b/opends/src/dsml/org/opends/dsml/protocol/DSMLCompareOperation.java
index b5a581d..00cdb82 100644
--- a/opends/src/dsml/org/opends/dsml/protocol/DSMLCompareOperation.java
+++ b/opends/src/dsml/org/opends/dsml/protocol/DSMLCompareOperation.java
@@ -32,12 +32,12 @@
 
 import org.opends.messages.Message;
 import org.opends.server.protocols.asn1.ASN1Exception;
-import org.opends.server.protocols.asn1.ASN1OctetString;
 import org.opends.server.protocols.ldap.CompareRequestProtocolOp;
 import org.opends.server.protocols.ldap.CompareResponseProtocolOp;
 import org.opends.server.protocols.ldap.LDAPMessage;
 import org.opends.server.protocols.ldap.ProtocolOp;
 import org.opends.server.tools.LDAPConnection;
+import org.opends.server.types.ByteString;
 import org.opends.server.types.LDAPException;
 
 
@@ -87,10 +87,8 @@
     // Read the attribute name and value for the compare request.
     AttributeValueAssertion attrValAssertion = compareRequest.getAssertion();
     String attrName = attrValAssertion.getName();
-    ASN1OctetString attrValue =
-      new ASN1OctetString(attrValAssertion.getValue());
-
-    ASN1OctetString dnStr = new ASN1OctetString(compareRequest.getDn());
+    ByteString attrValue = ByteString.valueOf(attrValAssertion.getValue());
+    ByteString dnStr = ByteString.valueOf(compareRequest.getDn());
 
     // Create and send the LDAP compare request to the server.
     ProtocolOp op = new CompareRequestProtocolOp(dnStr, attrName, attrValue);
diff --git a/opends/src/dsml/org/opends/dsml/protocol/DSMLDeleteOperation.java b/opends/src/dsml/org/opends/dsml/protocol/DSMLDeleteOperation.java
index b8811cd..cff2add 100644
--- a/opends/src/dsml/org/opends/dsml/protocol/DSMLDeleteOperation.java
+++ b/opends/src/dsml/org/opends/dsml/protocol/DSMLDeleteOperation.java
@@ -30,12 +30,12 @@
 
 import org.opends.messages.Message;
 import org.opends.server.protocols.asn1.ASN1Exception;
-import org.opends.server.protocols.asn1.ASN1OctetString;
 import org.opends.server.protocols.ldap.DeleteRequestProtocolOp;
 import org.opends.server.protocols.ldap.DeleteResponseProtocolOp;
 import org.opends.server.protocols.ldap.LDAPMessage;
 import org.opends.server.protocols.ldap.ProtocolOp;
 import org.opends.server.tools.LDAPConnection;
+import org.opends.server.types.ByteString;
 import org.opends.server.types.DN;
 import org.opends.server.types.LDAPException;
 
@@ -88,7 +88,7 @@
     delResponse.setRequestID(deleteRequest.getRequestID());
 
     // Create and send the LDAP delete request to the server.
-    ASN1OctetString dnStr = new ASN1OctetString(deleteRequest.getDn());
+    ByteString dnStr = ByteString.valueOf(deleteRequest.getDn());
     ProtocolOp op = new DeleteRequestProtocolOp(dnStr);
     LDAPMessage msg = new LDAPMessage(DSMLServlet.nextMessageID(), op);
     connection.getLDAPWriter().writeMessage(msg);
diff --git a/opends/src/dsml/org/opends/dsml/protocol/DSMLExtendedOperation.java b/opends/src/dsml/org/opends/dsml/protocol/DSMLExtendedOperation.java
index d8c5fad..b21dbcf 100644
--- a/opends/src/dsml/org/opends/dsml/protocol/DSMLExtendedOperation.java
+++ b/opends/src/dsml/org/opends/dsml/protocol/DSMLExtendedOperation.java
@@ -32,12 +32,12 @@
 
 import org.opends.messages.Message;
 import org.opends.server.protocols.asn1.ASN1Exception;
-import org.opends.server.protocols.asn1.ASN1OctetString;
 import org.opends.server.protocols.ldap.ExtendedRequestProtocolOp;
 import org.opends.server.protocols.ldap.ExtendedResponseProtocolOp;
 import org.opends.server.protocols.ldap.LDAPMessage;
 import org.opends.server.protocols.ldap.ProtocolOp;
 import org.opends.server.tools.LDAPConnection;
+import org.opends.server.types.ByteString;
 import org.opends.server.types.LDAPException;
 
 
@@ -86,7 +86,7 @@
 
     String requestName = extendedRequest.getRequestName();
     Object value = extendedRequest.getRequestValue();
-    ASN1OctetString asnValue = new ASN1OctetString(value.toString());
+    ByteString asnValue = ByteString.valueOf(value.toString());
 
     // Create and send the LDAP request to the server.
     ProtocolOp op = new ExtendedRequestProtocolOp(requestName, asnValue);
diff --git a/opends/src/dsml/org/opends/dsml/protocol/DSMLModifyDNOperation.java b/opends/src/dsml/org/opends/dsml/protocol/DSMLModifyDNOperation.java
index 5a58f20..433a59f 100644
--- a/opends/src/dsml/org/opends/dsml/protocol/DSMLModifyDNOperation.java
+++ b/opends/src/dsml/org/opends/dsml/protocol/DSMLModifyDNOperation.java
@@ -33,11 +33,11 @@
 import org.opends.messages.Message;
 import org.opends.server.tools.LDAPConnection;
 import org.opends.server.protocols.asn1.ASN1Exception;
-import org.opends.server.protocols.asn1.ASN1OctetString;
 import org.opends.server.protocols.ldap.LDAPMessage;
 import org.opends.server.protocols.ldap.ModifyDNRequestProtocolOp;
 import org.opends.server.protocols.ldap.ModifyDNResponseProtocolOp;
 import org.opends.server.protocols.ldap.ProtocolOp;
+import org.opends.server.types.ByteString;
 import org.opends.server.types.LDAPException;
 
 
@@ -84,22 +84,21 @@
   {
     LDAPResult modDNResponse = objFactory.createLDAPResult();
     modDNResponse.setRequestID(modifyDNRequest.getRequestID());
-
-    ASN1OctetString dnStr = new ASN1OctetString(modifyDNRequest.getDn());
-
+    ByteString dnStr = ByteString.valueOf(modifyDNRequest.getDn());
     ProtocolOp op = null;
 
-    if(modifyDNRequest.getNewSuperior() != null)
+    if (modifyDNRequest.getNewSuperior() != null)
     {
-      op = new ModifyDNRequestProtocolOp(dnStr,
-    new ASN1OctetString(modifyDNRequest.getNewrdn()),
-    modifyDNRequest.isDeleteoldrdn(),
-    new ASN1OctetString(modifyDNRequest.getNewSuperior()));
-    } else
+      op = new ModifyDNRequestProtocolOp(dnStr, ByteString
+          .valueOf(modifyDNRequest.getNewrdn()), modifyDNRequest
+          .isDeleteoldrdn(), ByteString.valueOf(modifyDNRequest
+          .getNewSuperior()));
+    }
+    else
     {
-      op = new ModifyDNRequestProtocolOp(dnStr,
-    new ASN1OctetString(modifyDNRequest.getNewrdn()),
-    modifyDNRequest.isDeleteoldrdn());
+      op = new ModifyDNRequestProtocolOp(dnStr, ByteString
+          .valueOf(modifyDNRequest.getNewrdn()), modifyDNRequest
+          .isDeleteoldrdn());
     }
 
     // Create and send the LDAP request to the server.
diff --git a/opends/src/dsml/org/opends/dsml/protocol/DSMLModifyOperation.java b/opends/src/dsml/org/opends/dsml/protocol/DSMLModifyOperation.java
index 578fc0d..17f2682 100644
--- a/opends/src/dsml/org/opends/dsml/protocol/DSMLModifyOperation.java
+++ b/opends/src/dsml/org/opends/dsml/protocol/DSMLModifyOperation.java
@@ -34,7 +34,6 @@
 
 import org.opends.messages.Message;
 import org.opends.server.protocols.asn1.ASN1Exception;
-import org.opends.server.protocols.asn1.ASN1OctetString;
 import org.opends.server.protocols.ldap.LDAPAttribute;
 import org.opends.server.protocols.ldap.LDAPMessage;
 import org.opends.server.protocols.ldap.LDAPModification;
@@ -42,6 +41,7 @@
 import org.opends.server.protocols.ldap.ModifyResponseProtocolOp;
 import org.opends.server.protocols.ldap.ProtocolOp;
 import org.opends.server.tools.LDAPConnection;
+import org.opends.server.types.ByteString;
 import org.opends.server.types.LDAPException;
 import org.opends.server.types.ModificationType;
 import org.opends.server.types.RawModification;
@@ -109,12 +109,12 @@
 
       // Read the attribute name and values.
       String attrType = attr.getName();
-      ArrayList<ASN1OctetString> values = new ArrayList<ASN1OctetString> ();
+      ArrayList<ByteString> values = new ArrayList<ByteString> ();
 
       List<String> vals = attr.getValue();
       for(String val : vals)
       {
-        values.add(new ASN1OctetString(val));
+        values.add(ByteString.valueOf(val));
       }
       LDAPAttribute ldapAttr = new LDAPAttribute(attrType, values);
 
@@ -123,7 +123,7 @@
 
     }
 
-    ASN1OctetString dnStr = new ASN1OctetString(modifyRequest.getDn());
+    ByteString dnStr = ByteString.valueOf(modifyRequest.getDn());
 
     // Create and send the LDAP request to the server.
     ProtocolOp op = new ModifyRequestProtocolOp(dnStr, modifications);
diff --git a/opends/src/dsml/org/opends/dsml/protocol/DSMLSearchOperation.java b/opends/src/dsml/org/opends/dsml/protocol/DSMLSearchOperation.java
index ffa9b75..171be52 100644
--- a/opends/src/dsml/org/opends/dsml/protocol/DSMLSearchOperation.java
+++ b/opends/src/dsml/org/opends/dsml/protocol/DSMLSearchOperation.java
@@ -25,25 +25,26 @@
  *      Copyright 2006-2008 Sun Microsystems, Inc.
  */
 package org.opends.dsml.protocol;
+
+
+
 import org.opends.messages.Message;
 
-
-
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.LinkedHashSet;
 import java.util.LinkedList;
 import java.util.List;
+
 import javax.xml.bind.JAXBElement;
+
 import org.opends.server.protocols.asn1.ASN1Exception;
-import org.opends.server.protocols.asn1.ASN1OctetString;
 import org.opends.server.protocols.ldap.LDAPAttribute;
 import org.opends.server.protocols.ldap.LDAPConstants;
 import org.opends.server.protocols.ldap.LDAPFilter;
 import org.opends.server.protocols.ldap.LDAPMessage;
 import org.opends.server.protocols.ldap.SearchRequestProtocolOp;
 import org.opends.server.protocols.ldap.SearchResultEntryProtocolOp;
-import org.opends.server.protocols.ldap.SearchResultReferenceProtocolOp;
 import org.opends.server.protocols.ldap.SearchResultDoneProtocolOp;
 import org.opends.server.tools.LDAPConnection;
 import org.opends.server.types.ByteString;
@@ -55,17 +56,21 @@
 
 
 /**
- * This class provides the functionality for the performing an
- * LDAP SEARCH operation based on the specified DSML request.
+ * This class provides the functionality for the performing an LDAP
+ * SEARCH operation based on the specified DSML request.
  */
 public class DSMLSearchOperation
 {
+
   private LDAPConnection connection;
 
+
+
   /**
    * Create the instance with the specified connection.
    *
-   * @param connection    The LDAP connection to send the request on.
+   * @param connection
+   *          The LDAP connection to send the request on.
    */
 
   public DSMLSearchOperation(LDAPConnection connection)
@@ -73,301 +78,381 @@
     this.connection = connection;
   }
 
+
+
   /**
-   * Returns a new AND search filter with the provided filter components.
+   * Returns a new AND search filter with the provided filter
+   * components.
    *
-   * @param filterSet The filter components for this filter
-   *
-   * @return a new AND search filter with the provided filter components.
-   *
-   * @throws LDAPException an LDAPException is thrown if the creation of a
-   *                       filter component fails.
+   * @param filterSet
+   *          The filter components for this filter
+   * @return a new AND search filter with the provided filter
+   *         components.
+   * @throws LDAPException
+   *           an LDAPException is thrown if the creation of a filter
+   *           component fails.
    */
   private static LDAPFilter createANDFilter(FilterSet filterSet)
-          throws LDAPException {
+      throws LDAPException
+  {
     List<JAXBElement<?>> list = filterSet.getFilterGroup();
     ArrayList<RawFilter> filters = new ArrayList<RawFilter>(list.size());
 
-    for(JAXBElement<?> filter : list) {
+    for (JAXBElement<?> filter : list)
+    {
       filters.add(createFilter(filter));
     }
     return LDAPFilter.createANDFilter(filters);
   }
 
+
+
   /**
-   * Returns a new Approximate search filter with the provided information.
+   * Returns a new Approximate search filter with the provided
+   * information.
    *
-   * @param ava the attribute value assertion for this approximate filter.
-   *
-   * @return a new Approximate search filter with the provided information.
+   * @param ava
+   *          the attribute value assertion for this approximate
+   *          filter.
+   * @return a new Approximate search filter with the provided
+   *         information.
    */
   private static LDAPFilter createApproximateFilter(AttributeValueAssertion ava)
   {
-    return LDAPFilter.createApproximateFilter(ava.getName(),
-                                           new ASN1OctetString(ava.getValue()));
+    return LDAPFilter.createApproximateFilter(ava.getName(), ByteString
+        .valueOf(ava.getValue()));
   }
 
+
+
   /**
-   * Returns a new Equality search filter with the provided information.
+   * Returns a new Equality search filter with the provided
+   * information.
    *
-   * @param ava the attribute value assertion for this Equality filter.
-   *
-   * @return a new Equality search filter with the provided information.
+   * @param ava
+   *          the attribute value assertion for this Equality filter.
+   * @return a new Equality search filter with the provided
+   *         information.
    */
-  private static LDAPFilter createEqualityFilter(AttributeValueAssertion ava) {
-    return LDAPFilter.createEqualityFilter(ava.getName(),
-                                          new ASN1OctetString(ava.getValue()));
+  private static LDAPFilter createEqualityFilter(AttributeValueAssertion ava)
+  {
+    return LDAPFilter.createEqualityFilter(ava.getName(), ByteString
+        .valueOf(ava.getValue()));
   }
 
+
+
   /**
-   * Returns a new Extensible search filter with the provided information.
+   * Returns a new Extensible search filter with the provided
+   * information.
    *
-   * @param mra the matching rule assertion for this Extensible filter.
-   *
-   * @return a new Extensible search filter with the provided information.
+   * @param mra
+   *          the matching rule assertion for this Extensible filter.
+   * @return a new Extensible search filter with the provided
+   *         information.
    */
-  private static LDAPFilter createExtensibleFilter(MatchingRuleAssertion mra) {
-    return LDAPFilter.createExtensibleFilter(mra.getMatchingRule(),
-                                        mra.getName(),
-                                        new ASN1OctetString(mra.getValue()),
-                                        mra.isDnAttributes());
+  private static LDAPFilter createExtensibleFilter(MatchingRuleAssertion mra)
+  {
+    return LDAPFilter.createExtensibleFilter(mra.getMatchingRule(), mra
+        .getName(), ByteString.valueOf(mra.getValue()), mra.isDnAttributes());
   }
 
+
+
   /**
-   * Returns a new GreaterOrEqual search filter with the provided information.
+   * Returns a new GreaterOrEqual search filter with the provided
+   * information.
    *
-   * @param ava the attribute value assertion for this GreaterOrEqual filter.
-   *
-   * @return a new GreaterOrEqual search filter with the provided information.
+   * @param ava
+   *          the attribute value assertion for this GreaterOrEqual
+   *          filter.
+   * @return a new GreaterOrEqual search filter with the provided
+   *         information.
    */
   private static LDAPFilter createGreaterOrEqualFilter(
-                              AttributeValueAssertion ava) {
-    return LDAPFilter.createGreaterOrEqualFilter(ava.getName(),
-                                          new ASN1OctetString(ava.getValue()));
+      AttributeValueAssertion ava)
+  {
+    return LDAPFilter.createGreaterOrEqualFilter(ava.getName(), ByteString
+        .valueOf(ava.getValue()));
   }
 
+
+
   /**
-   * Returns a new LessOrEqual search filter with the provided information.
+   * Returns a new LessOrEqual search filter with the provided
+   * information.
    *
-   * @param ava the attribute value assertion for this LessOrEqual filter.
-   *
-   * @return a new LessOrEqual search filter with the provided information.
+   * @param ava
+   *          the attribute value assertion for this LessOrEqual
+   *          filter.
+   * @return a new LessOrEqual search filter with the provided
+   *         information.
    */
-  private static LDAPFilter createLessOrEqualFilter(
-                              AttributeValueAssertion ava) {
-    return LDAPFilter.createLessOrEqualFilter(ava.getName(),
-                                          new ASN1OctetString(ava.getValue()));
+  private static LDAPFilter createLessOrEqualFilter(AttributeValueAssertion ava)
+  {
+    return LDAPFilter.createLessOrEqualFilter(ava.getName(), ByteString
+        .valueOf(ava.getValue()));
   }
 
+
+
   /**
    * Returns a new NOT search filter with the provided information.
    *
-   * @param filter the filter for this NOT filter.
-   *
+   * @param filter
+   *          the filter for this NOT filter.
    * @return a new NOT search filter with the provided information.
-   *
-   * @throws LDAPException an LDAPException is thrown if the creation of the
-   *                       provided filter fails.
+   * @throws LDAPException
+   *           an LDAPException is thrown if the creation of the
+   *           provided filter fails.
    */
-  private static LDAPFilter createNOTFilter(Filter filter)
-          throws LDAPException {
+  private static LDAPFilter createNOTFilter(Filter filter) throws LDAPException
+  {
     return LDAPFilter.createNOTFilter(createFilter(filter));
   }
 
+
+
   /**
-   * Returns a new OR search filter with the provided filter components.
+   * Returns a new OR search filter with the provided filter
+   * components.
    *
-   * @param filterSet The filter components for this filter
-   *
-   * @return a new OR search filter with the provided filter components.
-   *
-   * @throws LDAPException an LDAPException is thrown if the creation of a
-   *                       filter component fails.
+   * @param filterSet
+   *          The filter components for this filter
+   * @return a new OR search filter with the provided filter
+   *         components.
+   * @throws LDAPException
+   *           an LDAPException is thrown if the creation of a filter
+   *           component fails.
    */
   private static LDAPFilter createORFilter(FilterSet filterSet)
-          throws LDAPException {
+      throws LDAPException
+  {
     List<JAXBElement<?>> list = filterSet.getFilterGroup();
     ArrayList<RawFilter> filters = new ArrayList<RawFilter>(list.size());
 
-    for(JAXBElement<?> filter : list) {
+    for (JAXBElement<?> filter : list)
+    {
       filters.add(createFilter(filter));
     }
     return LDAPFilter.createORFilter(filters);
   }
 
+
+
   /**
-   * Returns a new Present search filter with the provided information.
+   * Returns a new Present search filter with the provided
+   * information.
    *
-   * @param ad the attribute description for this Present filter.
-   *
+   * @param ad
+   *          the attribute description for this Present filter.
    * @returna new Present search filter with the provided information.
-   *
-   * @throws LDAPException an LDAPException is thrown if the ASN.1 element
-   *                       provided by the attribute description cannot be
-   *                       decoded as a raw search filter.
+   * @throws LDAPException
+   *           an LDAPException is thrown if the ASN.1 element
+   *           provided by the attribute description cannot be decoded
+   *           as a raw search filter.
    */
   private static LDAPFilter createPresentFilter(AttributeDescription ad)
-          throws LDAPException {
-    return LDAPFilter.decode(
-             new StringBuilder(ad.getName()).append("=*").toString());
+      throws LDAPException
+  {
+    return LDAPFilter.decode(new StringBuilder(ad.getName()).append("=*")
+        .toString());
   }
 
+
+
   /**
-   * Returns a new Substring search filter with the provided information.
+   * Returns a new Substring search filter with the provided
+   * information.
    *
-   * @param sf the substring filter for this Substring filter.
-   *
-   * @return a new Substring search filter with the provided information.
+   * @param sf
+   *          the substring filter for this Substring filter.
+   * @return a new Substring search filter with the provided
+   *         information.
    */
-  private static LDAPFilter createSubstringFilter(SubstringFilter sf) {
+  private static LDAPFilter createSubstringFilter(SubstringFilter sf)
+  {
     List<String> anys = sf.getAny();
-    ArrayList<ByteString> subAnyElements =
-                                         new ArrayList<ByteString>(anys.size());
+    ArrayList<ByteString> subAnyElements = new ArrayList<ByteString>(anys
+        .size());
 
-    for(String s : anys) {
-      subAnyElements.add(new ASN1OctetString(s));
+    for (String s : anys)
+    {
+      subAnyElements.add(ByteString.valueOf(s));
     }
-    return LDAPFilter.createSubstringFilter(sf.getName(),
-                                        new ASN1OctetString(sf.getInitial()),
-                                        subAnyElements,
-                                        new ASN1OctetString(sf.getFinal()));
+    return LDAPFilter.createSubstringFilter(sf.getName(), ByteString.valueOf(sf
+        .getInitial()), subAnyElements, ByteString.valueOf(sf.getFinal()));
   }
 
+
+
   /**
-   * Returns a new LDAPFilter according to the tag name of the provided element
-   * that can be "and", "or", "not", "equalityMatch", "substrings",
-   * "greaterOrEqual", "lessOrEqual", "present", "approxMatch",
-   * "extensibleMatch".
+   * Returns a new LDAPFilter according to the tag name of the
+   * provided element that can be "and", "or", "not", "equalityMatch",
+   * "substrings", "greaterOrEqual", "lessOrEqual", "present",
+   * "approxMatch", "extensibleMatch".
    *
-   * @param xmlElement a JAXBElement that contains the name of the filter to
-   *                   create and the associated argument.
-   *
-   * @return a new LDAPFilter according to the tag name of the provided element.
-   *
-   * @throws LDAPException an LDAPException is thrown if the creation of the
-   *                       targeted filter fails.
+   * @param xmlElement
+   *          a JAXBElement that contains the name of the filter to
+   *          create and the associated argument.
+   * @return a new LDAPFilter according to the tag name of the
+   *         provided element.
+   * @throws LDAPException
+   *           an LDAPException is thrown if the creation of the
+   *           targeted filter fails.
    */
   private static LDAPFilter createFilter(JAXBElement<?> xmlElement)
-          throws LDAPException {
+      throws LDAPException
+  {
     LDAPFilter result = null;
 
     String filterName = xmlElement.getName().getLocalPart();
 
-    if ( "and".equals(filterName) ) {
+    if ("and".equals(filterName))
+    {
       // <xsd:element name="and" type="FilterSet"/>
-      result = createANDFilter((FilterSet)xmlElement.getValue());
+      result = createANDFilter((FilterSet) xmlElement.getValue());
     }
-    else if ( "or".equals(filterName) ) {
+    else if ("or".equals(filterName))
+    {
       // <xsd:element name="or" type="FilterSet"/>
-      result = createORFilter((FilterSet)xmlElement.getValue());
+      result = createORFilter((FilterSet) xmlElement.getValue());
     }
-    else if ( "not".equals(filterName) ) {
+    else if ("not".equals(filterName))
+    {
       // <xsd:element name="not" type="Filter"/>
-      result = createNOTFilter((Filter)xmlElement.getValue());
+      result = createNOTFilter((Filter) xmlElement.getValue());
     }
-    else if ( "equalityMatch".equals(filterName) ) {
-      // <xsd:element name="equalityMatch" type="AttributeValueAssertion"/>
-      result = createEqualityFilter((AttributeValueAssertion)
-                                                         xmlElement.getValue());
+    else if ("equalityMatch".equals(filterName))
+    {
+      // <xsd:element name="equalityMatch"
+      // type="AttributeValueAssertion"/>
+      result = createEqualityFilter((AttributeValueAssertion) xmlElement
+          .getValue());
     }
-    else if ( "substrings".equals(filterName) ) {
+    else if ("substrings".equals(filterName))
+    {
       // <xsd:element name="substrings" type="SubstringFilter"/>
-      result = createSubstringFilter((SubstringFilter)xmlElement.getValue());
+      result = createSubstringFilter((SubstringFilter) xmlElement.getValue());
     }
-    else if ( "greaterOrEqual".equals(filterName) ) {
-      // <xsd:element name="greaterOrEqual" type="AttributeValueAssertion"/>
-      result = createGreaterOrEqualFilter((AttributeValueAssertion)
-                                                         xmlElement.getValue());
+    else if ("greaterOrEqual".equals(filterName))
+    {
+      // <xsd:element name="greaterOrEqual"
+      // type="AttributeValueAssertion"/>
+      result = createGreaterOrEqualFilter((AttributeValueAssertion) xmlElement
+          .getValue());
     }
-    else if ( "lessOrEqual".equals(filterName) ) {
-      // <xsd:element name="lessOrEqual" type="AttributeValueAssertion"/>
-      result = createLessOrEqualFilter((AttributeValueAssertion)
-                                                         xmlElement.getValue());
+    else if ("lessOrEqual".equals(filterName))
+    {
+      // <xsd:element name="lessOrEqual"
+      // type="AttributeValueAssertion"/>
+      result = createLessOrEqualFilter((AttributeValueAssertion) xmlElement
+          .getValue());
     }
-    else if ( "present".equals(filterName) ) {
+    else if ("present".equals(filterName))
+    {
       // <xsd:element name="present" type="AttributeDescription"/>
-      result = createPresentFilter((AttributeDescription)xmlElement.getValue());
+      result =
+        createPresentFilter((AttributeDescription) xmlElement.getValue());
     }
-    else if ( "approxMatch".equals(filterName) ) {
-      // <xsd:element name="approxMatch" type="AttributeValueAssertion"/>
-      result = createApproximateFilter((AttributeValueAssertion)
-                                                         xmlElement.getValue());
+    else if ("approxMatch".equals(filterName))
+    {
+      // <xsd:element name="approxMatch"
+      // type="AttributeValueAssertion"/>
+      result = createApproximateFilter((AttributeValueAssertion) xmlElement
+          .getValue());
     }
-    else if ( "extensibleMatch".equals(filterName) ) {
-      // <xsd:element name="extensibleMatch" type="MatchingRuleAssertion"/>
-      result = createExtensibleFilter((MatchingRuleAssertion)
-                                                         xmlElement.getValue());
+    else if ("extensibleMatch".equals(filterName))
+    {
+      // <xsd:element name="extensibleMatch"
+      // type="MatchingRuleAssertion"/>
+      result = createExtensibleFilter((MatchingRuleAssertion) xmlElement
+          .getValue());
     }
     return result;
   }
 
+
+
   /**
-   * Returns a new LDAPFilter according to the filter assigned to the provided
-   * filter.
+   * Returns a new LDAPFilter according to the filter assigned to the
+   * provided filter.
    *
-   * @param filter a filter that contains the object filter to create.
-   *
-   * @return a new LDAPFilter according to the filter assigned to the provided
-   *         filter.
-   *
-   * @throws LDAPException an LDAPException is thrown if the creation of the
-   *                       targeted filter fails.
+   * @param filter
+   *          a filter that contains the object filter to create.
+   * @return a new LDAPFilter according to the filter assigned to the
+   *         provided filter.
+   * @throws LDAPException
+   *           an LDAPException is thrown if the creation of the
+   *           targeted filter fails.
    */
-  private static LDAPFilter createFilter(Filter filter)
-          throws LDAPException {
+  private static LDAPFilter createFilter(Filter filter) throws LDAPException
+  {
 
     LDAPFilter result = null;
 
-    if ( filter.getAnd() != null ) {
+    if (filter.getAnd() != null)
+    {
       result = createANDFilter(filter.getAnd());
     }
-    else if ( filter.getApproxMatch() != null ) {
+    else if (filter.getApproxMatch() != null)
+    {
       result = createApproximateFilter(filter.getApproxMatch());
     }
-    else if ( filter.getEqualityMatch() != null ) {
+    else if (filter.getEqualityMatch() != null)
+    {
       result = createEqualityFilter(filter.getEqualityMatch());
     }
-    else if ( filter.getExtensibleMatch() != null ) {
+    else if (filter.getExtensibleMatch() != null)
+    {
       result = createExtensibleFilter(filter.getExtensibleMatch());
     }
-    else if ( filter.getGreaterOrEqual() != null ) {
+    else if (filter.getGreaterOrEqual() != null)
+    {
       result = createGreaterOrEqualFilter(filter.getGreaterOrEqual());
     }
-    else if ( filter.getLessOrEqual() != null ) {
+    else if (filter.getLessOrEqual() != null)
+    {
       result = createLessOrEqualFilter(filter.getLessOrEqual());
     }
-    else if ( filter.getNot() != null ) {
+    else if (filter.getNot() != null)
+    {
       result = createNOTFilter(filter.getNot());
     }
-    else if ( filter.getOr() != null ) {
+    else if (filter.getOr() != null)
+    {
       result = createORFilter(filter.getOr());
     }
-    else if ( filter.getPresent() != null ) {
+    else if (filter.getPresent() != null)
+    {
       result = createPresentFilter(filter.getPresent());
     }
-    else if ( filter.getSubstrings() != null ) {
+    else if (filter.getSubstrings() != null)
+    {
       result = createSubstringFilter(filter.getSubstrings());
     }
     return result;
   }
 
+
+
   /**
    * Perform the LDAP SEARCH operation and send the result back to the
    * client.
    *
-   * @param  objFactory     The object factory for this operation.
-   * @param  searchRequest  The search request for this operation.
-   *
-   * @return  The result of the add operation.
-   *
-   * @throws  IOException  If an I/O problem occurs.
-   *
-   * @throws  LDAPException  If an error occurs while interacting with an LDAP
-   *                         element.
+   * @param objFactory
+   *          The object factory for this operation.
+   * @param searchRequest
+   *          The search request for this operation.
+   * @return The result of the add operation.
+   * @throws IOException
+   *           If an I/O problem occurs.
+   * @throws LDAPException
+   *           If an error occurs while interacting with an LDAP
+   *           element.
    */
   public SearchResponse doSearch(ObjectFactory objFactory,
-         SearchRequest searchRequest)
-         throws IOException, LDAPException
+      SearchRequest searchRequest) throws IOException, LDAPException
   {
     SearchResponse searchResponse = objFactory.createSearchResponse();
     searchResponse.setRequestID(searchRequest.getRequestID());
@@ -391,10 +476,11 @@
 
     SearchScope scope = SearchScope.WHOLE_SUBTREE;
     String scopeStr = searchRequest.getScope().toLowerCase();
-    if(scopeStr.equals("singlelevel") || scopeStr.equals("one"))
+    if (scopeStr.equals("singlelevel") || scopeStr.equals("one"))
     {
       scope = SearchScope.SINGLE_LEVEL;
-    } else if(scopeStr.equals("baseobject") || scopeStr.equals("base"))
+    }
+    else if (scopeStr.equals("baseobject") || scopeStr.equals("base"))
     {
       scope = SearchScope.BASE_OBJECT;
     }
@@ -402,25 +488,23 @@
     LinkedHashSet<String> attributes = new LinkedHashSet<String>();
     // Get the list of attributes.
     AttributeDescriptions attrDescriptions = searchRequest.getAttributes();
-    if(attrDescriptions != null)
+    if (attrDescriptions != null)
     {
       List<AttributeDescription> attrDesc = attrDescriptions.getAttribute();
-      for(AttributeDescription desc : attrDesc)
+      for (AttributeDescription desc : attrDesc)
       {
         attributes.add(desc.getName());
       }
     }
 
-    SearchRequestProtocolOp protocolOp = new SearchRequestProtocolOp(
-        new ASN1OctetString(searchRequest.getDn()),
-        scope, derefPolicy,
-                (int) searchRequest.getSizeLimit(),
-        (int) searchRequest.getTimeLimit(),
+    SearchRequestProtocolOp protocolOp = new SearchRequestProtocolOp(ByteString
+        .valueOf(searchRequest.getDn()), scope, derefPolicy,
+        (int) searchRequest.getSizeLimit(), (int) searchRequest.getTimeLimit(),
         searchRequest.isTypesOnly(), filter, attributes);
     try
     {
-      LDAPMessage msg = new LDAPMessage(DSMLServlet.nextMessageID(),
-                                        protocolOp);
+      LDAPMessage msg =
+        new LDAPMessage(DSMLServlet.nextMessageID(), protocolOp);
       connection.getLDAPWriter().writeMessage(msg);
 
       byte opType;
@@ -428,68 +512,68 @@
       {
         int resultCode = 0;
         Message errorMessage = null;
-        LDAPMessage responseMessage =
-             connection.getLDAPReader().readMessage();
+        LDAPMessage responseMessage = connection.getLDAPReader().readMessage();
 
         opType = responseMessage.getProtocolOpType();
-        switch(opType)
+        switch (opType)
         {
-          case LDAPConstants.OP_TYPE_SEARCH_RESULT_ENTRY:
-            SearchResultEntryProtocolOp searchEntryOp =
-              responseMessage.getSearchResultEntryProtocolOp();
+        case LDAPConstants.OP_TYPE_SEARCH_RESULT_ENTRY:
+          SearchResultEntryProtocolOp searchEntryOp = responseMessage
+              .getSearchResultEntryProtocolOp();
 
-            SearchResultEntry entry = objFactory.createSearchResultEntry();
-            java.util.List<DsmlAttr> attrList = entry.getAttr();
+          SearchResultEntry entry = objFactory.createSearchResultEntry();
+          java.util.List<DsmlAttr> attrList = entry.getAttr();
 
-            LinkedList<LDAPAttribute> attrs = searchEntryOp.getAttributes();
+          LinkedList<LDAPAttribute> attrs = searchEntryOp.getAttributes();
 
-            for(LDAPAttribute attr : attrs)
+          for (LDAPAttribute attr : attrs)
+          {
+            String nm = attr.getAttributeType();
+            DsmlAttr dsmlAttr = objFactory.createDsmlAttr();
+
+            dsmlAttr.setName(nm);
+            List<String> dsmlAttrVal = dsmlAttr.getValue();
+            ArrayList<ByteString> vals = attr.getValues();
+            for (ByteString val : vals)
             {
-              String nm = attr.getAttributeType();
-              DsmlAttr dsmlAttr = objFactory.createDsmlAttr();
-
-              dsmlAttr.setName(nm);
-              List<String> dsmlAttrVal = dsmlAttr.getValue();
-              ArrayList<ASN1OctetString> vals = attr.getValues();
-              for(ASN1OctetString val : vals)
-              {
-                dsmlAttrVal.add(val.toString());
-              }
-              attrList.add(dsmlAttr);
+              dsmlAttrVal.add(val.toString());
             }
+            attrList.add(dsmlAttr);
+          }
 
-            entry.setDn(searchEntryOp.getDN().toString());
-            searchResponse.getSearchResultEntry().add(entry);
-            break;
+          entry.setDn(searchEntryOp.getDN().toString());
+          searchResponse.getSearchResultEntry().add(entry);
+          break;
 
-          case LDAPConstants.OP_TYPE_SEARCH_RESULT_REFERENCE:
-            SearchResultReferenceProtocolOp searchRefOp =
-              responseMessage.getSearchResultReferenceProtocolOp();
-            break;
+        case LDAPConstants.OP_TYPE_SEARCH_RESULT_REFERENCE:
+          responseMessage.getSearchResultReferenceProtocolOp();
+          break;
 
-          case LDAPConstants.OP_TYPE_SEARCH_RESULT_DONE:
-            SearchResultDoneProtocolOp searchOp =
-              responseMessage.getSearchResultDoneProtocolOp();
-            resultCode = searchOp.getResultCode();
-            errorMessage = searchOp.getErrorMessage();
-            LDAPResult result = objFactory.createLDAPResult();
-            ResultCode code = objFactory.createResultCode();
-            code.setCode(resultCode);
-            result.setResultCode(code);
-            result.setErrorMessage(
-                    errorMessage != null ? errorMessage.toString() : null);
-            if(searchOp.getMatchedDN() != null)
-            {
-               result.setMatchedDN(searchOp.getMatchedDN().toString());
-            }
-            searchResponse.setSearchResultDone(result);
-            break;
-          default:
-             throw new RuntimeException("Invalid protocol operation:" + opType);
-         }
-      } while(opType != LDAPConstants.OP_TYPE_SEARCH_RESULT_DONE);
+        case LDAPConstants.OP_TYPE_SEARCH_RESULT_DONE:
+          SearchResultDoneProtocolOp searchOp = responseMessage
+              .getSearchResultDoneProtocolOp();
+          resultCode = searchOp.getResultCode();
+          errorMessage = searchOp.getErrorMessage();
+          LDAPResult result = objFactory.createLDAPResult();
+          ResultCode code = objFactory.createResultCode();
+          code.setCode(resultCode);
+          result.setResultCode(code);
+          result.setErrorMessage(errorMessage != null ? errorMessage.toString()
+              : null);
+          if (searchOp.getMatchedDN() != null)
+          {
+            result.setMatchedDN(searchOp.getMatchedDN().toString());
+          }
+          searchResponse.setSearchResultDone(result);
+          break;
+        default:
+          throw new RuntimeException("Invalid protocol operation:" + opType);
+        }
+      }
+      while (opType != LDAPConstants.OP_TYPE_SEARCH_RESULT_DONE);
 
-    } catch(ASN1Exception ae)
+    }
+    catch (ASN1Exception ae)
     {
       ae.printStackTrace();
       throw new IOException(ae.getMessage());
@@ -498,4 +582,3 @@
     return searchResponse;
   }
 }
-
diff --git a/opends/src/guitools/org/opends/guitools/controlpanel/task/ModifyEntryTask.java b/opends/src/guitools/org/opends/guitools/controlpanel/task/ModifyEntryTask.java
index e3d60ec..fdb47c5 100644
--- a/opends/src/guitools/org/opends/guitools/controlpanel/task/ModifyEntryTask.java
+++ b/opends/src/guitools/org/opends/guitools/controlpanel/task/ModifyEntryTask.java
@@ -62,16 +62,7 @@
 import org.opends.messages.AdminToolMessages;
 import org.opends.messages.Message;
 import org.opends.server.config.ConfigConstants;
-import org.opends.server.types.AttributeType;
-import org.opends.server.types.AttributeValue;
-import org.opends.server.types.ByteString;
-import org.opends.server.types.ByteStringFactory;
-import org.opends.server.types.DN;
-import org.opends.server.types.DirectoryException;
-import org.opends.server.types.Entry;
-import org.opends.server.types.OpenDsException;
-import org.opends.server.types.RDN;
-import org.opends.server.types.Schema;
+import org.opends.server.types.*;
 
 /**
  * The task that is called when we must modify an entry.
@@ -691,7 +682,7 @@
     Attribute attribute = new BasicAttribute(attrName);
     for (AttributeValue value : values)
     {
-      attribute.add(value.getValue().value());
+      attribute.add(value.getValue().toByteArray());
     }
     return attribute;
   }
@@ -709,17 +700,17 @@
     ByteString v;
     if (value instanceof String)
     {
-      v = ByteStringFactory.create((String)value);
+      v = ByteString.valueOf((String)value);
     }
     else if (value instanceof byte[])
     {
-      v = ByteStringFactory.create((byte[])value);
+      v = ByteString.wrap((byte[])value);
     }
     else
     {
-      v = ByteStringFactory.create(String.valueOf(value));
+      v = ByteString.valueOf(String.valueOf(value));
     }
-    return new AttributeValue(attrType, v);
+    return AttributeValues.create(attrType, v);
   }
 
   /**
diff --git a/opends/src/guitools/org/opends/guitools/controlpanel/task/NewEntryTask.java b/opends/src/guitools/org/opends/guitools/controlpanel/task/NewEntryTask.java
index 0fb0385..10ad4ab 100644
--- a/opends/src/guitools/org/opends/guitools/controlpanel/task/NewEntryTask.java
+++ b/opends/src/guitools/org/opends/guitools/controlpanel/task/NewEntryTask.java
@@ -224,7 +224,7 @@
         BasicAttribute a = new BasicAttribute(attrName);
         for (AttributeValue value : values)
         {
-          a.add(value.getValueBytes());
+          a.add(value.getValue().toByteArray());
         }
         attrs.put(a);
       }
diff --git a/opends/src/guitools/org/opends/guitools/controlpanel/task/Task.java b/opends/src/guitools/org/opends/guitools/controlpanel/task/Task.java
index 6b33397..edbbba4 100644
--- a/opends/src/guitools/org/opends/guitools/controlpanel/task/Task.java
+++ b/opends/src/guitools/org/opends/guitools/controlpanel/task/Task.java
@@ -54,7 +54,6 @@
 import org.opends.guitools.controlpanel.util.Utilities;
 import org.opends.messages.Message;
 import org.opends.server.types.ByteString;
-import org.opends.server.types.ByteStringFactory;
 import org.opends.server.types.DN;
 import org.opends.server.types.Schema;
 import org.opends.server.util.Base64;
@@ -473,8 +472,8 @@
           else
           {
             // Get the String value
-            ByteString v = ByteStringFactory.create(bytes);
-            return v.stringValue();
+            ByteString v = ByteString.wrap(bytes);
+            return v.toString();
           }
         }
       }
diff --git a/opends/src/guitools/org/opends/guitools/controlpanel/ui/AbstractBrowseEntriesPanel.java b/opends/src/guitools/org/opends/guitools/controlpanel/ui/AbstractBrowseEntriesPanel.java
index 4bdc8ae..6f79e74 100644
--- a/opends/src/guitools/org/opends/guitools/controlpanel/ui/AbstractBrowseEntriesPanel.java
+++ b/opends/src/guitools/org/opends/guitools/controlpanel/ui/AbstractBrowseEntriesPanel.java
@@ -99,12 +99,7 @@
 import org.opends.quicksetup.util.UIKeyStore;
 import org.opends.quicksetup.util.Utils;
 import org.opends.server.protocols.ldap.LDAPFilter;
-import org.opends.server.types.AttributeType;
-import org.opends.server.types.AttributeValue;
-import org.opends.server.types.DN;
-import org.opends.server.types.DirectoryException;
-import org.opends.server.types.LDAPException;
-import org.opends.server.types.SearchFilter;
+import org.opends.server.types.*;
 
 /**
  * The abstract class used to refactor some code.  The classes that extend this
@@ -821,7 +816,7 @@
                 attr.toString().toLowerCase());
           LDAPFilter ldapFilter =
             new LDAPFilter(SearchFilter.createEqualityFilter(
-              attrType, new AttributeValue(attrType, s)));
+              attrType, AttributeValues.create(attrType, s)));
           returnValue = ldapFilter.toString();
         }
       }
diff --git a/opends/src/guitools/org/opends/guitools/controlpanel/ui/JavaPropertiesPanel.java b/opends/src/guitools/org/opends/guitools/controlpanel/ui/JavaPropertiesPanel.java
index 054a678..6d72733 100644
--- a/opends/src/guitools/org/opends/guitools/controlpanel/ui/JavaPropertiesPanel.java
+++ b/opends/src/guitools/org/opends/guitools/controlpanel/ui/JavaPropertiesPanel.java
@@ -22,7 +22,7 @@
  * CDDL HEADER END
  *
  *
- *      Copyright 2008 Sun Microsystems, Inc.
+ *      Copyright 2008-2009 Sun Microsystems, Inc.
  */
 
 package org.opends.guitools.controlpanel.ui;
@@ -174,6 +174,7 @@
   /**
    * {@inheritDoc}
    */
+  @Override
   public Message getTitle()
   {
     return INFO_CTRL_PANEL_JAVA_PROPERTIES_TITLE.get();
@@ -182,6 +183,7 @@
   /**
    * {@inheritDoc}
    */
+  @Override
   public Component getPreferredFocusComponent()
   {
     return javaHome;
@@ -190,6 +192,7 @@
   /**
    * {@inheritDoc}
    */
+  @Override
   public boolean requiresScroll()
   {
     return false;
@@ -198,6 +201,7 @@
   /**
    * {@inheritDoc}
    */
+  @Override
   public void setInfo(ControlPanelInfo info)
   {
     super.setInfo(info);
@@ -425,6 +429,7 @@
   /**
    * {@inheritDoc}
    */
+  @Override
   public void toBeDisplayed(boolean visible)
   {
     if (visible && (firstDisplay || !updatedByUser()))
@@ -557,6 +562,7 @@
       /**
        * {@inheritDoc}
        */
+      @Override
       public Void processBackgroundTask() throws Throwable
       {
         String propertiesFile = getPropertiesFile();
@@ -623,6 +629,7 @@
       /**
        * {@inheritDoc}
        */
+      @Override
       public void backgroundTaskCompleted(Void returnValue,
           Throwable t)
       {
@@ -701,6 +708,7 @@
   /**
    * {@inheritDoc}
    */
+  @Override
   public void okClicked()
   {
     editor.stopCellEditing();
@@ -748,6 +756,7 @@
           new BackgroundTask<Set<String>>()
         {
           private String jvm;
+          @Override
           public Set<String> processBackgroundTask() throws Throwable
           {
             Set<String> notWorkingArgs = new HashSet<String>();
@@ -776,6 +785,7 @@
           /**
            * {@inheritDoc}
            */
+          @Override
           public void backgroundTaskCompleted(Set<String> returnValue,
               Throwable t)
           {
@@ -949,6 +959,7 @@
     /**
      * {@inheritDoc}
      */
+    @Override
     public int hashCode()
     {
       return hashCode;
@@ -957,6 +968,7 @@
     /**
      * {@inheritDoc}
      */
+    @Override
     public String toString()
     {
       return toString;
@@ -965,6 +977,7 @@
     /**
      * {@inheritDoc}
      */
+    @Override
     public boolean equals(Object o)
     {
       boolean equals = o == this;
@@ -1055,6 +1068,7 @@
      * Updates the table model contents and sorts its contents depending on the
      * sort options set by the user.
      */
+    @Override
     public void forceResort()
     {
       updateDataArray();
@@ -1090,6 +1104,7 @@
     /**
      * {@inheritDoc}
      */
+    @Override
     public String getColumnName(int col) {
       return COLUMN_NAMES[col];
     }
@@ -1110,6 +1125,7 @@
      * @return <CODE>true</CODE> if the sort is ascending and <CODE>false</CODE>
      * otherwise.
      */
+    @Override
     public boolean isSortAscending()
     {
       return sortAscending;
@@ -1119,6 +1135,7 @@
      * Sets whether to sort ascending of descending.
      * @param sortAscending whether to sort ascending or descending.
      */
+    @Override
     public void setSortAscending(boolean sortAscending)
     {
       this.sortAscending = sortAscending;
@@ -1128,6 +1145,7 @@
      * Returns the column index used to sort.
      * @return the column index used to sort.
      */
+    @Override
     public int getSortColumn()
     {
       return sortColumn;
@@ -1137,6 +1155,7 @@
      * Sets the column index used to sort.
      * @param sortColumn column index used to sort..
      */
+    @Override
     public void setSortColumn(int sortColumn)
     {
       this.sortColumn = sortColumn;
@@ -1145,6 +1164,7 @@
     /**
      * {@inheritDoc}
      */
+    @Override
     public boolean isCellEditable(int row, int col) {
       if (col == 0)
       {
@@ -1158,6 +1178,7 @@
     /**
      * {@inheritDoc}
      */
+    @Override
     public void setValueAt(Object value, int row, int col)
     {
       dataArray.get(row)[col] = (String)value;
@@ -1248,6 +1269,7 @@
     /**
      * {@inheritDoc}
      */
+    @Override
     public Type getType()
     {
       return Type.JAVA_SETTINGS_UPDATE;
@@ -1256,6 +1278,7 @@
     /**
      * {@inheritDoc}
      */
+    @Override
     public Set<String> getBackends()
     {
       return backendSet;
@@ -1264,6 +1287,7 @@
     /**
      * {@inheritDoc}
      */
+    @Override
     public Message getTaskDescription()
     {
       return INFO_CTRL_PANEL_UPDATE_JAVA_SETTINGS_TASK_DESCRIPTION.get();
@@ -1272,6 +1296,7 @@
     /**
      * {@inheritDoc}
      */
+    @Override
     public boolean canLaunch(Task taskToBeLaunched,
         Collection<Message> incompatibilityReasons)
     {
@@ -1300,6 +1325,7 @@
     /**
      * {@inheritDoc}
      */
+    @Override
     protected String getCommandLinePath()
     {
       return null;
@@ -1308,6 +1334,7 @@
     /**
      * {@inheritDoc}
      */
+    @Override
     protected ArrayList<String> getCommandLineArguments()
     {
       return new ArrayList<String>();
@@ -1316,6 +1343,7 @@
     /**
      * {@inheritDoc}
      */
+    @Override
     public void runTask()
     {
       state = State.RUNNING;
diff --git a/opends/src/guitools/org/opends/guitools/controlpanel/ui/NewBaseDNPanel.java b/opends/src/guitools/org/opends/guitools/controlpanel/ui/NewBaseDNPanel.java
index 5e6e02c..7fbe664 100644
--- a/opends/src/guitools/org/opends/guitools/controlpanel/ui/NewBaseDNPanel.java
+++ b/opends/src/guitools/org/opends/guitools/controlpanel/ui/NewBaseDNPanel.java
@@ -1293,7 +1293,7 @@
 
           while (it.hasNext())
           {
-            oc.add(it.next().getStringValue());
+            oc.add(it.next().getValue().toString());
           }
           attrs.put(oc);
 
@@ -1306,7 +1306,7 @@
             it = odsAttr.iterator();
             while (it.hasNext())
             {
-              attr.add(it.next().getStringValue());
+              attr.add(it.next().getValue().toString());
             }
             attrs.put(attr);
 
@@ -1315,7 +1315,7 @@
               args.add("--index-name");
               AttributeValue value =
                 odsAttr.iterator().next();
-              args.add(value.getStringValue());
+              args.add(value.getValue().toString());
             }
             else if (attrName.equalsIgnoreCase("ds-cfg-index-type"))
             {
@@ -1323,7 +1323,7 @@
               while (it.hasNext())
               {
                 args.add("--set");
-                args.add("index-type:"+it.next().getStringValue());
+                args.add("index-type:"+it.next().getValue().toString());
               }
             }
           }
diff --git a/opends/src/guitools/org/opends/guitools/controlpanel/ui/NewIndexPanel.java b/opends/src/guitools/org/opends/guitools/controlpanel/ui/NewIndexPanel.java
index fc46116..6814967 100644
--- a/opends/src/guitools/org/opends/guitools/controlpanel/ui/NewIndexPanel.java
+++ b/opends/src/guitools/org/opends/guitools/controlpanel/ui/NewIndexPanel.java
@@ -635,7 +635,7 @@
           indexEntry.getObjectClassAttribute().iterator();
         while (it.hasNext())
         {
-          oc.add(it.next().getStringValue());
+          oc.add(it.next().getValue().toString());
         }
         attrs.put(oc);
 
@@ -647,7 +647,7 @@
           it = odsAttr.iterator();
           while (it.hasNext())
           {
-            attr.add(it.next().getStringValue());
+            attr.add(it.next().getValue().toString());
           }
           attrs.put(attr);
         }
diff --git a/opends/src/guitools/org/opends/guitools/controlpanel/ui/NewVLVIndexPanel.java b/opends/src/guitools/org/opends/guitools/controlpanel/ui/NewVLVIndexPanel.java
index ffb8cf1..733eb10 100644
--- a/opends/src/guitools/org/opends/guitools/controlpanel/ui/NewVLVIndexPanel.java
+++ b/opends/src/guitools/org/opends/guitools/controlpanel/ui/NewVLVIndexPanel.java
@@ -91,6 +91,7 @@
   /**
    * {@inheritDoc}
    */
+  @Override
   public Message getTitle()
   {
     return INFO_CTRL_PANEL_NEW_VLV_INDEX_TITLE.get();
@@ -99,6 +100,7 @@
   /**
    * {@inheritDoc}
    */
+  @Override
   public Component getPreferredFocusComponent()
   {
     return name;
@@ -129,6 +131,7 @@
   /**
    * {@inheritDoc}
    */
+  @Override
   public void okClicked()
   {
     List<Message> errors = checkErrors(true);
@@ -211,6 +214,7 @@
     /**
      * {@inheritDoc}
      */
+    @Override
     public Type getType()
     {
       return Type.NEW_INDEX;
@@ -219,6 +223,7 @@
     /**
      * {@inheritDoc}
      */
+    @Override
     public Set<String> getBackends()
     {
       return backendSet;
@@ -227,6 +232,7 @@
     /**
      * {@inheritDoc}
      */
+    @Override
     public Message getTaskDescription()
     {
       return INFO_CTRL_PANEL_NEW_VLV_INDEX_TASK_DESCRIPTION.get(
@@ -236,6 +242,7 @@
     /**
      * {@inheritDoc}
      */
+    @Override
     public boolean canLaunch(Task taskToBeLaunched,
         Collection<Message> incompatibilityReasons)
     {
@@ -420,6 +427,7 @@
     /**
      * {@inheritDoc}
      */
+    @Override
     protected String getCommandLinePath()
     {
       return null;
@@ -428,6 +436,7 @@
     /**
      * {@inheritDoc}
      */
+    @Override
     protected ArrayList<String> getCommandLineArguments()
     {
       return new ArrayList<String>();
@@ -448,6 +457,7 @@
     /**
      * {@inheritDoc}
      */
+    @Override
     public void runTask()
     {
       state = State.RUNNING;
@@ -481,6 +491,7 @@
     /**
      * {@inheritDoc}
      */
+    @Override
     public void postOperation()
     {
       if ((lastException == null) && (state == State.FINISHED_SUCCESSFULLY) &&
diff --git a/opends/src/guitools/org/opends/guitools/controlpanel/ui/SimplifiedViewEntryPanel.java b/opends/src/guitools/org/opends/guitools/controlpanel/ui/SimplifiedViewEntryPanel.java
index 7c3e77d..a76b807 100644
--- a/opends/src/guitools/org/opends/guitools/controlpanel/ui/SimplifiedViewEntryPanel.java
+++ b/opends/src/guitools/org/opends/guitools/controlpanel/ui/SimplifiedViewEntryPanel.java
@@ -90,15 +90,7 @@
 import org.opends.messages.Message;
 import org.opends.messages.MessageBuilder;
 import org.opends.server.schema.SchemaConstants;
-import org.opends.server.types.AttributeType;
-import org.opends.server.types.AttributeValue;
-import org.opends.server.types.DN;
-import org.opends.server.types.Entry;
-import org.opends.server.types.LDIFImportConfig;
-import org.opends.server.types.ObjectClass;
-import org.opends.server.types.OpenDsException;
-import org.opends.server.types.RDN;
-import org.opends.server.types.Schema;
+import org.opends.server.types.*;
 import org.opends.server.util.Base64;
 import org.opends.server.util.LDIFReader;
 import org.opends.server.util.ServerConstants;
@@ -1610,7 +1602,7 @@
           String attrName = rdn.getAttributeName(i);
           AttributeValue value = rdn.getAttributeValue(i);
 
-          String sValue = value.getStringValue();
+          String sValue = value.getValue().toString();
 
           Set<String> values = getDisplayedStringValues(attrName);
           if (!values.contains(sValue))
@@ -1632,7 +1624,8 @@
                 AttributeType attr = rdn.getAttributeType(i);
                 attributeTypes.add(attr);
                 attributeNames.add(rdn.getAttributeName(i));
-                attributeValues.add(new AttributeValue(attr, firstNonEmpty));
+                attributeValues.add(AttributeValues.create(
+                    attr, firstNonEmpty));
               }
             }
           }
@@ -1671,7 +1664,8 @@
                   {
                     attributeTypes.add(attr);
                     attributeNames.add(attrName);
-                    attributeValues.add(new AttributeValue(attr, (String)o));
+                    attributeValues.add(
+                        AttributeValues.create(attr, (String)o));
                   }
                   break;
                 }
diff --git a/opends/src/guitools/org/opends/guitools/controlpanel/ui/TableViewEntryPanel.java b/opends/src/guitools/org/opends/guitools/controlpanel/ui/TableViewEntryPanel.java
index 371dd84..d6eb841 100644
--- a/opends/src/guitools/org/opends/guitools/controlpanel/ui/TableViewEntryPanel.java
+++ b/opends/src/guitools/org/opends/guitools/controlpanel/ui/TableViewEntryPanel.java
@@ -64,15 +64,7 @@
 import org.opends.guitools.controlpanel.ui.renderer.LDAPEntryTableCellRenderer;
 import org.opends.guitools.controlpanel.util.Utilities;
 import org.opends.messages.Message;
-import org.opends.server.types.AttributeType;
-import org.opends.server.types.AttributeValue;
-import org.opends.server.types.DN;
-import org.opends.server.types.Entry;
-import org.opends.server.types.LDIFImportConfig;
-import org.opends.server.types.ObjectClass;
-import org.opends.server.types.OpenDsException;
-import org.opends.server.types.RDN;
-import org.opends.server.types.Schema;
+import org.opends.server.types.*;
 import org.opends.server.util.LDIFReader;
 import org.opends.server.util.ServerConstants;
 
@@ -314,7 +306,7 @@
           String attrName = rdn.getAttributeName(i);
           AttributeValue value = rdn.getAttributeValue(i);
 
-          String sValue = value.getStringValue();
+          String sValue = value.getValue().toString();
 
           Set<String> values = getDisplayedStringValues(attrName);
           if (!values.contains(sValue))
@@ -336,7 +328,8 @@
                 AttributeType attr = rdn.getAttributeType(i);
                 attributeTypes.add(attr);
                 attributeNames.add(rdn.getAttributeName(i));
-                attributeValues.add(new AttributeValue(attr, firstNonEmpty));
+                attributeValues.add(AttributeValues.create(
+                    attr, firstNonEmpty));
               }
             }
           }
@@ -375,7 +368,8 @@
                 {
                   attributeTypes.add(attr);
                   attributeNames.add(attrName);
-                  attributeValues.add(new AttributeValue(attr, (String)o));
+                  attributeValues.add(AttributeValues.create(
+                      attr, (String)o));
                 }
                 break;
               }
diff --git a/opends/src/guitools/org/opends/guitools/controlpanel/ui/nodes/BasicNode.java b/opends/src/guitools/org/opends/guitools/controlpanel/ui/nodes/BasicNode.java
index dea8328..e859a66 100644
--- a/opends/src/guitools/org/opends/guitools/controlpanel/ui/nodes/BasicNode.java
+++ b/opends/src/guitools/org/opends/guitools/controlpanel/ui/nodes/BasicNode.java
@@ -389,7 +389,7 @@
           }
           else
           {
-            result = rdn.getAttributeValue(0).getStringValue();
+            result = rdn.getAttributeValue(0).getValue().toString();
           }
         }
         else {
diff --git a/opends/src/guitools/org/opends/guitools/controlpanel/util/Utilities.java b/opends/src/guitools/org/opends/guitools/controlpanel/util/Utilities.java
index 84854a2..81fdc94 100644
--- a/opends/src/guitools/org/opends/guitools/controlpanel/util/Utilities.java
+++ b/opends/src/guitools/org/opends/guitools/controlpanel/util/Utilities.java
@@ -104,13 +104,7 @@
 import org.opends.server.core.DirectoryServer;
 import org.opends.server.core.LockFileManager;
 import org.opends.server.schema.SchemaConstants;
-import org.opends.server.types.AttributeType;
-import org.opends.server.types.AttributeValue;
-import org.opends.server.types.DN;
-import org.opends.server.types.OpenDsException;
-import org.opends.server.types.RDN;
-import org.opends.server.types.Schema;
-import org.opends.server.types.SchemaFileElement;
+import org.opends.server.types.*;
 import org.opends.server.util.ServerConstants;
 import org.opends.server.util.StaticUtils;
 
@@ -1255,7 +1249,8 @@
   public static String getRDNString(String attrName, String attrValue)
   {
     AttributeType attrType = DirectoryServer.getDefaultAttributeType(attrName);
-    AttributeValue value = new AttributeValue(attrType, attrValue);
+    AttributeValue value =
+        AttributeValues.create(attrType, attrValue);
     RDN rdn = new RDN(attrType, attrName, value);
     return rdn.toString();
   }
diff --git a/opends/src/messages/messages/extension.properties b/opends/src/messages/messages/extension.properties
index 9811b59..2c81485e 100644
--- a/opends/src/messages/messages/extension.properties
+++ b/opends/src/messages/messages/extension.properties
@@ -347,34 +347,6 @@
 INFO_FILE_TRUSTMANAGER_UPDATED_PIN_109=The PIN to use to access the \
  file-based trust manager has been updated.  The new value will take effect \
  the next time the trust manager is accessed
-SEVERE_ERR_NULL_SECURITY_PROVIDER_READ_ERROR_110=An unexpected error occurred \
- while attempting to read data from the client using the null connection \
- security provider:  %s
-SEVERE_ERR_NULL_SECURITY_PROVIDER_WRITE_ERROR_111=An unexpected error \
- occurred while attempting to write data to the client using the null \
- connection security provider:  %s
-SEVERE_ERR_TLS_SECURITY_PROVIDER_CANNOT_INITIALIZE_112=An error occurred \
- while attempting to initialize the SSL context for use in the TLS connection \
- security provider:  %s
-SEVERE_ERR_TLS_SECURITY_PROVIDER_UNEXPECTED_UNWRAP_STATUS_113=An unexpected \
- status result was returned to the TLS connection security provider when \
- attempting to unwrap encrypted data read from the client:  %s
-SEVERE_ERR_TLS_SECURITY_PROVIDER_READ_ERROR_114=An unexpected error occurred \
- while attempting to read data from the client using the TLS connection \
- security provider:  %s
-SEVERE_ERR_TLS_SECURITY_PROVIDER_WRITE_NEEDS_UNWRAP_115=An attempt was made \
- to write data to a client through the TLS connection security provider, but \
- the SSL indicated that it was necessary to read data from the client in order \
- to perform the SSL negotiation, but no data was available for reading.  This \
- is an unexpected condition, and it is not possible to continue processing on \
- this client connection without the potential for blocking other client \
- connections, so connection will be closed
-SEVERE_ERR_TLS_SECURITY_PROVIDER_UNEXPECTED_WRAP_STATUS_116=An unexpected \
- status result was returned to the TLS connection security provider when \
- attempting to wrap clear-text data for writing to the client:  %s
-SEVERE_ERR_TLS_SECURITY_PROVIDER_WRITE_ERROR_117=An unexpected error occurred \
- while attempting to write data to the client using the TLS connection \
- security provider:  %s
 MILD_ERR_SEDCM_NO_PEER_CERTIFICATE_118=Could not map the provided certificate \
  chain to a user entry because no peer certificate was available
 MILD_ERR_SEDCM_PEER_CERT_NOT_X509_119=Could not map the provided certificate \
diff --git a/opends/src/messages/messages/jeb.properties b/opends/src/messages/messages/jeb.properties
index cc7923a..a21503e 100644
--- a/opends/src/messages/messages/jeb.properties
+++ b/opends/src/messages/messages/jeb.properties
@@ -215,7 +215,7 @@
 NOTICE_JEB_REFERRAL_RESULT_MESSAGE_112=A referral entry %s indicates that the \
  operation must be processed at a different server
 INFO_JEB_IMPORT_ENVIRONMENT_CONFIG_119=Database environment properties: %s
-SEVERE_ERR_JEB_INCOMPATIBLE_ENTRY_VERSION_126=Entry record with ID %s is not \
+SEVERE_ERR_JEB_INCOMPATIBLE_ENTRY_VERSION_126=Entry record is not \
  compatible with this version of the backend database. Entry version: %x
 NOTICE_JEB_LOOKTHROUGH_LIMIT_EXCEEDED_127=This search operation has checked the \
  maximum of %d entries for matches
diff --git a/opends/src/messages/messages/protocol.properties b/opends/src/messages/messages/protocol.properties
index d299721..7bd8b01 100644
--- a/opends/src/messages/messages/protocol.properties
+++ b/opends/src/messages/messages/protocol.properties
@@ -47,118 +47,46 @@
 #
 # ORDINAL is an integer unique among other ordinals in this file
 #
-MILD_ERR_ASN1_NULL_ELEMENT_1=Cannot decode the provided byte array as an \
- ASN.1 element because the array was null
-MILD_ERR_ASN1_SHORT_ELEMENT_2=Cannot decode the provided byte array as an \
- ASN.1 element because the length of the array (%d bytes) is less than the \
- minimum required for an ASN.1 element (2 bytes)
-MILD_ERR_ASN1_INVALID_NUM_LENGTH_BYTES_3=Cannot decode the provided byte \
- array as an ASN.1 element because it contained a multi-byte length with an \
- invalid number of bytes (%d)
-MILD_ERR_ASN1_TRUNCATED_LENGTH_4=Cannot decode the provided byte array as an \
- ASN.1 element because it contained a multi-byte length of %d bytes but the \
- array was too short to contain the entire length
-MILD_ERR_ASN1_LENGTH_MISMATCH_5=Cannot decode the provided byte array as an \
- ASN.1 element because the decoded value length (%d bytes) does not equal the \
- number of bytes remaining in the provided array (%d)
-MILD_ERR_ASN1_ELEMENT_SET_NULL_6=Cannot decode the provided byte array as a \
- set of ASN.1 elements because the array was null
-MILD_ERR_ASN1_ELEMENT_SET_NO_LENGTH_7=Cannot decode the provided byte array \
- as a set of ASN.1 elements because the end of the array was reached after \
- having read the BER type but none of the value for an element
-MILD_ERR_ASN1_ELEMENT_SET_INVALID_NUM_LENGTH_BYTES_8=Cannot decode the \
- provided byte array as a set of ASN.1 elements because it contained a \
- multi-byte length with an invalid number of bytes (%d)
-MILD_ERR_ASN1_ELEMENT_SET_TRUNCATED_LENGTH_9=Cannot decode the provided byte \
- array as a set of ASN.1 elements because it contained a multi-byte length of \
- %d bytes but the array was too short to contain the entire length
-MILD_ERR_ASN1_ELEMENT_SET_TRUNCATED_VALUE_10=Cannot decode the provided byte \
- array as a set of ASN.1 elements because the decoded length of an element \
- (%d) is more than the number of bytes remaining (%d)
-MILD_ERR_ASN1_BOOLEAN_SET_VALUE_NULL_11=Cannot decode the provided byte array \
- as the value of an ASN.1 Boolean element because the array was null
-MILD_ERR_ASN1_BOOLEAN_SET_VALUE_INVALID_LENGTH_12=Cannot decode the provided \
- byte array as the value of an ASN.1 Boolean element because the array did not \
- have a length of exactly one byte (provided length was %d)
-MILD_ERR_ASN1_BOOLEAN_DECODE_ELEMENT_NULL_13=Cannot decode the provided ASN.1 \
- element as a Boolean element because the provided element was null
-MILD_ERR_ASN1_BOOLEAN_DECODE_ELEMENT_INVALID_LENGTH_14=Cannot decode the \
- provided ASN.1 element as a Boolean element because the length of the element \
- value was not exactly one byte (actual length was %d)
-MILD_ERR_ASN1_BOOLEAN_DECODE_ARRAY_NULL_15=Cannot decode the provided byte \
- array as an ASN.1 Boolean element because the array was null
-MILD_ERR_ASN1_BOOLEAN_SHORT_ELEMENT_16=Cannot decode the provided byte array \
- as an ASN.1 Boolean element because the length of the array (%d bytes) is \
- less than the minimum required for a Boolean element (3 bytes)
-MILD_ERR_ASN1_BOOLEAN_DECODE_ARRAY_INVALID_LENGTH_17=Cannot decode the \
- provided byte array as an ASN.1 Boolean element because the decoded value \
- length was not exactly one byte (decoded length was %d)
-MILD_ERR_ASN1_NULL_SET_VALUE_INVALID_LENGTH_18=Cannot decode the provided \
- byte array as the value of an ASN.1 null element because the array did not \
- have a length of exactly zero byte (provided length was %d)
-MILD_ERR_ASN1_NULL_DECODE_ELEMENT_NULL_19=Cannot decode the provided ASN.1 \
- element as a null element because the provided element was null
-MILD_ERR_ASN1_NULL_DECODE_ELEMENT_INVALID_LENGTH_20=Cannot decode the \
- provided ASN.1 element as a null element because the length of the element \
- value was not exactly zero bytes (actual length was %d)
-MILD_ERR_ASN1_NULL_DECODE_ARRAY_NULL_21=Cannot decode the provided byte array \
- as an ASN.1 null element because the array was null
-MILD_ERR_ASN1_NULL_DECODE_ARRAY_INVALID_LENGTH_22=Cannot decode the provided \
- byte array as an ASN.1 null element because the decoded value length was not \
- exactly zero bytes (decoded length was %d)
-MILD_ERR_ASN1_OCTET_STRING_DECODE_ELEMENT_NULL_23=Cannot decode the provided \
- ASN.1 element as an octet string element because the provided element was \
- null
-MILD_ERR_ASN1_OCTET_STRING_DECODE_ARRAY_NULL_24=Cannot decode the provided \
- byte array as an ASN.1 octet string element because the array was null
-MILD_ERR_ASN1_INTEGER_SET_VALUE_NULL_25=Cannot decode the provided byte array \
- as the value of an ASN.1 integer element because the array was null
-MILD_ERR_ASN1_INTEGER_SET_VALUE_INVALID_LENGTH_26=Cannot decode the provided \
- byte array as the value of an ASN.1 integer element because the array did not \
- have a length between 1 and 4 bytes (provided length was %d)
-MILD_ERR_ASN1_INTEGER_DECODE_ELEMENT_NULL_27=Cannot decode the provided ASN.1 \
- element as an integer element because the provided element was null
-MILD_ERR_ASN1_INTEGER_DECODE_ELEMENT_INVALID_LENGTH_28=Cannot decode the \
- provided ASN.1 element as an integer element because the length of the \
+MILD_ERR_ASN1_TRUCATED_TYPE_BYTE_1=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_2=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_3=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_4=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_5=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_6=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_7=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_8=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_9=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_10=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_11=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_INTEGER_DECODE_ARRAY_NULL_29=Cannot decode the provided byte \
- array as an ASN.1 integer element because the array was null
-MILD_ERR_ASN1_INTEGER_SHORT_ELEMENT_30=Cannot decode the provided byte array \
- as an ASN.1 integer element because the length of the array (%d bytes) is \
- less than the minimum required for an integer element (3 bytes)
-MILD_ERR_ASN1_INTEGER_DECODE_ARRAY_INVALID_LENGTH_31=Cannot decode the \
- provided byte array as an ASN.1 integer element because the decoded value \
- length was not between 1 and 4 bytes (decoded length was %d)
-MILD_ERR_ASN1_ENUMERATED_SET_VALUE_NULL_32=Cannot decode the provided byte \
- array as the value of an ASN.1 enumerated element because the array was null
-MILD_ERR_ASN1_ENUMERATED_SET_VALUE_INVALID_LENGTH_33=Cannot decode the \
- provided byte array as the value of an ASN.1 enumerated element because the \
- array did not have a length between 1 and 4 bytes (provided length was %d)
-MILD_ERR_ASN1_ENUMERATED_DECODE_ELEMENT_NULL_34=Cannot decode the provided \
- ASN.1 element as an enumerated element because the provided element was null
-MILD_ERR_ASN1_ENUMERATED_DECODE_ELEMENT_INVALID_LENGTH_35=Cannot decode the \
- provided ASN.1 element as an enumerated element because the length of the \
- element value was not between one and four bytes (actual length was %d)
-MILD_ERR_ASN1_ENUMERATED_DECODE_ARRAY_NULL_36=Cannot decode the provided byte \
- array as an ASN.1 enumerated element because the array was null
-MILD_ERR_ASN1_ENUMERATED_SHORT_ELEMENT_37=Cannot decode the provided byte \
- array as an ASN.1 enumerated element because the length of the array (%d \
- bytes) is less than the minimum required for an enumerated element (3 bytes)
-MILD_ERR_ASN1_ENUMERATED_DECODE_ARRAY_INVALID_LENGTH_38=Cannot decode the \
- provided byte array as an ASN.1 enumerated element because the decoded value \
- length was not between 1 and 4 bytes (decoded length was %d)
-MILD_ERR_ASN1_SEQUENCE_SET_VALUE_NULL_39=Cannot decode the provided byte \
- array as the value of an ASN.1 sequence element because the array was null
-MILD_ERR_ASN1_SEQUENCE_DECODE_ELEMENT_NULL_40=Cannot decode the provided \
- ASN.1 element as a sequence element because the provided element was null
-MILD_ERR_ASN1_SEQUENCE_DECODE_ARRAY_NULL_41=Cannot decode the provided byte \
- array as an ASN.1 sequence element because the array was null
-MILD_ERR_ASN1_SET_SET_VALUE_NULL_42=Cannot decode the provided byte array as \
- the value of an ASN.1 set element because the array was null
-MILD_ERR_ASN1_SET_DECODE_ELEMENT_NULL_43=Cannot decode the provided ASN.1 \
- element as a set element because the provided element was null
-MILD_ERR_ASN1_SET_DECODE_ARRAY_NULL_44=Cannot decode the provided byte array \
- as an ASN.1 set element because the array was null
+MILD_ERR_ASN1_SEQUENCE_READ_NOT_STARTED_12=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_13=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_14=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_15=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_45=Cannot decode the provided ASN.1 \
  sequence as an LDAP message because the sequence was null
 MILD_ERR_LDAP_MESSAGE_DECODE_INVALID_ELEMENT_COUNT_46=Cannot decode the \
@@ -1465,4 +1393,13 @@
  Please check the configuration attributes
 SEVERE_ERR_SNMP_CONNHANDLER_NO_VALID_TRAP_DESTINATIONS_1466=No valid trap \
  destinations has been found. No trap will be sent
-
+SEVERE_ERR_ASN1_READ_ERROR_1500=An error occured while accessing the \
+ underlying data source: %s
+SEVERE_ERR_ASN1_EOF_ERROR_1501=An unexpected end of file reached while trying \
+ to read %d bytes from the underlying data source
+SEVERE_ERR_ASN1_INVALID_STATE_1502=Invalid reader state: %d
+SEVERE_ERR_SUBTREE_DELETE_INVALID_CONTROL_VALUE_1503=Cannot decode the provided \
+ subtree delete control because it contains a value
+ SEVERE_ERR_CONNHANDLER_SSL_CANNOT_INITIALIZE_1504=An error occurred \
+ while attempting to initialize the SSL context for use in the LDAP \
+ Connection Handler:  %s
diff --git a/opends/src/messages/src/org/opends/messages/MessageBuilder.java b/opends/src/messages/src/org/opends/messages/MessageBuilder.java
index 7481597..79cdc80 100644
--- a/opends/src/messages/src/org/opends/messages/MessageBuilder.java
+++ b/opends/src/messages/src/org/opends/messages/MessageBuilder.java
@@ -22,7 +22,7 @@
  * CDDL HEADER END
  *
  *
- *      Copyright 2007-2008 Sun Microsystems, Inc.
+ *      Copyright 2007-2009 Sun Microsystems, Inc.
  */
 
 package org.opends.messages;
@@ -270,19 +270,20 @@
    * @return Message raw message representing builder content
    */
   public Message toMessage() {
+    if(messages.isEmpty())
+    {
+      return Message.EMPTY;
+    }
+
     StringBuffer fmtString = new StringBuffer();
     for (int i = 0; i < messages.size(); i++) {
       fmtString.append("%s");
     }
 
-    if (messages.isEmpty()) {
-      return Message.raw(fmtString, messages.toArray());
-    } else {
-      // Inherit the category and severity of the first message.
-      MessageDescriptor md = messages.get(0).getDescriptor();
-      return Message.raw(md.getCategory(), md.getSeverity(), fmtString,
-          messages.toArray());
-    }
+    // Inherit the category and severity of the first message.
+    MessageDescriptor md = messages.get(0).getDescriptor();
+    return Message.raw(md.getCategory(), md.getSeverity(), fmtString,
+        messages.toArray());
   }
 
   /**
diff --git a/opends/src/quicksetup/org/opends/quicksetup/installer/ui/SecurityOptionsDialog.java b/opends/src/quicksetup/org/opends/quicksetup/installer/ui/SecurityOptionsDialog.java
index fe66fa2..743787c 100644
--- a/opends/src/quicksetup/org/opends/quicksetup/installer/ui/SecurityOptionsDialog.java
+++ b/opends/src/quicksetup/org/opends/quicksetup/installer/ui/SecurityOptionsDialog.java
@@ -22,7 +22,7 @@
  * CDDL HEADER END
  *
  *
- *      Copyright 2008 Sun Microsystems, Inc.
+ *      Copyright 2008-2009 Sun Microsystems, Inc.
  */
 
 package org.opends.quicksetup.installer.ui;
@@ -129,6 +129,7 @@
 
     addWindowListener(new WindowAdapter()
     {
+      @Override
       public void windowClosing(WindowEvent e)
       {
         cancelClicked();
@@ -664,6 +665,7 @@
   {
     BackgroundTask worker = new BackgroundTask()
     {
+      @Override
       public Object processBackgroundTask()
       {
         ArrayList<Message> errorMsgs = new ArrayList<Message>();
@@ -675,6 +677,7 @@
         return errorMsgs;
       }
 
+      @Override
       public void backgroundTaskCompleted(Object returnValue,
           Throwable throwable)
       {
diff --git a/opends/src/quicksetup/org/opends/quicksetup/ui/CertificateDialog.java b/opends/src/quicksetup/org/opends/quicksetup/ui/CertificateDialog.java
index 4e99e1c..8e0c0cd 100644
--- a/opends/src/quicksetup/org/opends/quicksetup/ui/CertificateDialog.java
+++ b/opends/src/quicksetup/org/opends/quicksetup/ui/CertificateDialog.java
@@ -22,7 +22,7 @@
  * CDDL HEADER END
  *
  *
- *      Copyright 2008 Sun Microsystems, Inc.
+ *      Copyright 2008-2009 Sun Microsystems, Inc.
  */
 
 package org.opends.quicksetup.ui;
@@ -142,6 +142,7 @@
 
     addWindowListener(new WindowAdapter()
     {
+      @Override
       public void windowClosing(WindowEvent e)
       {
         doNotAccept();
diff --git a/opends/src/quicksetup/org/opends/quicksetup/ui/UIFactory.java b/opends/src/quicksetup/org/opends/quicksetup/ui/UIFactory.java
index 419caba..346cd3d 100644
--- a/opends/src/quicksetup/org/opends/quicksetup/ui/UIFactory.java
+++ b/opends/src/quicksetup/org/opends/quicksetup/ui/UIFactory.java
@@ -22,7 +22,7 @@
  * CDDL HEADER END
  *
  *
- *      Copyright 2006-2008 Sun Microsystems, Inc.
+ *      Copyright 2006-2009 Sun Microsystems, Inc.
  */
 
 package org.opends.quicksetup.ui;
@@ -1287,6 +1287,7 @@
       col.setHeaderRenderer(headerRenderer);
     }
     MouseAdapter listMouseListener = new MouseAdapter() {
+      @Override
       public void mouseClicked(MouseEvent e) {
         TableColumnModel columnModel = table.getColumnModel();
         int viewColumn = columnModel.getColumnIndexAtX(e.getX());
@@ -1754,6 +1755,7 @@
   /**
    * {@inheritDoc}
    */
+  @Override
   public Component getTableCellRendererComponent(JTable table, Object value,
       boolean isSelected, boolean hasFocus, int row, int column) {
     setText((String)value);
@@ -1818,6 +1820,7 @@
   /**
    * {@inheritDoc}
    */
+  @Override
   public void setText(String text)
   {
     // Scroll can be null in constructor
@@ -1841,6 +1844,7 @@
   /**
    * {@inheritDoc}
    */
+  @Override
   public void scrollRectToVisible(Rectangle rect)
   {
     if (!ignoreScrollToVisible)
diff --git a/opends/src/quicksetup/org/opends/quicksetup/util/InProcessServerController.java b/opends/src/quicksetup/org/opends/quicksetup/util/InProcessServerController.java
index 69f7f20..0f18997 100644
--- a/opends/src/quicksetup/org/opends/quicksetup/util/InProcessServerController.java
+++ b/opends/src/quicksetup/org/opends/quicksetup/util/InProcessServerController.java
@@ -42,7 +42,6 @@
 import org.opends.server.loggers.AccessLogger;
 import org.opends.server.types.Modification;
 import org.opends.server.types.ResultCode;
-import org.opends.server.types.ByteStringFactory;
 import org.opends.server.types.ByteString;
 import org.opends.server.types.InitializationException;
 import org.opends.server.types.Attribute;
@@ -60,7 +59,6 @@
 import org.opends.server.protocols.internal.InternalClientConnection;
 import org.opends.server.protocols.internal.InternalSearchOperation;
 import org.opends.server.protocols.ldap.LDAPAttribute;
-import org.opends.server.protocols.asn1.ASN1OctetString;
 import org.opends.server.core.ModifyOperation;
 import org.opends.server.core.DirectoryServer;
 import org.opends.server.core.AddOperation;
@@ -411,7 +409,7 @@
     InternalClientConnection cc =
             InternalClientConnection.getRootConnection();
     ByteString dnByteString =
-            ByteStringFactory.create(
+        ByteString.valueOf(
                     cre.getDN().toString());
     ResultCode rc;
     switch (cre.getChangeOperationType()) {
@@ -467,8 +465,8 @@
           // can ignore this add.
           boolean ignore = true;
           for (RawAttribute attr : rawAttrs) {
-            ArrayList<ASN1OctetString> values = attr.getValues();
-            for (ASN1OctetString value : values) {
+            ArrayList<ByteString> values = attr.getValues();
+            for (ByteString value : values) {
               CompareOperation compOp =
                 cc.processCompare(dnByteString, attr.getAttributeType(), value);
               if (ResultCode.ASSERTION_FAILED.equals(compOp.getResultCode())) {
diff --git a/opends/src/server/org/opends/server/admin/ACIPropertyDefinition.java b/opends/src/server/org/opends/server/admin/ACIPropertyDefinition.java
index 23bbc93..4c32e8c 100644
--- a/opends/src/server/org/opends/server/admin/ACIPropertyDefinition.java
+++ b/opends/src/server/org/opends/server/admin/ACIPropertyDefinition.java
@@ -30,8 +30,8 @@
 import org.opends.server.authorization.dseecompat.Aci;
 import org.opends.server.authorization.dseecompat.AciException;
 import org.opends.server.types.DN;
+import org.opends.server.types.ByteString;
 import static org.opends.server.util.Validator.ensureNotNull;
-import org.opends.server.protocols.asn1.ASN1OctetString;
 
 import java.util.EnumSet;
 
@@ -116,7 +116,7 @@
     ensureNotNull(value);
 
     try {
-      return Aci.decode(new ASN1OctetString(value), DN.NULL_DN);
+      return Aci.decode(ByteString.valueOf(value), DN.NULL_DN);
     } catch (AciException e) {
       // TODO: it would be nice to throw the cause.
       throw new IllegalPropertyValueStringException(this, value);
diff --git a/opends/src/server/org/opends/server/admin/AdministrationConnector.java b/opends/src/server/org/opends/server/admin/AdministrationConnector.java
index 2cd04fd..f819898 100644
--- a/opends/src/server/org/opends/server/admin/AdministrationConnector.java
+++ b/opends/src/server/org/opends/server/admin/AdministrationConnector.java
@@ -73,11 +73,12 @@
 
 /**
  * This class is a wrapper on top of LDAPConnectionHandler to manage
- * the administration connector, which is an LDAPConnectionHandler with specific
- * (limited) configuration properties.
+ * the administration connector, which is an LDAPConnectionHandler
+ * with specific (limited) configuration properties.
  */
-public final class AdministrationConnector
-  implements ConfigurationChangeListener<AdministrationConnectorCfg> {
+public final class AdministrationConnector implements
+    ConfigurationChangeListener<AdministrationConnectorCfg>
+{
 
   /**
    * Default Administration Connector port.
@@ -89,44 +90,68 @@
    */
   public static final int ADMIN_CERT_VALIDITY = 2 * 365;
 
- // Friendly name of the administration connector
+  // Friendly name of the administration connector
   private static final String FRIENDLY_NAME = "Administration Connector";
 
   // The tracer object for the debug logger.
   private static final DebugTracer TRACER = getTracer();
+
   private LDAPConnectionHandler adminConnectionHandler;
-  private AdministrationConnectorCfg config;  //
+
+  private AdministrationConnectorCfg config; //
+
   // Predefined values for Administration Connector configuration
   //
   private static final String ADMIN_CLASS_NAME =
     "org.opends.server.protocols.ldap.LDAPConnectionHandler";
+
   private static final boolean ADMIN_ALLOW_LDAP_V2 = true;
+
   private static final boolean ADMIN_ALLOW_START_TLS = false;
+
   private static final SortedSet<AddressMask> ADMIN_ALLOWED_CLIENT =
     new TreeSet<AddressMask>();
+
   private static final SortedSet<AddressMask> ADMIN_DENIED_CLIENT =
     new TreeSet<AddressMask>();
+
   private static final boolean ADMIN_ENABLED = true;
+
   private static final boolean ADMIN_KEEP_STATS = true;
+
   private static final boolean ADMIN_USE_SSL = true;
+
   private static final int ADMIN_ACCEPT_BACKLOG = 128;
+
   private static final boolean ADMIN_ALLOW_TCP_REUSE_ADDRESS = true;
+
   private static final long ADMIN_MAX_BLOCKED_WRITE_TIME_LIMIT = 120000; // 2mn
+
   private static final int ADMIN_MAX_REQUEST_SIZE = 5000000; // 5 Mb
+
   private static final int ADMIN_NUM_REQUEST_HANDLERS = 1;
+
   private static final boolean ADMIN_SEND_REJECTION_NOTICE = true;
+
   private static final boolean ADMIN_USE_TCP_KEEP_ALIVE = true;
+
   private static final boolean ADMIN_USE_TCP_NO_DELAY = true;
+
   private static final SSLClientAuthPolicy ADMIN_SSL_CLIENT_AUTH_POLICY =
     SSLClientAuthPolicy.DISABLED;
+
   private static final SortedSet<String> ADMIN_SSL_CIPHER_SUITE =
     new TreeSet<String>();
+
   private static final SortedSet<String> ADMIN_SSL_PROTOCOL =
     new TreeSet<String>();
 
+
+
   /**
    * Initializes this administration connector provider based on the
-   * information in the provided administration connector configuration.
+   * information in the provided administration connector
+   * configuration.
    *
    * @param configuration
    *          The connection handler configuration that contains the
@@ -141,8 +166,9 @@
    *           related to the server configuration.
    */
   public void initializeAdministrationConnector(
-    AdministrationConnectorCfg configuration)
-    throws ConfigException, InitializationException {
+      AdministrationConnectorCfg configuration) throws ConfigException,
+      InitializationException
+  {
 
     this.config = configuration;
 
@@ -152,364 +178,495 @@
 
     createSelfSignedCertifIfNeeded();
 
-    // Administration Connector uses the LDAP connection handler implementation
-    adminConnectionHandler =
-      new LDAPConnectionHandler(new SynchronousStrategy(), FRIENDLY_NAME);
-    adminConnectionHandler.
-      initializeConnectionHandler(ldapConnectionHandlerCfg);
+
+    // Administration Connector uses the LDAP connection handler
+    // implementation
+    adminConnectionHandler = new LDAPConnectionHandler(
+        new SynchronousStrategy(), FRIENDLY_NAME);
+    adminConnectionHandler
+        .initializeConnectionHandler(ldapConnectionHandlerCfg);
     adminConnectionHandler.setAdminConnectionHandler();
 
     // Register this as a change listener.
     config.addChangeListener(this);
   }
 
+
+
   /**
    * Create an instance of the administration connector.
    */
-  public AdministrationConnector() {
+  public AdministrationConnector()
+  {
     // Do nothing.
   }
 
+
+
   /**
-   * Retrieves the connection handler linked to this administration connector.
+   * Retrieves the connection handler linked to this administration
+   * connector.
    *
-   * @return The connection handler linked to this administration connector.
+   * @return The connection handler linked to this administration
+   *         connector.
    */
-  public LDAPConnectionHandler getConnectionHandler() {
+  public LDAPConnectionHandler getConnectionHandler()
+  {
     return adminConnectionHandler;
   }
 
+
+
   /**
    * {@inheritDoc}
    */
   public boolean isConfigurationChangeAcceptable(
-    AdministrationConnectorCfg configuration,
-    List<Message> unacceptableReasons) {
-    LDAPConnectionHandlerCfg cfg =
-      new FakeLDAPConnectionHandlerCfg(configuration);
-    return adminConnectionHandler.isConfigurationAcceptable(
-      cfg, unacceptableReasons);
+      AdministrationConnectorCfg configuration,
+      List<Message> unacceptableReasons)
+  {
+    LDAPConnectionHandlerCfg cfg = new FakeLDAPConnectionHandlerCfg(
+        configuration);
+    return adminConnectionHandler.isConfigurationAcceptable(cfg,
+        unacceptableReasons);
   }
 
+
+
   /**
    * {@inheritDoc}
    */
   public ConfigChangeResult applyConfigurationChange(
-    AdministrationConnectorCfg configuration) {
-    return new ConfigChangeResult(
-      ResultCode.SUCCESS, true, new ArrayList<Message>());
+      AdministrationConnectorCfg configuration)
+  {
+    return new ConfigChangeResult(ResultCode.SUCCESS, true,
+        new ArrayList<Message>());
   }
 
+
+
   /**
-   * This private class implements a fake LDAP connection Handler configuration.
-   * This allows to re-use the LDAPConnectionHandler as it is.
-   *
+   * This private class implements a fake LDAP connection Handler
+   * configuration. This allows to re-use the LDAPConnectionHandler as
+   * it is.
    */
-  private static class FakeLDAPConnectionHandlerCfg
-    implements LDAPConnectionHandlerCfg {
+  private static class FakeLDAPConnectionHandlerCfg implements
+      LDAPConnectionHandlerCfg
+  {
 
     private final AdministrationConnectorCfg config;
 
-    public FakeLDAPConnectionHandlerCfg(AdministrationConnectorCfg config) {
+
+
+    public FakeLDAPConnectionHandlerCfg(AdministrationConnectorCfg config)
+    {
       this.config = config;
     }
 
+
+
     /**
      * {@inheritDoc}
      */
-    public Class<? extends LDAPConnectionHandlerCfg> configurationClass() {
+    public Class<? extends LDAPConnectionHandlerCfg> configurationClass()
+    {
       return LDAPConnectionHandlerCfg.class;
     }
 
+
+
     /**
      * {@inheritDoc}
      */
     public void addLDAPChangeListener(
-      ConfigurationChangeListener<LDAPConnectionHandlerCfg> listener) {
+        ConfigurationChangeListener<LDAPConnectionHandlerCfg> listener)
+    {
       // do nothing. change listener already added.
     }
 
+
+
     /**
      * {@inheritDoc}
      */
     public void removeLDAPChangeListener(
-      ConfigurationChangeListener<LDAPConnectionHandlerCfg> listener) {
+        ConfigurationChangeListener<LDAPConnectionHandlerCfg> listener)
+    {
       // do nothing. change listener already added.
     }
 
+
+
     /**
      * {@inheritDoc}
      */
-    public int getAcceptBacklog() {
+    public int getAcceptBacklog()
+    {
       return ADMIN_ACCEPT_BACKLOG;
     }
 
+
+
     /**
      * {@inheritDoc}
      */
-    public boolean isAllowLDAPV2() {
+    public boolean isAllowLDAPV2()
+    {
       return ADMIN_ALLOW_LDAP_V2;
     }
 
+
+
     /**
      * {@inheritDoc}
      */
-    public boolean isAllowStartTLS() {
+    public boolean isAllowStartTLS()
+    {
       return ADMIN_ALLOW_START_TLS;
     }
 
+
+
     /**
      * {@inheritDoc}
      */
-    public boolean isAllowTCPReuseAddress() {
+    public boolean isAllowTCPReuseAddress()
+    {
       return ADMIN_ALLOW_TCP_REUSE_ADDRESS;
     }
 
+
+
     /**
      * {@inheritDoc}
      */
-    public String getJavaClass() {
+    public String getJavaClass()
+    {
       return ADMIN_CLASS_NAME;
     }
 
+
+
     /**
      * {@inheritDoc}
      */
-    public boolean isKeepStats() {
+    public boolean isKeepStats()
+    {
       return ADMIN_KEEP_STATS;
     }
 
+
+
     /**
      * {@inheritDoc}
      */
-    public String getKeyManagerProvider() {
+    public String getKeyManagerProvider()
+    {
       return config.getKeyManagerProvider();
     }
 
+
+
     /**
      * {@inheritDoc}
      */
-    public DN getKeyManagerProviderDN() {
+    public DN getKeyManagerProviderDN()
+    {
       return config.getKeyManagerProviderDN();
     }
 
+
+
     /**
      * {@inheritDoc}
      */
-    public SortedSet<InetAddress> getListenAddress() {
+    public SortedSet<InetAddress> getListenAddress()
+    {
       return config.getListenAddress();
     }
 
+
+
     /**
      * {@inheritDoc}
      */
-    public int getListenPort() {
+    public int getListenPort()
+    {
       return config.getListenPort();
     }
 
+
+
     /**
      * {@inheritDoc}
      */
-    public long getMaxBlockedWriteTimeLimit() {
+    public long getMaxBlockedWriteTimeLimit()
+    {
       return ADMIN_MAX_BLOCKED_WRITE_TIME_LIMIT;
     }
 
+
+
     /**
      * {@inheritDoc}
      */
-    public long getMaxRequestSize() {
+    public long getMaxRequestSize()
+    {
       return ADMIN_MAX_REQUEST_SIZE;
     }
 
+
+
     /**
      * {@inheritDoc}
      */
-    public int getNumRequestHandlers() {
+    public int getNumRequestHandlers()
+    {
       return ADMIN_NUM_REQUEST_HANDLERS;
     }
 
+
+
     /**
      * {@inheritDoc}
      */
-    public boolean isSendRejectionNotice() {
+    public boolean isSendRejectionNotice()
+    {
       return ADMIN_SEND_REJECTION_NOTICE;
     }
 
+
+
     /**
      * {@inheritDoc}
      */
-    public String getSSLCertNickname() {
+    public String getSSLCertNickname()
+    {
       return config.getSSLCertNickname();
     }
 
+
+
     /**
      * {@inheritDoc}
      */
-    public SortedSet<String> getSSLCipherSuite() {
+    public SortedSet<String> getSSLCipherSuite()
+    {
       return ADMIN_SSL_CIPHER_SUITE;
     }
 
+
+
     /**
      * {@inheritDoc}
      */
-    public SSLClientAuthPolicy getSSLClientAuthPolicy() {
+    public SSLClientAuthPolicy getSSLClientAuthPolicy()
+    {
       return ADMIN_SSL_CLIENT_AUTH_POLICY;
     }
 
+
+
     /**
      * {@inheritDoc}
      */
-    public SortedSet<String> getSSLProtocol() {
+    public SortedSet<String> getSSLProtocol()
+    {
       return ADMIN_SSL_PROTOCOL;
     }
 
+
+
     /**
      * {@inheritDoc}
      */
-    public String getTrustManagerProvider() {
+    public String getTrustManagerProvider()
+    {
       return config.getTrustManagerProvider();
     }
 
+
+
     /**
      * {@inheritDoc}
      */
-    public DN getTrustManagerProviderDN() {
+    public DN getTrustManagerProviderDN()
+    {
       return config.getTrustManagerProviderDN();
     }
 
+
+
     /**
      * {@inheritDoc}
      */
-    public boolean isUseSSL() {
+    public boolean isUseSSL()
+    {
       return ADMIN_USE_SSL;
     }
 
-    /**
-     * {@inheritDoc}
-     */
-    public boolean isUseTCPKeepAlive() {
-      return ADMIN_USE_TCP_KEEP_ALIVE;
-    }
+
 
     /**
      * {@inheritDoc}
      */
-    public boolean isUseTCPNoDelay() {
+    public boolean isUseTCPKeepAlive()
+    {
+      return ADMIN_USE_TCP_KEEP_ALIVE;
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isUseTCPNoDelay()
+    {
       return ADMIN_USE_TCP_NO_DELAY;
     }
 
+
+
     /**
      * {@inheritDoc}
      */
     public void addChangeListener(
-      ConfigurationChangeListener<ConnectionHandlerCfg> listener) {
+        ConfigurationChangeListener<ConnectionHandlerCfg> listener)
+    {
       // do nothing. change listener already added.
     }
 
+
+
     /**
      * {@inheritDoc}
      */
     public void removeChangeListener(
-      ConfigurationChangeListener<ConnectionHandlerCfg> listener) {
+        ConfigurationChangeListener<ConnectionHandlerCfg> listener)
+    {
       // do nothing. change listener already added.
     }
 
+
+
     /**
      * {@inheritDoc}
      */
-    public SortedSet<AddressMask> getAllowedClient() {
+    public SortedSet<AddressMask> getAllowedClient()
+    {
       return ADMIN_ALLOWED_CLIENT;
     }
 
+
+
     /**
      * {@inheritDoc}
      */
-    public SortedSet<AddressMask> getDeniedClient() {
+    public SortedSet<AddressMask> getDeniedClient()
+    {
       return ADMIN_DENIED_CLIENT;
     }
 
-    /**
-     * {@inheritDoc}
-     */
-    public boolean isEnabled() {
-      return ADMIN_ENABLED;
-    }
+
 
     /**
      * {@inheritDoc}
      */
-    public DN dn() {
+    public boolean isEnabled()
+    {
+      return ADMIN_ENABLED;
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public DN dn()
+    {
       return config.dn();
     }
   }
 
+
+
   /**
    * Creates a self-signed JKS certificate if needed.
    */
-  private void createSelfSignedCertifIfNeeded()
-    throws InitializationException {
+  private void createSelfSignedCertifIfNeeded() throws InitializationException
+  {
 
-    try {
+    try
+    {
 
       // Check if certificate generation is needed
       String certAlias = config.getSSLCertNickname();
       KeyManagerProviderCfg keyMgrConfig =
         getAdminConnectorKeyManagerConfig(config.getKeyManagerProvider());
+
       TrustManagerProviderCfg trustMgrConfig =
         getAdminConnectorTrustManagerConfig(config.getTrustManagerProvider());
 
-      if (!(keyMgrConfig instanceof FileBasedKeyManagerProviderCfg) ||
-        !(trustMgrConfig instanceof FileBasedTrustManagerProviderCfg)) {
+      if (!(keyMgrConfig instanceof FileBasedKeyManagerProviderCfg)
+          || !(trustMgrConfig instanceof FileBasedTrustManagerProviderCfg))
+      {
         // The default config has been changed, nothing to do
         return;
       }
 
       FileBasedKeyManagerProviderCfg fbKeyManagerConfig =
         (FileBasedKeyManagerProviderCfg) keyMgrConfig;
-      String keystorePath =
-        getFullPath(fbKeyManagerConfig.getKeyStoreFile());
+      String keystorePath = getFullPath(fbKeyManagerConfig.getKeyStoreFile());
       FileBasedTrustManagerProviderCfg fbTrustManagerConfig =
         (FileBasedTrustManagerProviderCfg) trustMgrConfig;
-      String truststorePath =
-        getFullPath(fbTrustManagerConfig.getTrustStoreFile());
+      String truststorePath = getFullPath(fbTrustManagerConfig
+          .getTrustStoreFile());
       String pinFilePath = getFullPath(fbKeyManagerConfig.getKeyStorePinFile());
 
       // Check that either we do not have any file,
-      // or we have the 3 required files (keystore, truststore, pin file)
+      // or we have the 3 required files (keystore, truststore, pin
+      // file)
       boolean keystore = false;
       boolean truststore = false;
       boolean pinFile = false;
       int nbFiles = 0;
-      if (new File(keystorePath).exists()) {
+      if (new File(keystorePath).exists())
+      {
         keystore = true;
         nbFiles++;
       }
-      if (new File(truststorePath).exists()) {
+      if (new File(truststorePath).exists())
+      {
         truststore = true;
         nbFiles++;
       }
-      if (new File(pinFilePath).exists()) {
+      if (new File(pinFilePath).exists())
+      {
         pinFile = true;
         nbFiles++;
       }
-      if (nbFiles == 3) {
+      if (nbFiles == 3)
+      {
         // nothing to do
         return;
       }
-      if (nbFiles != 0) {
+      if (nbFiles != 0)
+      {
         // 1 or 2 files are missing : error
         String err = "";
-        if (!keystore) {
+        if (!keystore)
+        {
           err += keystorePath + " ";
         }
-        if (!truststore) {
+        if (!truststore)
+        {
           err += truststorePath + " ";
         }
-        if (!pinFile) {
+        if (!pinFile)
+        {
           err += pinFilePath + " ";
         }
-        Message message =
-          ERR_ADMIN_CERTIFICATE_GENERATION_MISSING_FILES.get(err);
+        Message message = ERR_ADMIN_CERTIFICATE_GENERATION_MISSING_FILES
+            .get(err);
         logError(message);
         throw new InitializationException(message);
       }
@@ -519,30 +676,28 @@
 
       // Generate a self-signed certificate
       CertificateManager certManager = new CertificateManager(
-        getFullPath(fbKeyManagerConfig.getKeyStoreFile()),
-        fbKeyManagerConfig.getKeyStoreType(),
-        pwd);
-      String subjectDN = "cn=" +
-        Rdn.escapeValue(InetAddress.getLocalHost().getHostName()) +
-        ",O=" + FRIENDLY_NAME + " Self-Signed Certificate";
-      certManager.generateSelfSignedCertificate(
-        certAlias, subjectDN, ADMIN_CERT_VALIDITY);
+          getFullPath(fbKeyManagerConfig.getKeyStoreFile()), fbKeyManagerConfig
+              .getKeyStoreType(), pwd);
+      String subjectDN = "cn="
+          + Rdn.escapeValue(InetAddress.getLocalHost().getHostName()) + ",O="
+          + FRIENDLY_NAME + " Self-Signed Certificate";
+      certManager.generateSelfSignedCertificate(certAlias, subjectDN,
+          ADMIN_CERT_VALIDITY);
 
       // Export the certificate
-      String tempCertPath = getFullPath("config" + File.separator +
-        "admin-cert.txt");
-      SetupUtils.exportCertificate(certManager, certAlias,
-        tempCertPath);
+      String tempCertPath = getFullPath("config" + File.separator
+          + "admin-cert.txt");
+      SetupUtils.exportCertificate(certManager, certAlias, tempCertPath);
 
-      // Create a new trust store and import the server certificate into it
-      CertificateManager trustManager = new CertificateManager(
-        truststorePath,
-        CertificateManager.KEY_STORE_TYPE_JKS,
-        pwd);
+      // Create a new trust store and import the server certificate
+      // into it
+      CertificateManager trustManager = new CertificateManager(truststorePath,
+          CertificateManager.KEY_STORE_TYPE_JKS, pwd);
       trustManager.addCertificate(certAlias, new File(tempCertPath));
 
       // Generate a password file
-      if (!new File(pinFilePath).exists()) {
+      if (!new File(pinFilePath).exists())
+      {
         FileWriter file = new FileWriter(pinFilePath);
         PrintWriter out = new PrintWriter(file);
         out.println(pwd);
@@ -552,16 +707,21 @@
       }
 
       // Change the password file permission if possible
-      if (FilePermission.canSetPermissions()) {
-        try {
+      if (FilePermission.canSetPermissions())
+      {
+        try
+        {
           if (!FilePermission.setPermissions(new File(pinFilePath),
-            new FilePermission(0600))) {
+              new FilePermission(0600)))
+          {
             // Log a warning that the permissions were not set.
-            Message message =
-              WARN_ADMIN_SET_PERMISSIONS_FAILED.get(pinFilePath);
+            Message message = WARN_ADMIN_SET_PERMISSIONS_FAILED
+                .get(pinFilePath);
             ErrorLogger.logError(message);
           }
-        } catch (DirectoryException e) {
+        }
+        catch (DirectoryException e)
+        {
           // Log a warning that the permissions were not set.
           Message message = WARN_ADMIN_SET_PERMISSIONS_FAILED.get(pinFilePath);
           ErrorLogger.logError(message);
@@ -571,21 +731,32 @@
       // Delete the exported certificate
       File f = new File(tempCertPath);
       f.delete();
-
-    } catch (ConfigException e) {
+    }
+    catch (ConfigException e)
+    {
       handleCertifExceptions(e);
-    } catch (KeyStoreException e) {
+    }
+    catch (KeyStoreException e)
+    {
       handleCertifExceptions(e);
-    } catch (IOException e) {
+    }
+    catch (IOException e)
+    {
       handleCertifExceptions(e);
-    } catch (CertificateEncodingException e) {
+    }
+    catch (CertificateEncodingException e)
+    {
       handleCertifExceptions(e);
     }
   }
 
-  private void handleCertifExceptions(Exception e) throws
-    InitializationException {
-    if (debugEnabled()) {
+
+
+  private void handleCertifExceptions(Exception e)
+      throws InitializationException
+  {
+    if (debugEnabled())
+    {
       TRACER.debugCaught(DebugLogLevel.ERROR, e);
     }
     Message message = ERR_ADMIN_CERTIFICATE_GENERATION.get(e.getMessage());
@@ -593,23 +764,31 @@
     throw new InitializationException(message);
   }
 
+
+
   private KeyManagerProviderCfg getAdminConnectorKeyManagerConfig(String name)
-    throws ConfigException {
+      throws ConfigException
+  {
     RootCfg root = ServerManagementContext.getInstance().getRootConfiguration();
     return root.getKeyManagerProvider(name);
   }
 
+
+
   private TrustManagerProviderCfg getAdminConnectorTrustManagerConfig(
-    String name)
-    throws ConfigException {
-    RootCfg root =
-      ServerManagementContext.getInstance().getRootConfiguration();
+      String name) throws ConfigException
+  {
+    RootCfg root = ServerManagementContext.getInstance().getRootConfiguration();
     return root.getTrustManagerProvider(name);
   }
 
-  private static String getFullPath(String path) {
+
+
+  private static String getFullPath(String path)
+  {
     File file = new File(path);
-    if (!file.isAbsolute()) {
+    if (!file.isAbsolute())
+    {
       path = DirectoryServer.getInstanceRoot() + File.separator + path;
     }
 
diff --git a/opends/src/server/org/opends/server/admin/AdministrationDataSync.java b/opends/src/server/org/opends/server/admin/AdministrationDataSync.java
index 7664712..c2225a3 100644
--- a/opends/src/server/org/opends/server/admin/AdministrationDataSync.java
+++ b/opends/src/server/org/opends/server/admin/AdministrationDataSync.java
@@ -27,12 +27,12 @@
 package org.opends.server.admin;
 
 
+
 import java.util.LinkedHashSet;
 import java.util.LinkedList;
 import java.util.List;
 
 import org.opends.server.core.DirectoryServer;
-import org.opends.server.protocols.asn1.ASN1OctetString;
 import org.opends.server.protocols.internal.InternalClientConnection;
 import org.opends.server.protocols.internal.InternalSearchOperation;
 import org.opends.server.protocols.ldap.LDAPFilter;
@@ -40,6 +40,7 @@
 import org.opends.server.types.Attribute;
 import org.opends.server.types.AttributeType;
 import org.opends.server.types.Attributes;
+import org.opends.server.types.ByteString;
 import org.opends.server.types.DN;
 import org.opends.server.types.DereferencePolicy;
 import org.opends.server.types.DirectoryException;
@@ -52,10 +53,11 @@
 import org.opends.server.types.SearchScope;
 
 
+
 /**
  * Check if information found in "cn=admin data" is coherent with
- * cn=config. If and inconsistancy is detected, we log a warning message
- * and update "cn=admin data"
+ * cn=config. If and inconsistency is detected, we log a warning
+ * message and update "cn=admin data"
  */
 public final class AdministrationDataSync
 {
@@ -66,25 +68,31 @@
   private InternalClientConnection internalConnection;
 
   /**
-   * The attribute name used to store the port.
-   * TODO Use the default one.
+   * The attribute name used to store the port. TODO Use the default
+   * one.
    */
   private static final String LDAP_PORT = "ds-cfg-listen-port";
 
+
+
   /**
-   * Create an object that will syncrhonize configuration and the admin data.
+   * Create an object that will syncrhonize configuration and the
+   * admin data.
    *
-   * @param internalConnection The root connection.
+   * @param internalConnection
+   *          The root connection.
    */
   public AdministrationDataSync(InternalClientConnection internalConnection)
   {
-    this.internalConnection = internalConnection ;
+    this.internalConnection = internalConnection;
   }
 
+
+
   /**
    * Check if information found in "cn=admin data" is coherent with
-   * cn=config. If and inconsistancy is detected, we log a warning message
-   * and update "cn=admin data"
+   * cn=config. If and inconsistancy is detected, we log a warning
+   * message and update "cn=admin data"
    */
   public void synchronize()
   {
@@ -92,9 +100,11 @@
     checkAdminConnector();
   }
 
+
+
   /**
-   * Check if the admin connector is in sync. The desynchronization could
-   * occurs after the upgrade from 1.0.
+   * Check if the admin connector is in sync. The desynchronization
+   * could occurs after the upgrade from 1.0.
    */
   private void checkAdminConnector()
   {
@@ -107,25 +117,25 @@
     }
 
     // Get the admin port
-    String adminPort =
-      getAttr("cn=Administration Connector,cn=config", LDAP_PORT);
+    String adminPort = getAttr("cn=Administration Connector,cn=config",
+        LDAP_PORT);
     if (adminPort == null)
     {
       // best effort.
-      return ;
+      return;
     }
 
     LinkedList<Modification> mods = new LinkedList<Modification>();
     // adminport
     String attName = "adminport";
-    AttributeType attrType =
-    DirectoryServer.getAttributeType(attName.toLowerCase());
+    AttributeType attrType = DirectoryServer.getAttributeType(attName
+        .toLowerCase());
     if (attrType == null)
     {
       attrType = DirectoryServer.getDefaultAttributeType(attName.toLowerCase());
     }
-    mods.add(new Modification(ModificationType.REPLACE, Attributes
-        .create(attrType, adminPort)));
+    mods.add(new Modification(ModificationType.REPLACE, Attributes.create(
+        attrType, adminPort)));
 
     // adminEnabled
     attName = "adminEnabled";
@@ -134,16 +144,18 @@
     {
       attrType = DirectoryServer.getDefaultAttributeType(attName.toLowerCase());
     }
-    mods.add(new Modification(ModificationType.REPLACE, Attributes
-        .create(attrType, "true")));
+    mods.add(new Modification(ModificationType.REPLACE, Attributes.create(
+        attrType, "true")));
 
     // Process modification
-    internalConnection.processModify(serverEntryDN,mods);
+    internalConnection.processModify(serverEntryDN, mods);
   }
 
+
+
   /**
-   * Look for the DN of the local register server.
-   * Assumption: default Connection Handler naming is used.
+   * Look for the DN of the local register server. Assumption: default
+   * Connection Handler naming is used.
    *
    * @return The DN of the local register server or null.
    */
@@ -152,16 +164,16 @@
     DN returnDN = null;
 
     // Get the LDAP and LDAPS port
-    String ldapPort =
-      getAttr("cn=LDAP Connection Handler,cn=Connection Handlers,cn=config",
-          LDAP_PORT);
-    String ldapsPort =
-      getAttr("cn=LDAPS Connection Handler,cn=Connection Handlers,cn=config",
-          LDAP_PORT);
+    String ldapPort = getAttr(
+        "cn=LDAP Connection Handler,cn=Connection Handlers,cn=config",
+        LDAP_PORT);
+    String ldapsPort = getAttr(
+        "cn=LDAPS Connection Handler,cn=Connection Handlers,cn=config",
+        LDAP_PORT);
     boolean ldapsPortEnable = false;
-    String val =
-      getAttr("cn=LDAPS Connection Handler,cn=Connection Handlers,cn=config",
-          "ds-cfg-enabled");
+    String val = getAttr(
+        "cn=LDAPS Connection Handler,cn=Connection Handlers,cn=config",
+        "ds-cfg-enabled");
     if (val != null)
     {
       ldapsPortEnable = val.toLowerCase().equals("true");
@@ -169,7 +181,7 @@
     if ((ldapPort == null) && (ldapsPort == null))
     {
       // best effort (see assumption)
-      return null ;
+      return null;
     }
 
     // Get the IP address of the local host.
@@ -180,7 +192,7 @@
     }
     catch (Throwable t)
     {
-     // best effort.
+      // best effort.
       return null;
     }
 
@@ -198,7 +210,7 @@
           SearchScope.SINGLE_LEVEL, "objectclass=*");
       if (op.getResultCode() == ResultCode.SUCCESS)
       {
-        Entry entry =  null;
+        Entry entry = null;
         for (Entry currentEntry : op.getSearchEntries())
         {
           String currentHostname = currentEntry.getAttributeValue(hostnameType,
@@ -211,8 +223,8 @@
             {
               // Check if one of the port match
               attrName = "ldapport";
-              AttributeType portType =
-                DirectoryServer.getAttributeType(attrName);
+              AttributeType portType = DirectoryServer
+                  .getAttributeType(attrName);
               if (portType == null)
               {
                 portType = DirectoryServer.getDefaultAttributeType(attrName);
@@ -221,8 +233,8 @@
                   DirectoryStringSyntax.DECODER);
               if (currentport.equals(ldapPort))
               {
-                entry = currentEntry ;
-                break ;
+                entry = currentEntry;
+                break;
               }
               if (ldapsPortEnable)
               {
@@ -242,7 +254,7 @@
               }
             }
           }
-          catch(Exception e)
+          catch (Exception e)
           {
             // best effort.
             continue;
@@ -255,7 +267,8 @@
         }
       }
 
-    } catch (DirectoryException e)
+    }
+    catch (DirectoryException e)
     {
       // never happens because the filter is always valid.
       return null;
@@ -263,17 +276,21 @@
     return returnDN;
   }
 
+
+
   /**
-   * get an attribute from and entry.
-   * @param DN the DN of the entry.
-   * @param attrName the attribute name.
-   * @return The Administration connector port.
+   * Gets an attribute value from an entry.
+   *
+   * @param DN
+   *          The DN of the entry.
+   * @param attrName
+   *          The attribute name.
+   * @return The attribute value or {@code null} if the value could
+   *         not be retrieved.
    */
   private String getAttr(String baseDN, String attrName)
   {
-    String value = null  ;
-    //
-    // prepare the ldap search
+    // Prepare the ldap search
     LDAPFilter filter;
     try
     {
@@ -287,14 +304,11 @@
       return null;
     }
 
-    ASN1OctetString asn1BaseDn = new ASN1OctetString(baseDN);
     LinkedHashSet<String> attributes = new LinkedHashSet<String>(1);
     attributes.add(attrName);
     InternalSearchOperation search = internalConnection.processSearch(
-        asn1BaseDn,
-        SearchScope.BASE_OBJECT,
-        DereferencePolicy.DEREF_ALWAYS, 0, 0, false,
-        filter,attributes);
+        ByteString.valueOf(baseDN), SearchScope.BASE_OBJECT,
+        DereferencePolicy.DEREF_ALWAYS, 0, 0, false, filter, attributes);
 
     if ((search.getResultCode() != ResultCode.SUCCESS))
     {
@@ -305,6 +319,7 @@
     }
 
     SearchResultEntry adminConnectorEntry = null;
+
     /*
      * Read the port from the PORT attribute
      */
@@ -331,8 +346,7 @@
     }
 
     // Get the attribute value
-    value = attrs.get(0).iterator().next().getStringValue();
-    return value;
+    return attrs.get(0).iterator().next().toString();
   }
 
 }
diff --git a/opends/src/server/org/opends/server/admin/ManagedObjectPath.java b/opends/src/server/org/opends/server/admin/ManagedObjectPath.java
index 3d79b04..568b89c 100644
--- a/opends/src/server/org/opends/server/admin/ManagedObjectPath.java
+++ b/opends/src/server/org/opends/server/admin/ManagedObjectPath.java
@@ -39,12 +39,7 @@
 import org.opends.server.admin.std.meta.RootCfgDefn;
 import org.opends.server.admin.std.server.RootCfg;
 import org.opends.server.core.DirectoryServer;
-import org.opends.server.types.AttributeType;
-import org.opends.server.types.AttributeValue;
-import org.opends.server.types.DN;
-import org.opends.server.types.DirectoryException;
-import org.opends.server.types.RDN;
-
+import org.opends.server.types.*;
 
 
 /**
@@ -162,7 +157,7 @@
       String type = profile.getRelationChildRDNType(r);
       AttributeType atype = DirectoryServer.getAttributeType(
           type.toLowerCase(), true);
-      AttributeValue avalue = new AttributeValue(atype, name);
+      AttributeValue avalue = AttributeValues.create(atype, name);
       dn = dn.concat(RDN.create(atype, avalue));
     }
 
@@ -182,7 +177,7 @@
       String type = profile.getRelationChildRDNType(r);
       AttributeType atype = DirectoryServer.getAttributeType(
           type.toLowerCase(), true);
-      AttributeValue avalue = new AttributeValue(atype, d.getName());
+      AttributeValue avalue = AttributeValues.create(atype, d.getName());
       dn = dn.concat(RDN.create(atype, avalue));
     }
 
diff --git a/opends/src/server/org/opends/server/admin/Reference.java b/opends/src/server/org/opends/server/admin/Reference.java
index 071244e..81e3aae 100644
--- a/opends/src/server/org/opends/server/admin/Reference.java
+++ b/opends/src/server/org/opends/server/admin/Reference.java
@@ -104,7 +104,7 @@
           + s + "\"");
     }
 
-    String name = av.getStringValue();
+    String name = av.getValue().toString();
 
     // Check that the DN was valid.
     DN expected = p.child(rd, name).toDN();
diff --git a/opends/src/server/org/opends/server/admin/server/ConfigAddListenerAdaptor.java b/opends/src/server/org/opends/server/admin/server/ConfigAddListenerAdaptor.java
index 318e3b7..ad7efc4 100644
--- a/opends/src/server/org/opends/server/admin/server/ConfigAddListenerAdaptor.java
+++ b/opends/src/server/org/opends/server/admin/server/ConfigAddListenerAdaptor.java
@@ -216,7 +216,7 @@
       MessageBuilder unacceptableReason) {
     DN dn = configEntry.getDN();
     AttributeValue av = dn.getRDN().getAttributeValue(0);
-    String name = av.getStringValue().trim();
+    String name = av.getValue().toString().trim();
 
     try {
       ManagedObjectPath<?, ? extends S> childPath;
diff --git a/opends/src/server/org/opends/server/admin/server/ConfigDeleteListenerAdaptor.java b/opends/src/server/org/opends/server/admin/server/ConfigDeleteListenerAdaptor.java
index 52eddb6..c40da8b 100644
--- a/opends/src/server/org/opends/server/admin/server/ConfigDeleteListenerAdaptor.java
+++ b/opends/src/server/org/opends/server/admin/server/ConfigDeleteListenerAdaptor.java
@@ -217,7 +217,7 @@
       MessageBuilder unacceptableReason) {
     DN dn = configEntry.getDN();
     AttributeValue av = dn.getRDN().getAttributeValue(0);
-    String name = av.getStringValue().trim();
+    String name = av.getValue().toString().trim();
 
     try {
       ManagedObjectPath<?, ? extends S> childPath;
diff --git a/opends/src/server/org/opends/server/admin/server/ServerManagementContext.java b/opends/src/server/org/opends/server/admin/server/ServerManagementContext.java
index 42fd5fd..5784ef2 100644
--- a/opends/src/server/org/opends/server/admin/server/ServerManagementContext.java
+++ b/opends/src/server/org/opends/server/admin/server/ServerManagementContext.java
@@ -352,7 +352,7 @@
      */
     public static <PD> PD decode(PropertyDefinition<PD> pd,
         AttributeValue value) throws IllegalPropertyValueStringException {
-      String s = value.getStringValue();
+      String s = value.getValue().toString();
       return pd.castValue(pd.accept(new ValueDecoder(), s));
     }
 
@@ -664,7 +664,7 @@
     for (DN child : children) {
       // Assume that RDNs are single-valued and can be trimmed.
       AttributeValue av = child.getRDN().getAttributeValue(0);
-      names.add(av.getStringValue().trim());
+      names.add(av.getValue().toString().trim());
     }
 
     return names.toArray(new String[names.size()]);
@@ -716,7 +716,7 @@
     for (DN child : children) {
       // Assume that RDNs are single-valued and can be trimmed.
       AttributeValue av = child.getRDN().getAttributeValue(0);
-      names.add(av.getStringValue().trim());
+      names.add(av.toString().trim());
     }
 
     return names.toArray(new String[names.size()]);
diff --git a/opends/src/server/org/opends/server/api/AccessControlHandler.java b/opends/src/server/org/opends/server/api/AccessControlHandler.java
index d0cb74e..e7d6578 100644
--- a/opends/src/server/org/opends/server/api/AccessControlHandler.java
+++ b/opends/src/server/org/opends/server/api/AccessControlHandler.java
@@ -22,13 +22,14 @@
  * CDDL HEADER END
  *
  *
- *      Copyright 2006-2008 Sun Microsystems, Inc.
+ *      Copyright 2006-2009 Sun Microsystems, Inc.
  */
 package org.opends.server.api;
+
+
+
 import org.opends.messages.Message;
 
-
-
 import java.util.List;
 
 import org.opends.server.admin.std.server.AccessControlHandlerCfg;
@@ -40,13 +41,14 @@
 
 /**
  * This class defines the set of methods and structures that must be
- * implemented by a Directory Server access control handler.  All
+ * implemented by a Directory Server access control handler. All
  * methods in this class should take the entire request into account
  * when making the determination, including any request controls that
  * might have been provided.
  *
- * @param  <T>  The type of access control configuration handled by
- *              this access control provider implementation.
+ * @param <T>
+ *          The type of access control configuration handled by this
+ *          access control provider implementation.
  */
 @org.opends.server.types.PublicAPI(
      stability=org.opends.server.types.StabilityLevel.VOLATILE,
@@ -60,53 +62,48 @@
    * Initializes the access control handler implementation based on
    * the information in the provided configuration entry.
    *
-   * @param  configuration  The configuration object that contains the
-   *                        information to use to initialize this
-   *                        access control handler.
-   *
-   * @throws  ConfigException  If an unrecoverable problem arises in
-   *                           the process of performing the
-   *                           initialization.
-   *
-   * @throws  InitializationException  If a problem occurs during
-   *                                   initialization that is not
-   *                                   related to the server
-   *                                   configuration.
+   * @param configuration
+   *          The configuration object that contains the information
+   *          to use to initialize this access control handler.
+   * @throws ConfigException
+   *           If an unrecoverable problem arises in the process of
+   *           performing the initialization.
+   * @throws InitializationException
+   *           If a problem occurs during initialization that is not
+   *           related to the server configuration.
    */
   public abstract void initializeAccessControlHandler(T configuration)
 
-         throws ConfigException, InitializationException;
+  throws ConfigException, InitializationException;
 
 
 
   /**
    * Indicates whether the provided configuration is acceptable for
-   * this access control handler.  It should be possible to call this
+   * this access control handler. It should be possible to call this
    * method on an uninitialized access control handler instance in
    * order to determine whether the handler would be able to use the
-   * provided configuration.
-   * <BR><BR>
+   * provided configuration. <BR>
+   * <BR>
    * Note that implementations which use a subclass of the provided
-   * configuration class will likely need to cast the configuration
-   * to the appropriate subclass type.
+   * configuration class will likely need to cast the configuration to
+   * the appropriate subclass type.
    *
-   * @param  configuration        The access control handler
-   *                              configuration for which to make the
-   *                              determination.
-   * @param  unacceptableReasons  A list that may be used to hold the
-   *                              reasons that the provided
-   *                              configuration is not acceptable.
-   *
-   * @return  {@code true} if the provided configuration is acceptable
-   *          for this access control handler, or {@code false} if
-   *          not.
+   * @param configuration
+   *          The access control handler configuration for which to
+   *          make the determination.
+   * @param unacceptableReasons
+   *          A list that may be used to hold the reasons that the
+   *          provided configuration is not acceptable.
+   * @return {@code true} if the provided configuration is acceptable
+   *         for this access control handler, or {@code false} if not.
    */
   public boolean isConfigurationAcceptable(
-                      AccessControlHandlerCfg configuration,
-                      List<Message> unacceptableReasons)
+      AccessControlHandlerCfg configuration,
+      List<Message> unacceptableReasons)
   {
     // This default implementation does not perform any special
-    // validation.  It should be overridden by access control handler
+    // validation. It should be overridden by access control handler
     // implementations that wish to perform more detailed validation.
     return true;
   }
@@ -125,152 +122,143 @@
 
   /**
    * Indicates whether the provided add operation is allowed based on
-   * the access control configuration.  This method should not alter
+   * the access control configuration. This method should not alter
    * the provided add operation in any way.
    *
-   * @param  addOperation  The operation for which to make the
-   *                       determination.
-   *
-   * @return  {@code true} if the operation should be allowed by the
-   *          access control configuration, or {@code false} if not.
+   * @param addOperation
+   *          The operation for which to make the determination.
+   * @return {@code true} if the operation should be allowed by the
+   *         access control configuration, or {@code false} if not.
    */
-  public abstract boolean isAllowed(LocalBackendAddOperation
-                                         addOperation);
+  public abstract boolean isAllowed(
+      LocalBackendAddOperation addOperation);
+
 
 
   /**
-   * Indicates whether the provided control is allowed based on
-   * the access control configuration and the specified
-   * operation. This method should not alter the provided
-   * operation in any way.
+   * Indicates whether the provided control is allowed based on the
+   * access control configuration and the specified operation. This
+   * method should not alter the provided operation in any way.
    *
-   * @param  dn  A DN that can be used in the access determination.
-   *
-   * @param  op  The operation to use in the
-   *                       determination.
-   *
-   * @param control The control for which to make the determination.
-   *
-   * @return  {@code true} if the control should be allowed by the
-   *          access control configuration, or {@code false} if not.
+   * @param dn
+   *          A DN that can be used in the access determination.
+   * @param op
+   *          The operation to use in the determination.
+   * @param control
+   *          The control for which to make the determination.
+   * @return {@code true} if the control should be allowed by the
+   *         access control configuration, or {@code false} if not.
    */
-  public abstract boolean isAllowed(DN dn, Operation  op,
+  public abstract boolean isAllowed(DN dn, Operation op,
                                     Control control);
 
 
 
   /**
    * Indicates whether the provided bind operation is allowed based on
-   * the access control configuration.  This method should not alter
+   * the access control configuration. This method should not alter
    * the provided bind operation in any way.
    *
-   * @param  bindOperation  The operation for which to make the
-   *                        determination.
-   *
-   * @return  {@code true} if the operation should be allowed by the
-   *          access control configuration, or {@code false} if not.
+   * @param bindOperation
+   *          The operation for which to make the determination.
+   * @return {@code true} if the operation should be allowed by the
+   *         access control configuration, or {@code false} if not.
    */
-  public abstract boolean isAllowed(LocalBackendBindOperation
-                                         bindOperation);
+  public abstract boolean isAllowed(
+      LocalBackendBindOperation bindOperation);
 
 
 
   /**
    * Indicates whether the provided compare operation is allowed based
-   * on the access control configuration.  This method should not
-   * alter the provided compare operation in any way.
+   * on the access control configuration. This method should not alter
+   * the provided compare operation in any way.
    *
-   * @param  compareOperation  The operation for which to make the
-   *                           determination.
-   *
-   * @return  {@code true} if the operation should be allowed by the
-   *          access control configuration, or {@code false} if not.
+   * @param compareOperation
+   *          The operation for which to make the determination.
+   * @return {@code true} if the operation should be allowed by the
+   *         access control configuration, or {@code false} if not.
    */
-  public abstract boolean isAllowed(LocalBackendCompareOperation
-      compareOperation);
+  public abstract boolean isAllowed(
+      LocalBackendCompareOperation compareOperation);
 
 
 
   /**
    * Indicates whether the provided delete operation is allowed based
-   * on the access control configuration.  This method should not
-   * alter the provided delete operation in any way.
+   * on the access control configuration. This method should not alter
+   * the provided delete operation in any way.
    *
-   * @param  deleteOperation  The operation for which to make the
-   *                          determination.
-   *
-   * @return  {@code true} if the operation should be allowed by the
-   *          access control configuration, or {@code false} if not.
+   * @param deleteOperation
+   *          The operation for which to make the determination.
+   * @return {@code true} if the operation should be allowed by the
+   *         access control configuration, or {@code false} if not.
    */
-  public abstract boolean isAllowed(LocalBackendDeleteOperation
-                                         deleteOperation);
+  public abstract boolean isAllowed(
+      LocalBackendDeleteOperation deleteOperation);
 
 
 
   /**
    * Indicates whether the provided extended operation is allowed
-   * based on the access control configuration.  This method should
-   * not alter the provided extended operation in any way.
+   * based on the access control configuration. This method should not
+   * alter the provided extended operation in any way.
    *
-   * @param  extendedOperation  The operation for which to make the
-   *                            determination.
-   *
-   * @return  {@code true} if the operation should be allowed by the
-   *          access control configuration, or {@code false} if not.
+   * @param extendedOperation
+   *          The operation for which to make the determination.
+   * @return {@code true} if the operation should be allowed by the
+   *         access control configuration, or {@code false} if not.
    */
-  public abstract boolean isAllowed(ExtendedOperation
-                                         extendedOperation);
+  public abstract boolean isAllowed(
+      ExtendedOperation extendedOperation);
 
 
 
   /**
    * Indicates whether the provided modify operation is allowed based
-   * on the access control configuration.  This method should not
-   * alter the provided modify operation in any way.
+   * on the access control configuration. This method should not alter
+   * the provided modify operation in any way.
    *
-   * @param  modifyOperation  The operation for which to make the
-   *                          determination.
-   *
-   * @return  {@code true} if the operation should be allowed by the
-   *          access control configuration, or {@code false} if not.
+   * @param modifyOperation
+   *          The operation for which to make the determination.
+   * @return {@code true} if the operation should be allowed by the
+   *         access control configuration, or {@code false} if not.
    */
-  public abstract boolean isAllowed(LocalBackendModifyOperation
-                                         modifyOperation);
+  public abstract boolean isAllowed(
+      LocalBackendModifyOperation modifyOperation);
 
 
 
   /**
    * Indicates whether the provided modify DN operation is allowed
-   * based on the access control configuration.  This method should
-   * not alter the provided modify DN operation in any way.
+   * based on the access control configuration. This method should not
+   * alter the provided modify DN operation in any way.
    *
-   * @param  modifyDNOperation  The operation for which to make the
-   *                            determination.
-   *
-   * @return  {@code true} if the operation should be allowed by the
-   *          access control configuration, or {@code false} if not.
+   * @param modifyDNOperation
+   *          The operation for which to make the determination.
+   * @return {@code true} if the operation should be allowed by the
+   *         access control configuration, or {@code false} if not.
    */
-  public abstract boolean isAllowed(LocalBackendModifyDNOperation
-                                         modifyDNOperation);
+  public abstract boolean isAllowed(
+      LocalBackendModifyDNOperation modifyDNOperation);
 
 
 
   /**
    * Indicates whether the provided search operation is allowed based
-   * on the access control configuration.  This method may only alter
+   * on the access control configuration. This method may only alter
    * the provided search operation in order to add an opaque block of
    * data to it that will be made available for use in determining
    * whether matching search result entries or search result
    * references may be allowed.
    *
-   * @param  searchOperation  The operation for which to make the
-   *                          determination.
-   *
-   * @return  {@code true} if the operation should be allowed by the
-   *          access control configuration, or {@code false} if not.
+   * @param searchOperation
+   *          The operation for which to make the determination.
+   * @return {@code true} if the operation should be allowed by the
+   *         access control configuration, or {@code false} if not.
    */
-  public abstract boolean isAllowed(LocalBackendSearchOperation
-                                         searchOperation);
+  public abstract boolean isAllowed(
+      LocalBackendSearchOperation searchOperation);
 
 
 
@@ -279,17 +267,18 @@
    * the client. Implementations <b>must not under any
    * circumstances</b> modify the search entry in any way.
    *
-   * @param  searchOperation  The search operation with which the
-   *                          provided entry is associated.
-   * @param  searchEntry      The search result entry for which to
-   *                          make the determination.
-   *
-   * @return  {@code true} if the access control configuration allows
-   *          the entry to be returned to the client, or {@code false}
-   *          if not.
+   * @param searchOperation
+   *          The search operation with which the provided entry is
+   *          associated.
+   * @param searchEntry
+   *          The search result entry for which to make the
+   *          determination.
+   * @return {@code true} if the access control configuration allows
+   *         the entry to be returned to the client, or {@code false}
+   *         if not.
    */
   public abstract boolean maySend(SearchOperation searchOperation,
-                                  SearchResultEntry searchEntry);
+      SearchResultEntry searchEntry);
 
 
 
@@ -298,16 +287,16 @@
    * contains any attributes or values that the client is not
    * permitted to access.
    *
-   * @param searchOperation The search operation with which the
-   *                        provided entry is associated.
-   * @param searchEntry     The search result entry to be filtered.
-   *
-   * @return  Returns the entry with filtered attributes and values
-   *          removed.
+   * @param searchOperation
+   *          The search operation with which the provided entry is
+   *          associated.
+   * @param searchEntry
+   *          The search result entry to be filtered.
+   * @return Returns the entry with filtered attributes and values
+   *         removed.
    */
-  public abstract SearchResultEntry
-                       filterEntry(SearchOperation searchOperation,
-                                   SearchResultEntry searchEntry);
+  public abstract SearchResultEntry filterEntry(
+      SearchOperation searchOperation, SearchResultEntry searchEntry);
 
 
 
@@ -315,38 +304,40 @@
    * Indicates whether the provided search result reference may be
    * sent to the client based on the access control configuration.
    *
-   * @param  dn         A DN that can be used in the access
-   *                    determination.
-   *
-   * @param  searchOperation  The search operation with which the
-   *                          provided reference is associated.
-   * @param  searchReference  The search result reference for which to
-   *                          make the determination.
-   *
-   * @return  {@code true} if the access control configuration allows
-   *          the reference to be returned to the client, or
-   *          {@code false} if not.
+   * @param dn
+   *          A DN that can be used in the access determination.
+   * @param searchOperation
+   *          The search operation with which the provided reference
+   *          is associated.
+   * @param searchReference
+   *          The search result reference for which to make the
+   *          determination.
+   * @return {@code true} if the access control configuration allows
+   *         the reference to be returned to the client, or {@code
+   *         false} if not.
    */
   public abstract boolean maySend(DN dn,
-                             SearchOperation searchOperation,
-                             SearchResultReference searchReference);
+                               SearchOperation searchOperation,
+                               SearchResultReference searchReference);
+
+
 
   /**
    * Indicates if the specified proxy user entry can proxy, or act on
    * the behalf of the specified proxied user entry. The operation
    * parameter is used in the evaluation.
    *
-   * @param proxyUser The entry to use as the proxy user.
-   * @param proxiedUser The entry to be proxied by the proxy user.
-   * @param operation The operation to use in the evaluation.
-   *
-   * @return  {@code true} if the access control configuration allows
-   *          the proxy user to proxy the proxied user, or
-   *          {@code false} if not.
+   * @param proxyUser
+   *          The entry to use as the proxy user.
+   * @param proxiedUser
+   *          The entry to be proxied by the proxy user.
+   * @param operation
+   *          The operation to use in the evaluation.
+   * @return {@code true} if the access control configuration allows
+   *         the proxy user to proxy the proxied user, or {@code
+   *         false} if not.
    */
-  public abstract boolean mayProxy(Entry proxyUser,
-                                   Entry proxiedUser,
-                                   Operation operation);
+  public abstract boolean mayProxy(Entry proxyUser, Entry proxiedUser,
+      Operation operation);
 
 }
-
diff --git a/opends/src/server/org/opends/server/api/ApproximateMatchingRule.java b/opends/src/server/org/opends/server/api/ApproximateMatchingRule.java
index 7a7c557..2017afb 100644
--- a/opends/src/server/org/opends/server/api/ApproximateMatchingRule.java
+++ b/opends/src/server/org/opends/server/api/ApproximateMatchingRule.java
@@ -28,9 +28,8 @@
 
 
 
-import org.opends.server.types.ByteString;
 import org.opends.server.types.ConditionResult;
-
+import org.opends.server.types.ByteSequence;
 
 
 /**
@@ -58,8 +57,8 @@
    * @return  {@code true} if the provided values are approximately
    *          equal, or {@code false} if not.
    */
-  public abstract boolean approximatelyMatch(ByteString value1,
-                                             ByteString value2);
+  public abstract boolean approximatelyMatch(ByteSequence value1,
+                                             ByteSequence value2);
 
 
 
@@ -82,8 +81,8 @@
    *          if it does not match, or {@code UNDEFINED} if the result
    *          is undefined.
    */
-  public ConditionResult valuesMatch(ByteString attributeValue,
-                                     ByteString assertionValue)
+  public ConditionResult valuesMatch(ByteSequence attributeValue,
+                                     ByteSequence assertionValue)
   {
     if (approximatelyMatch(attributeValue, assertionValue))
     {
diff --git a/opends/src/server/org/opends/server/api/AttributeSyntax.java b/opends/src/server/org/opends/server/api/AttributeSyntax.java
index 93a4367..f26466c 100644
--- a/opends/src/server/org/opends/server/api/AttributeSyntax.java
+++ b/opends/src/server/org/opends/server/api/AttributeSyntax.java
@@ -33,8 +33,8 @@
 
 import org.opends.server.admin.std.server.AttributeSyntaxCfg;
 import org.opends.server.config.ConfigException;
-import org.opends.server.types.ByteString;
 import org.opends.server.types.InitializationException;
+import org.opends.server.types.ByteSequence;
 
 import org.opends.messages.MessageBuilder;
 
@@ -209,7 +209,7 @@
    * @return  {@code true} if the provided value is acceptable for use
    *          with this syntax, or {@code false} if not.
    */
-  public abstract boolean valueIsAcceptable(ByteString value,
+  public abstract boolean valueIsAcceptable(ByteSequence value,
                                MessageBuilder invalidReason);
 
 
diff --git a/opends/src/server/org/opends/server/api/ClientConnection.java b/opends/src/server/org/opends/server/api/ClientConnection.java
index e7d4e34..2dc2816 100644
--- a/opends/src/server/org/opends/server/api/ClientConnection.java
+++ b/opends/src/server/org/opends/server/api/ClientConnection.java
@@ -448,45 +448,6 @@
   public abstract boolean isSecure();
 
 
-
-  /**
-   * Retrieves the connection security provider for this client
-   * connection.
-   *
-   * @return  The connection security provider for this client
-   *          connection.
-   */
-  public abstract ConnectionSecurityProvider
-                       getConnectionSecurityProvider();
-
-
-
-  /**
-   * Specifies the connection security provider for this client
-   * connection.
-   *
-   * @param  securityProvider  The connection security provider to use
-   *                           for communication on this client
-   *                           connection.
-   */
-  public abstract void setConnectionSecurityProvider(
-                            ConnectionSecurityProvider
-                                 securityProvider);
-
-
-
-  /**
-   * Retrieves the human-readable name of the security mechanism that
-   * is used to protect communication with this client.
-   *
-   * @return  The human-readable name of the security mechanism that
-   *          is used to protect communication with this client, or
-   *          {@code null} if no security is in place.
-   */
-  public abstract String getSecurityMechanism();
-
-
-
   /**
    * Retrieves a {@code Selector} that may be used to ensure that
    * write  operations complete in a timely manner, or terminate the
@@ -1333,7 +1294,7 @@
       {
         for (AttributeValue v : a)
         {
-          String privName = toLowerCase(v.getStringValue());
+          String privName = toLowerCase(v.getValue().toString());
 
           // If the name of the privilege is prefixed with a minus
           // sign, then we will take away that privilege from the
@@ -1836,5 +1797,12 @@
   {
     return 0L;
   }
+
+  /**
+   * Return the Security Strength Factor of a client connection.
+   *
+   * @return An integer representing the SSF value of a connection.
+   */
+  public abstract int getSSF();
 }
 
diff --git a/opends/src/server/org/opends/server/api/CompressedSchema.java b/opends/src/server/org/opends/server/api/CompressedSchema.java
index 464570e..7d30c84 100644
--- a/opends/src/server/org/opends/server/api/CompressedSchema.java
+++ b/opends/src/server/org/opends/server/api/CompressedSchema.java
@@ -22,7 +22,7 @@
  * CDDL HEADER END
  *
  *
- *      Copyright 2008 Sun Microsystems, Inc.
+ *      Copyright 2009 Sun Microsystems, Inc.
  */
 package org.opends.server.api;
 
@@ -30,10 +30,7 @@
 
 import java.util.Map;
 
-import org.opends.server.types.Attribute;
-import org.opends.server.types.DirectoryException;
-import org.opends.server.types.ObjectClass;
-
+import org.opends.server.types.*;
 
 
 /**
@@ -52,28 +49,27 @@
    * the same set had been previously encoded, then the cached value
    * will be used.  Otherwise, a new value will be created.
    *
-   * @param  objectClasses  The set of object classes for which to
-   *                        retrieve the corresponding byte array
-   *                        token.
-   *
-   * @return  A byte array containing the identifier assigned to the
-   *          object class set.
+   * @param  entryBuffer   The buffer to encode the object classes to.
+   * @param  objectClasses The set of object classes for which to
+   *                       retrieve the corresponding byte array
+   *                       token.
    *
    * @throws  DirectoryException  If a problem occurs while attempting
    *                              to determine the appropriate
    *                              identifier.
    */
-  public abstract byte[]
-         encodeObjectClasses(Map<ObjectClass,String> objectClasses)
+  public abstract void
+         encodeObjectClasses(ByteStringBuilder entryBuffer,
+                             Map<ObjectClass,String> objectClasses)
          throws DirectoryException;
 
 
 
   /**
-   * Decodes an object class set from the provided byte array.
+   * Decodes an object class set from the provided byte string.
    *
-   * @param  encodedObjectClasses  The byte array containing the
-   *                               object class set identifier.
+   * @param  entryBuffer         The byte string containing the
+   *                             object class set identifier.
    *
    * @return  The decoded object class set.
    *
@@ -81,7 +77,7 @@
    *                              decoded as an object class set.
    */
   public abstract Map<ObjectClass,String>
-         decodeObjectClasses(byte[] encodedObjectClasses)
+         decodeObjectClasses(ByteSequenceReader entryBuffer)
          throws DirectoryException;
 
 
@@ -90,36 +86,32 @@
    * Encodes the information in the provided attribute to a byte
    * array.
    *
-   * @param  attribute  The attribute to be encoded.
-   *
-   * @return  An encoded representation of the provided attribute.
+   * @param  entryBuffer The buffer to encode the attribute to.
+   * @param  attribute   The attribute to be encoded.
    *
    * @throws  DirectoryException  If a problem occurs while attempting
    *                              to determine the appropriate
    *                              identifier.
    */
-  public abstract byte[] encodeAttribute(Attribute attribute)
+  public abstract void encodeAttribute(ByteStringBuilder entryBuffer,
+                                       Attribute attribute)
          throws DirectoryException;
 
 
 
   /**
-   * Decodes the contents of the provided array as an attribute.
+   * Decodes the contents of the provided array as an attribute at the
+   * current position.
    *
-   * @param  encodedEntry  The byte array containing the encoded
+   * @param  entryBuffer   The byte array containing the encoded
    *                       entry.
-   * @param  startPos      The position within the array of the first
-   *                       byte for the attribute to decode.
-   * @param  length        The number of bytes contained in the
-   *                       encoded attribute.
    *
    * @return  The decoded attribute.
    *
    * @throws  DirectoryException  If the attribute could not be
    *                              decoded properly for some reason.
    */
-  public abstract Attribute decodeAttribute(byte[] encodedEntry,
-                                            int startPos, int length)
-          throws DirectoryException;
+  public abstract Attribute decodeAttribute(
+      ByteSequenceReader entryBuffer) throws DirectoryException;
 }
 
diff --git a/opends/src/server/org/opends/server/api/ConnectionSecurityProvider.java b/opends/src/server/org/opends/server/api/ConnectionSecurityProvider.java
deleted file mode 100644
index e7f4ca5..0000000
--- a/opends/src/server/org/opends/server/api/ConnectionSecurityProvider.java
+++ /dev/null
@@ -1,234 +0,0 @@
-/*
- * CDDL HEADER START
- *
- * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
- *
- * You can obtain a copy of the license at
- * trunk/opends/resource/legal-notices/OpenDS.LICENSE
- * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
- * See the License for the specific language governing permissions
- * and limitations under the License.
- *
- * When distributing Covered Code, include this CDDL HEADER in each
- * file and include the License file at
- * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
- * add the following below this CDDL 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.server.api;
-
-
-
-import java.nio.ByteBuffer;
-import java.nio.channels.SocketChannel;
-import org.opends.server.config.ConfigEntry;
-import org.opends.server.config.ConfigException;
-import org.opends.server.types.DirectoryException;
-import org.opends.server.types.InitializationException;
-
-
-
-/**
- * This class defines an API that may be used to encode and decode
- * data for communication with clients over a secure channel (e.g.,
- * SSL/TLS, Kerberos confidentiality, etc.).
- */
-@org.opends.server.types.PublicAPI(
-     stability=org.opends.server.types.StabilityLevel.VOLATILE,
-     mayInstantiate=true,
-     mayExtend=true,
-     mayInvoke=true)
-public abstract class ConnectionSecurityProvider
-{
-  /**
-   * Initializes this connection security provider using the
-   * information in the provided configuration entry.
-   *
-   * @param  configEntry  The entry that contains the configuration
-   *                      for this connection security provider.
-   *
-   * @throws  ConfigException  If the provided entry does not contain
-   *                           an acceptable configuration for this
-   *                           security provider.
-   *
-   * @throws  InitializationException  If a problem occurs during
-   *                                   initialization that is not
-   *                                   related to the provided
-   *                                   configuration.
-   */
-  public abstract void initializeConnectionSecurityProvider(
-                            ConfigEntry configEntry)
-         throws ConfigException, InitializationException;
-
-
-
-  /**
-   * Performs any finalization that may be necessary for this
-   * connection security provider.
-   */
-  public abstract void finalizeConnectionSecurityProvider();
-
-
-
-  /**
-   * Retrieves the name used to identify this security mechanism.
-   *
-   * @return  The name used to identify this security mechanism.
-   */
-  public abstract String getSecurityMechanismName();
-
-
-
-  /**
-   * Indicates whether client connections using this connection
-   * security provider should be considered secure.
-   *
-   * @return  {@code true} if client connections using this connection
-   *          security provider should be considered secure, or
-   *          {@code false} if not.
-   */
-  public abstract boolean isSecure();
-
- /**
-  * Indicates whether the security provider is active or not. Some
-  * security providers (DIGEST-MD5, GSSAPI) perform
-  * confidentiality/integrity processing of messages and require
-  * several handshakes to setup.
-  *
-  * @return  {@code true} if the security provider is active, or,
-  *          {@code false} if not.
-  */
-  public abstract boolean isActive();
-
-
-  /**
-   * Creates a new instance of this connection security provider that
-   * will be used to encode and decode all communication on the
-   * provided client connection.
-   *
-   * @param  clientConnection  The client connection with which this
-   *                           security provider will be associated.
-   * @param  socketChannel     The socket channel that may be used to
-   *                           communicate with the client.
-   *
-   * @return  The created connection security provider instance.
-   *
-   * @throws  DirectoryException  If a problem occurs while creating a
-   *                              new instance of this security
-   *                              provider for the given client
-   *                              connection.
-   */
-  public abstract ConnectionSecurityProvider
-                       newInstance(ClientConnection clientConnection,
-                                   SocketChannel socketChannel)
-         throws DirectoryException;
-
-
-
-  /**
-   * Indicates that the associated client connection is being closed
-   * and that this security provider should perform any necessary
-   * processing to deal with that.  If it is indicated that the
-   * connection is still valid, then the security provider may attempt
-   * to communicate with the client to perform a graceful shutdown.
-   *
-   * @param  connectionValid  Indicates whether the Directory Server
-   *                          believes that the client connection is
-   *                          still valid and may be used for
-   *                          communication with the client.  Note
-   *                          that this may be inaccurate, or that the
-   *                          state of the connection may change
-   *                          during the course of this method, so the
-   *                          security provider must be able to handle
-   *                          failures if they arise.
-   */
-  public abstract void disconnect(boolean connectionValid);
-
-
-
-  /**
-   * Retrieves the size in bytes that the client should use for the
-   * byte buffer meant to hold clear-text data read from or to be
-   * written to the client.
-   *
-   * @return  The size in bytes that the client should use for the
-   *          byte buffer meant to hold clear-text data read from or
-   *          to be written to the client.
-   */
-  public abstract int getClearBufferSize();
-
-
-
-  /**
-   * Retrieves the size in bytes that the client should use for the
-   * byte buffer meant to hold encoded data read from or to be written
-   * to the client.
-   *
-   * @return  The size in bytes that the client should use for the
-   *          byte buffer meant to hold encoded data read from or to
-   *          be written to the client.
-   */
-  public abstract int getEncodedBufferSize();
-
-
-
-  /**
-   * Reads data from a client connection, performing any necessary
-   * negotiation in the process.  Whenever any clear-text data has
-   * been obtained, then the connection security provider should make
-   * that available to the client by calling the
-   * {@code ClientConnection.processDataRead} method.
-   *
-   * @return  {@code true} if all the data in the provided buffer was
-   *          processed and the client connection can remain
-   *          established, or {@code false} if a decoding error
-   *          occurred and requests from this client should no longer
-   *          be processed.  Note that if this method does return
-   *          {@code false}, then it must have already disconnected
-   *          the client.
-   *
-   * @throws  DirectoryException  If a problem occurs while reading
-   *                              data from the client.
-   */
-  public abstract boolean readData()
-         throws DirectoryException;
-
-
-
-  /**
-   * Writes the data contained in the provided clear-text buffer to
-   * the client, performing any necessary encoding in the process.  It
-   * must be capable of dealing with input buffers that are larger
-   * than the value returned by the {@code getClearBufferSize} method.
-   * When this method returns, the provided buffer should be in its
-   * original state with regard to the position and limit.
-   *
-   * @param  clearData  The buffer containing the clear-text data to
-   *                    write to the client.
-   *
-   * @return  {@code true} if all the data in the provided buffer was
-   *          written to the client and the connection may remain
-   *          established, or {@code false} if a problem occurred and
-   *          the client connection is no longer valid.  Note that if
-   *          this method does return {@code false}, then it must have
-   *          already disconnected the client.
-   */
-  public abstract boolean writeData(ByteBuffer clearData);
-
-  /**
-   * Return the Security Strength Factor.
-   *
-   * @return The SSF.
-   */
-  public abstract int getSSF();
-}
-
diff --git a/opends/src/server/org/opends/server/api/DebugLogPublisher.java b/opends/src/server/org/opends/server/api/DebugLogPublisher.java
index 80fa351..d65d9ae 100644
--- a/opends/src/server/org/opends/server/api/DebugLogPublisher.java
+++ b/opends/src/server/org/opends/server/api/DebugLogPublisher.java
@@ -22,7 +22,7 @@
  * CDDL HEADER END
  *
  *
- *      Copyright 2008 Sun Microsystems, Inc.
+ *      Copyright 2009 Sun Microsystems, Inc.
  */
 package org.opends.server.api;
 import org.opends.messages.Message;
@@ -595,7 +595,8 @@
    * @param  settings        The current trace settings in effect.
    * @param  signature       The method signature.
    * @param  sourceLocation  The location of the method in the source.
-   * @param  element         The protocol element to dump.
+   * @param  decodedForm     The string reprentation of the protocol
+   *                         element.
    * @param  stackTrace      The stack trace at the time the protocol
    *                         element is logged or null if its not
    *                         available.
@@ -604,7 +605,7 @@
                                             TraceSettings settings,
                                             String signature,
                                             String sourceLocation,
-                                            ProtocolElement element,
+                                            String decodedForm,
                                       StackTraceElement[] stackTrace);
 
   /**
diff --git a/opends/src/server/org/opends/server/api/DirectoryThread.java b/opends/src/server/org/opends/server/api/DirectoryThread.java
index 5ed904b..0cf23af 100644
--- a/opends/src/server/org/opends/server/api/DirectoryThread.java
+++ b/opends/src/server/org/opends/server/api/DirectoryThread.java
@@ -34,9 +34,6 @@
 import org.opends.server.backends.task.Task;
 import org.opends.server.core.DirectoryServer;
 
-import static org.opends.server.util.ServerConstants.*;
-import static org.opends.server.util.StaticUtils.*;
-
 
 
 /**
diff --git a/opends/src/server/org/opends/server/api/EqualityMatchingRule.java b/opends/src/server/org/opends/server/api/EqualityMatchingRule.java
index b240484..9a0fb1b 100644
--- a/opends/src/server/org/opends/server/api/EqualityMatchingRule.java
+++ b/opends/src/server/org/opends/server/api/EqualityMatchingRule.java
@@ -28,13 +28,7 @@
 
 
 
-import org.opends.server.loggers.debug.DebugTracer;
-import org.opends.server.types.AttributeValue;
-import org.opends.server.types.ByteString;
-import org.opends.server.types.ConditionResult;
-import org.opends.server.types.DebugLogLevel;
-
-import static org.opends.server.loggers.debug.DebugLogger.*;
+import org.opends.server.types.*;
 
 
 
@@ -51,11 +45,6 @@
 public abstract class EqualityMatchingRule extends MatchingRule
 {
   /**
-   * The tracer object for the debug logger.
-   */
-  private static final DebugTracer TRACER = getTracer();
-
-  /**
    * Indicates whether the two provided normalized values are equal to
    * each other.
    *
@@ -67,10 +56,10 @@
    * @return  {@code true} if the provided values are equal, or
    *          {@code false} if not.
    */
-  public abstract boolean areEqual(ByteString value1,
-                                   ByteString value2);
-
-
+  public boolean areEqual(ByteSequence value1, ByteSequence value2)
+  {
+    return value1.equals(value2);
+  }
 
   /**
    * Indicates whether the provided attribute value should be
@@ -90,8 +79,9 @@
    *          a match for the provided assertion value, or
    *          {@code false} if not.
    */
-  public ConditionResult valuesMatch(ByteString attributeValue,
-                                     ByteString assertionValue)
+  @Override
+  public ConditionResult valuesMatch(ByteSequence attributeValue,
+                                     ByteSequence assertionValue)
   {
     if (areEqual(attributeValue, assertionValue))
     {
@@ -122,33 +112,9 @@
    * @return  The hash code generated for the provided attribute
    *          value.
    */
-  public int generateHashCode(AttributeValue attributeValue)
+  public int generateHashCode(ByteSequence attributeValue)
   {
-    try
-    {
-      return attributeValue.getNormalizedValue().hashCode();
-    }
-    catch (Exception e)
-    {
-      if (debugEnabled())
-      {
-        TRACER.debugCaught(DebugLogLevel.ERROR, e);
-      }
-
-      try
-      {
-        return attributeValue.getValue().hashCode();
-      }
-      catch (Exception e2)
-      {
-        if (debugEnabled())
-        {
-          TRACER.debugCaught(DebugLogLevel.ERROR, e2);
-        }
-
-        return 0;
-      }
-    }
+    return attributeValue.hashCode();
   }
 }
 
diff --git a/opends/src/server/org/opends/server/api/ExtensibleIndexer.java b/opends/src/server/org/opends/server/api/ExtensibleIndexer.java
index 47edcc2..a7c6584 100644
--- a/opends/src/server/org/opends/server/api/ExtensibleIndexer.java
+++ b/opends/src/server/org/opends/server/api/ExtensibleIndexer.java
@@ -26,20 +26,25 @@
  */
 package org.opends.server.api;
 
+
+
 import java.util.Map;
 import java.util.Set;
+
 import org.opends.server.types.AttributeValue;
 
+
+
 /**
- * This class is  registered with a Backend  and it provides call-
- * backs for indexing attribute values. An index implementation will
- * use this interface to create the keys for an attribute value.
+ * This class is registered with a Backend and it provides call- backs
+ * for indexing attribute values. An index implementation will use
+ * this interface to create the keys for an attribute value.
  */
 @org.opends.server.types.PublicAPI(
-     stability=org.opends.server.types.StabilityLevel.VOLATILE,
-     mayInstantiate=false,
-     mayExtend=true,
-     mayInvoke=false)
+    stability = org.opends.server.types.StabilityLevel.VOLATILE,
+    mayInstantiate = false,
+    mayExtend = true,
+    mayInvoke = false)
 public abstract class ExtensibleIndexer
 {
   /**
@@ -47,46 +52,57 @@
    * appended with the identifier returned from
    * {@link #getExtensibleIndexID()} will be used as the index
    * database name.
-   * @return  The name of the index for this indexer.
+   *
+   * @return The name of the index for this indexer.
    */
   public abstract String getPreferredIndexName();
 
 
+
   /**
    * Returns an index identifier associated with this indexer. An
-   * identifier should be selected based on the matching rule type.
-   * A unique identifier will map to  a unique index database in
-   * the backend implementation. If multiple matching rules
-   * need to share the index database, the corresponding indexers
-   * should always use the same identifier.
-   * @return index ID A String containing the ID associated with
-   *                          this indexer.
+   * identifier should be selected based on the matching rule type. A
+   * unique identifier will map to a unique index database in the
+   * backend implementation. If multiple matching rules need to share
+   * the index database, the corresponding indexers should always use
+   * the same identifier.
+   *
+   * @return index ID A String containing the ID associated with this
+   *         indexer.
    */
   public abstract String getExtensibleIndexID();
 
 
+
   /**
    * Generates the set of index keys for an attribute.
-   * @param value The attribute value  for which  keys are required.
-   * @param keys The set into which the generated keys will be
-   *                          inserted.
+   *
+   * @param value
+   *          The attribute value for which keys are required.
+   * @param keys
+   *          The set into which the generated keys will be inserted.
    */
   public abstract void getKeys(AttributeValue value,
-                                                  Set<byte[]> keys);
+      Set<byte[]> keys);
+
 
 
   /**
    * Generates a map of index keys and a boolean flag indicating
    * whether the corresponding key will be inserted or deleted.
-   * @param value The attribute for which keys are required.
-   * @param modifiedKeys A map containing the keys and a boolean.
-   *              Keys corresponding to the boolean value <code>true
-   *              </code> should be inserted and <code>false</code>
-   *              should be deleted.
-   * @param insert <code>true</code> if generated keys should
-   *            be inserted or <code>false</code> otherwise.
+   *
+   * @param value
+   *          The attribute for which keys are required.
+   * @param modifiedKeys
+   *          A map containing the keys and a boolean. Keys
+   *          corresponding to the boolean value <code>true
+   *              </code>
+   *          should be inserted and <code>false</code> should be
+   *          deleted.
+   * @param insert
+   *          <code>true</code> if generated keys should be inserted
+   *          or <code>false</code> otherwise.
    */
   public abstract void getKeys(AttributeValue value,
-                                  Map<byte[], Boolean> modifiedKeys,
-                                  Boolean insert);
+      Map<byte[], Boolean> modifiedKeys, Boolean insert);
 }
\ No newline at end of file
diff --git a/opends/src/server/org/opends/server/api/ExtensibleMatchingRule.java b/opends/src/server/org/opends/server/api/ExtensibleMatchingRule.java
index 798da0d..4c54a99 100644
--- a/opends/src/server/org/opends/server/api/ExtensibleMatchingRule.java
+++ b/opends/src/server/org/opends/server/api/ExtensibleMatchingRule.java
@@ -26,51 +26,59 @@
  */
 package org.opends.server.api;
 
+
+
 import java.util.Collection;
-import org.opends.server.types.ByteString;
+
+import org.opends.server.types.ByteSequence;
 import org.opends.server.types.DirectoryException;
 import org.opends.server.types.IndexConfig;
 
 
+
 /**
  * This class defines the set of methods and structures that must be
  * implemented by a Directory Server module that implements an
  * Extensible matching rule.
  */
 @org.opends.server.types.PublicAPI(
-     stability=org.opends.server.types.StabilityLevel.VOLATILE,
-     mayInstantiate=false,
-     mayExtend=true,
-     mayInvoke=false)
+    stability = org.opends.server.types.StabilityLevel.VOLATILE,
+    mayInstantiate = false,
+    mayExtend = true,
+    mayInvoke = false)
 public abstract class ExtensibleMatchingRule extends MatchingRule
 {
   /**
-  * Returns a collection of extensible indexers associated with this
-  * matching rule.
-  * @param config The index configuration to be used by this
-  *                      matching rule.
-  * @return ExtensibleIndexer associated with this matching rule.
-  */
-  public  abstract Collection<ExtensibleIndexer> getIndexers(
-          IndexConfig config);
-
+   * Returns a collection of extensible indexers associated with this
+   * matching rule.
+   *
+   * @param config
+   *          The index configuration to be used by this matching
+   *          rule.
+   * @return The collection of extensible indexers associated with
+   *         this matching rule.
+   */
+  public abstract Collection<ExtensibleIndexer> getIndexers(
+      IndexConfig config);
 
 
 
   /**
-   * Queries the index using factory of type T and returns
-   * a query of type T for the provided assertion value.
-   * @param  <T>  The type of IndexQueryFactory.
-   * @param  assertionValue  An assertion value which needs to be
-   *                                               queried.
-   * @param factory  An IndexQueryFactory which will be used for
-   *                                creating  queries.
-   * @return T  The generated index query.
-   * @throws DirectoryException  If an  error occurs while generating
-   *                the query.
+   * Returns an index query appropriate for the provided attribute
+   * value assertion.
+   *
+   * @param <T>
+   *          The type of index query created by the {@code factory}.
+   * @param assertionValue
+   *          The attribute value assertion.
+   * @param factory
+   *          The index query factory which should be used to
+   *          construct the index query.
+   * @return The index query appropriate for the provided attribute
+   *         value assertion.
+   * @throws DirectoryException
+   *           If an error occurs while generating the index query.
    */
-  public  abstract <T> T createIndexQuery(
-                   ByteString assertionValue,
-                   IndexQueryFactory<T> factory)
-                                          throws DirectoryException;
+  public abstract <T> T createIndexQuery(ByteSequence assertionValue,
+      IndexQueryFactory<T> factory) throws DirectoryException;
 }
\ No newline at end of file
diff --git a/opends/src/server/org/opends/server/api/IndexQueryFactory.java b/opends/src/server/org/opends/server/api/IndexQueryFactory.java
index a4f173d..28e811f 100644
--- a/opends/src/server/org/opends/server/api/IndexQueryFactory.java
+++ b/opends/src/server/org/opends/server/api/IndexQueryFactory.java
@@ -26,39 +26,50 @@
  */
 package org.opends.server.api;
 
+
+
 import java.util.Collection;
 
+import org.opends.server.types.ByteSequence;
+
+
+
 /**
- * This class acts as a factory for creating index queries. This
+ * A factory for creating arbitrarily complex index queries. This
  * interface is implemented by the underlying backend implementation
  * and passed to extensible matching rules so that they can construct
  * arbitrarily complex index queries.
  *
- * @param  <T>  The type of Results  returned by the factory.
+ * @param <T>
+ *          The type of query created by this factory.
  */
 @org.opends.server.types.PublicAPI(
-     stability=org.opends.server.types.StabilityLevel.VOLATILE,
-     mayInstantiate=false,
-     mayExtend=true,
-     mayInvoke=false)
+    stability = org.opends.server.types.StabilityLevel.VOLATILE,
+    mayInstantiate = false,
+    mayExtend = true,
+    mayInvoke = false)
 public interface IndexQueryFactory<T>
 {
 
   /**
-   * Returns a query requesting an index record matching the
-   * provided key.
-   * @param indexID An identifier of the index type.
-   * @param key A byte array containing the key.
+   * Returns a query requesting an index record matching the provided
+   * key.
+   *
+   * @param indexID
+   *          An identifier of the index type.
+   * @param key
+   *          A byte sequence containing the key.
    * @return A query requesting the index record matching the key.
    */
-  T createExactMatchQuery(String indexID,byte[] key);
+  T createExactMatchQuery(String indexID, ByteSequence key);
 
 
 
   /**
-   * Returns a query requesting all  index records. A backend
-   * implementation may choose to return all or no records as
-   * part of the optimization.
+   * Returns a query requesting all index records. A backend
+   * implementation may choose to return all or no records as part of
+   * the optimization.
+   *
    * @return A query requesting all index records.
    */
   T createMatchAllQuery();
@@ -66,53 +77,59 @@
 
 
   /**
-   * Rreturns a query requesting all index records in the specified
+   * Returns a query requesting all index records in the specified
    * range.
-   * @param indexID An identifier of the index type.
-   * @param lower  The lower bound of the range.   A 0 length byte
-   *                      array indicates  no lower bound and the
-   *                      range will start from the smallest key.
-   * @param upper The upper bound of the range. A 0 length byte array
-   *                      indicates no upper bound and the range will
-   *                      end at  the largest key.
-   * @param lowerIncluded true if a key exactly matching the lower
-   *                       bound is included in the range, false if
-   *                       only keys strictly greater than the lower
-   *                       bound are included.This value is ignored if
-   *                       the lower bound is not specified.
-   * @param upperIncluded true if a key exactly matching the upper
-   *                      bound is included in the range, false if
-   *                      only keys strictly less than the upper
-   *                      bound are included. This value is ignored if
-   *                      the upper bound is not specified.
+   *
+   * @param indexID
+   *          An identifier of the index type.
+   * @param lower
+   *          The lower bound of the range. A 0 length byte array
+   *          indicates no lower bound and the range will start from
+   *          the smallest key.
+   * @param upper
+   *          The upper bound of the range. A 0 length byte array
+   *          indicates no upper bound and the range will end at the
+   *          largest key.
+   * @param lowerIncluded
+   *          true if a key exactly matching the lower bound is
+   *          included in the range, false if only keys strictly
+   *          greater than the lower bound are included.This value
+   *          is ignored if the lower bound is not specified.
+   * @param upperIncluded
+   *          true if a key exactly matching the upper bound is
+   *          included in the range, false if only keys strictly
+   *          less than the upper bound are included. This value is
+   *          ignored if the upper bound is not specified.
    * @return A query requesting all index records in the specified
-   * range.
+   *         range.
    */
-  T createRangeMatchQuery(
-                              String indexID,
-                              byte[]  lower,
-                              byte[] upper,
-                              boolean lowerIncluded,
-                              boolean upperIncluded);
+  T createRangeMatchQuery(String indexID, ByteSequence lower,
+      ByteSequence upper, boolean lowerIncluded,
+      boolean upperIncluded);
 
 
 
   /**
-   * Returns a query requesting  intersection from a Collection of
+   * Returns a query which returns the intersection of a collection of
    * sub-queries.
-   *@param  subquery  A Collection of sub-queries.
-   *@return A query requesting intersection of  the records.
+   *
+   * @param subquery
+   *          A collection of sub-queries.
+   * @return A query which returns the intersection of a collection of
+   *         sub-queries.
    */
   T createIntersectionQuery(Collection<T> subquery);
 
 
 
-
   /**
-   * Returns a query requesting union from a Collection of
+   * Returns a query which combines the results of a collection of
    * sub-queries.
-   * @param  subquery  A Collection of sub-queries.
-   * @return A query requesting union of the records.
+   *
+   * @param subquery
+   *          A collection of sub-queries.
+   * @return A query which combines the results of a collection of
+   *         sub-queries.
    */
   T createUnionQuery(Collection<T> subquery);
 }
\ No newline at end of file
diff --git a/opends/src/server/org/opends/server/api/MatchingRule.java b/opends/src/server/org/opends/server/api/MatchingRule.java
index 9de97f5..47f06a1 100644
--- a/opends/src/server/org/opends/server/api/MatchingRule.java
+++ b/opends/src/server/org/opends/server/api/MatchingRule.java
@@ -26,7 +26,11 @@
  */
 package org.opends.server.api;
 
+
+
 import java.util.Collection;
+
+import org.opends.server.types.ByteSequence;
 import org.opends.server.types.ByteString;
 import org.opends.server.types.ConditionResult;
 import org.opends.server.types.DirectoryException;
@@ -39,17 +43,17 @@
  * rule.
  */
 @org.opends.server.types.PublicAPI(
-     stability=org.opends.server.types.StabilityLevel.VOLATILE,
-     mayInstantiate=false,
-     mayExtend=true,
-     mayInvoke=false)
+    stability = org.opends.server.types.StabilityLevel.VOLATILE,
+    mayInstantiate = false,
+    mayExtend = true,
+    mayInvoke = false)
 public abstract class MatchingRule
 {
   /**
    * Retrieves the common name for this matching rule.
    *
-   * @return  The common name for this matching rule, or {@code null}
-   *          if it does not have a name.
+   * @return The common name for this matching rule, or {@code null}
+   *         if it does not have a name.
    */
   public abstract String getName();
 
@@ -58,7 +62,7 @@
   /**
    * Retrieves all names for this matching rule.
    *
-   * @return  All names for this matching rule.
+   * @return All names for this matching rule.
    */
   public abstract Collection<String> getAllNames();
 
@@ -67,40 +71,39 @@
   /**
    * Retrieves the OID for this matching rule.
    *
-   * @return  The OID for this matching rule.
+   * @return The OID for this matching rule.
    */
   public abstract String getOID();
 
 
 
- /**
+  /**
    * Retrieves the normalized form of the provided assertion value,
    * which is best suite for efficiently performing matching
    * operations on that value.
    *
-   * @param  value  The assertion value to be normalized.
-   *
-   * @return  The normalized version of the provided value.
-   *
-   * @throws  DirectoryException  If the provided value is invalid
-   *                              according to the associated
-   *                              attribute syntax.
+   * @param value
+   *          The assertion value to be normalized.
+   * @return The normalized version of the provided value.
+   * @throws DirectoryException
+   *           If the provided value is invalid according to the
+   *           associated attribute syntax.
    */
-  public ByteString normalizeAssertionValue(ByteString value)
-         throws DirectoryException
+  public ByteString normalizeAssertionValue(ByteSequence value)
+      throws DirectoryException
   {
     // Default implementation is to use attribute value normalization.
-     return normalizeValue(value);
+    return normalizeValue(value);
   }
 
 
 
   /**
-   * Retrieves the name or OID for this matching rule.  If it has a
-   * name, then it will be returned.  Otherwise, the OID will be
+   * Retrieves the name or OID for this matching rule. If it has a
+   * name, then it will be returned. Otherwise, the OID will be
    * returned.
    *
-   * @return  The name or OID for this matching rule.
+   * @return The name or OID for this matching rule.
    */
   public final String getNameOrOID()
   {
@@ -120,8 +123,8 @@
   /**
    * Retrieves the description for this matching rule.
    *
-   * @return  The description for this matching rule, or {@code null}
-   *          if there is none.
+   * @return The description for this matching rule, or {@code null}
+   *         if there is none.
    */
   public abstract String getDescription();
 
@@ -131,22 +134,22 @@
    * Retrieves the OID of the syntax with which this matching rule is
    * associated.
    *
-   * @return  The OID of the syntax with which this matching rule is
-   *          associated.
+   * @return The OID of the syntax with which this matching rule is
+   *         associated.
    */
   public abstract String getSyntaxOID();
 
 
 
   /**
-   * Indicates whether this matching rule is declared "OBSOLETE".
-   * The default implementation will always return {@code false}.  If
-   * that is not acceptable for a particular matching rule
-   * implementation, then it should override this method and perform
-   * the appropriate processing to return the correct value.
+   * Indicates whether this matching rule is declared "OBSOLETE". The
+   * default implementation will always return {@code false}. If that
+   * is not acceptable for a particular matching rule implementation,
+   * then it should override this method and perform the appropriate
+   * processing to return the correct value.
    *
-   * @return  {@code true} if this matching rule is declared
-   *          "OBSOLETE", or {@code false} if not.
+   * @return {@code true} if this matching rule is declared
+   *         "OBSOLETE", or {@code false} if not.
    */
   public boolean isObsolete()
   {
@@ -157,60 +160,58 @@
 
   /**
    * Retrieves the normalized form of the provided value, which is
-   * best suite for efficiently performing matching operations on that
-   * value.
+   * best suite for efficiently performing matching operations on
+   * that value.
    *
-   * @param  value  The value to be normalized.
-   *
-   * @return  The normalized version of the provided value.
-   *
-   * @throws  DirectoryException  If the provided value is invalid
-   *                              according to the associated
-   *                              attribute syntax.
+   * @param value
+   *          The value to be normalized.
+   * @return The normalized version of the provided value.
+   * @throws DirectoryException
+   *           If the provided value is invalid according to the
+   *           associated attribute syntax.
    */
-  public abstract ByteString normalizeValue(ByteString value)
-         throws DirectoryException;
+  public abstract ByteString normalizeValue(ByteSequence value)
+      throws DirectoryException;
 
 
 
   /**
    * Indicates whether the provided attribute value should be
-   * considered a match for the given assertion value.  This will only
-   * be used for the purpose of extensible matching.  Subclasses
+   * considered a match for the given assertion value. This will only
+   * be used for the purpose of extensible matching. Subclasses
    * should define more specific methods that are appropriate to the
    * matching rule type.
    *
-   * @param  attributeValue  The attribute value in a form that has
-   *                         been normalized according to this
-   *                         matching rule.
-   * @param  assertionValue  The assertion value in a form that has
-   *                         been normalized according to this
-   *                         matching rule.
-   *
-   * @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.
+   * @param attributeValue
+   *          The attribute value in a form that has been normalized
+   *          according to this matching rule.
+   * @param assertionValue
+   *          The assertion value in a form that has been normalized
+   *          according to this matching rule.
+   * @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
-                       valuesMatch(ByteString attributeValue,
-                                   ByteString assertionValue);
+  public abstract ConditionResult valuesMatch(
+      ByteSequence attributeValue, ByteSequence assertionValue);
 
 
 
   /**
-   * Retrieves the hash code for this matching rule.  It will be
+   * Retrieves the hash code for this matching rule. It will be
    * calculated as the sum of the characters in the OID.
    *
-   * @return  The hash code for this matching rule.
+   * @return The hash code for this matching rule.
    */
+  @Override
   public final int hashCode()
   {
     int hashCode = 0;
 
     String oidString = getOID();
-    int    oidLength = oidString.length();
-    for (int i=0; i < oidLength; i++)
+    int oidLength = oidString.length();
+    for (int i = 0; i < oidLength; i++)
     {
       hashCode += oidString.charAt(i);
     }
@@ -222,14 +223,15 @@
 
   /**
    * Indicates whether the provided object is equal to this matching
-   * rule.  The provided object will be considered equal to this
+   * rule. The provided object will be considered equal to this
    * matching rule only if it is a matching rule with the same OID.
    *
-   * @param  o  The object for which to make the determination.
-   *
-   * @return  {@code true} if the provided object is equal to this
-   *          matching rule, or {@code false} if it is not.
+   * @param o
+   *          The object for which to make the determination.
+   * @return {@code true} if the provided object is equal to this
+   *         matching rule, or {@code false} if it is not.
    */
+  @Override
   public final boolean equals(Object o)
   {
     if (o == null)
@@ -242,7 +244,7 @@
       return true;
     }
 
-    if (! (o instanceof MatchingRule))
+    if (!(o instanceof MatchingRule))
     {
       return false;
     }
@@ -256,9 +258,10 @@
    * Retrieves a string representation of this matching rule in the
    * format defined in RFC 2252.
    *
-   * @return  A string representation of this matching rule in the
-   *          format defined in RFC 2252.
+   * @return A string representation of this matching rule in the
+   *         format defined in RFC 2252.
    */
+  @Override
   public final String toString()
   {
     StringBuilder buffer = new StringBuilder();
@@ -272,15 +275,15 @@
    * Appends a string representation of this matching rule in the
    * format defined in RFC 2252 to the provided buffer.
    *
-   * @param  buffer  The buffer to which the information should be
-   *                 appended.
+   * @param buffer
+   *          The buffer to which the information should be appended.
    */
   public final void toString(StringBuilder buffer)
   {
     buffer.append("( ");
     buffer.append(getOID());
     buffer.append(" NAME '");
-      buffer.append(getName());
+    buffer.append(getName());
 
     String description = getDescription();
     if ((description != null) && (description.length() > 0))
@@ -302,4 +305,3 @@
     buffer.append(" )");
   }
 }
-
diff --git a/opends/src/server/org/opends/server/api/OrderingMatchingRule.java b/opends/src/server/org/opends/server/api/OrderingMatchingRule.java
index e179685..7c561bf 100644
--- a/opends/src/server/org/opends/server/api/OrderingMatchingRule.java
+++ b/opends/src/server/org/opends/server/api/OrderingMatchingRule.java
@@ -22,7 +22,7 @@
  * CDDL HEADER END
  *
  *
- *      Copyright 2006-2008 Sun Microsystems, Inc.
+ *      Copyright 2006-2009 Sun Microsystems, Inc.
  */
 package org.opends.server.api;
 
@@ -31,9 +31,8 @@
 import java.io.Serializable;
 import java.util.Comparator;
 
-import org.opends.server.types.ByteString;
 import org.opends.server.types.ConditionResult;
-
+import org.opends.server.types.ByteSequence;
 
 
 /**
@@ -76,8 +75,8 @@
    *          ascending order, or zero if there is no difference
    *          between the values with regard to ordering.
    */
-  public abstract int compareValues(ByteString value1,
-                                    ByteString value2);
+  public abstract int compareValues(ByteSequence value1,
+                                    ByteSequence value2);
 
 
 
@@ -103,8 +102,8 @@
    *          a match for the provided assertion value, or
    *          {@code false} if not.
    */
-  public ConditionResult valuesMatch(ByteString attributeValue,
-                                     ByteString assertionValue)
+  public ConditionResult valuesMatch(ByteSequence attributeValue,
+                                     ByteSequence assertionValue)
   {
     return ConditionResult.UNDEFINED;
   }
diff --git a/opends/src/server/org/opends/server/api/PasswordGenerator.java b/opends/src/server/org/opends/server/api/PasswordGenerator.java
index 74e62a5..dcf1b1f 100644
--- a/opends/src/server/org/opends/server/api/PasswordGenerator.java
+++ b/opends/src/server/org/opends/server/api/PasswordGenerator.java
@@ -33,11 +33,7 @@
 
 import org.opends.server.admin.std.server.PasswordGeneratorCfg;
 import org.opends.server.config.ConfigException;
-import org.opends.server.types.ByteString;
-import org.opends.server.types.DirectoryException;
-import org.opends.server.types.Entry;
-import org.opends.server.types.InitializationException;
-
+import org.opends.server.types.*;
 
 
 /**
diff --git a/opends/src/server/org/opends/server/api/PasswordStorageScheme.java b/opends/src/server/org/opends/server/api/PasswordStorageScheme.java
index 5bbc774..4cb3b63 100644
--- a/opends/src/server/org/opends/server/api/PasswordStorageScheme.java
+++ b/opends/src/server/org/opends/server/api/PasswordStorageScheme.java
@@ -22,7 +22,7 @@
  * CDDL HEADER END
  *
  *
- *      Copyright 2006-2008 Sun Microsystems, Inc.
+ *      Copyright 2006-2009 Sun Microsystems, Inc.
  */
 package org.opends.server.api;
 import org.opends.messages.Message;
@@ -33,10 +33,7 @@
 
 import org.opends.server.admin.std.server.PasswordStorageSchemeCfg;
 import org.opends.server.config.ConfigException;
-import org.opends.server.types.ByteString;
-import org.opends.server.types.DirectoryException;
-import org.opends.server.types.InitializationException;
-
+import org.opends.server.types.*;
 
 
 /**
@@ -151,7 +148,7 @@
    * @throws  DirectoryException  If a problem occurs while
    *                              processing.
    */
-  public abstract ByteString encodePassword(ByteString plaintext)
+  public abstract ByteString encodePassword(ByteSequence plaintext)
          throws DirectoryException;
 
 
@@ -170,7 +167,7 @@
    *                              processing.
    */
   public abstract ByteString encodePasswordWithScheme(
-                                  ByteString plaintext)
+                                  ByteSequence plaintext)
          throws DirectoryException;
 
 
@@ -190,8 +187,8 @@
    *          the provided stored password, or {@code false} if not.
    */
   public abstract boolean passwordMatches(
-                               ByteString plaintextPassword,
-                               ByteString storedPassword);
+                               ByteSequence plaintextPassword,
+                               ByteSequence storedPassword);
 
 
 
@@ -242,8 +239,8 @@
    *                              support the authentication password
    *                              syntax.
    */
-  public abstract ByteString encodeAuthPassword(ByteString plaintext)
-         throws DirectoryException;
+  public abstract ByteString encodeAuthPassword(
+      ByteSequence plaintext) throws DirectoryException;
 
 
 
@@ -268,7 +265,7 @@
    *          password syntax.
    */
   public abstract boolean authPasswordMatches(
-                               ByteString plaintextPassword,
+                               ByteSequence plaintextPassword,
                                String authInfo, String authValue);
 
 
@@ -301,7 +298,7 @@
    *                              stored password.
    */
   public abstract ByteString getPlaintextValue(
-                                  ByteString storedPassword)
+                                  ByteSequence storedPassword)
          throws DirectoryException;
 
 
diff --git a/opends/src/server/org/opends/server/api/PasswordValidator.java b/opends/src/server/org/opends/server/api/PasswordValidator.java
index 8a52d7c..f2c4b8f 100644
--- a/opends/src/server/org/opends/server/api/PasswordValidator.java
+++ b/opends/src/server/org/opends/server/api/PasswordValidator.java
@@ -34,10 +34,7 @@
 
 import org.opends.server.admin.std.server.PasswordValidatorCfg;
 import org.opends.server.config.ConfigException;
-import org.opends.server.types.ByteString;
-import org.opends.server.types.Entry;
-import org.opends.server.types.InitializationException;
-import org.opends.server.types.Operation;
+import org.opends.server.types.*;
 
 import org.opends.messages.MessageBuilder;
 
diff --git a/opends/src/server/org/opends/server/api/SubstringMatchingRule.java b/opends/src/server/org/opends/server/api/SubstringMatchingRule.java
index c596465..978ac53 100644
--- a/opends/src/server/org/opends/server/api/SubstringMatchingRule.java
+++ b/opends/src/server/org/opends/server/api/SubstringMatchingRule.java
@@ -22,7 +22,7 @@
  * CDDL HEADER END
  *
  *
- *      Copyright 2006-2008 Sun Microsystems, Inc.
+ *      Copyright 2006-2009 Sun Microsystems, Inc.
  */
 package org.opends.server.api;
 
@@ -30,10 +30,7 @@
 
 import java.util.List;
 
-import org.opends.server.types.ByteString;
-import org.opends.server.types.ConditionResult;
-import org.opends.server.types.DirectoryException;
-
+import org.opends.server.types.*;
 
 
 /**
@@ -60,8 +57,8 @@
    *                              not acceptable according to the
    *                              associated syntax.
    */
-  public abstract ByteString normalizeSubstring(ByteString substring)
-         throws DirectoryException;
+  public abstract ByteString normalizeSubstring(
+      ByteSequence substring) throws DirectoryException;
 
 
 
@@ -86,11 +83,97 @@
    * @return  {@code true} if the provided value does match the given
    *          substring components, or {@code false} if not.
    */
-  public abstract boolean valueMatchesSubstring(
-                               ByteString value,
-                               ByteString subInitial,
-                               List<ByteString> subAnyElements,
-                               ByteString subFinal);
+  public boolean valueMatchesSubstring(ByteSequence value,
+                                    ByteSequence subInitial,
+                                    List<ByteSequence> subAnyElements,
+                                    ByteSequence subFinal)
+  {
+    int valueLength = value.length();
+
+    int pos = 0;
+    if (subInitial != null)
+    {
+      int initialLength = subInitial.length();
+      if (initialLength > valueLength)
+      {
+        return false;
+      }
+
+      for (; pos < initialLength; pos++)
+      {
+        if (subInitial.byteAt(pos) != value.byteAt(pos))
+        {
+          return false;
+        }
+      }
+    }
+
+
+    if ((subAnyElements != null) && (! subAnyElements.isEmpty()))
+    {
+      for (ByteSequence element : subAnyElements)
+      {
+        int anyLength = element.length();
+        if(anyLength == 0)
+            continue;
+        int end = valueLength - anyLength;
+        boolean match = false;
+        for (; pos <= end; pos++)
+        {
+          if (element.byteAt(0) == value.byteAt(pos))
+          {
+            boolean subMatch = true;
+            for (int i=1; i < anyLength; i++)
+            {
+              if (element.byteAt(i) != value.byteAt(pos+i))
+              {
+                subMatch = false;
+                break;
+              }
+            }
+
+            if (subMatch)
+            {
+              match = subMatch;
+              break;
+            }
+          }
+        }
+
+        if (match)
+        {
+          pos += anyLength;
+        }
+        else
+        {
+          return false;
+        }
+      }
+    }
+
+
+    if (subFinal != null)
+    {
+      int finalLength = subFinal.length();
+
+      if ((valueLength - finalLength) < pos)
+      {
+        return false;
+      }
+
+      pos = valueLength - finalLength;
+      for (int i=0; i < finalLength; i++,pos++)
+      {
+        if (subFinal.byteAt(i) != value.byteAt(pos))
+        {
+          return false;
+        }
+      }
+    }
+
+
+    return true;
+  }
 
 
 
@@ -116,8 +199,9 @@
    *          a match for the provided assertion value, or
    *          {@code false} if not.
    */
-  public ConditionResult valuesMatch(ByteString attributeValue,
-                                     ByteString assertionValue)
+  @Override
+  public ConditionResult valuesMatch(ByteSequence attributeValue,
+                                     ByteSequence assertionValue)
   {
     return ConditionResult.UNDEFINED;
   }
diff --git a/opends/src/server/org/opends/server/api/VirtualAttributeProvider.java b/opends/src/server/org/opends/server/api/VirtualAttributeProvider.java
index 9b1c147..65bbe41 100644
--- a/opends/src/server/org/opends/server/api/VirtualAttributeProvider.java
+++ b/opends/src/server/org/opends/server/api/VirtualAttributeProvider.java
@@ -37,13 +37,7 @@
 import org.opends.server.admin.std.server.VirtualAttributeCfg;
 import org.opends.server.config.ConfigException;
 import org.opends.server.core.SearchOperation;
-import org.opends.server.types.AttributeValue;
-import org.opends.server.types.ByteString;
-import org.opends.server.types.ConditionResult;
-import org.opends.server.types.DebugLogLevel;
-import org.opends.server.types.Entry;
-import org.opends.server.types.InitializationException;
-import org.opends.server.types.VirtualAttributeRule;
+import org.opends.server.types.*;
 
 import static org.opends.server.loggers.debug.DebugLogger.*;
 import org.opends.server.loggers.debug.DebugTracer;
@@ -317,7 +311,7 @@
     }
 
 
-    ArrayList<ByteString> normalizedSubAny;
+    ArrayList<ByteSequence> normalizedSubAny;
     if (subAny == null)
     {
       normalizedSubAny = null;
@@ -325,7 +319,7 @@
     else
     {
       normalizedSubAny =
-           new ArrayList<ByteString>(subAny.size());
+           new ArrayList<ByteSequence>(subAny.size());
       for (ByteString subAnyElement : subAny)
       {
         try
diff --git a/opends/src/server/org/opends/server/authorization/dseecompat/Aci.java b/opends/src/server/org/opends/server/authorization/dseecompat/Aci.java
index 96df8da..a1acb5c 100644
--- a/opends/src/server/org/opends/server/authorization/dseecompat/Aci.java
+++ b/opends/src/server/org/opends/server/authorization/dseecompat/Aci.java
@@ -28,8 +28,8 @@
 package org.opends.server.authorization.dseecompat;
 import org.opends.messages.Message;
 
-import org.opends.server.types.ByteString;
 import org.opends.server.types.DN;
+import org.opends.server.types.ByteSequence;
 import static org.opends.messages.AccessControlMessages.*;
 import static org.opends.server.util.StaticUtils.isDigit;
 
@@ -362,9 +362,9 @@
      * @return  Returns a decoded ACI representing the string argument.
      * @throws AciException If the parsing of the ACI string fails.
      */
-    public static Aci decode (ByteString byteString, DN dn)
+    public static Aci decode (ByteSequence byteString, DN dn)
     throws AciException {
-        String input=byteString.stringValue();
+        String input=byteString.toString();
         //Perform a quick pattern check against the string to catch any
         //obvious syntax errors.
         if (!Pattern.matches(aciRegex, input)) {
@@ -387,7 +387,7 @@
      * @return A string representation of the ACI.
      */
     public String toString() {
-        return new String(aciString);
+        return aciString;
     }
 
     /**
diff --git a/opends/src/server/org/opends/server/authorization/dseecompat/AciContainer.java b/opends/src/server/org/opends/server/authorization/dseecompat/AciContainer.java
index 6a9c7b0..d12f2bf 100644
--- a/opends/src/server/org/opends/server/authorization/dseecompat/AciContainer.java
+++ b/opends/src/server/org/opends/server/authorization/dseecompat/AciContainer.java
@@ -27,22 +27,22 @@
 
 package org.opends.server.authorization.dseecompat;
 
+import org.opends.server.protocols.ldap.LDAPClientConnection;
 import org.opends.server.types.*;
 import org.opends.server.api.ClientConnection;
 import org.opends.server.api.Group;
 import org.opends.server.core.AddOperationBasis;
-import org.opends.server.api.ConnectionSecurityProvider;
 import org.opends.server.core.SearchOperation;
-import org.opends.server.extensions.TLSConnectionSecurityProvider;
 import org.opends.server.types.Operation;
 import java.net.InetAddress;
+import java.security.cert.Certificate;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.HashMap;
 
 import static org.opends.server.authorization.dseecompat.Aci.*;
 import static org.opends.server.authorization.dseecompat.AciHandler.*;
-import org.opends.server.controls.GetEffectiveRights;
+import org.opends.server.controls.GetEffectiveRightsRequestControl;
 import static org.opends.server.util.ServerConstants.OID_GET_EFFECTIVE_RIGHTS;
 
 /**
@@ -287,8 +287,8 @@
       if(operation instanceof SearchOperation && (rights == ACI_READ)) {
         //Checks if a geteffectiverights control was sent and
         //sets up the structures needed.
-        GetEffectiveRights getEffectiveRightsControl =
-              (GetEffectiveRights)
+        GetEffectiveRightsRequestControl getEffectiveRightsControl =
+              (GetEffectiveRightsRequestControl)
                       operation.getAttachment(OID_GET_EFFECTIVE_RIGHTS);
         if(getEffectiveRightsControl != null) {
           hasGetEffectiveRightsControl=true;
@@ -835,15 +835,14 @@
              */
             if (authInfo.hasAuthenticationType(AuthenticationType.SASL) &&
                  authInfo.hasSASLMechanism(saslMech)) {
-              ConnectionSecurityProvider provider =
-                    clientConnection.getConnectionSecurityProvider();
-              if (provider instanceof TLSConnectionSecurityProvider) {
-                TLSConnectionSecurityProvider tlsProvider =
-                      (TLSConnectionSecurityProvider) provider;
-                 if (tlsProvider.getClientCertificateChain() != null) {
-                   matched = EnumEvalResult.TRUE;
-                 }
-              }
+
+                if(clientConnection instanceof LDAPClientConnection) {
+                    LDAPClientConnection lc =
+                                       (LDAPClientConnection) clientConnection;
+                    Certificate[] certChain = lc.getClientCertificateChain();
+                    if(certChain.length != 0)
+                        matched = EnumEvalResult.TRUE;
+                }
             }
           } else {
             // A particular SASL mechanism.
@@ -985,6 +984,6 @@
    * {@inheritDoc}
    */
   public int getCurrentSSF() {
-      return clientConnection.getConnectionSecurityProvider().getSSF();
+      return clientConnection.getSSF();
   }
 }
diff --git a/opends/src/server/org/opends/server/authorization/dseecompat/AciEffectiveRights.java b/opends/src/server/org/opends/server/authorization/dseecompat/AciEffectiveRights.java
index 7dee8d6..45296a1 100644
--- a/opends/src/server/org/opends/server/authorization/dseecompat/AciEffectiveRights.java
+++ b/opends/src/server/org/opends/server/authorization/dseecompat/AciEffectiveRights.java
@@ -29,7 +29,6 @@
 
 import static org.opends.server.authorization.dseecompat.Aci.*;
 import org.opends.server.core.DirectoryServer;
-import org.opends.server.protocols.asn1.ASN1OctetString;
 import org.opends.server.types.*;
 
 import java.util.LinkedHashSet;
@@ -326,15 +325,15 @@
       //Write right is more complicated. Create a dummy value and set that as
       //the attribute's value. Call the special writeRightsString method, rather
       //than rightsString.
-      AttributeValue val=new AttributeValue(a, "dum###Val");
+      AttributeValue val= AttributeValues.create(a, "dum###Val");
       container.setCurrentAttributeValue(val);
       evalInfo.append(attributeLevelWriteRights(container, handler, skipCheck));
       addAttrLevelRightsInfo(container, mask, a, retEntry, "write");
       evalInfo.append(',');
       //Perform both selfwrite_add and selfwrite_delete and append results.
-      ByteString clientDNStr=
-              new ASN1OctetString(container.getClientDN().toString());
-      AttributeValue val1=new AttributeValue(a, clientDNStr);
+      AttributeValue val1=
+          AttributeValues.create(a,
+              container.getClientDN().toString());
       if(!specificAttr)
         container.setCurrentAttributeType(dnAttributeType);
       container.setCurrentAttributeValue(val1);
diff --git a/opends/src/server/org/opends/server/authorization/dseecompat/AciHandler.java b/opends/src/server/org/opends/server/authorization/dseecompat/AciHandler.java
index d505d25..268290f 100644
--- a/opends/src/server/org/opends/server/authorization/dseecompat/AciHandler.java
+++ b/opends/src/server/org/opends/server/authorization/dseecompat/AciHandler.java
@@ -47,9 +47,10 @@
 import org.opends.server.loggers.debug.DebugTracer;
 import org.opends.server.protocols.internal.InternalClientConnection;
 import org.opends.server.protocols.internal.InternalSearchOperation;
+import org.opends.server.protocols.ldap.LDAPControl;
 import org.opends.server.types.*;
 import org.opends.server.workflowelement.localbackend.*;
-import org.opends.server.controls.GetEffectiveRights;
+import org.opends.server.controls.GetEffectiveRightsRequestControl;
 import org.opends.server.backends.jeb.EntryContainer;
 
 
@@ -568,7 +569,8 @@
            (isAttributeDN(container.getCurrentAttributeType())))  {
           String DNString=null;
           try {
-           DNString  =  container.getCurrentAttributeValue().getStringValue();
+            DNString =
+                container.getCurrentAttributeValue().getValue().toString();
             DN tmpDN = DN.decode(DNString);
             //Have a valid DN, compare to clientDN to see if the ACI_SELF
             //right should be set.
@@ -911,7 +913,8 @@
            DirectoryServer.getAttributeType(baseName)) == null)
            attributeType = DirectoryServer.getDefaultAttributeType(baseName);
        AttributeValue attributeValue =
-           new AttributeValue(attributeType, operation.getAssertionValue());
+           AttributeValues.create(attributeType,
+               operation.getAssertionValue());
        operationContainer.setCurrentAttributeType(attributeType);
        operationContainer.setCurrentAttributeValue(attributeValue);
        return isAllowed(operationContainer, operation);
@@ -1186,12 +1189,20 @@
       op.setAttachment(ORIG_AUTH_ENTRY, op.getAuthorizationEntry());
     else if(control.getOID().equals(OID_GET_EFFECTIVE_RIGHTS)) {
       try {
-        GetEffectiveRights getEffectiveRightsControl =
-                GetEffectiveRights.decodeControl(control);
+        GetEffectiveRightsRequestControl getEffectiveRightsControl;
+        if(control instanceof LDAPControl)
+        {
+          getEffectiveRightsControl = GetEffectiveRightsRequestControl.DECODER
+              .decode(control.isCritical(), ((LDAPControl) control).getValue());
+        }
+        else
+        {
+          getEffectiveRightsControl = (GetEffectiveRightsRequestControl)control;
+        }
         op.setAttachment(OID_GET_EFFECTIVE_RIGHTS, getEffectiveRightsControl);
-      } catch  (LDAPException le)  {
+      } catch  (DirectoryException de)  {
         Message message =
-            WARN_ACI_SYNTAX_DECODE_EFFECTIVERIGHTS_FAIL.get(le.getMessage());
+            WARN_ACI_SYNTAX_DECODE_EFFECTIVERIGHTS_FAIL.get(de.getMessage());
         logError(message);
         ret=false;
       }
@@ -1231,7 +1242,7 @@
 
       // Load the values, a bind rule might want to evaluate them.
       for (String URLString : URLStrings) {
-        builder.add(new AttributeValue(refAttrType, URLString));
+        builder.add(AttributeValues.create(refAttrType, URLString));
       }
 
       e.addAttribute(builder.toAttribute(),null);
diff --git a/opends/src/server/org/opends/server/authorization/dseecompat/AciList.java b/opends/src/server/org/opends/server/authorization/dseecompat/AciList.java
index 8ef7ac6..b069c07 100644
--- a/opends/src/server/org/opends/server/authorization/dseecompat/AciList.java
+++ b/opends/src/server/org/opends/server/authorization/dseecompat/AciList.java
@@ -394,7 +394,7 @@
         for(Aci aci : hashEntry.getValue()) {
           try {
              Aci newAci =
-               Aci.decode(ByteStringFactory.create(aci.toString()), relocateDN);
+               Aci.decode(ByteString.valueOf(aci.toString()), relocateDN);
              acis.add(newAci);
           } catch (AciException ex) {
             //This should never happen since only a copy of the
diff --git a/opends/src/server/org/opends/server/authorization/dseecompat/AciListenerManager.java b/opends/src/server/org/opends/server/authorization/dseecompat/AciListenerManager.java
index c99571e..9954423 100644
--- a/opends/src/server/org/opends/server/authorization/dseecompat/AciListenerManager.java
+++ b/opends/src/server/org/opends/server/authorization/dseecompat/AciListenerManager.java
@@ -39,6 +39,7 @@
 import org.opends.server.types.operation.PostResponseModifyDNOperation;
 import org.opends.server.protocols.internal.InternalClientConnection;
 import org.opends.server.protocols.internal.InternalSearchOperation;
+import org.opends.server.protocols.ldap.LDAPControl;
 import static org.opends.server.loggers.ErrorLogger.logError;
 import static org.opends.server.loggers.debug.DebugLogger.*;
 import org.opends.server.loggers.debug.DebugTracer;
@@ -240,10 +241,11 @@
       //Add manageDsaIT control so any ACIs in referral entries will be
       //picked up.
       ArrayList<Control> controls = new ArrayList<Control>(1);
-      controls.add(new Control(OID_MANAGE_DSAIT_CONTROL, true));
+      controls.add(new LDAPControl(OID_MANAGE_DSAIT_CONTROL, true));
       //Add group membership control to let a backend look for it and
       //decide if it would abort searches.
-      controls.add(new Control(OID_INTERNAL_GROUP_MEMBERSHIP_UPDATE ,false));
+      controls.add(new LDAPControl(
+          OID_INTERNAL_GROUP_MEMBERSHIP_UPDATE ,false));
       for (DN baseDN : backend.getBaseDNs()) {
         try {
           if (! backend.entryExists(baseDN))  {
diff --git a/opends/src/server/org/opends/server/authorization/dseecompat/GroupDN.java b/opends/src/server/org/opends/server/authorization/dseecompat/GroupDN.java
index e3eb0fc..7402d3b 100644
--- a/opends/src/server/org/opends/server/authorization/dseecompat/GroupDN.java
+++ b/opends/src/server/org/opends/server/authorization/dseecompat/GroupDN.java
@@ -148,7 +148,7 @@
         List<Attribute> attrs = e.getAttribute(attributeType);
         for(AttributeValue v : attrs.get(0)) {
             try {
-                DN groupDN=DN.decode(v.getStringValue());
+                DN groupDN=DN.decode(v.getValue().toString());
                 if(suffixDN != null &&
                    !groupDN.isDescendantOf(suffixDN))
                         continue;
diff --git a/opends/src/server/org/opends/server/authorization/dseecompat/PatternDN.java b/opends/src/server/org/opends/server/authorization/dseecompat/PatternDN.java
index 440bf22..5a84589 100644
--- a/opends/src/server/org/opends/server/authorization/dseecompat/PatternDN.java
+++ b/opends/src/server/org/opends/server/authorization/dseecompat/PatternDN.java
@@ -31,7 +31,6 @@
 import org.opends.server.types.*;
 import static org.opends.messages.SchemaMessages.*;
 import static org.opends.messages.AccessControlMessages.*;
-import org.opends.server.protocols.asn1.ASN1OctetString;
 import static org.opends.server.util.StaticUtils.isDigit;
 import static org.opends.server.util.StaticUtils.isHexDigit;
 import static org.opends.server.util.StaticUtils.hexStringToByteArray;
@@ -448,7 +447,7 @@
       if (pos >= length)
       {
         ArrayList<ByteString> arrayList = new ArrayList<ByteString>(1);
-        arrayList.add(new ASN1OctetString());
+        arrayList.add(ByteString.empty());
         rdnComponents.add(new PatternRDN(name, arrayList, dnString));
         break;
       }
@@ -583,7 +582,7 @@
         if (pos >= length)
         {
           ArrayList<ByteString> arrayList = new ArrayList<ByteString>(1);
-          arrayList.add(new ASN1OctetString());
+          arrayList.add(ByteString.empty());
           rdn.addValue(name, arrayList, dnString);
           rdnComponents.add(rdn);
           break;
@@ -1198,7 +1197,7 @@
       try
       {
         byte[] bytes = hexStringToByteArray(hexString.toString());
-        attributeValues.add(new ASN1OctetString(bytes));
+        attributeValues.add(ByteString.wrap(bytes));
         return pos;
       }
       catch (Exception e)
@@ -1262,7 +1261,7 @@
         }
       }
 
-      attributeValues.add(new ASN1OctetString(valueString.toString()));
+      attributeValues.add(ByteString.valueOf(valueString.toString()));
       return pos;
     }
 
@@ -1281,7 +1280,7 @@
       else if (c == '*')
       {
         escaped = false;
-        attributeValues.add(new ASN1OctetString(valueString.toString()));
+        attributeValues.add(ByteString.valueOf(valueString.toString()));
       }
       else
       {
@@ -1379,7 +1378,7 @@
             throw new DirectoryException(ResultCode.INVALID_DN_SYNTAX,
                                          message);
           }
-          attributeValues.add(new ASN1OctetString(valueString.toString()));
+          attributeValues.add(ByteString.valueOf(valueString.toString()));
           valueString = new StringBuilder();
           hexChars = new StringBuilder();
         }
@@ -1412,7 +1411,7 @@
       }
 
 
-      attributeValues.add(new ASN1OctetString(valueString.toString()));
+      attributeValues.add(ByteString.valueOf(valueString.toString()));
       return pos;
     }
   }
diff --git a/opends/src/server/org/opends/server/authorization/dseecompat/PatternRDN.java b/opends/src/server/org/opends/server/authorization/dseecompat/PatternRDN.java
index 61b08f8..8df9b4c 100644
--- a/opends/src/server/org/opends/server/authorization/dseecompat/PatternRDN.java
+++ b/opends/src/server/org/opends/server/authorization/dseecompat/PatternRDN.java
@@ -273,13 +273,13 @@
         // Handle this just like a substring filter.
 
         ByteString subInitial = pattern.get(0);
-        if (subInitial.value().length == 0)
+        if (subInitial.length() == 0)
         {
           subInitial = null;
         }
 
         ByteString subFinal = pattern.get(pattern.size() - 1);
-        if (subFinal.value().length == 0)
+        if (subFinal.length() == 0)
         {
           subFinal = null;
         }
@@ -308,7 +308,8 @@
       }
       else
       {
-        ByteString thisNormValue = type.normalize(pattern.get(0));
+        ByteString thisNormValue =
+            type.getEqualityMatchingRule().normalizeValue(pattern.get(0));
         ByteString thatNormValue = value.getNormalizedValue();
         EqualityMatchingRule mr = type.getEqualityMatchingRule();
         return mr.areEqual(thisNormValue, thatNormValue);
diff --git a/opends/src/server/org/opends/server/authorization/dseecompat/UserAttr.java b/opends/src/server/org/opends/server/authorization/dseecompat/UserAttr.java
index df24463..c496469 100644
--- a/opends/src/server/org/opends/server/authorization/dseecompat/UserAttr.java
+++ b/opends/src/server/org/opends/server/authorization/dseecompat/UserAttr.java
@@ -221,7 +221,7 @@
                         filter, null);
         LinkedList<SearchResultEntry> result = op.getSearchEntries();
         if (!result.isEmpty()) {
-            AttributeValue val=new AttributeValue(attrType, attrVal);
+            AttributeValue val= AttributeValues.create(attrType, attrVal);
             SearchResultEntry resultEntry = result.getFirst();
             if(resultEntry.hasValue(attrType, null, val)) {
                 Entry e=evalCtx.getResourceEntry();
@@ -284,7 +284,7 @@
         if(!attrs.isEmpty()) {
             for(Attribute a : attrs) {
                 for(AttributeValue v : a) {
-                    String urlStr=v.getStringValue();
+                    String urlStr=v.getValue().toString();
                     LDAPURL url;
                     try {
                        url=LDAPURL.decode(urlStr, true);
diff --git a/opends/src/server/org/opends/server/authorization/dseecompat/UserDN.java b/opends/src/server/org/opends/server/authorization/dseecompat/UserDN.java
index a20e5a9..34748af 100644
--- a/opends/src/server/org/opends/server/authorization/dseecompat/UserDN.java
+++ b/opends/src/server/org/opends/server/authorization/dseecompat/UserDN.java
@@ -361,7 +361,7 @@
         List<Attribute> attrs =  e.getAttribute(attrType);
         for(AttributeValue v : attrs.get(0)) {
             try {
-                DN dn=DN.decode(v.getStringValue());
+                DN dn=DN.decode(v.getValue().toString());
                 if(dn.equals(clientDN)) {
                     matched=EnumEvalResult.TRUE;
                     break;
diff --git a/opends/src/server/org/opends/server/backends/BackupBackend.java b/opends/src/server/org/opends/server/backends/BackupBackend.java
index 351fc74..c40ea0d 100644
--- a/opends/src/server/org/opends/server/backends/BackupBackend.java
+++ b/opends/src/server/org/opends/server/backends/BackupBackend.java
@@ -44,32 +44,7 @@
 import org.opends.server.core.ModifyDNOperation;
 import org.opends.server.core.SearchOperation;
 import org.opends.server.loggers.debug.DebugTracer;
-import org.opends.server.protocols.asn1.ASN1OctetString;
-import org.opends.server.types.Attribute;
-import org.opends.server.types.AttributeBuilder;
-import org.opends.server.types.AttributeType;
-import org.opends.server.types.AttributeValue;
-import org.opends.server.types.Attributes;
-import org.opends.server.types.BackupConfig;
-import org.opends.server.types.BackupDirectory;
-import org.opends.server.types.BackupInfo;
-import org.opends.server.types.ConditionResult;
-import org.opends.server.types.ConfigChangeResult;
-import org.opends.server.types.DebugLogLevel;
-import org.opends.server.types.DirectoryException;
-import org.opends.server.types.DN;
-import org.opends.server.types.Entry;
-import org.opends.server.types.IndexType;
-import org.opends.server.types.InitializationException;
-import org.opends.server.types.LDIFExportConfig;
-import org.opends.server.types.LDIFImportConfig;
-import org.opends.server.types.LDIFImportResult;
-import org.opends.server.types.ObjectClass;
-import org.opends.server.types.RDN;
-import org.opends.server.types.RestoreConfig;
-import org.opends.server.types.ResultCode;
-import org.opends.server.types.SearchFilter;
-import org.opends.server.types.SearchScope;
+import org.opends.server.types.*;
 import org.opends.server.schema.BooleanSyntax;
 import org.opends.server.schema.GeneralizedTimeSyntax;
 import org.opends.server.util.Validator;
@@ -446,7 +421,7 @@
           {
             BackupDirectory backupDirectory =
                 BackupDirectory.readBackupDirectoryDescriptor(
-                    v.getStringValue());
+                    v.getValue().toString());
             count += backupDirectory.getBackups().keySet().size();
           }
           catch (Exception e)
@@ -555,7 +530,8 @@
     try
     {
       backupDirectory =
-           BackupDirectory.readBackupDirectoryDescriptor(v.getStringValue());
+           BackupDirectory.readBackupDirectoryDescriptor(
+               v.getValue().toString());
     }
     catch (ConfigException ce)
     {
@@ -602,7 +578,7 @@
 
     t = DirectoryServer.getAttributeType(ATTR_BACKUP_BACKEND_DN, true);
     attrList = new ArrayList<Attribute>(1);
-    attrList.add(Attributes.create(t, new AttributeValue(t,
+    attrList.add(Attributes.create(t, AttributeValues.create(t,
         backupDirectory.getConfigEntryDN().toString())));
     userAttrs.put(t, attrList);
 
@@ -637,7 +613,7 @@
           .valueOf(entryDN));
       throw new DirectoryException(ResultCode.CONSTRAINT_VIOLATION, message);
     }
-    String backupID = idValue.getStringValue();
+    String backupID = idValue.getValue().toString();
 
     // Next, get the backup directory from the parent DN.
     DN parentDN = entryDN.getParentDNInSuffix();
@@ -659,7 +635,7 @@
     BackupDirectory backupDirectory;
     try {
       backupDirectory = BackupDirectory.readBackupDirectoryDescriptor(v
-          .getStringValue());
+          .getValue().toString());
     } catch (ConfigException ce) {
       if (debugEnabled()) {
         TRACER.debugCaught(DebugLogLevel.ERROR, ce);
@@ -716,7 +692,7 @@
     if (backupDate != null) {
       t = DirectoryServer.getAttributeType(ATTR_BACKUP_DATE, true);
       attrList = new ArrayList<Attribute>(1);
-      attrList.add(Attributes.create(t, new AttributeValue(t,
+      attrList.add(Attributes.create(t, AttributeValues.create(t,
           GeneralizedTimeSyntax.format(backupDate))));
       userAttrs.put(t, attrList);
     }
@@ -744,7 +720,7 @@
       t = DirectoryServer.getAttributeType(ATTR_BACKUP_DEPENDENCY, true);
       AttributeBuilder builder = new AttributeBuilder(t);
       for (String s : dependencies) {
-        builder.add(new AttributeValue(t, s));
+        builder.add(AttributeValues.create(t, s));
       }
       attrList = new ArrayList<Attribute>(1);
       attrList.add(builder.toAttribute());
@@ -755,8 +731,9 @@
     if (signedHash != null) {
       t = DirectoryServer.getAttributeType(ATTR_BACKUP_SIGNED_HASH, true);
       attrList = new ArrayList<Attribute>(1);
-      attrList.add(Attributes.create(t, new AttributeValue(t,
-          new ASN1OctetString(signedHash))));
+      attrList.add(Attributes.create(t,
+          AttributeValues.create(t,
+              ByteString.wrap(signedHash))));
       userAttrs.put(t, attrList);
     }
 
@@ -764,8 +741,9 @@
     if (unsignedHash != null) {
       t = DirectoryServer.getAttributeType(ATTR_BACKUP_UNSIGNED_HASH, true);
       attrList = new ArrayList<Attribute>(1);
-      attrList.add(Attributes.create(t, new AttributeValue(t,
-          new ASN1OctetString(unsignedHash))));
+      attrList.add(Attributes.create(t,
+          AttributeValues.create(t,
+              ByteString.wrap(unsignedHash))));
       userAttrs.put(t, attrList);
     }
 
@@ -774,7 +752,7 @@
       for (Map.Entry<String, String> e : properties.entrySet()) {
         t = DirectoryServer.getAttributeType(toLowerCase(e.getKey()), true);
         attrList = new ArrayList<Attribute>(1);
-        attrList.add(Attributes.create(t, new AttributeValue(
+        attrList.add(Attributes.create(t, AttributeValues.create(
             t, e.getValue())));
         userAttrs.put(t, attrList);
       }
@@ -919,7 +897,7 @@
                 {
                   BackupDirectory backupDirectory =
                        BackupDirectory.readBackupDirectoryDescriptor(
-                            v.getStringValue());
+                            v.getValue().toString());
                   AttributeType idType =
                        DirectoryServer.getAttributeType(ATTR_BACKUP_ID,
                                                         true);
@@ -976,7 +954,7 @@
             {
               BackupDirectory backupDirectory =
                    BackupDirectory.readBackupDirectoryDescriptor(
-                        v.getStringValue());
+                        v.getValue().toString());
               AttributeType idType =
                    DirectoryServer.getAttributeType(ATTR_BACKUP_ID,
                                                     true);
@@ -1238,7 +1216,7 @@
                                String rdnStringValue)
   {
     AttributeValue attrValue =
-         new AttributeValue(rdnAttrType, rdnStringValue);
+        AttributeValues.create(rdnAttrType, rdnStringValue);
     return parentDN.concat(RDN.create(rdnAttrType, attrValue));
   }
 
diff --git a/opends/src/server/org/opends/server/backends/LDIFBackend.java b/opends/src/server/org/opends/server/backends/LDIFBackend.java
index 69ed96c..761a3b9 100644
--- a/opends/src/server/org/opends/server/backends/LDIFBackend.java
+++ b/opends/src/server/org/opends/server/backends/LDIFBackend.java
@@ -44,6 +44,7 @@
 import org.opends.server.api.AlertGenerator;
 import org.opends.server.api.Backend;
 import org.opends.server.config.ConfigException;
+import org.opends.server.controls.SubtreeDeleteControl;
 import org.opends.server.core.AddOperation;
 import org.opends.server.core.DeleteOperation;
 import org.opends.server.core.DirectoryServer;
@@ -106,7 +107,7 @@
   private DN[] baseDNs;
 
   // The mapping between parent DNs and their immediate children.
-  private HashMap<DN,HashSet<DN>> childDNs;
+  private final HashMap<DN,HashSet<DN>> childDNs;
 
   // The base DNs for this backend, in a hash set.
   private HashSet<DN> baseDNSet;
@@ -121,10 +122,10 @@
   private LDIFBackendCfg currentConfig;
 
   // The mapping between entry DNs and the corresponding entries.
-  private LinkedHashMap<DN,Entry> entryMap;
+  private final LinkedHashMap<DN,Entry> entryMap;
 
   // A read-write lock used to protect access to this backend.
-  private ReentrantReadWriteLock backendLock;
+  private final ReentrantReadWriteLock backendLock;
 
   // The path to the LDIF file containing the data for this backend.
   private String ldifFilePath;
@@ -733,13 +734,12 @@
       else
       {
         boolean subtreeDelete = false;
-        for (Control c : deleteOperation.getRequestControls())
+
+        if (deleteOperation != null
+            && deleteOperation
+                .getRequestControl(SubtreeDeleteControl.DECODER) != null)
         {
-          if (c.getOID().equals(OID_SUBTREE_DELETE_CONTROL))
-          {
-            subtreeDelete = true;
-            break;
-          }
+          subtreeDelete = true;
         }
 
         if (! subtreeDelete)
@@ -1579,6 +1579,7 @@
   /**
    * {@inheritDoc}
    */
+  @Override
   public void preloadEntryCache() throws UnsupportedOperationException {
     throw new UnsupportedOperationException("Operation not supported.");
   }
diff --git a/opends/src/server/org/opends/server/backends/MemoryBackend.java b/opends/src/server/org/opends/server/backends/MemoryBackend.java
index 054570b..eb1e2be 100644
--- a/opends/src/server/org/opends/server/backends/MemoryBackend.java
+++ b/opends/src/server/org/opends/server/backends/MemoryBackend.java
@@ -39,6 +39,7 @@
 import org.opends.server.admin.std.server.MemoryBackendCfg;
 import org.opends.server.api.Backend;
 import org.opends.server.config.ConfigException;
+import org.opends.server.controls.SubtreeDeleteControl;
 import org.opends.server.core.AddOperation;
 import org.opends.server.core.DeleteOperation;
 import org.opends.server.core.DirectoryServer;
@@ -475,15 +476,12 @@
 
     // Check to see if the entry contains a subtree delete control.
     boolean subtreeDelete = false;
-    if (deleteOperation != null)
+
+    if (deleteOperation != null
+        && deleteOperation
+            .getRequestControl(SubtreeDeleteControl.DECODER) != null)
     {
-      for (Control c : deleteOperation.getRequestControls())
-      {
-        if (c.getOID().equals(OID_SUBTREE_DELETE_CONTROL))
-        {
-          subtreeDelete = true;
-        }
-      }
+      subtreeDelete = true;
     }
 
     HashSet<DN> children = childDNs.get(entryDN);
@@ -989,6 +987,7 @@
   /**
    * {@inheritDoc}
    */
+  @Override
   public void preloadEntryCache() throws UnsupportedOperationException {
     throw new UnsupportedOperationException("Operation not supported.");
   }
diff --git a/opends/src/server/org/opends/server/backends/MonitorBackend.java b/opends/src/server/org/opends/server/backends/MonitorBackend.java
index bd774fe..90658b9 100644
--- a/opends/src/server/org/opends/server/backends/MonitorBackend.java
+++ b/opends/src/server/org/opends/server/backends/MonitorBackend.java
@@ -432,7 +432,7 @@
 
     // Get the RDN value and see if it matches the instance name for one of
     // the directory server monitor providers.
-    String rdnValue = entryRDN.getAttributeValue(0).getStringValue();
+    String rdnValue = entryRDN.getAttributeValue(0).getValue().toString();
     MonitorProvider<? extends MonitorProviderCfg> monitorProvider =
          DirectoryServer.getMonitorProvider(rdnValue.toLowerCase());
     if (monitorProvider == null)
@@ -506,7 +506,7 @@
   public boolean entryExists(DN entryDN)
          throws DirectoryException
   {
-      return this.isATreeNode(entryDN);
+    return this.isATreeNode(entryDN);
   }
 
 
@@ -1295,6 +1295,7 @@
   /**
    * {@inheritDoc}
    */
+  @Override
   public void preloadEntryCache() throws UnsupportedOperationException {
     throw new UnsupportedOperationException("Operation not supported.");
   }
diff --git a/opends/src/server/org/opends/server/backends/NullBackend.java b/opends/src/server/org/opends/server/backends/NullBackend.java
index fe77fd6..0690326 100644
--- a/opends/src/server/org/opends/server/backends/NullBackend.java
+++ b/opends/src/server/org/opends/server/backends/NullBackend.java
@@ -31,7 +31,6 @@
 import java.util.HashMap;
 import java.util.HashSet;
 
-import java.util.List;
 import java.util.Map;
 import org.opends.messages.Category;
 import org.opends.messages.Message;
@@ -48,19 +47,16 @@
 import org.opends.server.core.ModifyDNOperation;
 import org.opends.server.core.SearchOperation;
 import org.opends.server.loggers.debug.DebugTracer;
-import org.opends.server.protocols.asn1.ASN1OctetString;
 import org.opends.server.types.AttributeType;
 import org.opends.server.types.BackupConfig;
 import org.opends.server.types.BackupDirectory;
 import org.opends.server.types.ConditionResult;
-import org.opends.server.types.Control;
 import org.opends.server.types.DebugLogLevel;
 import org.opends.server.types.DirectoryException;
 import org.opends.server.types.DN;
 import org.opends.server.types.Entry;
 import org.opends.server.types.IndexType;
 import org.opends.server.types.InitializationException;
-import org.opends.server.types.LDAPException;
 import org.opends.server.types.LDIFExportConfig;
 import org.opends.server.types.LDIFImportConfig;
 import org.opends.server.types.LDIFImportResult;
@@ -80,34 +76,29 @@
 
 
 /**
- * This class implements /dev/null like backend for development and testing.
- *
- * The following behaviors of this backend implementation should be noted:
- *
- * * All read operations return success but no data.
- *
- * * All write operations return success but do nothing.
- *
- * * Bind operations fail with invalid credentials.
- *
- * * Compare operations are only possible on objectclass and return true
- *   for the following objeclasses only: top, nullbackendobject,
- *   extensibleobject. Otherwise comparison result is false or comparison
- *   fails altogether.
- *
- * * Controls are supported although this implementation does not provide
- *   any specific emulation for controls. Generally known request controls
- *   are accepted and default response controls returned where applicable.
- *
- * * Searches within this backend are always considered indexed.
- *
- * * Backend Import is supported by iterating over ldif reader on a single
- *   thread and issuing add operations which essentially do nothing at all.
- *
- * * Backend Export is supported but does nothing producing an empty ldif.
- *
- * * Backend Backup and Restore are not supported.
- *
+ * This class implements /dev/null like backend for development and
+ * testing. The following behaviors of this backend implementation
+ * should be noted:
+ * <ul>
+ * <li>All read operations return success but no data.
+ * <li>All write operations return success but do nothing.
+ * <li>Bind operations fail with invalid credentials.
+ * <li>Compare operations are only possible on objectclass and return
+ * true for the following objeclasses only: top, nullbackendobject,
+ * extensibleobject. Otherwise comparison result is false or comparison
+ * fails altogether.
+ * <li>Controls are supported although this implementation does not
+ * provide any specific emulation for controls. Generally known request
+ * controls are accepted and default response controls returned where
+ * applicable.
+ * <li>Searches within this backend are always considered indexed.
+ * <li>Backend Import is supported by iterating over ldif reader on a
+ * single thread and issuing add operations which essentially do nothing
+ * at all.
+ * <li>Backend Export is supported but does nothing producing an empty
+ * ldif.
+ * <li>Backend Backup and Restore are not supported.
+ * </ul>
  * This backend implementation is for development and testing only, does
  * not represent a complete and stable API, should be considered private
  * and subject to change without notice.
@@ -405,34 +396,14 @@
   public void search(SearchOperation searchOperation)
          throws DirectoryException
   {
-    List<Control> controls = searchOperation.getRequestControls();
-    PagedResultsControl pageRequest = null;
-
-    if (controls != null) {
-      for (Control control : controls) {
-        if (control.getOID().equals(OID_PAGED_RESULTS_CONTROL)) {
-          // Ignore all but the first paged results control.
-          if (pageRequest == null) {
-            try {
-              pageRequest = new PagedResultsControl(control.isCritical(),
-                control.getValue());
-            } catch (LDAPException e) {
-              if (debugEnabled()) {
-                TRACER.debugCaught(DebugLogLevel.ERROR, e);
-              }
-              throw new DirectoryException(ResultCode.PROTOCOL_ERROR,
-                e.getMessageObject(), e);
-            }
-          }
-        }
-      }
-    }
+    PagedResultsControl pageRequest =
+        searchOperation.getRequestControl(PagedResultsControl.DECODER);
 
     if (pageRequest != null) {
       // Indicate no more pages.
       PagedResultsControl control;
-      control = new PagedResultsControl(pageRequest.isCritical(), 0,
-        new ASN1OctetString());
+      control =
+          new PagedResultsControl(pageRequest.isCritical(), 0, null);
       searchOperation.getResponseControls().add(control);
     }
 
@@ -659,6 +630,7 @@
   /**
    * {@inheritDoc}
    */
+  @Override
   public void preloadEntryCache() throws UnsupportedOperationException {
     throw new UnsupportedOperationException("Operation not supported.");
   }
diff --git a/opends/src/server/org/opends/server/backends/RootDSEBackend.java b/opends/src/server/org/opends/server/backends/RootDSEBackend.java
index 475d54a..8481001 100644
--- a/opends/src/server/org/opends/server/backends/RootDSEBackend.java
+++ b/opends/src/server/org/opends/server/backends/RootDSEBackend.java
@@ -54,7 +54,6 @@
 import org.opends.server.core.WorkflowTopologyNode;
 import org.opends.server.core.networkgroups.NetworkGroup;
 import org.opends.server.loggers.debug.DebugTracer;
-import org.opends.server.protocols.asn1.ASN1OctetString;
 import org.opends.server.types.*;
 import org.opends.server.util.LDIFWriter;
 import org.opends.server.util.Validator;
@@ -838,7 +837,7 @@
     AttributeBuilder builder = new AttributeBuilder(type, name);
     for (DN dn : values) {
       builder.add(
-          new AttributeValue(type, new ASN1OctetString(dn.toString())));
+          AttributeValues.create(type, dn.toString()));
     }
 
     return builder.toAttribute();
@@ -871,7 +870,7 @@
     AttributeBuilder builder = new AttributeBuilder(type, name);
     builder.setInitialCapacity(values.size());
     for (String s : values) {
-      builder.add(new AttributeValue(type, new ASN1OctetString(s)));
+      builder.add(AttributeValues.create(type, s));
     }
 
     return builder.toAttribute();
diff --git a/opends/src/server/org/opends/server/backends/SchemaBackend.java b/opends/src/server/org/opends/server/backends/SchemaBackend.java
index 99f2410..72a789f 100644
--- a/opends/src/server/org/opends/server/backends/SchemaBackend.java
+++ b/opends/src/server/org/opends/server/backends/SchemaBackend.java
@@ -74,7 +74,6 @@
 import org.opends.server.core.SearchOperation;
 import org.opends.server.loggers.ErrorLogger;
 import org.opends.server.loggers.debug.DebugTracer;
-import org.opends.server.protocols.asn1.ASN1OctetString;
 import org.opends.server.schema.AttributeTypeSyntax;
 import org.opends.server.schema.DITContentRuleSyntax;
 import org.opends.server.schema.DITStructureRuleSyntax;
@@ -301,9 +300,11 @@
     cfg.getBaseDN().toArray(baseDNs);
     this.baseDNs = baseDNs;
 
-    creatorsName  = new AttributeValue(creatorsNameType, baseDNs[0].toString());
+    creatorsName  = AttributeValues.create(
+        creatorsNameType, baseDNs[0].toString());
     modifiersName =
-         new AttributeValue(modifiersNameType, baseDNs[0].toString());
+        AttributeValues.create(
+            modifiersNameType, baseDNs[0].toString());
 
     long createTime = DirectoryServer.getSchema().getOldestModificationTime();
     createTimestamp =
@@ -715,8 +716,9 @@
               value.getValue(), schema, false);
           attrType = DirectoryServer.getAttributeType(attrType.getOID());
 
-          newValueSet.add(new AttributeValue(attributeTypesType, attrType
-              .getDefinitionWithFileName()));
+          newValueSet.add(
+              AttributeValues.create(attributeTypesType,
+                  attrType.getDefinitionWithFileName()));
         }
         catch (DirectoryException e)
         {
@@ -741,8 +743,8 @@
           // add it to the valueset.
           String strippedStr = v.toString().replaceFirst(
               stripMinUpperBoundRegEx, "");
-          ASN1OctetString s = new ASN1OctetString(strippedStr);
-          AttributeValue strippedVal = new AttributeValue(s, s);
+          ByteString s = ByteString.valueOf(strippedStr);
+          AttributeValue strippedVal = AttributeValues.create(s, s);
           builder.add(strippedVal);
         }
         else
@@ -787,8 +789,8 @@
           ObjectClass oc = ObjectClassSyntax.decodeObjectClass(
               value.getValue(), schema, false);
           oc = DirectoryServer.getObjectClass(oc.getOID());
-          newValueSet.add(new AttributeValue(objectClassesType, oc
-              .getDefinitionWithFileName()));
+          newValueSet.add(AttributeValues.create(
+              objectClassesType, oc.getDefinitionWithFileName()));
         }
         catch (DirectoryException e)
         {
@@ -1123,7 +1125,7 @@
                 }
 
                 Message message = ERR_SCHEMA_MODIFY_CANNOT_DECODE_ATTRTYPE.get(
-                    v.getStringValue(), de.getMessageObject());
+                    v.getValue().toString(), de.getMessageObject());
                 throw new DirectoryException(
                                ResultCode.INVALID_ATTRIBUTE_SYNTAX, message,
                                de);
@@ -1150,7 +1152,7 @@
                 }
 
                 Message message = ERR_SCHEMA_MODIFY_CANNOT_DECODE_OBJECTCLASS.
-                    get(v.getStringValue(), de.getMessageObject());
+                    get(v.getValue().toString(), de.getMessageObject());
                 throw new DirectoryException(
                                ResultCode.INVALID_ATTRIBUTE_SYNTAX, message,
                                de);
@@ -1177,7 +1179,7 @@
                 }
 
                 Message message = ERR_SCHEMA_MODIFY_CANNOT_DECODE_NAME_FORM.get(
-                    v.getStringValue(), de.getMessageObject());
+                    v.getValue().toString(), de.getMessageObject());
                 throw new DirectoryException(
                                ResultCode.INVALID_ATTRIBUTE_SYNTAX, message,
                                de);
@@ -1204,7 +1206,7 @@
                 }
 
                 Message message = ERR_SCHEMA_MODIFY_CANNOT_DECODE_DCR.get(
-                    v.getStringValue(), de.getMessageObject());
+                    v.getValue().toString(), de.getMessageObject());
                 throw new DirectoryException(
                                ResultCode.INVALID_ATTRIBUTE_SYNTAX, message,
                                de);
@@ -1231,7 +1233,7 @@
                 }
 
                 Message message = ERR_SCHEMA_MODIFY_CANNOT_DECODE_DSR.get(
-                    v.getStringValue(), de.getMessageObject());
+                    v.getValue().toString(), de.getMessageObject());
                 throw new DirectoryException(
                                ResultCode.INVALID_ATTRIBUTE_SYNTAX, message,
                                de);
@@ -1258,7 +1260,7 @@
                 }
 
                 Message message = ERR_SCHEMA_MODIFY_CANNOT_DECODE_MR_USE.get(
-                    v.getStringValue(), de.getMessageObject());
+                    v.getValue().toString(), de.getMessageObject());
                 throw new DirectoryException(
                                ResultCode.INVALID_ATTRIBUTE_SYNTAX, message,
                                de);
@@ -1305,7 +1307,7 @@
                 }
 
                 Message message = ERR_SCHEMA_MODIFY_CANNOT_DECODE_ATTRTYPE.get(
-                    v.getStringValue(), de.getMessageObject());
+                    v.getValue().toString(), de.getMessageObject());
                 throw new DirectoryException(
                                ResultCode.INVALID_ATTRIBUTE_SYNTAX, message,
                                de);
@@ -1333,7 +1335,7 @@
                 }
 
                 Message message = ERR_SCHEMA_MODIFY_CANNOT_DECODE_OBJECTCLASS.
-                    get(v.getStringValue(), de.getMessageObject());
+                    get(v.getValue().toString(), de.getMessageObject());
                 throw new DirectoryException(
                                ResultCode.INVALID_ATTRIBUTE_SYNTAX, message,
                                de);
@@ -1360,7 +1362,7 @@
                 }
 
                 Message message = ERR_SCHEMA_MODIFY_CANNOT_DECODE_NAME_FORM.get(
-                    v.getStringValue(), de.getMessageObject());
+                    v.getValue().toString(), de.getMessageObject());
                 throw new DirectoryException(
                                ResultCode.INVALID_ATTRIBUTE_SYNTAX, message,
                                de);
@@ -1387,7 +1389,7 @@
                 }
 
                 Message message = ERR_SCHEMA_MODIFY_CANNOT_DECODE_DCR.get(
-                    v.getStringValue(), de.getMessageObject());
+                    v.getValue().toString(), de.getMessageObject());
                 throw new DirectoryException(
                                ResultCode.INVALID_ATTRIBUTE_SYNTAX, message,
                                de);
@@ -1415,7 +1417,7 @@
                 }
 
                 Message message = ERR_SCHEMA_MODIFY_CANNOT_DECODE_DSR.get(
-                    v.getStringValue(), de.getMessageObject());
+                    v.getValue().toString(), de.getMessageObject());
                 throw new DirectoryException(
                                ResultCode.INVALID_ATTRIBUTE_SYNTAX, message,
                                de);
@@ -1443,7 +1445,7 @@
                 }
 
                 Message message = ERR_SCHEMA_MODIFY_CANNOT_DECODE_MR_USE.get(
-                    v.getStringValue(), de.getMessageObject());
+                    v.getValue().toString(), de.getMessageObject());
                 throw new DirectoryException(
                                ResultCode.INVALID_ATTRIBUTE_SYNTAX, message,
                                de);
@@ -1496,7 +1498,8 @@
       authzDN = DN.nullDN();
     }
 
-    modifiersName = new AttributeValue(modifiersNameType, authzDN.toString());
+    modifiersName = AttributeValues.create(
+        modifiersNameType, authzDN.toString());
     modifyTimestamp = GeneralizedTimeSyntax.createGeneralizedTimeValue(
                            System.currentTimeMillis());
   }
@@ -1797,7 +1800,7 @@
           }
 
           Message message = ERR_SCHEMA_MODIFY_CANNOT_DECODE_ATTRTYPE.get(
-              v.getStringValue(), de.getMessageObject());
+              v.getValue().toString(), de.getMessageObject());
           throw new DirectoryException(
                          ResultCode.INVALID_ATTRIBUTE_SYNTAX, message,
                          de);
@@ -2123,7 +2126,7 @@
           }
 
           Message message = ERR_SCHEMA_MODIFY_CANNOT_DECODE_OBJECTCLASS.get(
-              v.getStringValue(), de.getMessageObject());
+              v.getValue().toString(), de.getMessageObject());
           throw new DirectoryException(
                          ResultCode.INVALID_ATTRIBUTE_SYNTAX, message,
                          de);
@@ -2428,7 +2431,7 @@
           }
 
           Message message = ERR_SCHEMA_MODIFY_CANNOT_DECODE_NAME_FORM.get(
-              v.getStringValue(), de.getMessageObject());
+              v.getValue().toString(), de.getMessageObject());
           throw new DirectoryException(
                          ResultCode.INVALID_ATTRIBUTE_SYNTAX, message,
                          de);
@@ -2959,7 +2962,7 @@
           }
 
           Message message = ERR_SCHEMA_MODIFY_CANNOT_DECODE_DSR.get(
-              v.getStringValue(), de.getMessageObject());
+              v.getValue().toString(), de.getMessageObject());
           throw new DirectoryException(
                          ResultCode.INVALID_ATTRIBUTE_SYNTAX, message,
                          de);
@@ -3331,7 +3334,8 @@
     {
       if (schemaFile.equals(nf.getSchemaFile()))
       {
-        values.add(new AttributeValue(nameFormsType, nf.getDefinition()));
+        values.add(AttributeValues.create(
+            nameFormsType, nf.getDefinition()));
       }
     }
 
@@ -3353,7 +3357,7 @@
     {
       if (schemaFile.equals(dcr.getSchemaFile()))
       {
-        values.add(new AttributeValue(ditContentRulesType,
+        values.add(AttributeValues.create(ditContentRulesType,
                                       dcr.getDefinition()));
       }
     }
@@ -3400,7 +3404,7 @@
     {
       if (schemaFile.equals(mru.getSchemaFile()))
       {
-        values.add(new AttributeValue(matchingRuleUsesType,
+        values.add(AttributeValues.create(matchingRuleUsesType,
                                       mru.getDefinition()));
       }
     }
@@ -3483,7 +3487,7 @@
                               addedTypes, depth+1);
     }
 
-    values.add(new AttributeValue(attributeTypesType,
+    values.add(AttributeValues.create(attributeTypesType,
                                   attributeType.getDefinition()));
     addedTypes.add(attributeType);
   }
@@ -3534,7 +3538,7 @@
                                  addedClasses, depth+1);
     }
 
-    values.add(new AttributeValue(objectClassesType,
+    values.add(AttributeValues.create(objectClassesType,
                                   objectClass.getDefinition()));
     addedClasses.add(objectClass);
   }
@@ -3585,7 +3589,7 @@
       }
     }
 
-    values.add(new AttributeValue(ditStructureRulesType,
+    values.add(AttributeValues.create(ditStructureRulesType,
                                   ditStructureRule.getDefinition()));
     addedDSRs.add(ditStructureRule);
   }
diff --git a/opends/src/server/org/opends/server/backends/TrustStoreBackend.java b/opends/src/server/org/opends/server/backends/TrustStoreBackend.java
index aba9109..abceec1 100644
--- a/opends/src/server/org/opends/server/backends/TrustStoreBackend.java
+++ b/opends/src/server/org/opends/server/backends/TrustStoreBackend.java
@@ -75,33 +75,7 @@
 import org.opends.server.core.SearchOperation;
 import org.opends.server.loggers.ErrorLogger;
 import org.opends.server.loggers.debug.DebugTracer;
-import org.opends.server.protocols.asn1.ASN1OctetString;
-import org.opends.server.types.Attribute;
-import org.opends.server.types.AttributeBuilder;
-import org.opends.server.types.AttributeType;
-import org.opends.server.types.AttributeValue;
-import org.opends.server.types.Attributes;
-import org.opends.server.types.BackupConfig;
-import org.opends.server.types.BackupDirectory;
-import org.opends.server.types.ByteString;
-import org.opends.server.types.ConditionResult;
-import org.opends.server.types.ConfigChangeResult;
-import org.opends.server.types.DN;
-import org.opends.server.types.DebugLogLevel;
-import org.opends.server.types.DirectoryException;
-import org.opends.server.types.Entry;
-import org.opends.server.types.FilePermission;
-import org.opends.server.types.IndexType;
-import org.opends.server.types.InitializationException;
-import org.opends.server.types.LDIFExportConfig;
-import org.opends.server.types.LDIFImportConfig;
-import org.opends.server.types.LDIFImportResult;
-import org.opends.server.types.ObjectClass;
-import org.opends.server.types.RDN;
-import org.opends.server.types.RestoreConfig;
-import org.opends.server.types.ResultCode;
-import org.opends.server.types.SearchFilter;
-import org.opends.server.types.SearchScope;
+import org.opends.server.types.*;
 import org.opends.server.util.CertificateManager;
 import org.opends.server.util.Validator;
 
@@ -581,7 +555,7 @@
                                    baseDN, null);
     }
 
-    String certAlias = v.getStringValue();
+    String certAlias = v.getValue().toString();
     ByteString certValue;
     try
     {
@@ -592,7 +566,7 @@
             String.valueOf(entryDN), certAlias);
         throw new DirectoryException(ResultCode.NO_SUCH_OBJECT, message);
       }
-      certValue = new ASN1OctetString(cert.getEncoded());
+      certValue = ByteString.wrap(cert.getEncoded());
     }
     catch (Exception e)
     {
@@ -630,7 +604,7 @@
         true);
     AttributeBuilder builder = new AttributeBuilder(t);
     builder.setOption("binary");
-    builder.add(new AttributeValue(t, certValue));
+    builder.add(AttributeValues.create(t, certValue));
     attrList = new ArrayList<Attribute>(1);
     attrList.add(builder.toAttribute());
     userAttrs.put(t, attrList);
@@ -1370,7 +1344,7 @@
                                String rdnStringValue)
   {
     AttributeValue attrValue =
-         new AttributeValue(rdnAttrType, rdnStringValue);
+        AttributeValues.create(rdnAttrType, rdnStringValue);
     return parentDN.concat(RDN.create(rdnAttrType, attrValue));
   }
 
@@ -1575,7 +1549,7 @@
       throw new DirectoryException(ResultCode.CONSTRAINT_VIOLATION, message,
                                    baseDN, null);
     }
-    String certAlias = v.getStringValue();
+    String certAlias = v.getValue().toString();
 
     try
     {
@@ -1642,7 +1616,7 @@
                DirectoryServer.getServerErrorResultCode(), message);
         }
 
-        byte[] certBytes = i.next().getValueBytes();
+        ByteString certBytes = i.next().getValue();
 
         if (i.hasNext())
         {
@@ -1665,7 +1639,7 @@
                  new FileOutputStream(tempFile.getPath(), false);
             try
             {
-              outputStream.write(certBytes);
+              certBytes.copyTo(outputStream);
             }
             finally
             {
@@ -1713,7 +1687,7 @@
       throw new DirectoryException(ResultCode.CONSTRAINT_VIOLATION, message,
                                    baseDN, null);
     }
-    String certAlias = v.getStringValue();
+    String certAlias = v.getValue().toString();
 
     try
     {
diff --git a/opends/src/server/org/opends/server/backends/jeb/ApproximateIndexer.java b/opends/src/server/org/opends/server/backends/jeb/ApproximateIndexer.java
index 4267aca..7fa1a0c 100644
--- a/opends/src/server/org/opends/server/backends/jeb/ApproximateIndexer.java
+++ b/opends/src/server/org/opends/server/backends/jeb/ApproximateIndexer.java
@@ -165,7 +165,7 @@
         try
         {
           byte[] keyBytes =
-               approximateRule.normalizeValue(value.getValue()).value();
+               approximateRule.normalizeValue(value.getValue()).toByteArray();
 
           keys.add(keyBytes);
         }
@@ -201,7 +201,7 @@
         try
         {
           byte[] keyBytes =
-              approximateRule.normalizeValue(value.getValue()).value();
+              approximateRule.normalizeValue(value.getValue()).toByteArray();
 
           Boolean cInsert = modifiedKeys.get(keyBytes);
           if(cInsert == null)
diff --git a/opends/src/server/org/opends/server/backends/jeb/AttributeIndex.java b/opends/src/server/org/opends/server/backends/jeb/AttributeIndex.java
index 75fe149..aa08a28 100644
--- a/opends/src/server/org/opends/server/backends/jeb/AttributeIndex.java
+++ b/opends/src/server/org/opends/server/backends/jeb/AttributeIndex.java
@@ -34,7 +34,6 @@
 import org.opends.server.api.SubstringMatchingRule;
 import org.opends.server.api.OrderingMatchingRule;
 import org.opends.server.api.ApproximateMatchingRule;
-import org.opends.server.protocols.asn1.ASN1OctetString;
 
 import static org.opends.server.loggers.debug.DebugLogger.*;
 import org.opends.server.loggers.debug.DebugTracer;
@@ -797,7 +796,7 @@
     {
       int len = Math.min(substrLength, remain);
       keyBytes = makeSubstringKey(value, i, len);
-      set.add(new ASN1OctetString(keyBytes));
+      set.add(ByteString.wrap(keyBytes));
     }
 
     return set;
@@ -947,7 +946,7 @@
     {
       // Make a key from the normalized assertion value.
       byte[] keyBytes =
-           equalityFilter.getAssertionValue().getNormalizedValue().value();
+          equalityFilter.getAssertionValue().getNormalizedValue().toByteArray();
       DatabaseEntry key = new DatabaseEntry(keyBytes);
 
       if(debugBuffer != null)
@@ -1026,7 +1025,7 @@
       OrderingMatchingRule orderingRule =
            filter.getAttributeType().getOrderingMatchingRule();
       byte[] lower = orderingRule.normalizeValue(
-           filter.getAssertionValue().getValue()).value();
+           filter.getAssertionValue().getValue()).toByteArray();
 
       // Set the upper bound to 0 to search all keys greater then the lower
       // bound.
@@ -1082,7 +1081,7 @@
       OrderingMatchingRule orderingRule =
            filter.getAttributeType().getOrderingMatchingRule();
       byte[] upper = orderingRule.normalizeValue(
-           filter.getAssertionValue().getValue()).value();
+           filter.getAssertionValue().getValue()).toByteArray();
 
       if(debugBuffer != null)
       {
@@ -1133,7 +1132,7 @@
         {
           ByteString normValue =
                matchRule.normalizeSubstring(filter.getSubInitialElement());
-          byte[] normBytes = normValue.value();
+          byte[] normBytes = normValue.toByteArray();
 
           EntryIDSet list = matchInitialSubstring(normBytes);
           results.retainAll(list);
@@ -1178,7 +1177,7 @@
       {
         // Normalize the substring according to the substring matching rule.
         ByteString normValue = matchRule.normalizeSubstring(element);
-        byte[] normBytes = normValue.value();
+        byte[] normBytes = normValue.toByteArray();
 
         // Get the candidate entry IDs from the index.
         EntryIDSet list = matchSubstring(normBytes);
@@ -1240,10 +1239,12 @@
            getAttributeType().getOrderingMatchingRule();
 
       // Set the lower bound for a range search.
-      byte[] lower = orderingRule.normalizeValue(lowerValue.getValue()).value();
+      byte[] lower =
+          orderingRule.normalizeValue(lowerValue.getValue()).toByteArray();
 
       // Set the upper bound for a range search.
-      byte[] upper = orderingRule.normalizeValue(upperValue.getValue()).value();
+      byte[] upper =
+          orderingRule.normalizeValue(upperValue.getValue()).toByteArray();
 
       // Read the range: lower <= keys <= upper.
       return orderingIndex.readRange(lower, upper, true, true);
@@ -1329,7 +1330,7 @@
       // Make a key from the normalized assertion value.
       byte[] keyBytes =
            approximateMatchingRule.normalizeValue(
-               approximateFilter.getAssertionValue().getValue()).value();
+               approximateFilter.getAssertionValue().getValue()).toByteArray();
       DatabaseEntry key = new DatabaseEntry(keyBytes);
 
       if(debugBuffer != null)
diff --git a/opends/src/server/org/opends/server/backends/jeb/DN2URI.java b/opends/src/server/org/opends/server/backends/jeb/DN2URI.java
index e2aed63..fbd5db1 100644
--- a/opends/src/server/org/opends/server/backends/jeb/DN2URI.java
+++ b/opends/src/server/org/opends/server/backends/jeb/DN2URI.java
@@ -33,20 +33,7 @@
 import org.opends.server.core.DirectoryServer;
 import org.opends.server.core.SearchOperation;
 import org.opends.server.loggers.debug.DebugTracer;
-import org.opends.server.protocols.asn1.ASN1OctetString;
-import org.opends.server.types.Attribute;
-import org.opends.server.types.AttributeType;
-import org.opends.server.types.AttributeValue;
-import org.opends.server.types.ConditionResult;
-import org.opends.server.types.DebugLogLevel;
-import org.opends.server.types.DirectoryException;
-import org.opends.server.types.DN;
-import org.opends.server.types.Entry;
-import org.opends.server.types.LDAPURL;
-import org.opends.server.types.Modification;
-import org.opends.server.types.ResultCode;
-import org.opends.server.types.SearchResultReference;
-import org.opends.server.types.SearchScope;
+import org.opends.server.types.*;
 import org.opends.server.util.StaticUtils;
 
 import java.io.UnsupportedEncodingException;
@@ -315,7 +302,7 @@
             {
               for (AttributeValue v : a)
               {
-                insert(txn, entryDN, v.getStringValue());
+                insert(txn, entryDN, v.getValue().toString());
               }
             }
             break;
@@ -329,7 +316,7 @@
             {
               for (AttributeValue v : a)
               {
-                delete(txn, entryDN, v.getStringValue());
+                delete(txn, entryDN, v.getValue().toString());
               }
             }
             break;
@@ -344,7 +331,7 @@
             {
               for (AttributeValue v : a)
               {
-                insert(txn, entryDN, v.getStringValue());
+                insert(txn, entryDN, v.getValue().toString());
               }
             }
             break;
@@ -679,7 +666,7 @@
           }
 
           // We have found a subordinate referral.
-          DN dn = DN.decode(new ASN1OctetString(key.getData()));
+          DN dn = DN.decode(ByteString.wrap(key.getData()));
 
           // Make sure the referral is within scope.
           if (searchOp.getScope() == SearchScope.SINGLE_LEVEL)
diff --git a/opends/src/server/org/opends/server/backends/jeb/EntryCachePreloader.java b/opends/src/server/org/opends/server/backends/jeb/EntryCachePreloader.java
index 9ef11f0..3cb5363 100644
--- a/opends/src/server/org/opends/server/backends/jeb/EntryCachePreloader.java
+++ b/opends/src/server/org/opends/server/backends/jeb/EntryCachePreloader.java
@@ -51,6 +51,7 @@
 import org.opends.server.loggers.debug.DebugTracer;
 
 import org.opends.server.types.Entry;
+import org.opends.server.types.ByteString;
 import static org.opends.server.util.StaticUtils.*;
 import static org.opends.server.loggers.debug.DebugLogger.*;
 import static org.opends.server.loggers.ErrorLogger.logError;
@@ -291,7 +292,7 @@
           long entryID =
             JebFormat.entryIDFromDatabase(preloadEntry.entryIDBytes);
           Entry entry =
-            JebFormat.entryFromDatabase(preloadEntry.entryBytes,
+            ID2Entry.entryFromDatabase(ByteString.wrap(preloadEntry.entryBytes),
             jeb.getRootContainer().getCompressedSchema());
           try {
             // Even if the entry does not end up in the cache its still
diff --git a/opends/src/server/org/opends/server/backends/jeb/EntryContainer.java b/opends/src/server/org/opends/server/backends/jeb/EntryContainer.java
index 4f0cb6e..30e8012 100644
--- a/opends/src/server/org/opends/server/backends/jeb/EntryContainer.java
+++ b/opends/src/server/org/opends/server/backends/jeb/EntryContainer.java
@@ -38,11 +38,11 @@
 import org.opends.server.core.ModifyOperation;
 import org.opends.server.core.ModifyDNOperation;
 import org.opends.server.core.SearchOperation;
-import org.opends.server.protocols.asn1.ASN1OctetString;
 import org.opends.server.protocols.ldap.LDAPResultCode;
 import org.opends.server.controls.PagedResultsControl;
 import org.opends.server.controls.ServerSideSortRequestControl;
 import org.opends.server.controls.ServerSideSortResponseControl;
+import org.opends.server.controls.SubtreeDeleteControl;
 import org.opends.server.controls.VLVRequestControl;
 import org.opends.server.types.*;
 import org.opends.server.util.StaticUtils;
@@ -59,7 +59,6 @@
 import static org.opends.server.loggers.debug.DebugLogger.*;
 import org.opends.server.loggers.debug.DebugTracer;
 import static org.opends.server.loggers.ErrorLogger.logError;
-import static org.opends.server.util.ServerConstants.*;
 import org.opends.server.admin.std.server.LocalDBBackendCfg;
 import org.opends.server.admin.std.server.LocalDBIndexCfg;
 import org.opends.server.admin.std.server.LocalDBVLVIndexCfg;
@@ -74,7 +73,7 @@
  * the guts of the backend API methods for LDAP operations.
  */
 public class EntryContainer
-    implements ConfigurationChangeListener<LocalDBBackendCfg>
+implements ConfigurationChangeListener<LocalDBBackendCfg>
 {
   /**
    * The tracer object for the debug logger.
@@ -130,17 +129,17 @@
   /**
    * The backend to which this entry entryContainer belongs.
    */
-  private Backend backend;
+  private final Backend backend;
 
   /**
    * The root container in which this entryContainer belongs.
    */
-  private RootContainer rootContainer;
+  private final RootContainer rootContainer;
 
   /**
    * The baseDN this entry container is responsible for.
    */
-  private DN baseDN;
+  private final DN baseDN;
 
   /**
    * The backend configuration.
@@ -150,7 +149,7 @@
   /**
    * The JE database environment.
    */
-  private Environment env;
+  private final Environment env;
 
   /**
    * The DN database maps a normalized DN string to an entry ID (8 bytes).
@@ -185,12 +184,12 @@
   /**
    * The set of attribute indexes.
    */
-  private HashMap<AttributeType, AttributeIndex> attrIndexMap;
+  private final HashMap<AttributeType, AttributeIndex> attrIndexMap;
 
   /**
    * The set of VLV indexes.
    */
-  private HashMap<String, VLVIndex> vlvIndexMap;
+  private final HashMap<String, VLVIndex> vlvIndexMap;
 
   private String databasePrefix;
   /**
@@ -198,15 +197,15 @@
    * indexes used within this entry container.
    */
   public class AttributeJEIndexCfgManager implements
-      ConfigurationAddListener<LocalDBIndexCfg>,
-      ConfigurationDeleteListener<LocalDBIndexCfg>
+  ConfigurationAddListener<LocalDBIndexCfg>,
+  ConfigurationDeleteListener<LocalDBIndexCfg>
   {
     /**
      * {@inheritDoc}
      */
     public boolean isConfigurationAddAcceptable(
-            LocalDBIndexCfg cfg,
-            List<Message> unacceptableReasons)
+        LocalDBIndexCfg cfg,
+        List<Message> unacceptableReasons)
     {
       // TODO: validate more before returning true?
       return true;
@@ -224,7 +223,7 @@
       try
       {
         AttributeIndex index =
-            new AttributeIndex(cfg, state, env, EntryContainer.this);
+          new AttributeIndex(cfg, state, env, EntryContainer.this);
         index.open();
         if(!index.isTrusted())
         {
@@ -238,13 +237,13 @@
       {
         messages.add(Message.raw(StaticUtils.stackTraceToSingleLineString(e)));
         ccr = new ConfigChangeResult(DirectoryServer.getServerErrorResultCode(),
-                                     adminActionRequired,
-                                     messages);
+            adminActionRequired,
+            messages);
         return ccr;
       }
 
       return new ConfigChangeResult(ResultCode.SUCCESS, adminActionRequired,
-                                    messages);
+          messages);
     }
 
     /**
@@ -277,8 +276,8 @@
       {
         messages.add(Message.raw(StaticUtils.stackTraceToSingleLineString(de)));
         ccr = new ConfigChangeResult(DirectoryServer.getServerErrorResultCode(),
-                                     adminActionRequired,
-                                     messages);
+            adminActionRequired,
+            messages);
         return ccr;
       }
       finally
@@ -287,7 +286,7 @@
       }
 
       return new ConfigChangeResult(ResultCode.SUCCESS, adminActionRequired,
-                                    messages);
+          messages);
     }
   }
 
@@ -296,8 +295,8 @@
    * used within this entry container.
    */
   public class VLVJEIndexCfgManager implements
-      ConfigurationAddListener<LocalDBVLVIndexCfg>,
-      ConfigurationDeleteListener<LocalDBVLVIndexCfg>
+  ConfigurationAddListener<LocalDBVLVIndexCfg>,
+  ConfigurationDeleteListener<LocalDBVLVIndexCfg>
   {
     /**
      * {@inheritDoc}
@@ -321,7 +320,7 @@
       String[] sortAttrs = cfg.getSortOrder().split(" ");
       SortKey[] sortKeys = new SortKey[sortAttrs.length];
       OrderingMatchingRule[] orderingRules =
-          new OrderingMatchingRule[sortAttrs.length];
+        new OrderingMatchingRule[sortAttrs.length];
       boolean[] ascending = new boolean[sortAttrs.length];
       for(int i = 0; i < sortAttrs.length; i++)
       {
@@ -344,14 +343,14 @@
         catch(Exception e)
         {
           Message msg =
-              ERR_JEB_CONFIG_VLV_INDEX_UNDEFINED_ATTR.get(
-                  String.valueOf(sortKeys[i]), cfg.getName());
+            ERR_JEB_CONFIG_VLV_INDEX_UNDEFINED_ATTR.get(
+                String.valueOf(sortKeys[i]), cfg.getName());
           unacceptableReasons.add(msg);
           return false;
         }
 
         AttributeType attrType =
-            DirectoryServer.getAttributeType(sortAttrs[i].toLowerCase());
+          DirectoryServer.getAttributeType(sortAttrs[i].toLowerCase());
         if(attrType == null)
         {
           Message msg = ERR_JEB_CONFIG_VLV_INDEX_UNDEFINED_ATTR.get(
@@ -391,21 +390,21 @@
       {
         messages.add(Message.raw(StaticUtils.stackTraceToSingleLineString(e)));
         ccr = new ConfigChangeResult(DirectoryServer.getServerErrorResultCode(),
-                                     adminActionRequired,
-                                     messages);
+            adminActionRequired,
+            messages);
         return ccr;
       }
 
       return new ConfigChangeResult(ResultCode.SUCCESS, adminActionRequired,
-                                    messages);
+          messages);
     }
 
     /**
      * {@inheritDoc}
      */
     public boolean isConfigurationDeleteAcceptable(
-            LocalDBVLVIndexCfg cfg,
-            List<Message> unacceptableReasons)
+        LocalDBVLVIndexCfg cfg,
+        List<Message> unacceptableReasons)
     {
       // TODO: validate more before returning true?
       return true;
@@ -424,7 +423,7 @@
       try
       {
         VLVIndex vlvIndex =
-            vlvIndexMap.get(cfg.getName().toLowerCase());
+          vlvIndexMap.get(cfg.getName().toLowerCase());
         vlvIndex.close();
         deleteDatabase(vlvIndex);
         vlvIndexMap.remove(cfg.getName());
@@ -433,8 +432,8 @@
       {
         messages.add(Message.raw(StaticUtils.stackTraceToSingleLineString(de)));
         ccr = new ConfigChangeResult(DirectoryServer.getServerErrorResultCode(),
-                                     adminActionRequired,
-                                     messages);
+            adminActionRequired,
+            messages);
         return ccr;
       }
       finally
@@ -443,7 +442,7 @@
       }
 
       return new ConfigChangeResult(ResultCode.SUCCESS, adminActionRequired,
-                                    messages);
+          messages);
     }
 
   }
@@ -471,9 +470,9 @@
    * @throws ConfigException if a configuration related error occurs.
    */
   public EntryContainer(DN baseDN, String databasePrefix, Backend backend,
-                        LocalDBBackendCfg config, Environment env,
-                        RootContainer rootContainer)
-      throws ConfigException
+      LocalDBBackendCfg config, Environment env,
+      RootContainer rootContainer)
+  throws ConfigException
   {
     this.backend = backend;
     this.baseDN = baseDN;
@@ -505,12 +504,12 @@
     config.addLocalDBChangeListener(this);
 
     attributeJEIndexCfgManager =
-        new AttributeJEIndexCfgManager();
+      new AttributeJEIndexCfgManager();
     config.addLocalDBIndexAddListener(attributeJEIndexCfgManager);
     config.addLocalDBIndexDeleteListener(attributeJEIndexCfgManager);
 
     vlvJEIndexCfgManager =
-        new VLVJEIndexCfgManager();
+      new VLVJEIndexCfgManager();
     config.addLocalDBVLVIndexAddListener(vlvJEIndexCfgManager);
     config.addLocalDBVLVIndexDeleteListener(vlvJEIndexCfgManager);
   }
@@ -522,17 +521,17 @@
    * @throws ConfigException if a configuration related error occurs.
    */
   public void open()
-      throws DatabaseException, ConfigException
+  throws DatabaseException, ConfigException
   {
     try
     {
       DataConfig entryDataConfig =
-          new DataConfig(config.isEntriesCompressed(),
-                         config.isCompactEncoding(),
-                         rootContainer.getCompressedSchema());
+        new DataConfig(config.isEntriesCompressed(),
+            config.isCompactEncoding(),
+            rootContainer.getCompressedSchema());
 
       id2entry = new ID2Entry(databasePrefix + "_" + ID2ENTRY_DATABASE_NAME,
-                              entryDataConfig, env, this);
+          entryDataConfig, env, this);
       id2entry.open();
 
       dn2id = new DN2ID(databasePrefix + "_" + DN2ID_DATABASE_NAME, env, this);
@@ -542,9 +541,9 @@
       state.open();
 
       id2children = new Index(databasePrefix + "_" + ID2CHILDREN_DATABASE_NAME,
-                              new ID2CIndexer(), state,
-                              config.getIndexEntryLimit(), 0, true,
-                              env,this);
+          new ID2CIndexer(), state,
+          config.getIndexEntryLimit(), 0, true,
+          env,this);
       id2children.open();
 
       if(!id2children.isTrusted())
@@ -554,9 +553,9 @@
       }
 
       id2subtree = new Index(databasePrefix + "_" + ID2SUBTREE_DATABASE_NAME,
-                             new ID2SIndexer(), state,
-                             config.getIndexEntryLimit(), 0, true,
-                             env, this);
+          new ID2SIndexer(), state,
+          config.getIndexEntryLimit(), 0, true,
+          env, this);
       id2subtree.open();
 
       if(!id2subtree.isTrusted())
@@ -566,7 +565,7 @@
       }
 
       dn2uri = new DN2URI(databasePrefix + "_" + REFERRAL_DATABASE_NAME,
-                          env, this);
+          env, this);
       dn2uri.open();
 
       for (String idx : config.listLocalDBIndexes())
@@ -574,7 +573,7 @@
         LocalDBIndexCfg indexCfg = config.getLocalDBIndex(idx);
 
         AttributeIndex index =
-            new AttributeIndex(indexCfg, state, env, this);
+          new AttributeIndex(indexCfg, state, env, this);
         index.open();
         if(!index.isTrusted())
         {
@@ -617,7 +616,7 @@
    * @throws DatabaseException If an error occurs in the JE database.
    */
   public void close()
-      throws DatabaseException
+  throws DatabaseException
   {
     // Close core indexes.
     dn2id.close();
@@ -819,13 +818,13 @@
    * @throws DatabaseException If an error occurs in the JE database.
    */
   public long getNumSubordinates(DN entryDN, boolean subtree)
-      throws DatabaseException
+  throws DatabaseException
   {
     EntryID entryID = dn2id.get(null, entryDN, LockMode.DEFAULT);
     if (entryID != null)
     {
       DatabaseEntry key =
-          new DatabaseEntry(JebFormat.entryIDToDatabase(entryID.longValue()));
+        new DatabaseEntry(JebFormat.entryIDToDatabase(entryID.longValue()));
       EntryIDSet entryIDSet;
       if(!subtree)
       {
@@ -857,97 +856,22 @@
    * @throws CanceledOperationException if this operation should be cancelled.
    */
   public void search(SearchOperation searchOperation)
-       throws DirectoryException, DatabaseException, CanceledOperationException
+  throws DirectoryException, DatabaseException, CanceledOperationException
   {
     DN baseDN = searchOperation.getBaseDN();
     SearchScope searchScope = searchOperation.getScope();
 
-    List<Control> controls = searchOperation.getRequestControls();
-    PagedResultsControl pageRequest = null;
-    ServerSideSortRequestControl sortRequest = null;
-    VLVRequestControl vlvRequest = null;
-    if (controls != null)
+    PagedResultsControl pageRequest = searchOperation
+    .getRequestControl(PagedResultsControl.DECODER);
+    ServerSideSortRequestControl sortRequest = searchOperation
+    .getRequestControl(ServerSideSortRequestControl.DECODER);
+    VLVRequestControl vlvRequest = searchOperation
+    .getRequestControl(VLVRequestControl.DECODER);
+
+    if (vlvRequest != null && pageRequest != null)
     {
-      for (Control control : controls)
-      {
-        if (control.getOID().equals(OID_PAGED_RESULTS_CONTROL))
-        {
-          // Ignore all but the first paged results control.
-          if (pageRequest == null)
-          {
-            try
-            {
-              pageRequest = new PagedResultsControl(control.isCritical(),
-                                                    control.getValue());
-            }
-            catch (LDAPException e)
-            {
-              if (debugEnabled())
-              {
-                TRACER.debugCaught(DebugLogLevel.ERROR, e);
-              }
-              throw new DirectoryException(ResultCode.PROTOCOL_ERROR,
-                                           e.getMessageObject(), e);
-            }
-
-            if (vlvRequest != null)
-            {
-              Message message =
-                  ERR_JEB_SEARCH_CANNOT_MIX_PAGEDRESULTS_AND_VLV.get();
-              throw new DirectoryException(ResultCode.CONSTRAINT_VIOLATION,
-                                           message);
-            }
-          }
-        }
-        else if (control.getOID().equals(OID_SERVER_SIDE_SORT_REQUEST_CONTROL))
-        {
-          // Ignore all but the first sort request control.
-          if (sortRequest == null)
-          {
-            try
-            {
-              sortRequest = ServerSideSortRequestControl.decodeControl(control);
-            }
-            catch (LDAPException e)
-            {
-              if (debugEnabled())
-              {
-                TRACER.debugCaught(DebugLogLevel.ERROR, e);
-              }
-              throw new DirectoryException(ResultCode.PROTOCOL_ERROR,
-                                           e.getMessageObject(), e);
-            }
-          }
-        }
-        else if (control.getOID().equals(OID_VLV_REQUEST_CONTROL))
-        {
-          // Ignore all but the first VLV request control.
-          if (vlvRequest == null)
-          {
-            try
-            {
-              vlvRequest = VLVRequestControl.decodeControl(control);
-            }
-            catch (LDAPException e)
-            {
-              if (debugEnabled())
-              {
-                TRACER.debugCaught(DebugLogLevel.ERROR, e);
-              }
-              throw new DirectoryException(ResultCode.PROTOCOL_ERROR,
-                                           e.getMessageObject(), e);
-            }
-
-            if (pageRequest != null)
-            {
-              Message message =
-                  ERR_JEB_SEARCH_CANNOT_MIX_PAGEDRESULTS_AND_VLV.get();
-              throw new DirectoryException(ResultCode.CONSTRAINT_VIOLATION,
-                                           message);
-            }
-          }
-        }
-      }
+      Message message = ERR_JEB_SEARCH_CANNOT_MIX_PAGEDRESULTS_AND_VLV.get();
+      throw new DirectoryException(ResultCode.CONSTRAINT_VIOLATION, message);
     }
 
     // Handle client abandon of paged results.
@@ -956,8 +880,7 @@
       if (pageRequest.getSize() == 0)
       {
         PagedResultsControl control;
-        control = new PagedResultsControl(pageRequest.isCritical(), 0,
-                                          new ASN1OctetString());
+        control = new PagedResultsControl(pageRequest.isCritical(), 0, null);
         searchOperation.getResponseControls().add(control);
         return;
       }
@@ -1006,8 +929,7 @@
       {
         // Indicate no more pages.
         PagedResultsControl control;
-        control = new PagedResultsControl(pageRequest.isCritical(), 0,
-                                          new ASN1OctetString());
+        control = new PagedResultsControl(pageRequest.isCritical(), 0, null);
         searchOperation.getResponseControls().add(control);
       }
 
@@ -1031,13 +953,13 @@
         try
         {
           entryIDList =
-              vlvIndex.evaluate(null, searchOperation, sortRequest, vlvRequest,
-                                debugBuffer);
+            vlvIndex.evaluate(null, searchOperation, sortRequest, vlvRequest,
+                debugBuffer);
           if(entryIDList != null)
           {
             searchOperation.addResponseControl(
                 new ServerSideSortResponseControl(LDAPResultCode.SUCCESS,
-                                                  null));
+                    null));
             candidatesAreInScope = true;
             break;
           }
@@ -1060,7 +982,7 @@
     {
       // Create an index filter to get the search result candidate entries.
       IndexFilter indexFilter =
-          new IndexFilter(this, searchOperation, debugBuffer);
+        new IndexFilter(this, searchOperation, debugBuffer);
 
       // Evaluate the filter against the attribute indexes.
       entryIDList = indexFilter.evaluate();
@@ -1074,7 +996,7 @@
         if (baseID == null)
         {
           Message message =
-                  ERR_JEB_SEARCH_NO_SUCH_OBJECT.get(baseDN.toString());
+            ERR_JEB_SEARCH_NO_SUCH_OBJECT.get(baseDN.toString());
           DN matchedDN = getMatchedDN(baseDN);
           throw new DirectoryException(ResultCode.NO_SUCH_OBJECT,
               message, matchedDN, null);
@@ -1114,9 +1036,9 @@
         try
         {
           entryIDList = EntryIDSetSorter.sort(this, entryIDList,
-                                              searchOperation,
-                                              sortRequest.getSortOrder(),
-                                              vlvRequest);
+              searchOperation,
+              sortRequest.getSortOrder(),
+              vlvRequest);
           searchOperation.addResponseControl(
               new ServerSideSortResponseControl(LDAPResultCode.SUCCESS, null));
         }
@@ -1155,7 +1077,7 @@
     if (entryIDList.isDefined())
     {
       searchIndexed(entryIDList, candidatesAreInScope, searchOperation,
-                    pageRequest);
+          pageRequest);
     }
     else
     {
@@ -1170,14 +1092,14 @@
       }
 
       ClientConnection clientConnection =
-          searchOperation.getClientConnection();
+        searchOperation.getClientConnection();
       if(! clientConnection.hasPrivilege(Privilege.UNINDEXED_SEARCH,
-                                         searchOperation))
+          searchOperation))
       {
         Message message =
-            ERR_JEB_SEARCH_UNINDEXED_INSUFFICIENT_PRIVILEGES.get();
+          ERR_JEB_SEARCH_UNINDEXED_INSUFFICIENT_PRIVILEGES.get();
         throw new DirectoryException(ResultCode.INSUFFICIENT_ACCESS_RIGHTS,
-                                     message);
+            message);
       }
 
       if (sortRequest != null)
@@ -1185,14 +1107,14 @@
         // FIXME -- Add support for sorting unindexed searches using indexes
         //          like DSEE currently does.
         searchOperation.addResponseControl(
-             new ServerSideSortResponseControl(
-                      LDAPResultCode.UNWILLING_TO_PERFORM, null));
+            new ServerSideSortResponseControl(
+                LDAPResultCode.UNWILLING_TO_PERFORM, null));
 
         if (sortRequest.isCritical())
         {
           Message message = ERR_JEB_SEARCH_CANNOT_SORT_UNINDEXED.get();
           throw new DirectoryException(
-                         ResultCode.UNAVAILABLE_CRITICAL_EXTENSION, message);
+              ResultCode.UNAVAILABLE_CRITICAL_EXTENSION, message);
         }
       }
 
@@ -1219,8 +1141,8 @@
    * processed.
    */
   private void searchNotIndexed(SearchOperation searchOperation,
-                                PagedResultsControl pageRequest)
-       throws DirectoryException, CanceledOperationException
+      PagedResultsControl pageRequest)
+  throws DirectoryException, CanceledOperationException
   {
     EntryCache<?> entryCache = DirectoryServer.getEntryCache();
     DN baseDN = searchOperation.getBaseDN();
@@ -1230,7 +1152,7 @@
     // The base entry must already have been processed if this is
     // a request for the next page in paged results.  So we skip
     // the base entry processing if the cookie is set.
-    if (pageRequest == null || pageRequest.getCookie().value().length == 0)
+    if (pageRequest == null || pageRequest.getCookie().length() == 0)
     {
       // Fetch the base entry.
       Entry baseEntry = null;
@@ -1284,7 +1206,7 @@
             // Indicate no more pages.
             PagedResultsControl control;
             control = new PagedResultsControl(pageRequest.isCritical(), 0,
-                                              new ASN1OctetString());
+                null);
             searchOperation.getResponseControls().add(control);
           }
         }
@@ -1312,7 +1234,7 @@
 
     // Set the starting value.
     byte[] begin;
-    if (pageRequest != null && pageRequest.getCookie().value().length != 0)
+    if (pageRequest != null && pageRequest.getCookie().length() != 0)
     {
       // The cookie contains the DN of the next entry to be returned.
       try
@@ -1326,10 +1248,10 @@
         {
           TRACER.debugCaught(DebugLogLevel.ERROR, e);
         }
-        String str = StaticUtils.bytesToHex(pageRequest.getCookie().value());
+        String str = pageRequest.getCookie().toHex();
         Message msg = ERR_JEB_INVALID_PAGED_RESULTS_COOKIE.get(str);
         throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM,
-                                     msg, e);
+            msg, e);
       }
     }
     else
@@ -1344,7 +1266,7 @@
 
     int lookthroughCount = 0;
     int lookthroughLimit =
-        searchOperation.getClientConnection().getLookthroughLimit();
+      searchOperation.getClientConnection().getLookthroughLimit();
 
     try
     {
@@ -1364,7 +1286,7 @@
             //Lookthrough limit exceeded
             searchOperation.setResultCode(ResultCode.ADMIN_LIMIT_EXCEEDED);
             searchOperation.appendErrorMessage(
-              NOTE_JEB_LOOKTHROUGH_LIMIT_EXCEEDED.get(lookthroughLimit));
+                NOTE_JEB_LOOKTHROUGH_LIMIT_EXCEEDED.get(lookthroughLimit));
             return;
           }
           int cmp = dn2id.getComparator().compare(key.getData(), end);
@@ -1377,14 +1299,14 @@
           // We have found a subordinate entry.
 
           EntryID entryID = new EntryID(data);
-          DN dn = DN.decode(new ASN1OctetString(key.getData()));
+          DN dn = DN.decode(ByteString.wrap(key.getData()));
 
           boolean isInScope = true;
           if (searchScope == SearchScope.SINGLE_LEVEL)
           {
             // Check if this entry is an immediate child.
             if ((dn.getNumComponents() !=
-                 baseDN.getNumComponents() + 1))
+              baseDN.getNumComponents() + 1))
             {
               isInScope = false;
             }
@@ -1398,7 +1320,7 @@
             // Try the entry cache first. Note no need to take a lock.
             lockList.clear();
             cacheEntry = entryCache.getEntry(backend, entryID.longValue(),
-                                             LockType.NONE, lockList);
+                LockType.NONE, lockList);
 
             if (cacheEntry == null)
             {
@@ -1420,15 +1342,15 @@
                 if (searchOperation.getFilter().matchesEntry(entry))
                 {
                   if (pageRequest != null &&
-                       searchOperation.getEntriesSent() ==
-                       pageRequest.getSize())
+                      searchOperation.getEntriesSent() ==
+                        pageRequest.getSize())
                   {
                     // The current page is full.
                     // Set the cookie to remember where we were.
-                    ASN1OctetString cookie = new ASN1OctetString(key.getData());
+                    ByteString cookie = ByteString.wrap(key.getData());
                     PagedResultsControl control;
                     control = new PagedResultsControl(pageRequest.isCritical(),
-                                                      0, cookie);
+                        0, cookie);
                     searchOperation.getResponseControls().add(control);
                     return;
                   }
@@ -1468,8 +1390,7 @@
     {
       // Indicate no more pages.
       PagedResultsControl control;
-      control = new PagedResultsControl(pageRequest.isCritical(), 0,
-                                        new ASN1OctetString());
+      control = new PagedResultsControl(pageRequest.isCritical(), 0, null);
       searchOperation.getResponseControls().add(control);
     }
 
@@ -1498,10 +1419,10 @@
    * processed.
    */
   private void searchIndexed(EntryIDSet entryIDList,
-                             boolean candidatesAreInScope,
-                             SearchOperation searchOperation,
-                             PagedResultsControl pageRequest)
-       throws DirectoryException, CanceledOperationException
+      boolean candidatesAreInScope,
+      SearchOperation searchOperation,
+      PagedResultsControl pageRequest)
+  throws DirectoryException, CanceledOperationException
   {
     EntryCache<?> entryCache = DirectoryServer.getEntryCache();
     SearchScope searchScope = searchOperation.getScope();
@@ -1511,12 +1432,12 @@
 
     // Set the starting value.
     EntryID begin = null;
-    if (pageRequest != null && pageRequest.getCookie().value().length != 0)
+    if (pageRequest != null && pageRequest.getCookie().length() != 0)
     {
       // The cookie contains the ID of the next entry to be returned.
       try
       {
-        begin = new EntryID(new DatabaseEntry(pageRequest.getCookie().value()));
+        begin = new EntryID(pageRequest.getCookie().toLong());
       }
       catch (Exception e)
       {
@@ -1524,10 +1445,10 @@
         {
           TRACER.debugCaught(DebugLogLevel.ERROR, e);
         }
-        String str = StaticUtils.bytesToHex(pageRequest.getCookie().value());
+        String str = pageRequest.getCookie().toHex();
         Message msg = ERR_JEB_INVALID_PAGED_RESULTS_COOKIE.get(str);
         throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM,
-                                     msg, e);
+            msg, e);
       }
     }
     else
@@ -1541,7 +1462,7 @@
 
     // Make sure the candidate list is smaller than the lookthrough limit
     int lookthroughLimit =
-        searchOperation.getClientConnection().getLookthroughLimit();
+      searchOperation.getClientConnection().getLookthroughLimit();
     if(lookthroughLimit > 0 && entryIDList.size() > lookthroughLimit)
     {
       //Lookthrough limit exceeded
@@ -1565,7 +1486,7 @@
         // Try the entry cache first. Note no need to take a lock.
         lockList.clear();
         cacheEntry = entryCache.getEntry(backend, id.longValue(),
-                                         LockType.NONE, lockList);
+            LockType.NONE, lockList);
 
         // Release any entry lock whatever happens during this block.
         // (This is actually redundant since we did not take a lock).
@@ -1606,8 +1527,8 @@
             {
               // Check if this entry is an immediate child.
               if ((entryDN.getNumComponents() ==
-                   baseDN.getNumComponents() + 1) &&
-                   entryDN.isDescendantOf(baseDN))
+                baseDN.getNumComponents() + 1) &&
+                entryDN.isDescendantOf(baseDN))
               {
                 isInScope = true;
               }
@@ -1622,8 +1543,8 @@
             else if (searchScope == SearchScope.SUBORDINATE_SUBTREE)
             {
               if ((entryDN.getNumComponents() >
-                   baseDN.getNumComponents()) &&
-                   entryDN.isDescendantOf(baseDN))
+              baseDN.getNumComponents()) &&
+              entryDN.isDescendantOf(baseDN))
               {
                 isInScope = true;
               }
@@ -1646,16 +1567,16 @@
                 if (searchOperation.getFilter().matchesEntry(entry))
                 {
                   if (pageRequest != null &&
-                       searchOperation.getEntriesSent() ==
-                       pageRequest.getSize())
+                      searchOperation.getEntriesSent() ==
+                        pageRequest.getSize())
                   {
                     // The current page is full.
                     // Set the cookie to remember where we were.
                     byte[] cookieBytes = id.getDatabaseEntry().getData();
-                    ASN1OctetString cookie = new ASN1OctetString(cookieBytes);
+                    ByteString cookie = ByteString.wrap(cookieBytes);
                     PagedResultsControl control;
                     control = new PagedResultsControl(pageRequest.isCritical(),
-                                                      0, cookie);
+                        0, cookie);
                     searchOperation.getResponseControls().add(control);
                     return;
                   }
@@ -1689,7 +1610,7 @@
     // exists. However, if we have returned at least one entry or subordinate
     // reference it implies the base does exist, so we can omit the check.
     if (searchOperation.getEntriesSent() == 0 &&
-         searchOperation.getReferencesSent() == 0)
+        searchOperation.getReferencesSent() == 0)
     {
       // Fetch the base entry if it exists.
       Entry baseEntry = null;
@@ -1727,8 +1648,7 @@
     {
       // Indicate no more pages.
       PagedResultsControl control;
-      control = new PagedResultsControl(pageRequest.isCritical(), 0,
-                                        new ASN1OctetString());
+      control = new PagedResultsControl(pageRequest.isCritical(), 0, null);
       searchOperation.getResponseControls().add(control);
     }
 
@@ -1750,7 +1670,7 @@
    * @throws CanceledOperationException if this operation should be cancelled.
    */
   public void addEntry(Entry entry, AddOperation addOperation)
-      throws DatabaseException, DirectoryException, CanceledOperationException
+  throws DatabaseException, DirectoryException, CanceledOperationException
   {
     Transaction txn = beginTransaction();
     DN parentDN = getParentWithinBase(entry.getDN());
@@ -1761,7 +1681,7 @@
       if (dn2id.get(txn, entry.getDN(), LockMode.DEFAULT) != null)
       {
         Message message =
-            ERR_JEB_ADD_ENTRY_ALREADY_EXISTS.get(entry.getDN().toString());
+          ERR_JEB_ADD_ENTRY_ALREADY_EXISTS.get(entry.getDN().toString());
         throw new DirectoryException(ResultCode.ENTRY_ALREADY_EXISTS,
             message);
       }
@@ -1792,7 +1712,7 @@
       {
         // Do not ever expect to come through here.
         Message message =
-            ERR_JEB_ADD_ENTRY_ALREADY_EXISTS.get(entry.getDN().toString());
+          ERR_JEB_ADD_ENTRY_ALREADY_EXISTS.get(entry.getDN().toString());
         throw new DirectoryException(ResultCode.ENTRY_ALREADY_EXISTS,
             message);
       }
@@ -1802,7 +1722,7 @@
       {
         // Do not ever expect to come through here.
         Message message =
-            ERR_JEB_ADD_ENTRY_ALREADY_EXISTS.get(entry.getDN().toString());
+          ERR_JEB_ADD_ENTRY_ALREADY_EXISTS.get(entry.getDN().toString());
         throw new DirectoryException(ResultCode.ENTRY_ALREADY_EXISTS,
             message);
       }
@@ -1812,7 +1732,7 @@
       {
         // Do not ever expect to come through here.
         Message message =
-            ERR_JEB_ADD_ENTRY_ALREADY_EXISTS.get(entry.getDN().toString());
+          ERR_JEB_ADD_ENTRY_ALREADY_EXISTS.get(entry.getDN().toString());
         throw new DirectoryException(ResultCode.ENTRY_ALREADY_EXISTS,
             message);
       }
@@ -1834,14 +1754,14 @@
 
         // Iterate up through the superior entries, starting above the parent.
         for (DN dn = getParentWithinBase(parentDN); dn != null;
-             dn = getParentWithinBase(dn))
+        dn = getParentWithinBase(dn))
         {
           // Read the ID from dn2id.
           EntryID nodeID = dn2id.get(txn, dn, LockMode.DEFAULT);
           if (nodeID == null)
           {
             Message msg =
-                ERR_JEB_MISSING_DN2ID_RECORD.get(dn.toNormalizedString());
+              ERR_JEB_MISSING_DN2ID_RECORD.get(dn.toNormalizedString());
             throw new JebException(msg);
           }
 
@@ -1913,7 +1833,7 @@
    * @throws CanceledOperationException if this operation should be cancelled.
    */
   public void deleteEntry(DN entryDN, DeleteOperation deleteOperation)
-      throws DirectoryException, DatabaseException, CanceledOperationException
+  throws DirectoryException, DatabaseException, CanceledOperationException
   {
     Transaction txn = beginTransaction();
     IndexBuffer indexBuffer = null;
@@ -1926,37 +1846,29 @@
       // Determine whether this is a subtree delete.
       boolean isSubtreeDelete = false;
 
-      if(deleteOperation != null)
+      if (deleteOperation != null
+          && deleteOperation
+              .getRequestControl(SubtreeDeleteControl.DECODER) != null)
       {
-        List<Control> controls = deleteOperation.getRequestControls();
-        if (controls != null)
-        {
-          for (Control control : controls)
-          {
-            if (control.getOID().equals(OID_SUBTREE_DELETE_CONTROL))
-            {
-              isSubtreeDelete = true;
-            }
-          }
-        }
+        isSubtreeDelete = true;
       }
 
       /*
-      * We will iterate backwards through a range of the dn2id keys to
-      * find subordinates of the target entry from the bottom of the tree
-      * upwards. For example, any subordinates of "dc=example,dc=com" appear
-      * in dn2id with a key ending in ",dc=example,dc=com". The entry
-      * "cn=joe,ou=people,dc=example,dc=com" will appear after the entry
-      * "ou=people,dc=example,dc=com".
-      */
+       * We will iterate backwards through a range of the dn2id keys to
+       * find subordinates of the target entry from the bottom of the tree
+       * upwards. For example, any subordinates of "dc=example,dc=com" appear
+       * in dn2id with a key ending in ",dc=example,dc=com". The entry
+       * "cn=joe,ou=people,dc=example,dc=com" will appear after the entry
+       * "ou=people,dc=example,dc=com".
+       */
       byte[] suffix = StaticUtils.getBytes("," + entryDN.toNormalizedString());
 
       /*
-      * Set the starting value to a value of equal length but slightly
-      * greater than the target DN. Since keys are compared in
-      * reverse order we must set the first byte (the comma).
-      * No possibility of overflow here.
-      */
+       * Set the starting value to a value of equal length but slightly
+       * greater than the target DN. Since keys are compared in
+       * reverse order we must set the first byte (the comma).
+       * No possibility of overflow here.
+       */
       byte[] begin = suffix.clone();
       begin[0] = (byte) (begin[0] + 1);
       int subordinateEntriesDeleted = 0;
@@ -2003,7 +1915,7 @@
             // the target entry is not a leaf.
 
             Message message =
-                ERR_JEB_DELETE_NOT_ALLOWED_ON_NONLEAF.get(entryDN.toString());
+              ERR_JEB_DELETE_NOT_ALLOWED_ON_NONLEAF.get(entryDN.toString());
             throw new DirectoryException(ResultCode.NOT_ALLOWED_ON_NONLEAF,
                 message);
           }
@@ -2016,11 +1928,11 @@
           }
 
           /*
-          * Delete this entry which by now must be a leaf because
-          * we have been deleting from the bottom of the tree upwards.
-          */
+           * Delete this entry which by now must be a leaf because
+           * we have been deleting from the bottom of the tree upwards.
+           */
           EntryID entryID = new EntryID(data);
-          DN subordinateDN = DN.decode(new ASN1OctetString(key.getData()));
+          DN subordinateDN = DN.decode(ByteString.wrap(key.getData()));
           deleteEntry(txn, indexBuffer, true, entryDN, subordinateDN, entryID);
           subordinateEntriesDeleted++;
 
@@ -2098,12 +2010,12 @@
   }
 
   private void deleteEntry(Transaction txn,
-                           IndexBuffer indexBuffer,
-                           boolean manageDsaIT,
-                           DN targetDN,
-                           DN leafDN,
-                           EntryID leafID)
-      throws DatabaseException, DirectoryException, JebException
+      IndexBuffer indexBuffer,
+      boolean manageDsaIT,
+      DN targetDN,
+      DN leafDN,
+      EntryID leafID)
+  throws DatabaseException, DirectoryException, JebException
   {
     if(leafID == null || leafDN == null)
     {
@@ -2113,7 +2025,7 @@
       if (leafID == null)
       {
         Message message =
-            ERR_JEB_DELETE_NO_SUCH_OBJECT.get(leafDN.toString());
+          ERR_JEB_DELETE_NO_SUCH_OBJECT.get(leafDN.toString());
         DN matchedDN = getMatchedDN(baseDN);
         throw new DirectoryException(ResultCode.NO_SUCH_OBJECT,
             message, matchedDN, null);
@@ -2169,7 +2081,7 @@
     if(indexBuffer != null)
     {
       byte[] leafIDKeyBytes =
-          JebFormat.entryIDToDatabase(leafID.longValue());
+        JebFormat.entryIDToDatabase(leafID.longValue());
       id2children.delete(indexBuffer, leafIDKeyBytes);
       id2subtree.delete(indexBuffer, leafIDKeyBytes);
     }
@@ -2183,21 +2095,21 @@
     // Iterate up through the superior entries from the target entry.
     boolean isParent = true;
     for (DN parentDN = getParentWithinBase(targetDN); parentDN != null;
-         parentDN = getParentWithinBase(parentDN))
+    parentDN = getParentWithinBase(parentDN))
     {
       // Read the ID from dn2id.
       EntryID parentID = dn2id.get(txn, parentDN, LockMode.DEFAULT);
       if (parentID == null)
       {
         Message msg =
-            ERR_JEB_MISSING_DN2ID_RECORD.get(parentDN.toNormalizedString());
+          ERR_JEB_MISSING_DN2ID_RECORD.get(parentDN.toNormalizedString());
         throw new JebException(msg);
       }
 
       if(indexBuffer != null)
       {
         byte[] parentIDBytes =
-            JebFormat.entryIDToDatabase(parentID.longValue());
+          JebFormat.entryIDToDatabase(parentID.longValue());
         // Remove from id2children.
         if (isParent)
         {
@@ -2239,7 +2151,7 @@
    *                              determination.
    */
   public boolean entryExists(DN entryDN)
-      throws DirectoryException
+  throws DirectoryException
   {
     EntryCache<?> entryCache = DirectoryServer.getEntryCache();
 
@@ -2283,7 +2195,7 @@
    * @throws DatabaseException An error occurred during a database operation.
    */
   public Entry getEntry(DN entryDN)
-      throws DatabaseException, DirectoryException
+  throws DatabaseException, DirectoryException
   {
     EntryCache<?> entryCache = DirectoryServer.getEntryCache();
     Entry entry = null;
@@ -2316,7 +2228,7 @@
         // The entryID does not exist.
         Message msg = ERR_JEB_MISSING_ID2ENTRY_RECORD.get(entryID.toString());
         throw new DirectoryException(DirectoryServer.getServerErrorResultCode(),
-          msg);
+            msg);
       }
 
       // Put the entry in the cache making sure not to overwrite
@@ -2347,7 +2259,7 @@
   public void replaceEntry(Entry oldEntry, Entry newEntry,
       ModifyOperation modifyOperation) throws DatabaseException,
       DirectoryException, CanceledOperationException
-  {
+      {
     Transaction txn = beginTransaction();
 
     try
@@ -2358,7 +2270,7 @@
       {
         // The entry does not exist.
         Message message =
-            ERR_JEB_MODIFY_NO_SUCH_OBJECT.get(newEntry.getDN().toString());
+          ERR_JEB_MODIFY_NO_SUCH_OBJECT.get(newEntry.getDN().toString());
         DN matchedDN = getMatchedDN(baseDN);
         throw new DirectoryException(ResultCode.NO_SUCH_OBJECT,
             message, matchedDN, null);
@@ -2443,7 +2355,7 @@
       throw new DirectoryException(DirectoryServer.getServerErrorResultCode(),
           message, e);
     }
-  }
+      }
 
   /**
    * Moves and/or renames the provided entry in this backend, altering any
@@ -2467,8 +2379,8 @@
    * @throws DatabaseException If an error occurs in the JE database.
    */
   public void renameEntry(DN currentDN, Entry entry,
-                          ModifyDNOperation modifyDNOperation)
-      throws DatabaseException, DirectoryException, CanceledOperationException
+      ModifyDNOperation modifyDNOperation)
+  throws DatabaseException, DirectoryException, CanceledOperationException
   {
     Transaction txn = beginTransaction();
     DN oldSuperiorDN = getParentWithinBase(currentDN);
@@ -2498,7 +2410,7 @@
         Message message = ERR_JEB_MODIFYDN_ALREADY_EXISTS.get(
             entry.getDN().toString());
         throw new DirectoryException(ResultCode.ENTRY_ALREADY_EXISTS,
-                                     message);
+            message);
       }
 
       EntryID oldApexID = dn2id.get(txn, currentDN, LockMode.DEFAULT);
@@ -2508,7 +2420,7 @@
         dn2uri.targetEntryReferrals(currentDN, null);
 
         Message message =
-                ERR_JEB_MODIFYDN_NO_SUCH_OBJECT.get(currentDN.toString());
+          ERR_JEB_MODIFYDN_NO_SUCH_OBJECT.get(currentDN.toString());
         DN matchedDN = getMatchedDN(baseDN);
         throw new DirectoryException(ResultCode.NO_SUCH_OBJECT,
             message, matchedDN, null);
@@ -2519,7 +2431,7 @@
       {
         Message msg = ERR_JEB_MISSING_ID2ENTRY_RECORD.get(oldApexID.toString());
         throw new DirectoryException(
-              DirectoryServer.getServerErrorResultCode(), msg);
+            DirectoryServer.getServerErrorResultCode(), msg);
       }
 
       if (!isManageDsaITOperation(modifyDNOperation))
@@ -2539,8 +2451,8 @@
         if (newSuperiorID == null)
         {
           Message msg =
-                  ERR_JEB_NEW_SUPERIOR_NO_SUCH_OBJECT.get(
-                          newSuperiorDN.toString());
+            ERR_JEB_NEW_SUPERIOR_NO_SUCH_OBJECT.get(
+                newSuperiorDN.toString());
           DN matchedDN = getMatchedDN(baseDN);
           throw new DirectoryException(ResultCode.NO_SUCH_OBJECT,
               msg, matchedDN, null);
@@ -2626,8 +2538,8 @@
 
           // Construct the new DN of the entry.
           DN newDN = modDN(oldEntry.getDN(),
-                           currentDN.getNumComponents(),
-                           entry.getDN());
+              currentDN.getNumComponents(),
+              entry.getDN());
 
           // Assign a new entry ID if we are renumbering.
           EntryID newID = oldID;
@@ -2709,12 +2621,12 @@
   }
 
   private void renameApexEntry(Transaction txn, IndexBuffer buffer,
-                               DN oldSuperiorDN, DN newSuperiorDN,
-                               EntryID oldID, EntryID newID,
-                               Entry oldEntry, Entry newEntry,
-                               boolean isApexEntryMoved,
-                               ModifyDNOperation modifyDNOperation)
-      throws DirectoryException, DatabaseException
+      DN oldSuperiorDN, DN newSuperiorDN,
+      EntryID oldID, EntryID newID,
+      Entry oldEntry, Entry newEntry,
+      boolean isApexEntryMoved,
+      ModifyDNOperation modifyDNOperation)
+  throws DirectoryException, DatabaseException
   {
     DN oldDN = oldEntry.getDN();
     DN newDN = newEntry.getDN();
@@ -2752,7 +2664,7 @@
       {
         parentID = dn2id.get(txn, dn, LockMode.DEFAULT);
         parentIDKeyBytes =
-            JebFormat.entryIDToDatabase(parentID.longValue());
+          JebFormat.entryIDToDatabase(parentID.longValue());
         if(isParent)
         {
           id2children.removeID(buffer, parentIDKeyBytes, oldID);
@@ -2791,7 +2703,7 @@
       {
         parentID = dn2id.get(txn, dn, LockMode.DEFAULT);
         parentIDKeyBytes =
-            JebFormat.entryIDToDatabase(parentID.longValue());
+          JebFormat.entryIDToDatabase(parentID.longValue());
         if(isParent)
         {
           id2children.insertID(buffer, parentIDKeyBytes, newID);
@@ -2810,18 +2722,18 @@
   }
 
   private void renameSubordinateEntry(Transaction txn, IndexBuffer buffer,
-                                      DN oldSuperiorDN, DN newSuperiorDN,
-                                      EntryID oldID, EntryID newID,
-                                      Entry oldEntry, DN newDN,
-                                      boolean isApexEntryMoved,
-                                      ModifyDNOperation modifyDNOperation)
-      throws DirectoryException, DatabaseException
+      DN oldSuperiorDN, DN newSuperiorDN,
+      EntryID oldID, EntryID newID,
+      Entry oldEntry, DN newDN,
+      boolean isApexEntryMoved,
+      ModifyDNOperation modifyDNOperation)
+  throws DirectoryException, DatabaseException
   {
     DN oldDN = oldEntry.getDN();
     Entry newEntry = oldEntry.duplicate(false);
     newEntry.setDN(newDN);
     List<Modification> modifications =
-        Collections.unmodifiableList(new ArrayList<Modification>(0));
+      Collections.unmodifiableList(new ArrayList<Modification>(0));
 
     // Create a new entry that is a copy of the old entry but with the new DN.
     // Also invoke any subordinate modify DN plugins on the entry.
@@ -2834,10 +2746,10 @@
     if (! modifyDNOperation.isSynchronizationOperation())
     {
       PluginConfigManager pluginManager =
-          DirectoryServer.getPluginConfigManager();
+        DirectoryServer.getPluginConfigManager();
       PluginResult.SubordinateModifyDN pluginResult =
-          pluginManager.invokeSubordinateModifyDNPlugins(
-              modifyDNOperation, oldEntry, newEntry, modifications);
+        pluginManager.invokeSubordinateModifyDNPlugins(
+            modifyDNOperation, oldEntry, newEntry, modifications);
 
       if (!pluginResult.continueProcessing())
       {
@@ -2854,10 +2766,10 @@
             invalidReason))
         {
           Message message =
-              ERR_JEB_MODIFYDN_ABORTED_BY_SUBORDINATE_SCHEMA_ERROR.get(
-                  oldDN.toString(),
-                  newDN.toString(),
-                  invalidReason.toString());
+            ERR_JEB_MODIFYDN_ABORTED_BY_SUBORDINATE_SCHEMA_ERROR.get(
+                oldDN.toString(),
+                newDN.toString(),
+                invalidReason.toString());
           throw new DirectoryException(
               DirectoryServer.getServerErrorResultCode(), message);
         }
@@ -2893,7 +2805,7 @@
       {
         EntryID parentID = dn2id.get(txn, dn, LockMode.DEFAULT);
         byte[] parentIDKeyBytes =
-            JebFormat.entryIDToDatabase(parentID.longValue());
+          JebFormat.entryIDToDatabase(parentID.longValue());
         id2subtree.removeID(buffer, parentIDKeyBytes, oldID);
       }
     }
@@ -2912,11 +2824,11 @@
       byte[] parentIDKeyBytes;
       boolean isParent = true;
       for (DN superiorDN = newDN; superiorDN != null;
-           superiorDN = getParentWithinBase(superiorDN))
+      superiorDN = getParentWithinBase(superiorDN))
       {
         newParentID = dn2id.get(txn, superiorDN, LockMode.DEFAULT);
         parentIDKeyBytes =
-            JebFormat.entryIDToDatabase(newParentID.longValue());
+          JebFormat.entryIDToDatabase(newParentID.longValue());
         if(isParent)
         {
           id2children.insertID(buffer, parentIDKeyBytes, newID);
@@ -2944,7 +2856,7 @@
         {
           EntryID parentID = dn2id.get(txn, dn, LockMode.DEFAULT);
           byte[] parentIDKeyBytes =
-              JebFormat.entryIDToDatabase(parentID.longValue());
+            JebFormat.entryIDToDatabase(parentID.longValue());
           id2subtree.insertID(buffer, parentIDKeyBytes, newID);
         }
       }
@@ -3010,7 +2922,7 @@
     public int compare(byte[] a, byte[] b)
     {
       for (int ai = a.length - 1, bi = b.length - 1;
-           ai >= 0 && bi >= 0; ai--, bi--)
+      ai >= 0 && bi >= 0; ai--, bi--)
       {
         if (a[ai] > b[bi])
         {
@@ -3047,7 +2959,7 @@
    * @throws JebException If an error occurs in the JE backend.
    */
   private void indexInsertEntry(Transaction txn, Entry entry, EntryID entryID)
-      throws DatabaseException, DirectoryException, JebException
+  throws DatabaseException, DirectoryException, JebException
   {
     for (AttributeIndex index : attrIndexMap.values())
     {
@@ -3070,8 +2982,8 @@
    * @throws DirectoryException If a Directory Server error occurs.
    */
   private void indexInsertEntry(IndexBuffer buffer, Entry entry,
-                                EntryID entryID)
-      throws DatabaseException, DirectoryException
+      EntryID entryID)
+  throws DatabaseException, DirectoryException
   {
     for (AttributeIndex index : attrIndexMap.values())
     {
@@ -3095,7 +3007,7 @@
    * @throws JebException If an error occurs in the JE backend.
    */
   private void indexRemoveEntry(Transaction txn, Entry entry, EntryID entryID)
-      throws DatabaseException, DirectoryException, JebException
+  throws DatabaseException, DirectoryException, JebException
   {
     for (AttributeIndex index : attrIndexMap.values())
     {
@@ -3118,8 +3030,8 @@
    * @throws DirectoryException If a Directory Server error occurs.
    */
   private void indexRemoveEntry(IndexBuffer buffer, Entry entry,
-                                EntryID entryID)
-      throws DatabaseException, DirectoryException
+      EntryID entryID)
+  throws DatabaseException, DirectoryException
   {
     for (AttributeIndex index : attrIndexMap.values())
     {
@@ -3146,9 +3058,9 @@
    * @throws JebException If an error occurs in the JE backend.
    */
   private void indexModifications(Transaction txn, Entry oldEntry,
-                                  Entry newEntry,
-                                  EntryID entryID, List<Modification> mods)
-      throws DatabaseException, DirectoryException, JebException
+      Entry newEntry,
+      EntryID entryID, List<Modification> mods)
+  throws DatabaseException, DirectoryException, JebException
   {
     // Process in index configuration order.
     for (AttributeIndex index : attrIndexMap.values())
@@ -3157,7 +3069,7 @@
       boolean attributeModified = false;
       AttributeType indexAttributeType = index.getAttributeType();
       Iterable<AttributeType> subTypes =
-          DirectoryServer.getSchema().getSubTypes(indexAttributeType);
+        DirectoryServer.getSchema().getSubTypes(indexAttributeType);
 
       for (Modification mod : mods)
       {
@@ -3202,9 +3114,9 @@
    * @throws DirectoryException If a Directory Server error occurs.
    */
   private void indexModifications(IndexBuffer buffer, Entry oldEntry,
-                                  Entry newEntry,
-                                  EntryID entryID, List<Modification> mods)
-      throws DatabaseException, DirectoryException
+      Entry newEntry,
+      EntryID entryID, List<Modification> mods)
+  throws DatabaseException, DirectoryException
   {
     // Process in index configuration order.
     for (AttributeIndex index : attrIndexMap.values())
@@ -3213,7 +3125,7 @@
       boolean attributeModified = false;
       AttributeType indexAttributeType = index.getAttributeType();
       Iterable<AttributeType> subTypes =
-          DirectoryServer.getSchema().getSubTypes(indexAttributeType);
+        DirectoryServer.getSchema().getSubTypes(indexAttributeType);
 
       for (Modification mod : mods)
       {
@@ -3257,7 +3169,7 @@
     if (entryID != null)
     {
       DatabaseEntry key =
-          new DatabaseEntry(JebFormat.entryIDToDatabase(entryID.longValue()));
+        new DatabaseEntry(JebFormat.entryIDToDatabase(entryID.longValue()));
       EntryIDSet entryIDSet;
       entryIDSet = id2subtree.readKey(key, null, LockMode.DEFAULT);
 
@@ -3371,7 +3283,7 @@
    * a new transaction.
    */
   public Transaction beginTransaction()
-      throws DatabaseException
+  throws DatabaseException
   {
     Transaction parentTxn = null;
     TransactionConfig txnConfig = null;
@@ -3391,7 +3303,7 @@
    * the transaction.
    */
   public static void transactionCommit(Transaction txn)
-      throws DatabaseException
+  throws DatabaseException
   {
     if (txn != null)
     {
@@ -3411,7 +3323,7 @@
    * transaction.
    */
   public static void transactionAbort(Transaction txn)
-      throws DatabaseException
+  throws DatabaseException
   {
     if (txn != null)
     {
@@ -3476,7 +3388,7 @@
    * database.
    */
   public void deleteDatabase(DatabaseContainer database)
-      throws DatabaseException
+  throws DatabaseException
   {
     if(database == state)
     {
@@ -3521,7 +3433,7 @@
    * to delete the index.
    */
   public void deleteAttributeIndex(AttributeIndex index)
-      throws DatabaseException
+  throws DatabaseException
   {
     index.close();
     if(env.getConfig().getTransactional())
@@ -3613,7 +3525,7 @@
    * @throws JebException If an error occurs in the JE backend.
    */
   public void setDatabasePrefix(String newDatabasePrefix)
-      throws DatabaseException, JebException
+  throws DatabaseException, JebException
 
   {
     List<DatabaseContainer> databases = new ArrayList<DatabaseContainer>();
@@ -3671,13 +3583,13 @@
         {
           transactionAbort(txn);
 
-        String msg = e.getMessage();
-        if (msg == null)
-        {
-          msg = stackTraceToSingleLineString(e);
-        }
-        Message message = ERR_JEB_UNCHECKED_EXCEPTION.get(msg);
-        throw new JebException(message, e);
+          String msg = e.getMessage();
+          if (msg == null)
+          {
+            msg = stackTraceToSingleLineString(e);
+          }
+          Message message = ERR_JEB_UNCHECKED_EXCEPTION.get(msg);
+          throw new JebException(message, e);
         }
       }
       else
@@ -3756,8 +3668,8 @@
       {
         adminActionRequired = true;
         Message message =
-                NOTE_JEB_CONFIG_INDEX_ENTRY_LIMIT_REQUIRES_REBUILD.get(
-                        id2children.getName());
+          NOTE_JEB_CONFIG_INDEX_ENTRY_LIMIT_REQUIRES_REBUILD.get(
+              id2children.getName());
         messages.add(message);
       }
 
@@ -3765,21 +3677,21 @@
       {
         adminActionRequired = true;
         Message message =
-                NOTE_JEB_CONFIG_INDEX_ENTRY_LIMIT_REQUIRES_REBUILD.get(
-                        id2subtree.getName());
+          NOTE_JEB_CONFIG_INDEX_ENTRY_LIMIT_REQUIRES_REBUILD.get(
+              id2subtree.getName());
         messages.add(message);
       }
     }
 
     DataConfig entryDataConfig =
-        new DataConfig(cfg.isEntriesCompressed(),
-                       cfg.isCompactEncoding(),
-                       rootContainer.getCompressedSchema());
+      new DataConfig(cfg.isEntriesCompressed(),
+          cfg.isCompactEncoding(),
+          rootContainer.getCompressedSchema());
     id2entry.setDataConfig(entryDataConfig);
 
     this.config = cfg;
     return new ConfigChangeResult(ResultCode.SUCCESS,
-                                  adminActionRequired, messages);
+        adminActionRequired, messages);
   }
 
   /**
@@ -3791,7 +3703,7 @@
    *                           configuration object.
    */
   public EnvironmentConfig getEnvironmentConfig()
-      throws DatabaseException
+  throws DatabaseException
   {
     return env.getConfig();
   }
@@ -3903,7 +3815,7 @@
    * @throws DatabaseException if a JE database error occurs.
    */
   public long clearDatabase(DatabaseContainer database)
-      throws DatabaseException
+  throws DatabaseException
   {
     long count = 0;
     database.close();
@@ -3948,7 +3860,7 @@
    * @throws DatabaseException if a JE database error occurs.
    */
   public long clearAttributeIndex(AttributeIndex index)
-      throws DatabaseException
+  throws DatabaseException
   {
     long count = 0;
 
@@ -3963,27 +3875,27 @@
           if(index.equalityIndex != null)
           {
             count += env.truncateDatabase(txn, index.equalityIndex.getName(),
-                                          true);
+                true);
           }
           if(index.presenceIndex != null)
           {
             count += env.truncateDatabase(txn, index.presenceIndex.getName(),
-                                          true);
+                true);
           }
           if(index.substringIndex != null)
           {
             count += env.truncateDatabase(txn, index.substringIndex.getName(),
-                                          true);
+                true);
           }
           if(index.orderingIndex != null)
           {
             count += env.truncateDatabase(txn, index.orderingIndex.getName(),
-                                          true);
+                true);
           }
           if(index.approximateIndex != null)
           {
             count += env.truncateDatabase(txn, index.approximateIndex.getName(),
-                                          true);
+                true);
           }
           transactionCommit(txn);
         }
@@ -3998,27 +3910,27 @@
         if(index.equalityIndex != null)
         {
           count += env.truncateDatabase(null, index.equalityIndex.getName(),
-                                        true);
+              true);
         }
         if(index.presenceIndex != null)
         {
           count += env.truncateDatabase(null, index.presenceIndex.getName(),
-                                        true);
+              true);
         }
         if(index.substringIndex != null)
         {
           count += env.truncateDatabase(null, index.substringIndex.getName(),
-                                        true);
+              true);
         }
         if(index.orderingIndex != null)
         {
           count += env.truncateDatabase(null, index.orderingIndex.getName(),
-                                        true);
+              true);
         }
         if(index.approximateIndex != null)
         {
           count += env.truncateDatabase(null, index.approximateIndex.getName(),
-                                        true);
+              true);
         }
       }
     }
@@ -4044,7 +3956,7 @@
    * existing entry from being performed
    */
   private DN getMatchedDN(DN baseDN)
-    throws DirectoryException
+  throws DirectoryException
   {
     DN matchedDN = null;
     DN parentDN  = baseDN.getParentDNInSuffix();
diff --git a/opends/src/server/org/opends/server/backends/jeb/EntryIDSetSorter.java b/opends/src/server/org/opends/server/backends/jeb/EntryIDSetSorter.java
index 58cf5cd..d2d9f51 100644
--- a/opends/src/server/org/opends/server/backends/jeb/EntryIDSetSorter.java
+++ b/opends/src/server/org/opends/server/backends/jeb/EntryIDSetSorter.java
@@ -39,14 +39,7 @@
 import org.opends.server.core.DirectoryServer;
 import org.opends.server.core.SearchOperation;
 import org.opends.server.protocols.ldap.LDAPResultCode;
-import org.opends.server.types.AttributeValue;
-import org.opends.server.types.DirectoryException;
-import org.opends.server.types.DN;
-import org.opends.server.types.Entry;
-import org.opends.server.types.ResultCode;
-import org.opends.server.types.SearchFilter;
-import org.opends.server.types.SearchScope;
-import org.opends.server.types.SortOrder;
+import org.opends.server.types.*;
 
 import static org.opends.messages.JebMessages.*;
 import static org.opends.server.util.StaticUtils.*;
@@ -206,9 +199,10 @@
       }
       else
       {
-        AttributeValue assertionValue = new
-             AttributeValue(sortOrder.getSortKeys()[0].getAttributeType(),
-                            vlvRequest.getGreaterThanOrEqualAssertion());
+        AttributeValue assertionValue =
+            AttributeValues.create(
+                sortOrder.getSortKeys()[0].getAttributeType(),
+                vlvRequest.getGreaterThanOrEqualAssertion());
 
         boolean targetFound     = false;
         int targetOffset        = 0;
diff --git a/opends/src/server/org/opends/server/backends/jeb/EqualityIndexer.java b/opends/src/server/org/opends/server/backends/jeb/EqualityIndexer.java
index 8aecf0e..38a2abb 100644
--- a/opends/src/server/org/opends/server/backends/jeb/EqualityIndexer.java
+++ b/opends/src/server/org/opends/server/backends/jeb/EqualityIndexer.java
@@ -172,7 +172,7 @@
       {
         try
         {
-          byte[] keyBytes = value.getNormalizedValue().value();
+          byte[] keyBytes = value.getNormalizedValue().toByteArray();
 
           keys.add(keyBytes);
         }
@@ -207,7 +207,7 @@
       {
         try
         {
-          byte[] keyBytes = value.getNormalizedValue().value();
+          byte[] keyBytes = value.getNormalizedValue().toByteArray();
 
           Boolean cInsert = modifiedKeys.get(keyBytes);
           if(cInsert == null)
diff --git a/opends/src/server/org/opends/server/backends/jeb/ExportJob.java b/opends/src/server/org/opends/server/backends/jeb/ExportJob.java
index 68477ab..9b540be 100644
--- a/opends/src/server/org/opends/server/backends/jeb/ExportJob.java
+++ b/opends/src/server/org/opends/server/backends/jeb/ExportJob.java
@@ -34,16 +34,13 @@
 import com.sleepycat.je.LockMode;
 import com.sleepycat.je.OperationStatus;
 
-import org.opends.server.types.DN;
-import org.opends.server.types.Entry;
-import org.opends.server.types.LDIFExportConfig;
 import org.opends.server.util.LDIFException;
 import org.opends.server.util.StaticUtils;
 
 import java.io.IOException;
 import java.util.*;
 
-import org.opends.server.types.DebugLogLevel;
+import org.opends.server.types.*;
 import static org.opends.server.loggers.ErrorLogger.logError;
 import static org.opends.server.loggers.debug.DebugLogger.*;
 import org.opends.server.loggers.debug.DebugTracer;
@@ -238,7 +235,7 @@
         Entry entry = null;
         try
         {
-          entry = JebFormat.entryFromDatabase(data.getData(),
+          entry = ID2Entry.entryFromDatabase(ByteString.wrap(data.getData()),
                        entryContainer.getRootContainer().getCompressedSchema());
         }
         catch (Exception e)
diff --git a/opends/src/server/org/opends/server/backends/jeb/ID2Entry.java b/opends/src/server/org/opends/server/backends/jeb/ID2Entry.java
index e054633..0f55969 100644
--- a/opends/src/server/org/opends/server/backends/jeb/ID2Entry.java
+++ b/opends/src/server/org/opends/server/backends/jeb/ID2Entry.java
@@ -33,9 +33,16 @@
 
 import com.sleepycat.je.*;
 
-import org.opends.server.types.DirectoryException;
-import org.opends.server.types.Entry;
+import org.opends.server.types.*;
 import org.opends.server.core.DirectoryServer;
+import org.opends.server.protocols.asn1.ASN1Writer;
+import org.opends.server.protocols.asn1.ASN1;
+import org.opends.server.protocols.asn1.ASN1Reader;
+import org.opends.server.protocols.asn1.ASN1Exception;
+import org.opends.server.api.CompressedSchema;
+
+import java.io.IOException;
+import java.util.zip.DataFormatException;
 
 /**
  * Represents the database containing the LDAP entries. The database key is
@@ -54,6 +61,139 @@
    */
   private DataConfig dataConfig;
 
+  private static ThreadLocal<EntryCoder> entryCodingBuffers =
+      new ThreadLocal<EntryCoder>();
+
+  /**
+   * A cached set of ByteStringBuilder buffers and ASN1Writer used to encode
+   * entries.
+   */
+  private static class EntryCoder
+  {
+    ByteStringBuilder encodedBuffer;
+    private ByteStringBuilder entryBuffer;
+    private ByteStringBuilder compressedEntryBuffer;
+    private ASN1Writer writer;
+
+    private EntryCoder()
+    {
+      encodedBuffer = new ByteStringBuilder();
+      entryBuffer = new ByteStringBuilder();
+      compressedEntryBuffer = new ByteStringBuilder();
+      writer = ASN1.getWriter(encodedBuffer);
+    }
+
+    private Entry decode(ByteString bytes, CompressedSchema compressedSchema)
+        throws DirectoryException,ASN1Exception,LDAPException,
+        DataFormatException, IOException
+    {
+      // Get the format version.
+      byte formatVersion = bytes.byteAt(0);
+      if(formatVersion != JebFormat.FORMAT_VERSION)
+      {
+        Message message =
+            ERR_JEB_INCOMPATIBLE_ENTRY_VERSION.get(formatVersion);
+        throw new ASN1Exception(message);
+      }
+
+      // Read the ASN1 sequence.
+      ASN1Reader reader = ASN1.getReader(bytes.subSequence(1, bytes.length()));
+      reader.readStartSequence();
+
+      // See if it was compressed.
+      int uncompressedSize = (int)reader.readInteger();
+
+      if(uncompressedSize > 0)
+      {
+        // We will use the cached buffers to avoid allocations.
+        // Reset the buffers;
+        entryBuffer.clear();
+        compressedEntryBuffer.clear();
+
+        // It was compressed.
+        reader.readOctetString(compressedEntryBuffer);
+        CryptoManager cryptoManager = DirectoryServer.getCryptoManager();
+        // TODO: Should handle the case where uncompress returns < 0
+        compressedEntryBuffer.uncompress(entryBuffer, cryptoManager,
+            uncompressedSize);
+
+        // Since we are used the cached buffers (ByteStringBuilders),
+        // the decoded attribute values will not refer back to the
+        // original buffer.
+        return Entry.decode(entryBuffer.asReader(), compressedSchema);
+      }
+      else
+      {
+        // Since we don't have to do any decompression, we can just decode
+        // the entry off the
+        ByteString encodedEntry = reader.readOctetString();
+        return Entry.decode(encodedEntry.asReader(), compressedSchema);
+      }
+    }
+
+    private ByteString encodeCopy(Entry entry, DataConfig dataConfig)
+        throws DirectoryException
+    {
+      encodeVolatile(entry, dataConfig);
+      return encodedBuffer.toByteString();
+    }
+
+    private DatabaseEntry encodeInternal(Entry entry, DataConfig dataConfig)
+        throws DirectoryException
+    {
+      encodeVolatile(entry, dataConfig);
+      return new DatabaseEntry(encodedBuffer.getBackingArray(), 0,
+          encodedBuffer.length());
+    }
+
+    private void encodeVolatile(Entry entry, DataConfig dataConfig)
+        throws DirectoryException
+    {
+      // Reset the buffers;
+      encodedBuffer.clear();
+      entryBuffer.clear();
+      compressedEntryBuffer.clear();
+
+      // Encode the entry for later use.
+      entry.encode(entryBuffer, dataConfig.getEntryEncodeConfig());
+
+      // First write the DB format version byte.
+      encodedBuffer.append(JebFormat.FORMAT_VERSION);
+
+      try
+      {
+        // Then start the ASN1 sequence.
+        writer.writeStartSequence(JebFormat.TAG_DATABASE_ENTRY);
+
+        // Do optional compression.
+        CryptoManager cryptoManager = DirectoryServer.getCryptoManager();
+        if (dataConfig.isCompressed() && cryptoManager != null &&
+            entryBuffer.compress(compressedEntryBuffer, cryptoManager))
+        {
+          // Compression needed and successful.
+          writer.writeInteger(entryBuffer.length());
+          writer.writeOctetString(compressedEntryBuffer);
+        }
+        else
+        {
+          writer.writeInteger(0);
+          writer.writeOctetString(entryBuffer);
+        }
+
+        writer.writeEndSequence();
+      }
+      catch(IOException ioe)
+      {
+        // TODO: This should never happen with byte buffer.
+        if(debugEnabled())
+        {
+          TRACER.debugCaught(DebugLogLevel.ERROR, ioe);
+        }
+
+      }
+    }
+  }
+
   /**
    * Create a new ID2Entry object.
    *
@@ -96,20 +236,75 @@
   }
 
   /**
-   * Convert an entry to its database format.
+   * Decodes an entry from its database representation.
+   * <p>
+   * An entry on disk is ASN1 encoded in this format:
    *
-   * @param entry The LDAP entry to be converted.
-   * @return The database entry.
+   * <pre>
+   * DatabaseEntry ::= [APPLICATION 0] IMPLICIT SEQUENCE {
+   *  uncompressedSize      INTEGER,      -- A zero value means not compressed.
+   *  dataBytes             OCTET STRING  -- Optionally compressed encoding of
+   *                                         the data bytes.
+   * }
+   *
+   * ID2EntryValue ::= DatabaseEntry
+   *  -- Where dataBytes contains an encoding of DirectoryServerEntry.
+   *
+   * DirectoryServerEntry ::= [APPLICATION 1] IMPLICIT SEQUENCE {
+   *  dn                      LDAPDN,
+   *  objectClasses           SET OF LDAPString,
+   *  userAttributes          AttributeList,
+   *  operationalAttributes   AttributeList
+   * }
+   * </pre>
+   *
+   * @param bytes A byte array containing the encoded database value.
+   * @param compressedSchema The compressed schema manager to use when decoding.
+   * @return The decoded entry.
+   * @throws ASN1Exception If the data is not in the expected ASN.1 encoding
+   * format.
+   * @throws LDAPException If the data is not in the expected ASN.1 encoding
+   * format.
+   * @throws DataFormatException If an error occurs while trying to decompress
+   * compressed data.
+   * @throws DirectoryException If a Directory Server error occurs.
+   * @throws IOException if an error occurs while reading the ASN1 sequence.
+   */
+  static public Entry entryFromDatabase(ByteString bytes,
+                                        CompressedSchema compressedSchema)
+      throws DirectoryException,ASN1Exception,LDAPException,
+      DataFormatException,IOException
+  {
+    EntryCoder coder = entryCodingBuffers.get();
+    if(coder == null)
+    {
+      coder = new EntryCoder();
+      entryCodingBuffers.set(coder);
+    }
+    return coder.decode(bytes, compressedSchema);
+  }
+
+  /**
+   * Encodes an entry to the raw database format, with optional compression.
+   *
+   * @param entry The entry to encode.
+   * @param dataConfig Compression and cryptographic options.
+   * @return A ByteSTring containing the encoded database value.
    *
    * @throws  DirectoryException  If a problem occurs while attempting to encode
    *                              the entry.
    */
-  public DatabaseEntry entryData(Entry entry)
-          throws DirectoryException
+  static public ByteString entryToDatabase(Entry entry, DataConfig dataConfig)
+      throws DirectoryException
   {
-    byte[] entryBytes;
-    entryBytes = JebFormat.entryToDatabase(entry, dataConfig);
-    return new DatabaseEntry(entryBytes);
+    EntryCoder coder = entryCodingBuffers.get();
+    if(coder == null)
+    {
+      coder = new EntryCoder();
+      entryCodingBuffers.set(coder);
+    }
+
+    return coder.encodeCopy(entry, dataConfig);
   }
 
   /**
@@ -128,7 +323,13 @@
        throws DatabaseException, DirectoryException
   {
     DatabaseEntry key = id.getDatabaseEntry();
-    DatabaseEntry data = entryData(entry);
+    EntryCoder coder = entryCodingBuffers.get();
+    if(coder == null)
+    {
+      coder = new EntryCoder();
+      entryCodingBuffers.set(coder);
+    }
+    DatabaseEntry data = coder.encodeInternal(entry, dataConfig);
 
     OperationStatus status;
     status = insert(txn, key, data);
@@ -154,7 +355,13 @@
        throws DatabaseException, DirectoryException
   {
     DatabaseEntry key = id.getDatabaseEntry();
-    DatabaseEntry data = entryData(entry);
+    EntryCoder coder = entryCodingBuffers.get();
+    if(coder == null)
+    {
+      coder = new EntryCoder();
+      entryCodingBuffers.set(coder);
+    }
+    DatabaseEntry data = coder.encodeInternal(entry, dataConfig);
 
     OperationStatus status;
     status = put(txn, key, data);
@@ -231,44 +438,19 @@
       return null;
     }
 
-    byte[] entryBytes = data.getData();
-    byte entryVersion = JebFormat.getEntryVersion(entryBytes);
-
-    //Try to decode the entry based on the version number. On later versions,
-    //a case could be written to upgrade entries if it is not the current
-    //version
-    Entry entry = null;
-    switch(entryVersion)
+    try
     {
-      case JebFormat.FORMAT_VERSION :
-        try
-        {
-          entry = JebFormat.entryFromDatabase(entryBytes,
-                       entryContainer.getRootContainer().getCompressedSchema());
-        }
-        catch (Exception e)
-        {
-          Message message = ERR_JEB_ENTRY_DATABASE_CORRUPT.get(id.toString());
-          throw new DirectoryException(
-              DirectoryServer.getServerErrorResultCode(), message);
-        }
-        break;
-
-      //case 0x00                     :
-      //  Call upgrade method? Call 0x00 decode method?
-      default   :
-        Message message =
-            ERR_JEB_INCOMPATIBLE_ENTRY_VERSION.get(id.toString(), entryVersion);
-        throw new DirectoryException(
-              DirectoryServer.getServerErrorResultCode(), message);
-    }
-
-    if (entry != null)
-    {
+      Entry entry = entryFromDatabase(ByteString.wrap(data.getData()),
+          entryContainer.getRootContainer().getCompressedSchema());
       entry.processVirtualAttributes();
+      return entry;
     }
-
-    return entry;
+    catch (Exception e)
+    {
+      Message message = ERR_JEB_ENTRY_DATABASE_CORRUPT.get(id.toString());
+      throw new DirectoryException(
+          DirectoryServer.getServerErrorResultCode(), message);
+    }
   }
 
   /**
diff --git a/opends/src/server/org/opends/server/backends/jeb/IndexQuery.java b/opends/src/server/org/opends/server/backends/jeb/IndexQuery.java
index 23e3e82..a811623 100644
--- a/opends/src/server/org/opends/server/backends/jeb/IndexQuery.java
+++ b/opends/src/server/org/opends/server/backends/jeb/IndexQuery.java
@@ -25,185 +25,198 @@
  *      Copyright 2009 Sun Microsystems, Inc.
  */
 
-
 package org.opends.server.backends.jeb;
 
+
+
 import java.util.Collection;
 import static org.opends.server.backends.jeb.IndexFilter.*;
 
 
+
 /**
  * This class represents a JE Backend Query.
  */
 @org.opends.server.types.PublicAPI(
-     stability=org.opends.server.types.StabilityLevel.VOLATILE,
-     mayInstantiate=false,
-     mayExtend=true,
-     mayInvoke=false)
+    stability = org.opends.server.types.StabilityLevel.VOLATILE,
+    mayInstantiate = false,
+    mayExtend = true,
+    mayInvoke = false)
 public abstract class IndexQuery
 {
   /**
-  * Evaluates the index query and returns the EntryIDSet.
-  * @return The EntryIDSet as a result of evaulation of this query.
-  */
+   * Evaluates the index query and returns the EntryIDSet.
+   *
+   * @return The EntryIDSet as a result of evaulation of this query.
+   */
   public abstract EntryIDSet evaluate();
 
 
 
-   /**
-    * Creates an IntersectionIndexQuery object from a collection of IndexQuery
-    * objects.
-    * @param subIndexQueries A collection of IndexQuery objects.
-    * @return An IntersectionIndexQuery object.
-    */
-   public static IndexQuery createIntersectionIndexQuery(
-           Collection<IndexQuery> subIndexQueries)
-   {
-     return new IntersectionIndexQuery(subIndexQueries);
-   }
-
-
-
-   /**
-    * Creates a union IndexQuery object from a collection of IndexQuery
-    * objects.
-    * @param subIndexQueries Collection of IndexQuery objects.
-    * @return A UnionIndexQuery object.
-    */
-   public static IndexQuery createUnionIndexQuery(
-           Collection<IndexQuery> subIndexQueries)
-   {
-     return new UnionIndexQuery(subIndexQueries);
-   }
-
-
-
-   /**
-    * Creates an empty IndexQuery object.
-    * @return A NullIndexQuery object.
-    */
-   public static IndexQuery createNullIndexQuery()
-   {
-     return new NullIndexQuery();
-   }
-}
-
-
-
-/**
-* This class creates a Null  IndexQuery. It is used when there
-*  is no record in the index. It may also be used when the
- * index contains all the records but an empty EntryIDSet should be
- * returned as part of the optimization.
-*/
-final class NullIndexQuery extends IndexQuery
-{
   /**
-   * {@inheritDoc}
+   * Creates an IntersectionIndexQuery object from a collection of
+   * IndexQuery objects.
+   *
+   * @param subIndexQueries
+   *          A collection of IndexQuery objects.
+   * @return An IntersectionIndexQuery object.
    */
-  @Override
-  public EntryIDSet evaluate()
+  public static IndexQuery createIntersectionIndexQuery(
+      Collection<IndexQuery> subIndexQueries)
   {
-    return new EntryIDSet();
-  }
-}
-
-
-
-
-
-/**
- * This class creates an intersection IndexQuery from a collection of
- * IndexQuery objects.
- */
-final class IntersectionIndexQuery extends IndexQuery
-{
-  /**
-   * Collection of IndexQuery objects.
-   */
-  private final  Collection<IndexQuery> subIndexQueries;
-
-
-  /**
-   * Creates an instance of IntersectionIndexQuery.
-   * @param subIndexQueries Collection of IndexQuery objects.
-   */
-  IntersectionIndexQuery(Collection<IndexQuery> subIndexQueries)
-  {
-    this.subIndexQueries = subIndexQueries;
+    return new IntersectionIndexQuery(subIndexQueries);
   }
 
 
-  /**
-   * {@inheritDoc}
-   */
-  @Override
-  public EntryIDSet evaluate()
-  {
-   EntryIDSet entryIDs = null;
-   for (IndexQuery query : subIndexQueries)
-   {
-     if (entryIDs == null)
-     {
-       entryIDs = query.evaluate();
-     }
-     else
-     {
-       entryIDs.retainAll(query.evaluate());
-     }
-     if (entryIDs.isDefined() &&
-         entryIDs.size() <= FILTER_CANDIDATE_THRESHOLD)
-     {
-       break;
-     }
-   }
-   return entryIDs;
-  }
-}
-
-/**
- * This class creates a union of IndexQuery objects.
- */
-final class UnionIndexQuery extends IndexQuery
-{
-  /**
-   * Collection containing IndexQuery objects.
-   */
-  private final Collection<IndexQuery> subIndexQueries;
 
   /**
-   * Creates an instance of UnionIndexQuery.
-   * @param subIndexQueries The Collection of IndexQuery objects.
+   * Creates a union IndexQuery object from a collection of IndexQuery
+   * objects.
+   *
+   * @param subIndexQueries
+   *          Collection of IndexQuery objects.
+   * @return A UnionIndexQuery object.
    */
-  UnionIndexQuery(Collection<IndexQuery> subIndexQueries)
+  public static IndexQuery createUnionIndexQuery(
+      Collection<IndexQuery> subIndexQueries)
   {
-    this.subIndexQueries = subIndexQueries;
+    return new UnionIndexQuery(subIndexQueries);
   }
 
 
+
   /**
-   * {@inheritDoc}
+   * Creates an empty IndexQuery object.
+   *
+   * @return A NullIndexQuery object.
    */
-  @Override
-  public EntryIDSet evaluate()
+  public static IndexQuery createNullIndexQuery()
   {
-    EntryIDSet entryIDs = null;
-    for (IndexQuery query : subIndexQueries)
+    return new NullIndexQuery();
+  }
+
+
+
+  /**
+   * This class creates a Null IndexQuery. It is used when there is no
+   * record in the index. It may also be used when the index contains
+   * all the records but an empty EntryIDSet should be returned as part
+   * of the optimization.
+   */
+  private static final class NullIndexQuery extends IndexQuery
+  {
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public EntryIDSet evaluate()
     {
-      if (entryIDs == null)
-      {
-        entryIDs = query.evaluate();
-      }
-      else
-      {
-        entryIDs.addAll(query.evaluate());
-      }
-      if (entryIDs.isDefined() &&
-          entryIDs.size() <= FILTER_CANDIDATE_THRESHOLD)
-      {
-        break;
-      }
+      return new EntryIDSet();
     }
-    return entryIDs;
   }
-}
\ No newline at end of file
+
+  /**
+   * This class creates an intersection IndexQuery from a collection of
+   * IndexQuery objects.
+   */
+  private static final class IntersectionIndexQuery extends IndexQuery
+  {
+    /**
+     * Collection of IndexQuery objects.
+     */
+    private final Collection<IndexQuery> subIndexQueries;
+
+
+
+    /**
+     * Creates an instance of IntersectionIndexQuery.
+     *
+     * @param subIndexQueries
+     *          Collection of IndexQuery objects.
+     */
+    private IntersectionIndexQuery(Collection<IndexQuery> subIndexQueries)
+    {
+      this.subIndexQueries = subIndexQueries;
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public EntryIDSet evaluate()
+    {
+      EntryIDSet entryIDs = null;
+      for (IndexQuery query : subIndexQueries)
+      {
+        if (entryIDs == null)
+        {
+          entryIDs = query.evaluate();
+        }
+        else
+        {
+          entryIDs.retainAll(query.evaluate());
+        }
+        if (entryIDs.isDefined()
+            && entryIDs.size() <= FILTER_CANDIDATE_THRESHOLD)
+        {
+          break;
+        }
+      }
+      return entryIDs;
+    }
+  }
+
+  /**
+   * This class creates a union of IndexQuery objects.
+   */
+  private static final class UnionIndexQuery extends IndexQuery
+  {
+    /**
+     * Collection containing IndexQuery objects.
+     */
+    private final Collection<IndexQuery> subIndexQueries;
+
+
+
+    /**
+     * Creates an instance of UnionIndexQuery.
+     *
+     * @param subIndexQueries
+     *          The Collection of IndexQuery objects.
+     */
+    private UnionIndexQuery(Collection<IndexQuery> subIndexQueries)
+    {
+      this.subIndexQueries = subIndexQueries;
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public EntryIDSet evaluate()
+    {
+      EntryIDSet entryIDs = null;
+      for (IndexQuery query : subIndexQueries)
+      {
+        if (entryIDs == null)
+        {
+          entryIDs = query.evaluate();
+        }
+        else
+        {
+          entryIDs.addAll(query.evaluate());
+        }
+        if (entryIDs.isDefined()
+            && entryIDs.size() <= FILTER_CANDIDATE_THRESHOLD)
+        {
+          break;
+        }
+      }
+      return entryIDs;
+    }
+  }
+}
diff --git a/opends/src/server/org/opends/server/backends/jeb/IndexQueryFactoryImpl.java b/opends/src/server/org/opends/server/backends/jeb/IndexQueryFactoryImpl.java
index 55efb41..4811e06 100644
--- a/opends/src/server/org/opends/server/backends/jeb/IndexQueryFactoryImpl.java
+++ b/opends/src/server/org/opends/server/backends/jeb/IndexQueryFactoryImpl.java
@@ -25,34 +25,41 @@
  *      Copyright 2009 Sun Microsystems, Inc.
  */
 
-
 package org.opends.server.backends.jeb;
 
+
+
 import com.sleepycat.je.DatabaseEntry;
 import com.sleepycat.je.LockMode;
 import java.util.Collection;
 import java.util.Map;
 import org.opends.server.api.IndexQueryFactory;
+import org.opends.server.types.ByteSequence;
+
+
 
 /**
  * This class is an implementation of IndexQueryFactory which creates
  * IndexQuery objects as part of the query of the JEB index.
-*/
-public final class IndexQueryFactoryImpl
-        implements IndexQueryFactory<IndexQuery>
+ */
+public final class IndexQueryFactoryImpl implements
+    IndexQueryFactory<IndexQuery>
 {
   /**
-   * The Map containing the string type identifier and the corresponding index.
+   * The Map containing the string type identifier and the corresponding
+   * index.
    */
-  private Map<String,Index> indexMap;
+  private Map<String, Index> indexMap;
 
 
 
   /**
    * Creates a new IndexQueryFactoryImpl object.
-   * @param indexMap A map containing the index id and the corresponding index.
+   *
+   * @param indexMap
+   *          A map containing the index id and the corresponding index.
    */
-  public IndexQueryFactoryImpl(Map<String,Index> indexMap)
+  public IndexQueryFactoryImpl(Map<String, Index> indexMap)
   {
     this.indexMap = indexMap;
   }
@@ -60,62 +67,61 @@
 
 
   /**
-   *{@inheritDoc}
+   * {@inheritDoc}
    */
   public IndexQuery createExactMatchQuery(final String indexID,
-          final byte[] value)
+      final ByteSequence value)
   {
     return new IndexQuery()
-    {
-
-      @Override
-      public EntryIDSet evaluate()
       {
-        //Read the database and get Record for the key.
-        DatabaseEntry key = new DatabaseEntry(value);
-        //Select the right index to be used.
-        Index index = indexMap.get(indexID);
-        EntryIDSet entrySet = index.readKey(key,null,LockMode.DEFAULT);
-        return entrySet;
-      }
-    };
+
+        @Override
+        public EntryIDSet evaluate()
+        {
+          // Read the database and get Record for the key.
+          DatabaseEntry key = new DatabaseEntry(value.toByteArray());
+
+          // Select the right index to be used.
+          Index index = indexMap.get(indexID);
+          EntryIDSet entrySet =
+              index.readKey(key, null, LockMode.DEFAULT);
+          return entrySet;
+        }
+      };
   }
 
 
 
   /**
-   *{@inheritDoc}
+   * {@inheritDoc}
    */
-  public IndexQuery createRangeMatchQuery(
-                                              final String indexID,
-                                              final byte[] lowerBound,
-                                              final byte[] upperBound,
-                                              final boolean includeLowerBound,
-                                              final boolean includeUpperBound)
+  public IndexQuery createRangeMatchQuery(final String indexID,
+      final ByteSequence lowerBound, final ByteSequence upperBound,
+      final boolean includeLowerBound, final boolean includeUpperBound)
   {
     return new IndexQuery()
-    {
-
-      @Override
-      public EntryIDSet evaluate()
       {
-        //Find the right index.
-        Index index = indexMap.get(indexID);
-        EntryIDSet entrySet =   index.readRange(lowerBound,upperBound,
-                includeLowerBound,
-            includeUpperBound);
-        return entrySet;
-      }
-    };
+
+        @Override
+        public EntryIDSet evaluate()
+        {
+          // Find the right index.
+          Index index = indexMap.get(indexID);
+          EntryIDSet entrySet =
+              index.readRange(lowerBound.toByteArray(), upperBound
+                  .toByteArray(), includeLowerBound, includeUpperBound);
+          return entrySet;
+        }
+      };
   }
 
 
 
   /**
-   *{@inheritDoc}
+   * {@inheritDoc}
    */
-  public IndexQuery  createIntersectionQuery(Collection<IndexQuery>
-                                                                subqueries)
+  public IndexQuery createIntersectionQuery(
+      Collection<IndexQuery> subqueries)
   {
     return IndexQuery.createIntersectionIndexQuery(subqueries);
   }
@@ -123,7 +129,7 @@
 
 
   /**
-   *{@inheritDoc}
+   * {@inheritDoc}
    */
   public IndexQuery createUnionQuery(Collection<IndexQuery> subqueries)
   {
@@ -133,20 +139,21 @@
 
 
   /**
-   *{@inheritDoc}
-   * It returns an empty EntryIDSet object  when either all or no record sets
-   * are requested.
+   * {@inheritDoc}
+   * <p>
+   * It returns an empty EntryIDSet object when either all or no record
+   * sets are requested.
    */
   public IndexQuery createMatchAllQuery()
   {
     return new IndexQuery()
-    {
-
-      @Override
-      public EntryIDSet evaluate()
       {
-        return new EntryIDSet();
-      }
-    };
+
+        @Override
+        public EntryIDSet evaluate()
+        {
+          return new EntryIDSet();
+        }
+      };
   }
 }
\ No newline at end of file
diff --git a/opends/src/server/org/opends/server/backends/jeb/IndexRebuildThread.java b/opends/src/server/org/opends/server/backends/jeb/IndexRebuildThread.java
index 4696030..85fc389 100644
--- a/opends/src/server/org/opends/server/backends/jeb/IndexRebuildThread.java
+++ b/opends/src/server/org/opends/server/backends/jeb/IndexRebuildThread.java
@@ -389,8 +389,9 @@
         try
         {
           EntryID entryID = new EntryID(key);
-          Entry entry = JebFormat.entryFromDatabase(data.getData(),
-                             ec.getRootContainer().getCompressedSchema());
+          Entry entry = ID2Entry.entryFromDatabase(
+              ByteString.wrap(data.getData()),
+              ec.getRootContainer().getCompressedSchema());
 
           // Insert into dn2id.
           if (dn2id.insert(txn, entry.getDN(), entryID))
@@ -472,8 +473,9 @@
         try
         {
           EntryID entryID = new EntryID(key);
-          Entry entry = JebFormat.entryFromDatabase(data.getData(),
-                             ec.getRootContainer().getCompressedSchema());
+          Entry entry = ID2Entry.entryFromDatabase(
+              ByteString.wrap(data.getData()),
+              ec.getRootContainer().getCompressedSchema());
 
           // Insert into dn2uri.
           if (dn2uri.addEntry(txn, entry))
@@ -558,8 +560,9 @@
         try
         {
           EntryID entryID = new EntryID(key);
-          Entry entry = JebFormat.entryFromDatabase(data.getData(),
-                             ec.getRootContainer().getCompressedSchema());
+          Entry entry = ID2Entry.entryFromDatabase(
+              ByteString.wrap(data.getData()),
+              ec.getRootContainer().getCompressedSchema());
 
           // Check that the parent entry exists.
           DN parentDN = ec.getParentWithinBase(entry.getDN());
@@ -671,8 +674,9 @@
         try
         {
           EntryID entryID = new EntryID(key);
-          Entry entry = JebFormat.entryFromDatabase(data.getData(),
-                             ec.getRootContainer().getCompressedSchema());
+          Entry entry = ID2Entry.entryFromDatabase(
+              ByteString.wrap(data.getData()),
+              ec.getRootContainer().getCompressedSchema());
 
           // Check that the parent entry exists.
           DN parentDN = ec.getParentWithinBase(entry.getDN());
@@ -809,8 +813,9 @@
         try
         {
           EntryID entryID = new EntryID(key);
-          Entry entry = JebFormat.entryFromDatabase(data.getData(),
-                             ec.getRootContainer().getCompressedSchema());
+          Entry entry = ID2Entry.entryFromDatabase(
+              ByteString.wrap(data.getData()),
+              ec.getRootContainer().getCompressedSchema());
 
           // Insert into attribute indexType.
           if(index.addEntry(txn, entryID, entry))
@@ -887,8 +892,9 @@
         try
         {
           EntryID entryID = new EntryID(key);
-          Entry entry = JebFormat.entryFromDatabase(data.getData(),
-                             ec.getRootContainer().getCompressedSchema());
+          Entry entry = ID2Entry.entryFromDatabase(
+              ByteString.wrap(data.getData()),
+              ec.getRootContainer().getCompressedSchema());
 
           // Insert into attribute indexType.
           if(vlvIndex.addEntry(txn, entryID, entry))
@@ -973,8 +979,9 @@
         try
         {
           EntryID entryID = new EntryID(key);
-          Entry entry = JebFormat.entryFromDatabase(data.getData(),
-                             ec.getRootContainer().getCompressedSchema());
+          Entry entry = ID2Entry.entryFromDatabase(
+              ByteString.wrap(data.getData()),
+              ec.getRootContainer().getCompressedSchema());
 
           // Insert into attribute indexType.
           if(index.addEntry(txn, entryID, entry))
diff --git a/opends/src/server/org/opends/server/backends/jeb/JECompressedSchema.java b/opends/src/server/org/opends/server/backends/jeb/JECompressedSchema.java
index f480da1..af4c396 100644
--- a/opends/src/server/org/opends/server/backends/jeb/JECompressedSchema.java
+++ b/opends/src/server/org/opends/server/backends/jeb/JECompressedSchema.java
@@ -32,31 +32,20 @@
 import static org.opends.server.loggers.debug.DebugLogger.*;
 import static org.opends.server.util.StaticUtils.*;
 
-import java.util.ArrayList;
 import java.util.LinkedHashMap;
 import java.util.LinkedHashSet;
 import java.util.Map;
 import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.atomic.AtomicInteger;
+import java.io.IOException;
 
 import org.opends.messages.Message;
 import org.opends.server.api.CompressedSchema;
 import org.opends.server.core.DirectoryServer;
 import org.opends.server.loggers.debug.DebugTracer;
-import org.opends.server.protocols.asn1.ASN1Element;
-import org.opends.server.protocols.asn1.ASN1Exception;
-import org.opends.server.protocols.asn1.ASN1OctetString;
-import org.opends.server.protocols.asn1.ASN1Sequence;
-import org.opends.server.types.Attribute;
-import org.opends.server.types.AttributeBuilder;
-import org.opends.server.types.AttributeType;
-import org.opends.server.types.AttributeValue;
-import org.opends.server.types.Attributes;
-import org.opends.server.types.ByteArray;
-import org.opends.server.types.DebugLogLevel;
-import org.opends.server.types.DirectoryException;
-import org.opends.server.types.ObjectClass;
+import org.opends.server.protocols.asn1.*;
+import org.opends.server.types.*;
 
 import com.sleepycat.je.Cursor;
 import com.sleepycat.je.Database;
@@ -107,21 +96,22 @@
   private AtomicInteger ocCounter;
 
   // The map between encoded representations and attribute types.
-  private ConcurrentHashMap<ByteArray,AttributeType> atDecodeMap;
+  private ConcurrentHashMap<ByteSequence,AttributeType> atDecodeMap;
 
   // The map between encoded representations and attribute options.
-  private ConcurrentHashMap<ByteArray,Set<String>> aoDecodeMap;
+  private ConcurrentHashMap<ByteSequence,Set<String>> aoDecodeMap;
 
   // The map between encoded representations and object class sets.
-  private ConcurrentHashMap<ByteArray,Map<ObjectClass,String>> ocDecodeMap;
+  private ConcurrentHashMap<ByteSequence,Map<ObjectClass,String>> ocDecodeMap;
 
   // The map between attribute descriptions and their encoded
   // representations.
-  private ConcurrentHashMap<AttributeType,
-               ConcurrentHashMap<Set<String>,ByteArray>> adEncodeMap;
+  private final ConcurrentHashMap<AttributeType,
+                ConcurrentHashMap<Set<String>, ByteSequence>> adEncodeMap;
 
   // The map between object class sets and encoded representations.
-  private ConcurrentHashMap<Map<ObjectClass,String>,ByteArray> ocEncodeMap;
+  private final ConcurrentHashMap<Map<ObjectClass,String>,
+      ByteSequence> ocEncodeMap;
 
   // The compressed attribute description schema database.
   private Database adDatabase;
@@ -132,6 +122,9 @@
   // The environment in which the databases are held.
   private Environment environment;
 
+  private final ByteStringBuilder storeWriterBuffer;
+  private final ASN1Writer storeWriter;
+
 
 
   /**
@@ -149,17 +142,21 @@
   {
     this.environment = environment;
 
-    atDecodeMap = new ConcurrentHashMap<ByteArray,AttributeType>();
-    aoDecodeMap = new ConcurrentHashMap<ByteArray,Set<String>>();
-    ocDecodeMap = new ConcurrentHashMap<ByteArray,Map<ObjectClass,String>>();
+    atDecodeMap = new ConcurrentHashMap<ByteSequence,AttributeType>();
+    aoDecodeMap = new ConcurrentHashMap<ByteSequence,Set<String>>();
+    ocDecodeMap = new ConcurrentHashMap<ByteSequence,Map<ObjectClass,String>>();
     adEncodeMap =
          new ConcurrentHashMap<AttributeType,
-                  ConcurrentHashMap<Set<String>,ByteArray>>();
-    ocEncodeMap = new ConcurrentHashMap<Map<ObjectClass,String>,ByteArray>();
+                  ConcurrentHashMap<Set<String>, ByteSequence>>();
+    ocEncodeMap = new ConcurrentHashMap<Map<ObjectClass,String>,
+        ByteSequence>();
 
     adCounter = new AtomicInteger(1);
     ocCounter = new AtomicInteger(1);
 
+    storeWriterBuffer = new ByteStringBuilder();
+    storeWriter = ASN1.getWriter(storeWriterBuffer);
+
     load();
   }
 
@@ -211,21 +208,23 @@
                                                  LockMode.READ_UNCOMMITTED);
       while (status == OperationStatus.SUCCESS)
       {
-        ByteArray token = new ByteArray(keyEntry.getData());
-        highestToken = Math.max(highestToken, decodeInt(token.array()));
+        byte[] tokenBytes = keyEntry.getData();
+        ByteString token = ByteString.wrap(tokenBytes);
+        highestToken = Math.max(highestToken, decodeInt(tokenBytes));
 
-        ArrayList<ASN1Element> elements =
-             ASN1Sequence.decodeAsSequence(valueEntry.getData()).elements();
+        ASN1Reader reader =
+            ASN1.getReader(valueEntry.getData());
+        reader.readStartSequence();
         LinkedHashMap<ObjectClass,String> ocMap =
-             new LinkedHashMap<ObjectClass,String>(elements.size());
-        for (int i=0; i < elements.size(); i++)
+             new LinkedHashMap<ObjectClass,String>();
+        while(reader.hasNextElement())
         {
-          ASN1OctetString os = elements.get(i).decodeAsOctetString();
-          String ocName = os.stringValue();
+          String ocName = reader.readOctetStringAsString();
           String lowerName = toLowerCase(ocName);
           ObjectClass oc = DirectoryServer.getObjectClass(lowerName, true);
           ocMap.put(oc, ocName);
         }
+        reader.readEndSequence();
 
         ocEncodeMap.put(ocMap, token);
         ocDecodeMap.put(token, ocMap);
@@ -266,34 +265,34 @@
                                                  LockMode.READ_UNCOMMITTED);
       while (status == OperationStatus.SUCCESS)
       {
-        ByteArray token = new ByteArray(keyEntry.getData());
-        highestToken = Math.max(highestToken, decodeInt(token.array()));
+        byte[] tokenBytes = keyEntry.getData();
+        ByteString token = ByteString.wrap(tokenBytes);
+        highestToken = Math.max(highestToken, decodeInt(tokenBytes));
 
-        ArrayList<ASN1Element> elements =
-             ASN1Sequence.decodeAsSequence(valueEntry.getData()).elements();
-
-        ASN1OctetString os = elements.get(0).decodeAsOctetString();
-        String attrName = os.stringValue();
+        ASN1Reader reader =
+            ASN1.getReader(valueEntry.getData());
+        reader.readStartSequence();
+        String attrName = reader.readOctetStringAsString();
         String lowerName = toLowerCase(attrName);
         AttributeType attrType =
-             DirectoryServer.getAttributeType(lowerName, true);
+            DirectoryServer.getAttributeType(lowerName, true);
 
         LinkedHashSet<String> options =
-             new LinkedHashSet<String>(elements.size()-1);
-        for (int i=1; i < elements.size(); i++)
+            new LinkedHashSet<String>();
+        while(reader.hasNextElement())
         {
-          os = elements.get(i).decodeAsOctetString();
-          options.add(os.stringValue());
+          options.add(reader.readOctetStringAsString());
         }
+        reader.readEndSequence();
 
         atDecodeMap.put(token, attrType);
         aoDecodeMap.put(token, options);
 
-        ConcurrentHashMap<Set<String>,ByteArray> map =
-             adEncodeMap.get(attrType);
+        ConcurrentHashMap<Set<String>, ByteSequence> map = adEncodeMap
+            .get(attrType);
         if (map == null)
         {
-          map = new ConcurrentHashMap<Set<String>,ByteArray>(1);
+          map = new ConcurrentHashMap<Set<String>, ByteSequence>(1);
           map.put(options, token);
           adEncodeMap.put(attrType, map);
         }
@@ -359,8 +358,8 @@
     atDecodeMap = null;
     aoDecodeMap = null;
     ocDecodeMap = null;
-    adEncodeMap = null;
-    ocEncodeMap = null;
+    //adEncodeMap = null;
+    //ocEncodeMap = null;
     adCounter   = null;
     ocCounter   = null;
   }
@@ -371,58 +370,45 @@
    * {@inheritDoc}
    */
   @Override()
-  public byte[] encodeObjectClasses(Map<ObjectClass,String> objectClasses)
+  public void encodeObjectClasses(ByteStringBuilder entryBuffer,
+                                  Map<ObjectClass,String> objectClasses)
          throws DirectoryException
   {
-    ByteArray encodedClasses = ocEncodeMap.get(objectClasses);
+    ByteSequence encodedClasses = ocEncodeMap.get(objectClasses);
     if (encodedClasses == null)
     {
       synchronized (ocEncodeMap)
       {
         int setValue = ocCounter.getAndIncrement();
         byte[] tokenArray = encodeInt(setValue);
+        encodedClasses = ByteString.wrap(tokenArray);
 
-        ArrayList<ASN1Element> elements =
-             new ArrayList<ASN1Element>(objectClasses.size());
-        for (String ocName : objectClasses.values())
-        {
-          elements.add(new ASN1OctetString(ocName));
-        }
-
-        byte[] encodedOCs = new ASN1Sequence(elements).encode();
-        store(ocDatabase, tokenArray, encodedOCs);
-
-        encodedClasses = new ByteArray(tokenArray);
+        storeObjectClass(tokenArray, objectClasses);
         ocEncodeMap.put(objectClasses, encodedClasses);
         ocDecodeMap.put(encodedClasses, objectClasses);
-
-        return tokenArray;
       }
     }
-    else
-    {
-      return encodedClasses.array();
-    }
+
+    entryBuffer.appendBERLength(encodedClasses.length());
+    encodedClasses.copyTo(entryBuffer);
   }
 
-
-
   /**
    * {@inheritDoc}
    */
   @Override()
   public Map<ObjectClass,String> decodeObjectClasses(
-                                      byte[] encodedObjectClasses)
-         throws DirectoryException
+      ByteSequenceReader entryBufferReader) throws DirectoryException
   {
-    ByteArray byteArray = new ByteArray(encodedObjectClasses);
+    int tokenLength = entryBufferReader.getBERLength();
+    ByteSequence byteArray = entryBufferReader.getByteSequence(tokenLength);
     Map<ObjectClass,String> ocMap = ocDecodeMap.get(byteArray);
     if (ocMap == null)
     {
-      Message message = ERR_JEB_COMPSCHEMA_UNKNOWN_OC_TOKEN.get(
-                             bytesToHex(encodedObjectClasses));
+      Message message = ERR_JEB_COMPSCHEMA_UNKNOWN_OC_TOKEN.get(byteArray
+          .toByteString().toHex());
       throw new DirectoryException(DirectoryServer.getServerErrorResultCode(),
-                                   message);
+          message);
     }
     else
     {
@@ -430,52 +416,90 @@
     }
   }
 
+  private void storeObjectClass(byte[] token,
+                                Map<ObjectClass,String> objectClasses)
+      throws DirectoryException
+  {
+    synchronized(storeWriter)
+    {
+      try
+      {
+        storeWriterBuffer.clear();
+        storeWriter.writeStartSequence();
+        for (String ocName : objectClasses.values())
+        {
+          storeWriter.writeOctetString(ocName);
+        }
+        storeWriter.writeEndSequence();
+        store(ocDatabase, token, storeWriterBuffer);
+      }
+      catch(IOException ioe)
+      {
+        // TODO: Shouldn't happen but should log a message
+      }
+    }
+  }
 
+  private void storeAttribute(byte[] token,
+                              AttributeType attrType, Set<String> options)
+      throws DirectoryException
+  {
+    synchronized(storeWriter)
+    {
+      try
+      {
+        storeWriterBuffer.clear();
+        storeWriter.writeStartSequence();
+        storeWriter.writeOctetString(attrType.getNameOrOID());
+        for (String option : options)
+        {
+          storeWriter.writeOctetString(option);
+        }
+        storeWriter.writeEndSequence();
+        store(adDatabase, token, storeWriterBuffer);
+      }
+      catch(IOException ioe)
+      {
+        // TODO: Shouldn't happen but should log a message
+      }
+    }
+  }
 
   /**
    * {@inheritDoc}
    */
   @Override()
-  public byte[] encodeAttribute(Attribute attribute)
-         throws DirectoryException
+  public void encodeAttribute(ByteStringBuilder entryBuffer,
+                              Attribute attribute) throws DirectoryException
   {
     AttributeType type = attribute.getAttributeType();
     Set<String> options = attribute.getOptions();
 
-    ConcurrentHashMap<Set<String>,ByteArray> map =
-         adEncodeMap.get(type);
+    ConcurrentHashMap<Set<String>, ByteSequence> map = adEncodeMap.get(type);
     if (map == null)
     {
       byte[] tokenArray;
+      ByteString byteString;
       synchronized (adEncodeMap)
       {
-        map = new ConcurrentHashMap<Set<String>,ByteArray>(1);
+        map = new ConcurrentHashMap<Set<String>, ByteSequence>(1);
 
         int intValue = adCounter.getAndIncrement();
         tokenArray = encodeInt(intValue);
-        ByteArray byteArray = new ByteArray(tokenArray);
-        map.put(options,byteArray);
+        byteString = ByteString.wrap(tokenArray);
+        map.put(options,byteString);
 
-        ArrayList<ASN1Element> elements =
-             new ArrayList<ASN1Element>(options.size()+1);
-        elements.add(new ASN1OctetString(attribute.getName()));
-        for (String option : options)
-        {
-          elements.add(new ASN1OctetString(option));
-        }
-        byte[] encodedValue = new ASN1Sequence(elements).encode();
-        store(adDatabase, tokenArray, encodedValue);
-
+        storeAttribute(tokenArray, type, options);
         adEncodeMap.put(type, map);
-        atDecodeMap.put(byteArray, type);
-        aoDecodeMap.put(byteArray, options);
+        atDecodeMap.put(byteString, type);
+        aoDecodeMap.put(byteString, options);
       }
 
-      return encodeAttribute(tokenArray, attribute);
+      encodeAttribute(entryBuffer, byteString, attribute);
     }
     else
     {
-      ByteArray byteArray = map.get(options);
+      ByteSequence byteArray = map.get(options);
       if (byteArray == null)
       {
         byte[] tokenArray;
@@ -483,29 +507,16 @@
         {
           int intValue = adCounter.getAndIncrement();
           tokenArray = encodeInt(intValue);
-          byteArray = new ByteArray(tokenArray);
+          byteArray = ByteString.wrap(tokenArray);
           map.put(options,byteArray);
 
-          ArrayList<ASN1Element> elements =
-               new ArrayList<ASN1Element>(options.size()+1);
-          elements.add(new ASN1OctetString(attribute.getName()));
-          for (String option : options)
-          {
-            elements.add(new ASN1OctetString(option));
-          }
-          byte[] encodedValue = new ASN1Sequence(elements).encode();
-          store(adDatabase, tokenArray, encodedValue);
-
+          storeAttribute(tokenArray, type, options);
           atDecodeMap.put(byteArray, type);
           aoDecodeMap.put(byteArray, options);
         }
+      }
 
-        return encodeAttribute(tokenArray, attribute);
-      }
-      else
-      {
-        return encodeAttribute(byteArray.array(), attribute);
-      }
+      encodeAttribute(entryBuffer, byteArray, attribute);
     }
   }
 
@@ -515,126 +526,70 @@
    * Encodes the information in the provided attribute to a byte
    * array.
    *
+   * @param  buffer     The byte buffer to encode the attribute into.
    * @param  adArray    The byte array that is a placeholder for the
    *                    attribute type and set of options.
    * @param  attribute  The attribute to be encoded.
-   *
-   * @return  An encoded representation of the provided attribute.
    */
-  private byte[] encodeAttribute(byte[] adArray, Attribute attribute)
+  private void encodeAttribute(ByteStringBuilder buffer, ByteSequence adArray,
+                                 Attribute attribute)
   {
-    int totalValuesLength = 0;
-    byte[][] subArrays = new  byte[attribute.size()*2][];
-    int pos = 0;
-    for (AttributeValue v : attribute)
+    // Write the length of the adArray followed by the adArray.
+    buffer.appendBERLength(adArray.length());
+    adArray.copyTo(buffer);
+
+    // Write the number of attributes
+    buffer.appendBERLength(attribute.size());
+
+    // Write the attribute values as length / value pairs
+    for(AttributeValue v : attribute)
     {
-      byte[] vBytes = v.getValueBytes();
-      byte[] lBytes = ASN1Element.encodeLength(vBytes.length);
-
-      subArrays[pos++] = lBytes;
-      subArrays[pos++] = vBytes;
-
-      totalValuesLength += lBytes.length + vBytes.length;
+      buffer.appendBERLength(v.getValue().length());
+      buffer.append(v.getValue());
     }
-
-    byte[] adArrayLength = ASN1Element.encodeLength(adArray.length);
-    byte[] countBytes = ASN1Element.encodeLength(attribute.size());
-    int totalLength = adArrayLength.length + adArray.length +
-                      countBytes.length + totalValuesLength;
-    byte[] array = new byte[totalLength];
-
-    System.arraycopy(adArrayLength, 0, array, 0,
-                     adArrayLength.length);
-    pos = adArrayLength.length;
-    System.arraycopy(adArray, 0, array, pos, adArray.length);
-    pos += adArray.length;
-    System.arraycopy(countBytes, 0, array, pos, countBytes.length);
-    pos += countBytes.length;
-
-    for (int i=0; i < subArrays.length; i++)
-    {
-      System.arraycopy(subArrays[i], 0, array, pos,
-                       subArrays[i].length);
-      pos += subArrays[i].length;
-    }
-
-    return array;
   }
 
-
-
   /**
    * {@inheritDoc}
    */
   @Override()
-  public Attribute decodeAttribute(byte[] encodedEntry, int startPos,
-                                   int length)
+  public Attribute decodeAttribute(ByteSequenceReader entryBufferReader)
          throws DirectoryException
   {
     // Figure out how many bytes are in the token that is the placeholder for
     // the attribute description.
-    int pos = startPos;
-    int adArrayLength = encodedEntry[pos] & 0x7F;
-    if (adArrayLength != encodedEntry[pos++])
-    {
-      int numLengthBytes = adArrayLength;
-      adArrayLength = 0;
-      for (int i=0; i < numLengthBytes; i++, pos++)
-      {
-        adArrayLength = (adArrayLength << 8) | (encodedEntry[pos] & 0xFF);
-      }
-    }
+    int adArrayLength = entryBufferReader.getBERLength();
 
 
     // Get the attribute description token and make sure it resolves to an
     // attribute type and option set.
-    ByteArray adArray = new ByteArray(new byte[adArrayLength]);
-    System.arraycopy(encodedEntry, pos, adArray.array(), 0, adArrayLength);
-    pos += adArrayLength;
+    ByteSequence adArray = entryBufferReader.getByteSequence(adArrayLength);
+
     AttributeType attrType = atDecodeMap.get(adArray);
     Set<String> options = aoDecodeMap.get(adArray);
     if ((attrType == null) || (options == null))
     {
-      Message message = ERR_JEB_COMPSCHEMA_UNRECOGNIZED_AD_TOKEN.get(
-                             bytesToHex(adArray.array()));
+      Message message = ERR_JEB_COMPSCHEMA_UNRECOGNIZED_AD_TOKEN.get(adArray
+          .toByteString().toHex());
       throw new DirectoryException(DirectoryServer.getServerErrorResultCode(),
-                                   message);
+          message);
     }
 
 
     // Determine the number of values for the attribute.
-    int numValues = encodedEntry[pos] & 0x7F;
-    if (numValues != encodedEntry[pos++])
-    {
-      int numValuesBytes = numValues;
-      numValues = 0;
-      for (int i=0; i < numValuesBytes; i++, pos++)
-      {
-        numValues = (numValues << 8) | (encodedEntry[pos] & 0xFF);
-      }
-    }
+    int numValues = entryBufferReader.getBERLength();
 
 
     // For the common case of a single value with no options, generate
     // less garbage.
     if (numValues == 1 && options.isEmpty())
     {
-      int valueLength = encodedEntry[pos] & 0x7F;
-      if (valueLength != encodedEntry[pos++])
-      {
-        int valueLengthBytes = valueLength;
-        valueLength = 0;
-        for (int j = 0; j < valueLengthBytes; j++, pos++)
-        {
-          valueLength = (valueLength << 8) | (encodedEntry[pos] & 0xFF);
-        }
-      }
+      int valueLength = entryBufferReader.getBERLength();
 
-      byte[] valueBytes = new byte[valueLength];
-      System.arraycopy(encodedEntry, pos, valueBytes, 0, valueLength);
-
-      return Attributes.create(attrType, new AttributeValue(attrType,
-          new ASN1OctetString(valueBytes)));
+      ByteString valueBytes =
+          entryBufferReader.getByteSequence(valueLength).toByteString();
+      return Attributes.create(attrType,
+          AttributeValues.create(attrType, valueBytes));
     }
     else
     {
@@ -644,30 +599,18 @@
       builder.setInitialCapacity(numValues);
       for (int i = 0; i < numValues; i++)
       {
-        int valueLength = encodedEntry[pos] & 0x7F;
-        if (valueLength != encodedEntry[pos++])
-        {
-          int valueLengthBytes = valueLength;
-          valueLength = 0;
-          for (int j = 0; j < valueLengthBytes; j++, pos++)
-          {
-            valueLength = (valueLength << 8) | (encodedEntry[pos] & 0xFF);
-          }
-        }
+        int valueLength = entryBufferReader.getBERLength();
 
-        byte[] valueBytes = new byte[valueLength];
-        System.arraycopy(encodedEntry, pos, valueBytes, 0, valueLength);
-        pos += valueLength;
-        builder.add(new AttributeValue(attrType,
-            new ASN1OctetString(valueBytes)));
+        ByteString valueBytes =
+            entryBufferReader.getByteSequence(valueLength).toByteString();
+        builder.add(AttributeValues.create(attrType,
+            valueBytes));
       }
 
       return builder.toAttribute();
     }
   }
 
-
-
   /**
    * Stores the provided key-value pair in the specified database container.
    *
@@ -678,12 +621,14 @@
    * @throws  DirectoryException  If a problem occurs while attempting to store
    *                              the data.
    */
-  private void store(Database database, byte[] keyBytes, byte[] valueBytes)
+  private void store(Database database, byte[] keyBytes,
+                     ByteStringBuilder valueBytes)
           throws DirectoryException
   {
     boolean successful = false;
     DatabaseEntry keyEntry   = new DatabaseEntry(keyBytes);
-    DatabaseEntry valueEntry = new DatabaseEntry(valueBytes);
+    DatabaseEntry valueEntry = new DatabaseEntry(valueBytes.getBackingArray(),
+        0, valueBytes.length());
 
     for (int i=0; i < 3; i++)
     {
diff --git a/opends/src/server/org/opends/server/backends/jeb/JEExtensibleIndexer.java b/opends/src/server/org/opends/server/backends/jeb/JEExtensibleIndexer.java
index 6e2e9d7..35ca4e7 100644
--- a/opends/src/server/org/opends/server/backends/jeb/JEExtensibleIndexer.java
+++ b/opends/src/server/org/opends/server/backends/jeb/JEExtensibleIndexer.java
@@ -73,13 +73,6 @@
 
 
   /**
-   * The extensible matching rule which needs to be indexed.
-   */
-  private final ExtensibleMatchingRule matchingRule;
-
-
-
-  /**
    * Creates a new extensible indexer for JE backend.
    *
    * @param attributeType The attribute type for which an indexer is
@@ -92,7 +85,6 @@
           ExtensibleIndexer extensibleIndexer)
   {
     this.attributeType = attributeType;
-    this.matchingRule = matchingRule;
     this.extensibleIndexer = extensibleIndexer;
   }
 
@@ -118,6 +110,7 @@
    *
    * @return A byte array comparator.
    */
+  @Override
   public Comparator<byte[]> getComparator()
   {
     return comparator;
diff --git a/opends/src/server/org/opends/server/backends/jeb/JebFormat.java b/opends/src/server/org/opends/server/backends/jeb/JebFormat.java
index 7a63e5d..c9f375d 100644
--- a/opends/src/server/org/opends/server/backends/jeb/JebFormat.java
+++ b/opends/src/server/org/opends/server/backends/jeb/JebFormat.java
@@ -26,23 +26,9 @@
  */
 package org.opends.server.backends.jeb;
 
-
-import org.opends.server.api.CompressedSchema;
-import org.opends.server.core.DirectoryServer;
-import org.opends.server.protocols.asn1.ASN1Element;
-import org.opends.server.protocols.asn1.ASN1Exception;
-import org.opends.server.protocols.asn1.ASN1Integer;
-import org.opends.server.protocols.asn1.ASN1OctetString;
-import org.opends.server.protocols.asn1.ASN1Sequence;
-import org.opends.server.types.*;
-
 import static org.opends.server.loggers.debug.DebugLogger.*;
 import org.opends.server.loggers.debug.DebugTracer;
 
-import java.util.ArrayList;
-import java.util.List;
-import java.util.zip.DataFormatException;
-
 /**
  * Handles the disk representation of LDAP data.
  */
@@ -70,219 +56,6 @@
   public static final byte TAG_DIRECTORY_SERVER_ENTRY = 0x61;
 
   /**
-   * Decode a DatabaseEntry.  The encoded bytes may be compressed and/or
-   * encrypted.
-   *
-   * @param bytes The encoded bytes of a DatabaseEntry.
-   * @return The decoded bytes.
-   * @throws ASN1Exception If the data is not in the expected ASN.1 encoding
-   * format.
-   * @throws DataFormatException If an error occurs while trying to decompress
-   * compressed data.
-   */
-  static public byte[] decodeDatabaseEntry(byte[] bytes)
-       throws ASN1Exception,DataFormatException
-  {
-    // FIXME: This array copy could be very costly on performance. We need to
-    // FIXME: find a faster way to implement this versioning feature.
-    // Remove version number from the encoded bytes
-    byte[] encodedBytes = new byte[bytes.length - 1];
-    System.arraycopy(bytes, 1, encodedBytes, 0, encodedBytes.length);
-
-    // Decode the sequence.
-    List<ASN1Element> elements;
-    elements = ASN1Sequence.decodeAsSequence(encodedBytes).elements();
-
-    // Decode the uncompressed size.
-    int uncompressedSize;
-    uncompressedSize = elements.get(0).decodeAsInteger().intValue();
-
-    // Decode the data bytes.
-    byte[] dataBytes;
-    dataBytes = elements.get(1).decodeAsOctetString().value();
-
-    byte[] uncompressedBytes;
-    if (uncompressedSize == 0)
-    {
-      // The bytes are not compressed.
-      uncompressedBytes = dataBytes;
-    }
-    else
-    {
-      // The bytes are compressed.
-      CryptoManager cryptoManager = DirectoryServer.getCryptoManager();
-      uncompressedBytes = new byte[uncompressedSize];
-      /* int len = */ cryptoManager.uncompress(dataBytes, uncompressedBytes);
-    }
-
-    return uncompressedBytes;
-  }
-
-  /**
-   * Decodes an entry from its database representation.
-   * <p>
-   * An entry on disk is ASN1 encoded in this format:
-   *
-   * <pre>
-   * DatabaseEntry ::= [APPLICATION 0] IMPLICIT SEQUENCE {
-   *  uncompressedSize      INTEGER,      -- A zero value means not compressed.
-   *  dataBytes             OCTET STRING  -- Optionally compressed encoding of
-   *                                         the data bytes.
-   * }
-   *
-   * ID2EntryValue ::= DatabaseEntry
-   *  -- Where dataBytes contains an encoding of DirectoryServerEntry.
-   *
-   * DirectoryServerEntry ::= [APPLICATION 1] IMPLICIT SEQUENCE {
-   *  dn                      LDAPDN,
-   *  objectClasses           SET OF LDAPString,
-   *  userAttributes          AttributeList,
-   *  operationalAttributes   AttributeList
-   * }
-   * </pre>
-   *
-   * @param bytes A byte array containing the encoded database value.
-   * @param compressedSchema The compressed schema manager to use when decoding.
-   * @return The decoded entry.
-   * @throws ASN1Exception If the data is not in the expected ASN.1 encoding
-   * format.
-   * @throws LDAPException If the data is not in the expected ASN.1 encoding
-   * format.
-   * @throws DataFormatException If an error occurs while trying to decompress
-   * compressed data.
-   * @throws DirectoryException If a Directory Server error occurs.
-   */
-  static public Entry entryFromDatabase(byte[] bytes,
-                                        CompressedSchema compressedSchema)
-       throws DirectoryException,ASN1Exception,LDAPException,DataFormatException
-  {
-    byte[] uncompressedBytes = decodeDatabaseEntry(bytes);
-    return decodeDirectoryServerEntry(uncompressedBytes, compressedSchema);
-  }
-
-  /**
-   * Decode an entry from a ASN1 encoded DirectoryServerEntry.
-   *
-   * @param bytes A byte array containing the encoding of DirectoryServerEntry.
-   * @param compressedSchema The compressed schema manager to use when decoding.
-   * @return The decoded entry.
-   * @throws ASN1Exception If the data is not in the expected ASN.1 encoding
-   * format.
-   * @throws LDAPException If the data is not in the expected ASN.1 encoding
-   * format.
-   * @throws DirectoryException If a Directory Server error occurs.
-   */
-  static private Entry decodeDirectoryServerEntry(byte[] bytes,
-                            CompressedSchema compressedSchema)
-       throws DirectoryException,ASN1Exception,LDAPException
-  {
-    return Entry.decode(bytes, compressedSchema);
-  }
-
-  /**
-   * Encodes a DatabaseEntry.  The encoded bytes may be compressed and/or
-   * encrypted.
-   *
-   * @param bytes The bytes to encode.
-   * @param dataConfig Compression and cryptographic options.
-   * @return A byte array containing the encoded DatabaseEntry.
-   */
-  static public byte[] encodeDatabaseEntry(byte[] bytes, DataConfig dataConfig)
-  {
-    int uncompressedSize = 0;
-
-    // Do optional compression.
-    CryptoManager cryptoManager = DirectoryServer.getCryptoManager();
-    if (dataConfig.isCompressed() && cryptoManager != null)
-    {
-      byte[] compressedBuffer = new byte[bytes.length];
-      int compressedSize = cryptoManager.compress(bytes,
-                                                  compressedBuffer);
-      if (compressedSize != -1)
-      {
-        // Compression was successful.
-        uncompressedSize = bytes.length;
-        bytes = new byte[compressedSize];
-        System.arraycopy(compressedBuffer, 0, bytes, 0, compressedSize);
-
-        if(debugEnabled())
-        {
-          TRACER.debugInfo("Compression %d/%d%n",
-                    compressedSize, uncompressedSize);
-        }
-
-      }
-
-    }
-
-    // Encode the DatabaseEntry.
-    ArrayList<ASN1Element> elements = new ArrayList<ASN1Element>(2);
-    elements.add(new ASN1Integer(uncompressedSize));
-    elements.add(new ASN1OctetString(bytes));
-    byte[] asn1Sequence =
-        new ASN1Sequence(TAG_DATABASE_ENTRY, elements).encode();
-
-    // FIXME: This array copy could be very costly on performance. We need to
-    // FIXME: find a faster way to implement this versioning feature.
-    // Prefix version number to the encoded bytes
-    byte[] encodedBytes = new byte[asn1Sequence.length + 1];
-    encodedBytes[0] = FORMAT_VERSION;
-    System.arraycopy(asn1Sequence, 0, encodedBytes, 1, asn1Sequence.length);
-
-    return encodedBytes;
-  }
-
-  /**
-   * Encodes an entry to the raw database format, with optional compression.
-   *
-   * @param entry The entry to encode.
-   * @param dataConfig Compression and cryptographic options.
-   * @return A byte array containing the encoded database value.
-   *
-   * @throws  DirectoryException  If a problem occurs while attempting to encode
-   *                              the entry.
-   */
-  static public byte[] entryToDatabase(Entry entry, DataConfig dataConfig)
-         throws DirectoryException
-  {
-    byte[] uncompressedBytes = encodeDirectoryServerEntry(entry,
-                                             dataConfig.getEntryEncodeConfig());
-    return encodeDatabaseEntry(uncompressedBytes, dataConfig);
-  }
-
-  /**
-   * Encodes an entry to the raw database format, without compression.
-   *
-   * @param entry The entry to encode.
-   * @return A byte array containing the encoded database value.
-   *
-   * @throws  DirectoryException  If a problem occurs while attempting to encode
-   *                              the entry.
-   */
-  static public byte[] entryToDatabase(Entry entry)
-         throws DirectoryException
-  {
-    return entryToDatabase(entry, new DataConfig(false, false, null));
-  }
-
-  /**
-   * Encode a ASN1 DirectoryServerEntry.
-   *
-   * @param entry The entry to encode.
-   * @encodeConfig The configuration to use when encoding the entry.
-   * @return A byte array containing the encoded DirectoryServerEntry.
-   *
-   * @throws  DirectoryException  If a problem occurs while attempting to encode
-   *                              the entry.
-   */
-  static private byte[] encodeDirectoryServerEntry(Entry entry,
-                                                 EntryEncodeConfig encodeConfig)
-         throws DirectoryException
-  {
-    return entry.encode(encodeConfig);
-  }
-
-  /**
    * Decode an entry ID value from its database representation. Note that
    * this method will throw an ArrayIndexOutOfBoundsException if the bytes
    * array length is less than 8.
@@ -454,16 +227,4 @@
 
     return bytes;
   }
-
-   /**
-   * Get the version number of the DatabaseEntry.
-   *
-   * @param bytes The encoded bytes of a DatabaseEntry.
-   * @return The version number.
-   */
-  public static byte getEntryVersion(byte[] bytes)
-  {
-    return bytes[0];
-  }
-
 }
diff --git a/opends/src/server/org/opends/server/backends/jeb/OctetStringKeyComparator.java b/opends/src/server/org/opends/server/backends/jeb/OctetStringKeyComparator.java
deleted file mode 100644
index f5410c3..0000000
--- a/opends/src/server/org/opends/server/backends/jeb/OctetStringKeyComparator.java
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * CDDL HEADER START
- *
- * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
- *
- * You can obtain a copy of the license at
- * trunk/opends/resource/legal-notices/OpenDS.LICENSE
- * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
- * See the License for the specific language governing permissions
- * and limitations under the License.
- *
- * When distributing Covered Code, include this CDDL HEADER in each
- * file and include the License file at
- * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
- * add the following below this CDDL 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.server.backends.jeb;
-
-import org.opends.server.protocols.asn1.ASN1OctetString;
-
-import java.util.Comparator;
-
-/**
- * This class implements a comparator for ASN1OctetString using
- * a byte array comparator supplied in its constructor.
- */
-public class OctetStringKeyComparator implements Comparator<ASN1OctetString>
-{
-  /**
-   * The byte array comparator used to compare the octet string values.
-   */
-  private Comparator<byte[]> comparator;
-
-  /**
-   * Create a new ASN1 octet string comparator.
-   * @param comparator The byte array comparator to be used to compare the
-   * octet string values.
-   */
-  public OctetStringKeyComparator(Comparator<byte[]> comparator)
-  {
-    this.comparator = comparator;
-  }
-
-  /**
-   * Compares its two arguments for order.  Returns a negative integer,
-   * zero, or a positive integer as the first argument is less than, equal
-   * to, or greater than the second.
-   *
-   * @param a the first object to be compared.
-   * @param b the second object to be compared.
-   * @return a negative integer, zero, or a positive integer as the
-   *         first argument is less than, equal to, or greater than the
-   *         second.
-   * @throws ClassCastException if the arguments' types prevent them from
-   *         being compared by this Comparator.
-   */
-  public int compare(ASN1OctetString a, ASN1OctetString b)
-       throws ClassCastException
-  {
-    return comparator.compare(a.value(), b.value());
-  }
-}
diff --git a/opends/src/server/org/opends/server/backends/jeb/OrderingIndexer.java b/opends/src/server/org/opends/server/backends/jeb/OrderingIndexer.java
index 6eed624..bb75ca9 100644
--- a/opends/src/server/org/opends/server/backends/jeb/OrderingIndexer.java
+++ b/opends/src/server/org/opends/server/backends/jeb/OrderingIndexer.java
@@ -170,7 +170,7 @@
         try
         {
           byte[] keyBytes = orderingRule.normalizeValue(value.getValue())
-              .value();
+              .toByteArray();
 
           keys.add(keyBytes);
         }
@@ -207,7 +207,7 @@
         try
         {
           byte[] keyBytes =
-               orderingRule.normalizeValue(value.getValue()).value();
+               orderingRule.normalizeValue(value.getValue()).toByteArray();
 
           Boolean cInsert = modifiedKeys.get(keyBytes);
           if(cInsert == null)
diff --git a/opends/src/server/org/opends/server/backends/jeb/SortValues.java b/opends/src/server/org/opends/server/backends/jeb/SortValues.java
index d3da96c..e1dc705 100644
--- a/opends/src/server/org/opends/server/backends/jeb/SortValues.java
+++ b/opends/src/server/org/opends/server/backends/jeb/SortValues.java
@@ -250,7 +250,7 @@
       }
       else
       {
-        buffer.append(values[i].getStringValue());
+        buffer.append(values[i].getValue().toString());
       }
     }
 
diff --git a/opends/src/server/org/opends/server/backends/jeb/SortValuesSet.java b/opends/src/server/org/opends/server/backends/jeb/SortValuesSet.java
index 98beeff..e3ec15a 100644
--- a/opends/src/server/org/opends/server/backends/jeb/SortValuesSet.java
+++ b/opends/src/server/org/opends/server/backends/jeb/SortValuesSet.java
@@ -27,15 +27,11 @@
 package org.opends.server.backends.jeb;
 
 import org.opends.server.types.*;
-import org.opends.server.protocols.asn1.ASN1OctetString;
-import org.opends.server.protocols.asn1.ASN1Element;
-
-import java.util.LinkedList;
 
 import com.sleepycat.je.DatabaseException;
 
 /**
- * This class representsa  partial sorted set of sorted entries in a VLV
+ * This class represents a partial sorted set of sorted entries in a VLV
  * index.
  */
 public class SortValuesSet
@@ -469,35 +465,23 @@
   private byte[] attributeValuesToDatabase(AttributeValue[] values)
       throws DirectoryException
   {
-    int totalValueBytes = 0;
-    LinkedList<byte[]> valueBytes = new LinkedList<byte[]>();
+    ByteStringBuilder builder = new ByteStringBuilder();
+
     for (AttributeValue v : values)
     {
-      byte[] vBytes;
       if(v == null)
       {
-        vBytes = new byte[0];
+        builder.appendBERLength(0);
       }
       else
       {
-        vBytes = v.getNormalizedValueBytes();
+        builder.appendBERLength(v.getNormalizedValue().length());
+        builder.append(v.getNormalizedValue());
       }
-      byte[] vLength = ASN1Element.encodeLength(vBytes.length);
-      valueBytes.add(vLength);
-      valueBytes.add(vBytes);
-      totalValueBytes += vLength.length + vBytes.length;
     }
+    builder.trimToSize();
 
-    byte[] attrBytes = new byte[totalValueBytes];
-
-    int pos = 0;
-    for (byte[] b : valueBytes)
-    {
-      System.arraycopy(b, 0, attrBytes, pos, b.length);
-      pos += b.length;
-    }
-
-    return attrBytes;
+    return builder.getBackingArray();
   }
 
   /**
@@ -570,8 +554,9 @@
          i < entryIDs.length * numValues;
          i++, j++)
     {
-      values[j] = new AttributeValue(sortKeys[j].getAttributeType(),
-                                     new ASN1OctetString(getValue(i)));
+      values[j] = AttributeValues.create(
+          sortKeys[j].getAttributeType(),
+          getValue(i));
     }
 
     return new SortValues(id, values, vlvIndex.sortOrder);
@@ -603,12 +588,12 @@
          i < (index + 1) * numValues;
          i++, j++)
     {
-      byte[] value = getValue(i);
+      ByteString value = getValue(i);
 
       if(value != null)
       {
-        values[j] = new AttributeValue(sortKeys[j].getAttributeType(),
-                                       new ASN1OctetString(value));
+        values[j] = AttributeValues.create(
+            sortKeys[j].getAttributeType(), value);
       }
     }
 
@@ -653,7 +638,7 @@
    * @throws DirectoryException If a Directory Server error occurs.
    * @throws DatabaseException If an error occurs in the JE database.
    */
-  public byte[] getValue(int index)
+  public ByteString getValue(int index)
       throws DatabaseException, DirectoryException
   {
     if(valuesBytesOffsets == null)
@@ -689,7 +674,7 @@
         {
           byte[] valueBytes = new byte[valueLength];
           System.arraycopy(valuesBytes, vBytesPos, valueBytes, 0, valueLength);
-          return valueBytes;
+          return ByteString.wrap(valueBytes);
         }
       }
       else
@@ -697,6 +682,6 @@
         vBytesPos += valueLength;
       }
     }
-    return new byte[0];
+    return ByteString.wrap(new byte[0]);
   }
 }
diff --git a/opends/src/server/org/opends/server/backends/jeb/SubstringIndexer.java b/opends/src/server/org/opends/server/backends/jeb/SubstringIndexer.java
index b75f9d4..d587a05 100644
--- a/opends/src/server/org/opends/server/backends/jeb/SubstringIndexer.java
+++ b/opends/src/server/org/opends/server/backends/jeb/SubstringIndexer.java
@@ -168,7 +168,7 @@
       {
         try
         {
-          byte[] normalizedBytes = value.getNormalizedValue().value();
+          byte[] normalizedBytes = value.getNormalizedValue().toByteArray();
 
           substringKeys(normalizedBytes, keys);
         }
@@ -245,7 +245,7 @@
       {
         try
         {
-          byte[] normalizedBytes = value.getNormalizedValue().value();
+          byte[] normalizedBytes = value.getNormalizedValue().toByteArray();
 
           substringKeys(normalizedBytes, modifiedKeys, insert);
         }
diff --git a/opends/src/server/org/opends/server/backends/jeb/VLVIndex.java b/opends/src/server/org/opends/server/backends/jeb/VLVIndex.java
index 0060666..16b856a 100644
--- a/opends/src/server/org/opends/server/backends/jeb/VLVIndex.java
+++ b/opends/src/server/org/opends/server/backends/jeb/VLVIndex.java
@@ -51,8 +51,6 @@
 import static org.opends.server.util.StaticUtils.stackTraceToSingleLineString;
 import org.opends.server.api.OrderingMatchingRule;
 import org.opends.server.config.ConfigException;
-import org.opends.server.protocols.asn1.ASN1Element;
-import org.opends.server.protocols.asn1.ASN1OctetString;
 import org.opends.server.protocols.ldap.LDAPResultCode;
 import org.opends.server.controls.VLVRequestControl;
 import org.opends.server.controls.VLVResponseControl;
@@ -1296,13 +1294,13 @@
 
         try
         {
-          byte[] vBytes = vlvRequest.getGreaterThanOrEqualAssertion().value();
-          byte[] vLength = ASN1Element.encodeLength(vBytes.length);
-          byte[] keyBytes = new byte[vBytes.length + vLength.length];
-          System.arraycopy(vLength, 0, keyBytes, 0, vLength.length);
-          System.arraycopy(vBytes, 0, keyBytes, vLength.length, vBytes.length);
+          ByteSequence vBytes = vlvRequest.getGreaterThanOrEqualAssertion();
+          ByteStringBuilder keyBytes =
+              new ByteStringBuilder(vBytes.length() + 4);
+          keyBytes.appendBERLength(vBytes.length());
+          vBytes.copyTo(keyBytes);
 
-          key.setData(keyBytes);
+          key.setData(keyBytes.getBackingArray(), 0, keyBytes.length());
           status = cursor.getSearchKeyRange(key, data, lockMode);
           if(status == OperationStatus.SUCCESS)
           {
@@ -1324,9 +1322,9 @@
                 new SortValuesSet(key.getData(), data.getData(), this);
             AttributeValue[] assertionValue = new AttributeValue[1];
             assertionValue[0] =
-                new AttributeValue(
+                AttributeValues.create(
                     sortOrder.getSortKeys()[0].getAttributeType(),
-                    vlvRequest.getGreaterThanOrEqualAssertion());
+                        vlvRequest.getGreaterThanOrEqualAssertion());
 
             int adjustedTargetOffset =
                 sortValuesSet.binarySearch(-1, assertionValue);
@@ -1582,39 +1580,25 @@
   byte[] encodeKey(long entryID, AttributeValue[] values)
       throws DirectoryException
   {
-    int totalValueBytes = 0;
-    LinkedList<byte[]> valueBytes = new LinkedList<byte[]>();
+    ByteStringBuilder builder = new ByteStringBuilder();
+
     for (AttributeValue v : values)
     {
       byte[] vBytes;
       if(v == null)
       {
-        vBytes = new byte[0];
+        builder.appendBERLength(0);
       }
       else
       {
-        vBytes = v.getNormalizedValueBytes();
+        builder.appendBERLength(v.getNormalizedValue().length());
+        builder.append(v.getNormalizedValue());
       }
-      byte[] vLength = ASN1Element.encodeLength(vBytes.length);
-      valueBytes.add(vLength);
-      valueBytes.add(vBytes);
-      totalValueBytes += vLength.length + vBytes.length;
     }
+    builder.append(entryID);
+    builder.trimToSize();
 
-    byte[] entryIDBytes =
-        JebFormat.entryIDToDatabase(entryID);
-    byte[] attrBytes = new byte[entryIDBytes.length + totalValueBytes];
-
-    int pos = 0;
-    for (byte[] b : valueBytes)
-    {
-      System.arraycopy(b, 0, attrBytes, pos, b.length);
-      pos += b.length;
-    }
-
-    System.arraycopy(entryIDBytes, 0, attrBytes, pos, entryIDBytes.length);
-
-    return attrBytes;
+    return builder.getBackingArray();
   }
 
   /**
@@ -1658,8 +1642,9 @@
         byte[] valueBytes = new byte[valueLength];
         System.arraycopy(keyBytes, vBytesPos, valueBytes, 0, valueLength);
         attributeValues[i] =
-            new AttributeValue(sortOrder.getSortKeys()[i].getAttributeType(),
-                new ASN1OctetString(valueBytes));
+            AttributeValues.create(
+                sortOrder.getSortKeys()[i].getAttributeType(),
+                ByteString.wrap(valueBytes));
       }
 
       vBytesPos += valueLength;
diff --git a/opends/src/server/org/opends/server/backends/jeb/VLVKeyComparator.java b/opends/src/server/org/opends/server/backends/jeb/VLVKeyComparator.java
index 8591466..a1445b6 100644
--- a/opends/src/server/org/opends/server/backends/jeb/VLVKeyComparator.java
+++ b/opends/src/server/org/opends/server/backends/jeb/VLVKeyComparator.java
@@ -29,6 +29,7 @@
 import org.opends.server.api.OrderingMatchingRule;
 import org.opends.server.types.AttributeValue;
 import org.opends.server.types.DirectoryException;
+import org.opends.server.types.ByteString;
 
 import java.util.Comparator;
 import java.io.Serializable;
@@ -282,12 +283,12 @@
         break;
       }
 
-      byte[] b1Bytes = set.getValue((index * orderingRules.length) + j);
-      byte[] b2Bytes = null;
+      ByteString b1Bytes = set.getValue((index * orderingRules.length) + j);
+      ByteString b2Bytes = null;
 
       if(values[j] != null)
       {
-        b2Bytes = values[j].getNormalizedValueBytes();
+        b2Bytes = values[j].getNormalizedValue();
       }
 
       // A null value will always come after a non-null value.
@@ -310,11 +311,11 @@
       int result;
       if(ascending[j])
       {
-        result = orderingRules[j].compare(b1Bytes, b2Bytes);
+        result = orderingRules[j].compareValues(b1Bytes, b2Bytes);
       }
       else
       {
-        result = orderingRules[j].compare(b2Bytes, b1Bytes);
+        result = orderingRules[j].compareValues(b2Bytes, b1Bytes);
       }
 
       if(result != 0)
diff --git a/opends/src/server/org/opends/server/backends/jeb/VerifyJob.java b/opends/src/server/org/opends/server/backends/jeb/VerifyJob.java
index 32e07fa..bc97f5b 100644
--- a/opends/src/server/org/opends/server/backends/jeb/VerifyJob.java
+++ b/opends/src/server/org/opends/server/backends/jeb/VerifyJob.java
@@ -44,7 +44,6 @@
 import org.opends.server.api.OrderingMatchingRule;
 import org.opends.server.api.ApproximateMatchingRule;
 import org.opends.server.core.DirectoryServer;
-import org.opends.server.protocols.asn1.ASN1OctetString;
 import org.opends.server.util.StaticUtils;
 import org.opends.server.util.ServerConstants;
 
@@ -472,8 +471,9 @@
         Entry entry;
         try
         {
-          entry = JebFormat.entryFromDatabase(data.getData(),
-                                 rootContainer.getCompressedSchema());
+          entry = ID2Entry.entryFromDatabase(
+              ByteString.wrap(data.getData()),
+              rootContainer.getCompressedSchema());
         }
         catch (Exception e)
         {
@@ -578,7 +578,7 @@
         DN dn;
         try
         {
-          dn = DN.decode(new ASN1OctetString(key.getData()));
+          dn = DN.decode(ByteString.wrap(key.getData()));
         }
         catch (DirectoryException e)
         {
@@ -955,7 +955,7 @@
       hashMap = new HashMap<ByteString, Long>();
       entryLimitMap.put(index, hashMap);
     }
-    ByteString octetString = new ASN1OctetString(key);
+    ByteString octetString = ByteString.wrap(key);
     Long counter = hashMap.get(octetString);
     if (counter == null)
     {
@@ -1142,7 +1142,7 @@
           attrType.getOrderingMatchingRule();
       ApproximateMatchingRule approximateMatchingRule =
           attrType.getApproximateMatchingRule();
-      ASN1OctetString previousValue = null;
+      ByteString previousValue = null;
 
       OperationStatus status;
       for (status = cursor.getFirst(key, data, LockMode.DEFAULT);
@@ -1184,7 +1184,7 @@
             case SUBSTRING:
               ArrayList<ByteString> subAnyElements =
                    new ArrayList<ByteString>(1);
-              subAnyElements.add(new ASN1OctetString(value));
+              subAnyElements.add(ByteString.wrap(value));
 
               sf = SearchFilter.createSubstringFilter(attrType,null,
                                                       subAnyElements,null);
@@ -1197,13 +1197,14 @@
               // 2. Make sure the key value is greater then the previous key
               //    value.
               assertionValue =
-                  new AttributeValue(attrType, new ASN1OctetString(value));
+                  AttributeValues.create(attrType,
+                      ByteString.wrap(value));
 
               sf = SearchFilter.createEqualityFilter(attrType,assertionValue);
 
               if(orderingMatchingRule != null && previousValue != null)
               {
-                ASN1OctetString thisValue = new ASN1OctetString(value);
+                ByteString thisValue = ByteString.wrap(value);
                 int order = orderingMatchingRule.compareValues(thisValue,
                                                                previousValue);
                 if(order > 0)
@@ -1214,8 +1215,8 @@
                     TRACER.debugError("Reversed ordering of index keys " +
                         "(keys dumped in the order found in database)%n" +
                         "Key 1:%n%s%nKey 2:%n%s",
-                               keyDump(index, thisValue.value()),
-                               keyDump(index,previousValue.value()));
+                               keyDump(index, thisValue.toByteArray()),
+                               keyDump(index,previousValue.toByteArray()));
                   }
                   continue;
                 }
@@ -1225,8 +1226,9 @@
                   if(debugEnabled())
                   {
                     TRACER.debugError("Duplicate index keys%nKey 1:%n%s%n" +
-                        "Key2:%n%s", keyDump(index, thisValue.value()),
-                                     keyDump(index,previousValue.value()));
+                        "Key2:%n%s", keyDump(index, thisValue.toByteArray()),
+                                     keyDump(index,
+                                         previousValue.toByteArray()));
                   }
                   continue;
                 }
@@ -1238,7 +1240,8 @@
               break;
             case EQ:
               assertionValue =
-                   new AttributeValue(attrType, new ASN1OctetString(value));
+                  AttributeValues.create(attrType,
+                      ByteString.wrap(value));
 
               sf = SearchFilter.createEqualityFilter(attrType,assertionValue);
               break;
@@ -1310,7 +1313,7 @@
               }
               else
               {
-                ByteString normalizedValue = new ASN1OctetString(value);
+                ByteString normalizedValue = ByteString.wrap(value);
                 List<Attribute> attrs = entry.getAttribute(attrType);
                 if ((attrs != null) && (!attrs.isEmpty()))
                 {
@@ -1839,7 +1842,7 @@
       {
         for (AttributeValue value : attr)
         {
-          byte[] normalizedBytes = value.getNormalizedValue().value();
+          byte[] normalizedBytes = value.getNormalizedValue().toByteArray();
 
           // Equality index.
           if (equalityIndex != null)
@@ -1886,7 +1889,7 @@
             DatabaseEntry key = new DatabaseEntry();
             for (ByteString keyBytes : keyBytesSet)
             {
-              key.setData(keyBytes.value());
+              key.setData(keyBytes.toByteArray());
               try
               {
                 ConditionResult cr;
@@ -1929,7 +1932,7 @@
                  attr.getAttributeType().getOrderingMatchingRule();
 
             normalizedBytes =
-                 orderingRule.normalizeValue(value.getValue()).value();
+                 orderingRule.normalizeValue(value.getValue()).toByteArray();
 
             DatabaseEntry key = new DatabaseEntry(normalizedBytes);
             try
@@ -1972,7 +1975,7 @@
                 attr.getAttributeType().getApproximateMatchingRule();
 
             normalizedBytes =
-                approximateRule.normalizeValue(value.getValue()).value();
+                approximateRule.normalizeValue(value.getValue()).toByteArray();
 
             DatabaseEntry key = new DatabaseEntry(normalizedBytes);
             try
diff --git a/opends/src/server/org/opends/server/backends/jeb/importLDIF/Importer.java b/opends/src/server/org/opends/server/backends/jeb/importLDIF/Importer.java
index 34dc4f1..6f3cc05 100644
--- a/opends/src/server/org/opends/server/backends/jeb/importLDIF/Importer.java
+++ b/opends/src/server/org/opends/server/backends/jeb/importLDIF/Importer.java
@@ -42,7 +42,6 @@
 import org.opends.server.config.ConfigException;
 import org.opends.server.core.DirectoryServer;
 import org.opends.server.backends.jeb.*;
-import org.opends.server.protocols.asn1.ASN1OctetString;
 import org.opends.messages.Message;
 import org.opends.messages.JebMessages;
 import static org.opends.messages.JebMessages.*;
@@ -868,7 +867,7 @@
               message = ERR_JEB_IMPORT_NO_WORKER_THREADS.get();
               throw new JebException(message);
             }
-            DN dn = DN.decode(new ASN1OctetString(key.getData()));
+            DN dn = DN.decode(ByteString.wrap(key.getData()));
             if(!context.getIncludeBranches().contains(dn)) {
               EntryID id = new EntryID(data);
               Entry entry =
diff --git a/opends/src/server/org/opends/server/backends/task/RecurringTask.java b/opends/src/server/org/opends/server/backends/task/RecurringTask.java
index 67fcec9..bffe9db 100644
--- a/opends/src/server/org/opends/server/backends/task/RecurringTask.java
+++ b/opends/src/server/org/opends/server/backends/task/RecurringTask.java
@@ -76,23 +76,23 @@
 
 
   // The DN of the entry that actually defines this task.
-  private DN recurringTaskEntryDN;
+  private final DN recurringTaskEntryDN;
 
   // The entry that actually defines this task.
-  private Entry recurringTaskEntry;
+  private final Entry recurringTaskEntry;
 
   // The unique ID for this recurring task.
-  private String recurringTaskID;
+  private final String recurringTaskID;
 
   // The fully-qualified name of the class that will be used to implement the
   // class.
-  private String taskClassName;
+  private final String taskClassName;
 
   // Task instance.
   private Task task;
 
   // Task scheduler for this task.
-  private TaskScheduler taskScheduler;
+  private final TaskScheduler taskScheduler;
 
   // Number of tokens in the task schedule tab.
   private static final int TASKTAB_NUM_TOKENS = 5;
@@ -180,7 +180,7 @@
       throw new DirectoryException(ResultCode.OBJECTCLASS_VIOLATION, message);
     }
 
-    recurringTaskID = value.getStringValue();
+    recurringTaskID = value.getValue().toString();
 
 
     // Get the schedule for this task.
@@ -224,7 +224,7 @@
       throw new DirectoryException(ResultCode.CONSTRAINT_VIOLATION, message);
     }
 
-    String taskScheduleTab = value.getStringValue();
+    String taskScheduleTab = value.toString();
     parseTaskTab(taskScheduleTab);
 
     // Get the class name from the entry.  If there isn't one, then fail.
@@ -267,7 +267,7 @@
       throw new DirectoryException(ResultCode.CONSTRAINT_VIOLATION, message);
     }
 
-    taskClassName = value.getStringValue();
+    taskClassName = value.getValue().toString();
 
 
     // Make sure that the specified class can be loaded.
diff --git a/opends/src/server/org/opends/server/backends/task/Task.java b/opends/src/server/org/opends/server/backends/task/Task.java
index d8e6ec3..fa02fd2 100644
--- a/opends/src/server/org/opends/server/backends/task/Task.java
+++ b/opends/src/server/org/opends/server/backends/task/Task.java
@@ -52,19 +52,7 @@
 import org.opends.server.core.DirectoryServer;
 import org.opends.server.loggers.ErrorLogger;
 import org.opends.server.loggers.debug.DebugTracer;
-import org.opends.server.types.Attribute;
-import org.opends.server.types.AttributeBuilder;
-import org.opends.server.types.AttributeType;
-import org.opends.server.types.AttributeValue;
-import org.opends.server.types.Attributes;
-import org.opends.server.types.DN;
-import org.opends.server.types.DebugLogLevel;
-import org.opends.server.types.DirectoryException;
-import org.opends.server.types.Entry;
-import org.opends.server.types.InitializationException;
-import org.opends.server.types.Modification;
-import org.opends.server.types.ModificationType;
-import org.opends.server.types.Operation;
+import org.opends.server.types.*;
 import org.opends.server.util.EMailMessage;
 import org.opends.server.util.StaticUtils;
 import org.opends.server.util.TimeThread;
@@ -440,7 +428,7 @@
       throw new InitializationException(message);
     }
 
-    return value.getStringValue();
+    return value.getValue().toString();
   }
 
 
@@ -480,7 +468,7 @@
     Iterator<AttributeValue> iterator = attrList.get(0).iterator();
     while (iterator.hasNext())
     {
-      valueStrings.add(iterator.next().getStringValue());
+      valueStrings.add(iterator.next().getValue().toString());
     }
 
     return valueStrings;
@@ -1006,7 +994,7 @@
       }
 
       List<Attribute> attrList = taskEntry.getAttribute(type);
-      AttributeValue value = new AttributeValue(type, messageString);
+      AttributeValue value = AttributeValues.create(type, messageString);
       if (attrList == null)
       {
         attrList = new ArrayList<Attribute>();
diff --git a/opends/src/server/org/opends/server/backends/task/TaskBackend.java b/opends/src/server/org/opends/server/backends/task/TaskBackend.java
index f25ab24..d00a78d 100644
--- a/opends/src/server/org/opends/server/backends/task/TaskBackend.java
+++ b/opends/src/server/org/opends/server/backends/task/TaskBackend.java
@@ -863,7 +863,7 @@
       }
 
       AttributeValue v = iterator.next();
-      String valueString = toLowerCase(v.getStringValue());
+      String valueString = toLowerCase(v.toString());
       if (!(valueString.startsWith("cancel") ||
         valueString.startsWith("stop"))) {
         acceptable = false;
@@ -2352,6 +2352,7 @@
   /**
    * {@inheritDoc}
    */
+  @Override
   public void preloadEntryCache() throws UnsupportedOperationException {
     throw new UnsupportedOperationException("Operation not supported.");
   }
diff --git a/opends/src/server/org/opends/server/backends/task/TaskScheduler.java b/opends/src/server/org/opends/server/backends/task/TaskScheduler.java
index e22b65a..71f5579 100644
--- a/opends/src/server/org/opends/server/backends/task/TaskScheduler.java
+++ b/opends/src/server/org/opends/server/backends/task/TaskScheduler.java
@@ -1979,7 +1979,7 @@
       throw new DirectoryException(ResultCode.OBJECTCLASS_VIOLATION, message);
     }
 
-    String taskClassName = value.getStringValue();
+    String taskClassName = value.getValue().toString();
     if (! DirectoryServer.getAllowedTasks().contains(taskClassName))
     {
       Message message = ERR_TASKSCHED_NOT_ALLOWED_TASK.get(taskClassName);
diff --git a/opends/src/server/org/opends/server/config/BooleanConfigAttribute.java b/opends/src/server/org/opends/server/config/BooleanConfigAttribute.java
index 052a7e8..a1dc506 100644
--- a/opends/src/server/org/opends/server/config/BooleanConfigAttribute.java
+++ b/opends/src/server/org/opends/server/config/BooleanConfigAttribute.java
@@ -40,9 +40,10 @@
 
 import org.opends.server.api.AttributeSyntax;
 import org.opends.server.core.DirectoryServer;
-import org.opends.server.protocols.asn1.ASN1OctetString;
 import org.opends.server.types.Attribute;
 import org.opends.server.types.AttributeValue;
+import org.opends.server.types.AttributeValues;
+import org.opends.server.types.ByteString;
 
 import static org.opends.server.config.ConfigConstants.*;
 import static org.opends.messages.ConfigMessages.*;
@@ -241,13 +242,15 @@
          new LinkedHashSet<AttributeValue>(1);
     if (booleanValue)
     {
-      valueSet.add(new AttributeValue(new ASN1OctetString(CONFIG_VALUE_TRUE),
-                                      new ASN1OctetString(CONFIG_VALUE_TRUE)));
+      valueSet.add(AttributeValues.create(
+          ByteString.valueOf(CONFIG_VALUE_TRUE),
+          ByteString.valueOf(CONFIG_VALUE_TRUE)));
     }
     else
     {
-      valueSet.add(new AttributeValue(new ASN1OctetString(CONFIG_VALUE_FALSE),
-                                      new ASN1OctetString(CONFIG_VALUE_FALSE)));
+      valueSet.add(AttributeValues.create(
+          ByteString.valueOf(CONFIG_VALUE_FALSE),
+          ByteString.valueOf(CONFIG_VALUE_FALSE)));
     }
 
     return valueSet;
@@ -288,7 +291,7 @@
   public boolean valueIsAcceptable(AttributeValue value,
                                    StringBuilder rejectReason)
   {
-    String stringValue = value.getStringValue();
+    String stringValue = value.getValue().toString();
     if (stringValue.equalsIgnoreCase(CONFIG_VALUE_TRUE) ||
         stringValue.equalsIgnoreCase(CONFIG_VALUE_FALSE))
     {
@@ -464,7 +467,8 @@
           {
             // Get the value and parse it as a Boolean.
             Iterator<AttributeValue> iterator = a.iterator();
-            String valueString = iterator.next().getStringValue().toLowerCase();
+            String valueString =
+                iterator.next().getValue().toString().toLowerCase();
 
             if (valueString.equals("true") || valueString.equals("yes") ||
                 valueString.equals("on") || valueString.equals("1"))
@@ -526,7 +530,8 @@
         {
           // Get the value and parse it as a Boolean.
           Iterator<AttributeValue> iterator = a.iterator();
-          String valueString = iterator.next().getStringValue().toLowerCase();
+          String valueString =
+              iterator.next().getValue().toString().toLowerCase();
 
           if (valueString.equals("true") || valueString.equals("yes") ||
               valueString.equals("on") || valueString.equals("1"))
diff --git a/opends/src/server/org/opends/server/config/ConfigAttribute.java b/opends/src/server/org/opends/server/config/ConfigAttribute.java
index b98adc5..2033a75 100644
--- a/opends/src/server/org/opends/server/config/ConfigAttribute.java
+++ b/opends/src/server/org/opends/server/config/ConfigAttribute.java
@@ -449,7 +449,7 @@
     if (! valueIsAcceptable(value, rejectReason))
     {
       Message message = ERR_CONFIG_ATTR_REJECTED_VALUE.get(
-          value.getStringValue(), name, rejectReason.toString());
+          value.getValue().toString(), name, rejectReason.toString());
       throw new ConfigException(message);
     }
 
@@ -470,7 +470,7 @@
       if (! valueIsAcceptable(value, rejectReason))
       {
         Message message = ERR_CONFIG_ATTR_REJECTED_VALUE.get(
-            value.getStringValue(), name, rejectReason.toString());
+            value.getValue().toString(), name, rejectReason.toString());
         throw new ConfigException(message);
       }
     }
@@ -589,14 +589,14 @@
       if (tempValues.contains(value))
       {
         Message message = ERR_CONFIG_ATTR_ADD_VALUES_ALREADY_EXISTS.get(
-            name, value.getStringValue());
+            name, value.getValue().toString());
         throw new ConfigException(message);
       }
 
       if (! valueIsAcceptable(value, rejectReason))
       {
         Message message = ERR_CONFIG_ATTR_REJECTED_VALUE.get(
-            value.getStringValue(), name, rejectReason.toString());
+            value.getValue().toString(), name, rejectReason.toString());
         throw new ConfigException(message);
       }
     }
@@ -657,7 +657,7 @@
       if (! tempValues.remove(value))
       {
         Message message =
-            ERR_CONFIG_ATTR_NO_SUCH_VALUE.get(name, value.getStringValue());
+           ERR_CONFIG_ATTR_NO_SUCH_VALUE.get(name, value.getValue().toString());
         throw new ConfigException(message);
       }
     }
diff --git a/opends/src/server/org/opends/server/config/DNConfigAttribute.java b/opends/src/server/org/opends/server/config/DNConfigAttribute.java
index dcccb9e..17d0145 100644
--- a/opends/src/server/org/opends/server/config/DNConfigAttribute.java
+++ b/opends/src/server/org/opends/server/config/DNConfigAttribute.java
@@ -40,11 +40,7 @@
 
 import org.opends.server.api.AttributeSyntax;
 import org.opends.server.core.DirectoryServer;
-import org.opends.server.protocols.asn1.ASN1OctetString;
-import org.opends.server.types.Attribute;
-import org.opends.server.types.AttributeValue;
-import org.opends.server.types.DN;
-import org.opends.server.types.DebugLogLevel;
+import org.opends.server.types.*;
 
 import static org.opends.server.config.ConfigConstants.*;
 import static org.opends.server.loggers.debug.DebugLogger.*;
@@ -448,8 +444,8 @@
       }
 
       AttributeValue attrValue =
-           new AttributeValue(new ASN1OctetString(value.toString()),
-                              new ASN1OctetString(value.toNormalizedString()));
+          AttributeValues.create(ByteString.valueOf(value.toString()),
+              ByteString.valueOf(value.toNormalizedString()));
 
       if (valueSet.contains(attrValue))
       {
@@ -496,8 +492,8 @@
     else
     {
       valueSet = new LinkedHashSet<AttributeValue>(1);
-      valueSet.add(new AttributeValue(new ASN1OctetString(value.toString()),
-                            new ASN1OctetString(value.toNormalizedString())));
+      valueSet.add(AttributeValues.create(ByteString.valueOf(value.toString()),
+          ByteString.valueOf(value.toNormalizedString())));
     }
 
     return valueSet;
@@ -524,8 +520,8 @@
 
     for (DN value : values)
     {
-      valueSet.add(new AttributeValue(new ASN1OctetString(value.toString()),
-                            new ASN1OctetString(value.toNormalizedString())));
+      valueSet.add(AttributeValues.create(ByteString.valueOf(value.toString()),
+          ByteString.valueOf(value.toNormalizedString())));
     }
 
     return valueSet;
@@ -577,7 +573,7 @@
     // Make sure that it can be parsed as a DN.
     try
     {
-      DN.decode(value.getStringValue());
+      DN.decode(value.getValue().toString());
     }
     catch (Exception e)
     {
@@ -587,7 +583,7 @@
       }
 
       rejectReason.append(ERR_CONFIG_ATTR_DN_CANNOT_PARSE.get(
-              value.getStringValue(), getName(),
+              value.getValue().toString(), getName(),
               String.valueOf(e)));
       return false;
     }
@@ -692,8 +688,8 @@
       }
 
 
-      valueSet.add(new AttributeValue(new ASN1OctetString(dn.toString()),
-                            new ASN1OctetString(dn.toNormalizedString())));
+      valueSet.add(AttributeValues.create(ByteString.valueOf(dn.toString()),
+          ByteString.valueOf(dn.toNormalizedString())));
     }
 
 
@@ -841,7 +837,7 @@
               DN dn;
               try
               {
-                dn = DN.decode(v.getStringValue());
+                dn = DN.decode(v.getValue().toString());
               }
               catch (Exception e)
               {
@@ -851,7 +847,7 @@
                 }
 
                 Message message = ERR_CONFIG_ATTR_DN_CANNOT_PARSE.get(
-                    v.getStringValue(), getName(), String.valueOf(e));
+                    v.getValue().toString(), getName(), String.valueOf(e));
                 throw new ConfigException(message, e);
               }
 
@@ -911,7 +907,7 @@
             DN dn;
             try
             {
-              dn = DN.decode(v.getStringValue());
+              dn = DN.decode(v.getValue().toString());
             }
             catch (Exception e)
             {
@@ -921,7 +917,7 @@
               }
 
               Message message = ERR_CONFIG_ATTR_DN_CANNOT_PARSE.get(
-                  v.getStringValue(), getName(), String.valueOf(e));
+                  v.getValue().toString(), getName(), String.valueOf(e));
               throw new ConfigException(message, e);
             }
 
diff --git a/opends/src/server/org/opends/server/config/IntegerConfigAttribute.java b/opends/src/server/org/opends/server/config/IntegerConfigAttribute.java
index 69bc80e..95f9121 100644
--- a/opends/src/server/org/opends/server/config/IntegerConfigAttribute.java
+++ b/opends/src/server/org/opends/server/config/IntegerConfigAttribute.java
@@ -40,10 +40,7 @@
 
 import org.opends.server.api.AttributeSyntax;
 import org.opends.server.core.DirectoryServer;
-import org.opends.server.protocols.asn1.ASN1OctetString;
-import org.opends.server.types.Attribute;
-import org.opends.server.types.AttributeValue;
-import org.opends.server.types.DebugLogLevel;
+import org.opends.server.types.*;
 
 import static org.opends.server.config.ConfigConstants.*;
 import static org.opends.server.loggers.debug.DebugLogger.*;
@@ -683,8 +680,8 @@
 
       String valueString = String.valueOf(value);
       AttributeValue attrValue =
-           new AttributeValue(new ASN1OctetString(valueString),
-                              new ASN1OctetString(valueString));
+          AttributeValues.create(ByteString.valueOf(valueString),
+              ByteString.valueOf(valueString));
 
       if (valueSet.contains(attrValue))
       {
@@ -726,8 +723,8 @@
          new LinkedHashSet<AttributeValue>(1);
 
     String valueString = String.valueOf(value);
-    valueSet.add(new AttributeValue(new ASN1OctetString(valueString),
-                                    new ASN1OctetString(valueString)));
+    valueSet.add(AttributeValues.create(ByteString.valueOf(valueString),
+        ByteString.valueOf(valueString)));
 
     return valueSet;
   }
@@ -754,8 +751,8 @@
     for (long value : values)
     {
       String valueString = String.valueOf(value);
-      valueSet.add(new AttributeValue(new ASN1OctetString(valueString),
-                                      new ASN1OctetString(valueString)));
+      valueSet.add(AttributeValues.create(ByteString.valueOf(valueString),
+          ByteString.valueOf(valueString)));
     }
 
     return valueSet;
@@ -797,7 +794,7 @@
                                    StringBuilder rejectReason)
   {
     // First, make sure we can represent it as a long.
-    String stringValue = value.getStringValue();
+    String stringValue = value.getValue().toString();
     long longValue;
     try
     {
@@ -951,8 +948,8 @@
       }
 
 
-      valueSet.add(new AttributeValue(new ASN1OctetString(valueString),
-                                      new ASN1OctetString(valueString)));
+      valueSet.add(AttributeValues.create(ByteString.valueOf(valueString),
+          ByteString.valueOf(valueString)));
     }
 
 
@@ -1101,12 +1098,12 @@
               long longValue;
               try
               {
-                longValue = Long.parseLong(v.getStringValue());
+                longValue = Long.parseLong(v.getValue().toString());
               }
               catch (Exception e)
               {
                 Message message = ERR_CONFIG_ATTR_INT_COULD_NOT_PARSE.get(
-                    v.getStringValue(), a.getName(), String.valueOf(e));
+                    v.getValue().toString(), a.getName(), String.valueOf(e));
                 throw new ConfigException(message, e);
               }
 
@@ -1183,12 +1180,12 @@
             long longValue;
             try
             {
-              longValue = Long.parseLong(v.getStringValue());
+              longValue = Long.parseLong(v.getValue().toString());
             }
             catch (Exception e)
             {
               Message message = ERR_CONFIG_ATTR_INT_COULD_NOT_PARSE.get(
-                  v.getStringValue(), a.getName(), String.valueOf(e));
+                  v.getValue().toString(), a.getName(), String.valueOf(e));
               throw new ConfigException(message, e);
             }
 
diff --git a/opends/src/server/org/opends/server/config/IntegerWithUnitConfigAttribute.java b/opends/src/server/org/opends/server/config/IntegerWithUnitConfigAttribute.java
index d2eb81c..7307545 100644
--- a/opends/src/server/org/opends/server/config/IntegerWithUnitConfigAttribute.java
+++ b/opends/src/server/org/opends/server/config/IntegerWithUnitConfigAttribute.java
@@ -41,10 +41,7 @@
 
 import org.opends.server.api.AttributeSyntax;
 import org.opends.server.core.DirectoryServer;
-import org.opends.server.protocols.asn1.ASN1OctetString;
-import org.opends.server.types.Attribute;
-import org.opends.server.types.AttributeValue;
-import org.opends.server.types.DebugLogLevel;
+import org.opends.server.types.*;
 
 import static org.opends.server.config.ConfigConstants.*;
 import static org.opends.server.loggers.debug.DebugLogger.*;
@@ -612,8 +609,8 @@
          new LinkedHashSet<AttributeValue>(1);
 
     String valueString = intValue + " " + unit;
-    valueSet.add(new AttributeValue(new ASN1OctetString(valueString),
-                                    new ASN1OctetString(valueString)));
+    valueSet.add(AttributeValues.create(ByteString.valueOf(valueString),
+        ByteString.valueOf(valueString)));
 
     return valueSet;
   }
@@ -656,7 +653,7 @@
                                    StringBuilder rejectReason)
   {
     // Get a string representation of the value and convert it to lowercase.
-    String lowerValue = value.getStringValue().toLowerCase();
+    String lowerValue = value.getValue().toString().toLowerCase();
 
     return valueIsAcceptable(lowerValue, rejectReason);
   }
@@ -833,8 +830,8 @@
       }
 
 
-      valueSet.add(new AttributeValue(new ASN1OctetString(valueString),
-                                      new ASN1OctetString(valueString)));
+      valueSet.add(AttributeValues.create(ByteString.valueOf(valueString),
+          ByteString.valueOf(valueString)));
     }
 
 
@@ -956,7 +953,7 @@
           {
             Iterator<AttributeValue> iterator = a.iterator();
 
-            String valueString = iterator.next().getStringValue();
+            String valueString = iterator.next().getValue().toString();
 
             if (iterator.hasNext())
             {
@@ -1041,7 +1038,7 @@
         {
           Iterator<AttributeValue> iterator = a.iterator();
 
-          String valueString = iterator.next().getStringValue();
+          String valueString = iterator.next().getValue().toString();
 
           if (iterator.hasNext())
           {
diff --git a/opends/src/server/org/opends/server/config/JMXMBean.java b/opends/src/server/org/opends/server/config/JMXMBean.java
index e2fb06f..ac7bf5e 100644
--- a/opends/src/server/org/opends/server/config/JMXMBean.java
+++ b/opends/src/server/org/opends/server/config/JMXMBean.java
@@ -56,14 +56,6 @@
 import org.opends.server.api.MonitorProvider;
 import org.opends.server.core.DirectoryServer;
 import org.opends.server.protocols.jmx.Credential;
-import org.opends.server.types.AttributeType;
-import org.opends.server.types.AttributeValue;
-import org.opends.server.types.DebugLogLevel;
-import org.opends.server.types.DirectoryException;
-import org.opends.server.types.DN;
-import org.opends.server.types.InvokableMethod;
-import org.opends.server.types.ResultCode;
-import org.opends.server.types.SearchScope;
 
 import static org.opends.server.loggers.debug.DebugLogger.*;
 import static org.opends.server.loggers.ErrorLogger.*;
@@ -72,12 +64,10 @@
 import static org.opends.server.util.ServerConstants.*;
 import static org.opends.server.util.StaticUtils.*;
 import org.opends.server.protocols.jmx.JmxClientConnection;
-import org.opends.server.protocols.asn1.ASN1OctetString;
 import org.opends.server.protocols.internal.InternalClientConnection;
 import org.opends.server.protocols.ldap.LDAPFilter;
 import org.opends.server.protocols.internal.InternalSearchOperation ;
-import org.opends.server.types.LDAPException;
-
+import org.opends.server.types.*;
 
 
 /**
@@ -448,12 +438,12 @@
           if (iterator.hasNext())
           {
             ArrayList<String> stringValues = new ArrayList<String>();
-            stringValues.add(value.getStringValue());
+            stringValues.add(value.getValue().toString());
 
             while (iterator.hasNext())
             {
               value = iterator.next();
-              stringValues.add(value.getStringValue());
+              stringValues.add(value.getValue().toString());
             }
 
             String[] valueArray = new String[stringValues.size()];
@@ -462,7 +452,7 @@
           }
           else
           {
-            return new Attribute(name, value.getStringValue());
+            return new Attribute(name, value.getValue().toString());
           }
         }
       }
@@ -522,12 +512,12 @@
     InternalSearchOperation op=null;
     if (clientConnection instanceof JmxClientConnection) {
         op = ((JmxClientConnection)clientConnection).processSearch(
-             new ASN1OctetString(configEntryDN.toString()),
+            ByteString.valueOf(configEntryDN.toString()),
              SearchScope.BASE_OBJECT, filter);
     }
     else if (clientConnection instanceof InternalClientConnection) {
         op = ((InternalClientConnection)clientConnection).processSearch(
-             new ASN1OctetString(configEntryDN.toString()),
+            ByteString.valueOf(configEntryDN.toString()),
              SearchScope.BASE_OBJECT, filter);
     }
     // BUG : op may be null
@@ -616,12 +606,12 @@
     InternalSearchOperation op=null;
     if (clientConnection instanceof JmxClientConnection) {
       op = ((JmxClientConnection)clientConnection).processSearch(
-        new ASN1OctetString(configEntryDN.toString()),
+          ByteString.valueOf(configEntryDN.toString()),
         SearchScope.BASE_OBJECT, filter);
     }
     else if (clientConnection instanceof InternalClientConnection) {
       op = ((InternalClientConnection)clientConnection).processSearch(
-        new ASN1OctetString(configEntryDN.toString()),
+          ByteString.valueOf(configEntryDN.toString()),
         SearchScope.BASE_OBJECT, filter);
     }
     // BUG: op may be null
@@ -681,12 +671,12 @@
             if (iterator.hasNext())
             {
               ArrayList<String> stringValues = new ArrayList<String>();
-              stringValues.add(value.getStringValue());
+              stringValues.add(value.getValue().toString());
 
               while (iterator.hasNext())
               {
                 value = iterator.next();
-                stringValues.add(value.getStringValue());
+                stringValues.add(value.getValue().toString());
               }
 
               String[] valueArray = new String[stringValues.size()];
@@ -696,7 +686,7 @@
             }
             else
             {
-              attrList.add(new Attribute(name, value.getStringValue()));
+              attrList.add(new Attribute(name, value.getValue().toString()));
               break monitorLoop;
             }
           }
diff --git a/opends/src/server/org/opends/server/config/MultiChoiceConfigAttribute.java b/opends/src/server/org/opends/server/config/MultiChoiceConfigAttribute.java
index bd935e9..aa2cc80 100644
--- a/opends/src/server/org/opends/server/config/MultiChoiceConfigAttribute.java
+++ b/opends/src/server/org/opends/server/config/MultiChoiceConfigAttribute.java
@@ -40,10 +40,7 @@
 
 import org.opends.server.api.AttributeSyntax;
 import org.opends.server.core.DirectoryServer;
-import org.opends.server.protocols.asn1.ASN1OctetString;
-import org.opends.server.types.Attribute;
-import org.opends.server.types.AttributeValue;
-import org.opends.server.types.DebugLogLevel;
+import org.opends.server.types.*;
 
 import static org.opends.server.config.ConfigConstants.*;
 import static org.opends.server.loggers.debug.DebugLogger.*;
@@ -512,8 +509,8 @@
       }
 
       AttributeValue attrValue =
-           new AttributeValue(new ASN1OctetString(value),
-                              new ASN1OctetString(value));
+          AttributeValues.create(ByteString.valueOf(value),
+              ByteString.valueOf(value));
 
       if (valueSet.contains(attrValue))
       {
@@ -554,8 +551,8 @@
     LinkedHashSet<AttributeValue> valueSet =
          new LinkedHashSet<AttributeValue>(1);
 
-    valueSet.add(new AttributeValue(new ASN1OctetString(value),
-                                    new ASN1OctetString(value)));
+    valueSet.add(AttributeValues.create(ByteString.valueOf(value),
+        ByteString.valueOf(value)));
 
     return valueSet;
   }
@@ -581,8 +578,8 @@
 
     for (String value : values)
     {
-      valueSet.add(new AttributeValue(new ASN1OctetString(value),
-                                      new ASN1OctetString(value)));
+      valueSet.add(AttributeValues.create(ByteString.valueOf(value),
+          ByteString.valueOf(value)));
     }
 
     return valueSet;
@@ -626,7 +623,7 @@
     // Make sure that the value is non-empty.
     String stringValue;
     if ((value == null) ||
-        ((stringValue = value.getStringValue()).length() == 0))
+        ((stringValue = value.getValue().toString()).length() == 0))
     {
       rejectReason.append(ERR_CONFIG_ATTR_EMPTY_STRING_VALUE.get(getName()));
       return false;
@@ -727,8 +724,8 @@
         }
       }
 
-      valueSet.add(new AttributeValue(new ASN1OctetString(valueString),
-                                      new ASN1OctetString(valueString)));
+      valueSet.add(AttributeValues.create(ByteString.valueOf(valueString),
+          ByteString.valueOf(valueString)));
     }
 
 
@@ -860,16 +857,16 @@
             pendingValues = new ArrayList<String>(numValues);
             for (AttributeValue v : a)
             {
-              String lowerValue = v.getStringValue().toLowerCase();
+              String lowerValue = v.getValue().toString().toLowerCase();
               if (! allowedValues.contains(lowerValue))
               {
                 // This is illegal -- the value is not allowed.
                 Message message = ERR_CONFIG_ATTR_VALUE_NOT_ALLOWED.get(
-                    v.getStringValue(), a.getName());
+                    v.getValue().toString(), a.getName());
                 throw new ConfigException(message);
               }
 
-              pendingValues.add(v.getStringValue());
+              pendingValues.add(v.getValue().toString());
             }
           }
         }
@@ -922,16 +919,16 @@
           activeValues = new ArrayList<String>(numValues);
           for (AttributeValue v : a)
           {
-            String lowerValue = v.getStringValue().toLowerCase();
+            String lowerValue = v.getValue().toString().toLowerCase();
             if (! allowedValues.contains(lowerValue))
             {
               // This is illegal -- the value is not allowed.
               Message message = ERR_CONFIG_ATTR_VALUE_NOT_ALLOWED.get(
-                  v.getStringValue(), a.getName());
+                  v.getValue().toString(), a.getName());
               throw new ConfigException(message);
             }
 
-            activeValues.add(v.getStringValue());
+            activeValues.add(v.getValue().toString());
           }
         }
       }
diff --git a/opends/src/server/org/opends/server/config/ReadOnlyConfigAttribute.java b/opends/src/server/org/opends/server/config/ReadOnlyConfigAttribute.java
index 9057570..6fa9e54 100644
--- a/opends/src/server/org/opends/server/config/ReadOnlyConfigAttribute.java
+++ b/opends/src/server/org/opends/server/config/ReadOnlyConfigAttribute.java
@@ -38,9 +38,10 @@
 
 import org.opends.server.api.AttributeSyntax;
 import org.opends.server.core.DirectoryServer;
-import org.opends.server.protocols.asn1.ASN1OctetString;
 import org.opends.server.types.Attribute;
 import org.opends.server.types.AttributeValue;
+import org.opends.server.types.ByteString;
+import org.opends.server.types.AttributeValues;
 
 import static org.opends.server.config.ConfigConstants.*;
 import static org.opends.messages.ConfigMessages.*;
@@ -280,8 +281,8 @@
     LinkedHashSet<AttributeValue> valueSet =
          new LinkedHashSet<AttributeValue>(1);
 
-    valueSet.add(new AttributeValue(new ASN1OctetString(value),
-                                    new ASN1OctetString(value)));
+    valueSet.add(AttributeValues.create(ByteString.valueOf(value),
+        ByteString.valueOf(value)));
 
     return valueSet;
   }
@@ -307,8 +308,8 @@
 
     for (String value : values)
     {
-      valueSet.add(new AttributeValue(new ASN1OctetString(value),
-                                      new ASN1OctetString(value)));
+      valueSet.add(AttributeValues.create(ByteString.valueOf(value),
+          ByteString.valueOf(value)));
     }
 
     return valueSet;
@@ -383,8 +384,8 @@
          new LinkedHashSet<AttributeValue>(numValues);
     for (String valueString : valueStrings)
     {
-      valueSet.add(new AttributeValue(new ASN1OctetString(valueString),
-                                      new ASN1OctetString(valueString)));
+      valueSet.add(AttributeValues.create(ByteString.valueOf(valueString),
+          ByteString.valueOf(valueString)));
     }
 
 
diff --git a/opends/src/server/org/opends/server/config/StringConfigAttribute.java b/opends/src/server/org/opends/server/config/StringConfigAttribute.java
index 6b79c98..83f8cbb 100644
--- a/opends/src/server/org/opends/server/config/StringConfigAttribute.java
+++ b/opends/src/server/org/opends/server/config/StringConfigAttribute.java
@@ -40,10 +40,7 @@
 
 import org.opends.server.api.AttributeSyntax;
 import org.opends.server.core.DirectoryServer;
-import org.opends.server.protocols.asn1.ASN1OctetString;
-import org.opends.server.types.Attribute;
-import org.opends.server.types.AttributeValue;
-import org.opends.server.types.DebugLogLevel;
+import org.opends.server.types.*;
 
 import static org.opends.server.config.ConfigConstants.*;
 import static org.opends.server.loggers.debug.DebugLogger.*;
@@ -451,8 +448,8 @@
       }
 
       AttributeValue attrValue =
-           new AttributeValue(new ASN1OctetString(value),
-                              new ASN1OctetString(value));
+          AttributeValues.create(ByteString.valueOf(value),
+              ByteString.valueOf(value));
 
       if (valueSet.contains(attrValue))
       {
@@ -493,8 +490,8 @@
     LinkedHashSet<AttributeValue> valueSet =
          new LinkedHashSet<AttributeValue>(1);
 
-    valueSet.add(new AttributeValue(new ASN1OctetString(value),
-                                    new ASN1OctetString(value)));
+    valueSet.add(AttributeValues.create(ByteString.valueOf(value),
+        ByteString.valueOf(value)));
 
     return valueSet;
   }
@@ -520,8 +517,8 @@
 
     for (String value : values)
     {
-      valueSet.add(new AttributeValue(new ASN1OctetString(value),
-                                      new ASN1OctetString(value)));
+      valueSet.add(AttributeValues.create(ByteString.valueOf(value),
+          ByteString.valueOf(value)));
     }
 
     return valueSet;
@@ -563,7 +560,7 @@
                                    StringBuilder rejectReason)
   {
     // The only requirement is that the value is not null or empty.
-    if ((value == null) || (value.getStringValue().length() == 0))
+    if ((value == null) || (value.getValue().toString().length() == 0))
     {
       rejectReason.append(ERR_CONFIG_ATTR_EMPTY_STRING_VALUE.get(getName()));
       return false;
@@ -641,8 +638,8 @@
         }
       }
 
-      valueSet.add(new AttributeValue(new ASN1OctetString(valueString),
-                                      new ASN1OctetString(valueString)));
+      valueSet.add(AttributeValues.create(ByteString.valueOf(valueString),
+          ByteString.valueOf(valueString)));
     }
 
 
@@ -774,7 +771,7 @@
             pendingValues = new ArrayList<String>(numValues);
             for (AttributeValue v : a)
             {
-              pendingValues.add(v.getStringValue());
+              pendingValues.add(v.getValue().toString());
             }
           }
         }
@@ -827,7 +824,7 @@
           activeValues = new ArrayList<String>(numValues);
           for (AttributeValue v : a)
           {
-            activeValues.add(v.getStringValue());
+            activeValues.add(v.getValue().toString());
           }
         }
       }
diff --git a/opends/src/server/org/opends/server/controls/AccountUsableRequestControl.java b/opends/src/server/org/opends/server/controls/AccountUsableRequestControl.java
index 2cdbdda..3ce783b 100644
--- a/opends/src/server/org/opends/server/controls/AccountUsableRequestControl.java
+++ b/opends/src/server/org/opends/server/controls/AccountUsableRequestControl.java
@@ -29,13 +29,16 @@
 
 
 
-import org.opends.server.protocols.ldap.LDAPResultCode;
+import org.opends.server.protocols.asn1.ASN1Writer;
+import org.opends.server.types.ByteString;
 import org.opends.server.types.Control;
-import org.opends.server.types.LDAPException;
+import org.opends.server.types.DirectoryException;
+import org.opends.server.types.ResultCode;
 
 import static org.opends.messages.ProtocolMessages.*;
 import static org.opends.server.util.ServerConstants.*;
 
+import java.io.IOException;
 
 
 /**
@@ -46,8 +49,41 @@
 public class AccountUsableRequestControl
        extends Control
 {
+  /**
+   * ControlDecoder implentation to decode this control from a ByteString.
+   */
+  private static final class Decoder
+      implements ControlDecoder<AccountUsableRequestControl>
+  {
+    /**
+     * {@inheritDoc}
+     */
+    public AccountUsableRequestControl decode(boolean isCritical,
+                                              ByteString value)
+           throws DirectoryException
+    {
+      if (value != null)
+      {
+        Message message = ERR_ACCTUSABLEREQ_CONTROL_HAS_VALUE.get();
+        throw new DirectoryException(ResultCode.PROTOCOL_ERROR, message);
+      }
 
 
+      return new AccountUsableRequestControl(isCritical);
+    }
+
+    public String getOID()
+    {
+      return OID_ACCOUNT_USABLE_CONTROL;
+    }
+
+  }
+
+  /**
+   * The Control Decoder that can be used to decode this control.
+   */
+  public static final ControlDecoder<AccountUsableRequestControl> DECODER =
+    new Decoder();
 
   /**
    * Creates a new instance of the account usable request control with the
@@ -55,67 +91,32 @@
    */
   public AccountUsableRequestControl()
   {
-    super(OID_ACCOUNT_USABLE_CONTROL, false);
-
+    this(false);
   }
 
-
-
   /**
    * Creates a new instance of the account usable request control with the
-   * provided information.
+   * default settings.
    *
-   * @param  oid         The OID to use for this control.
-   * @param  isCritical  Indicates whether support for this control should be
-   *                     considered a critical part of the client processing.
+   * @param  isCritical  Indicates whether this control should be
+   *                     considered critical in processing the
+   *                     request.
    */
-  public AccountUsableRequestControl(String oid, boolean isCritical)
+  public AccountUsableRequestControl(boolean isCritical)
   {
-    super(oid, isCritical);
+    super(OID_ACCOUNT_USABLE_CONTROL, isCritical);
 
   }
 
-
-
   /**
-   * Creates a new account usable request control from the contents of the
-   * provided control.
+   * Writes this control's value to an ASN.1 writer. The value (if any) must be
+   * written as an ASN1OctetString.
    *
-   * @param  control  The generic control containing the information to use to
-   *                  create this account usable request control.
-   *
-   * @return  The account usable request control decoded from the provided
-   *          control.
-   *
-   * @throws  LDAPException  If this control cannot be decoded as a valid
-   *                         account usable request control.
+   * @param writer The ASN.1 output stream to write to.
+   * @throws IOException If a problem occurs while writing to the stream.
    */
-  public static AccountUsableRequestControl decodeControl(Control control)
-         throws LDAPException
-  {
-    if (control.hasValue())
-    {
-      Message message = ERR_ACCTUSABLEREQ_CONTROL_HAS_VALUE.get();
-      throw new LDAPException(LDAPResultCode.PROTOCOL_ERROR, message);
-    }
-
-
-    return new AccountUsableRequestControl(control.getOID(),
-                                           control.isCritical());
-  }
-
-
-
-  /**
-   * Retrieves a string representation of this account usable request control.
-   *
-   * @return  A string representation of this account usable request control.
-   */
-  public String toString()
-  {
-    StringBuilder buffer = new StringBuilder();
-    toString(buffer);
-    return buffer.toString();
+  protected void writeValue(ASN1Writer writer) throws IOException {
+    // No value element.
   }
 
 
diff --git a/opends/src/server/org/opends/server/controls/AccountUsableResponseControl.java b/opends/src/server/org/opends/server/controls/AccountUsableResponseControl.java
index 9eb741a..49367c5 100644
--- a/opends/src/server/org/opends/server/controls/AccountUsableResponseControl.java
+++ b/opends/src/server/org/opends/server/controls/AccountUsableResponseControl.java
@@ -28,19 +28,12 @@
 import org.opends.messages.Message;
 
 
+import java.io.IOException;
 
-import java.util.ArrayList;
-
-import org.opends.server.protocols.asn1.ASN1Boolean;
-import org.opends.server.protocols.asn1.ASN1Element;
-import org.opends.server.protocols.asn1.ASN1Exception;
-import org.opends.server.protocols.asn1.ASN1Integer;
-import org.opends.server.protocols.asn1.ASN1OctetString;
-import org.opends.server.protocols.asn1.ASN1Sequence;
-import org.opends.server.protocols.ldap.LDAPResultCode;
-import org.opends.server.types.Control;
-import org.opends.server.types.DebugLogLevel;
-import org.opends.server.types.LDAPException;
+import org.opends.server.protocols.asn1.*;
+import static org.opends.server.protocols.asn1.ASN1Constants.
+    UNIVERSAL_OCTET_STRING_TYPE;
+import org.opends.server.types.*;
 
 import static org.opends.server.loggers.debug.DebugLogger.*;
 import org.opends.server.loggers.debug.DebugTracer;
@@ -69,9 +62,120 @@
  * </PRE>
  */
 public class AccountUsableResponseControl
-       extends Control
+    extends Control
 {
   /**
+   * ControlDecoder implentation to decode this control from a ByteString.
+   */
+  private final static class Decoder
+      implements ControlDecoder<AccountUsableResponseControl>
+  {
+    /**
+     * {@inheritDoc}
+     */
+    public AccountUsableResponseControl decode(boolean isCritical,
+                                               ByteString value)
+        throws DirectoryException
+    {
+      if (value == null)
+      {
+        // The response control must always have a value.
+        Message message = ERR_ACCTUSABLERES_NO_CONTROL_VALUE.get();
+        throw new DirectoryException(ResultCode.PROTOCOL_ERROR, message);
+      }
+
+
+      try
+      {
+        ASN1Reader reader = ASN1.getReader(value);
+        switch (reader.peekType())
+        {
+          case TYPE_SECONDS_BEFORE_EXPIRATION:
+            int secondsBeforeExpiration = (int)reader.readInteger();
+            return new AccountUsableResponseControl(isCritical,
+                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();
+            while(reader.hasNextElement())
+            {
+              switch (reader.peekType())
+              {
+                case TYPE_INACTIVE:
+                  isInactive = reader.readBoolean();
+                  break;
+                case TYPE_RESET:
+                  isReset = reader.readBoolean();
+                  break;
+                case TYPE_EXPIRED:
+                  isExpired = reader.readBoolean();
+                  break;
+                case TYPE_REMAINING_GRACE_LOGINS:
+                  remainingGraceLogins = (int)reader.readInteger();
+                  break;
+                case TYPE_SECONDS_BEFORE_UNLOCK:
+                  isLocked = true;
+                  secondsBeforeUnlock = (int)reader.readInteger();
+                  break;
+                default:
+                  Message message = ERR_ACCTUSABLERES_UNKNOWN_UNAVAILABLE_TYPE.
+                      get(byteToHex(reader.peekType()));
+                  throw new DirectoryException(ResultCode.PROTOCOL_ERROR,
+                      message);
+              }
+            }
+            reader.readEndSequence();
+
+            return new AccountUsableResponseControl(isCritical,
+                isInactive, isReset,
+                isExpired,
+                remainingGraceLogins,
+                isLocked,
+                secondsBeforeUnlock);
+
+          default:
+            Message message = ERR_ACCTUSABLERES_UNKNOWN_VALUE_ELEMENT_TYPE.get(
+                byteToHex(reader.peekType()));
+            throw new DirectoryException(ResultCode.PROTOCOL_ERROR, message);
+        }
+      }
+      catch (DirectoryException de)
+      {
+        throw de;
+      }
+      catch (Exception e)
+      {
+        if (debugEnabled())
+        {
+          TRACER.debugCaught(DebugLogLevel.ERROR, e);
+        }
+
+        Message message =
+            ERR_ACCTUSABLERES_DECODE_ERROR.get(getExceptionMessage(e));
+        throw new DirectoryException(ResultCode.PROTOCOL_ERROR, message);
+      }
+    }
+
+    public String getOID()
+    {
+      return OID_ACCOUNT_USABLE_CONTROL;
+    }
+
+  }
+
+  /**
+   * The Control Decoder that can be used to decode this control.
+   */
+  public static final ControlDecoder<AccountUsableResponseControl> DECODER =
+    new Decoder();
+
+  /**
    * The tracer object for the debug logger.
    */
   private static final DebugTracer TRACER = getTracer();
@@ -175,8 +279,26 @@
    */
   public AccountUsableResponseControl(int secondsBeforeExpiration)
   {
-    super(OID_ACCOUNT_USABLE_CONTROL, false,
-          encodeValue(secondsBeforeExpiration));
+    this(false, secondsBeforeExpiration);
+  }
+
+  /**
+   * 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.  It will use the default OID and criticality.
+   *
+   * @param  isCritical  Indicates whether this control should be
+   *                     considered critical in processing the
+   *                     request.
+   * @param  secondsBeforeExpiration  The length of time in seconds until the
+   *                                  user's password expires, or -1 if the
+   *                                  user's password will not expire or the
+   *                                  expiration time is unknown.
+   */
+  public AccountUsableResponseControl(boolean isCritical,
+                                      int secondsBeforeExpiration)
+  {
+    super(OID_ACCOUNT_USABLE_CONTROL, isCritical);
 
 
     this.secondsBeforeExpiration = secondsBeforeExpiration;
@@ -194,37 +316,50 @@
 
   /**
    * 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.
+   * indicate that the account is not available and provide information about
+   * the underlying reason.  It will use the default OID and criticality.
    *
-   * @param  oid                      The OID for this account usability
-   *                                  response control.
-   * @param  isCritical               Indicates whether this control should be
-   *                                  marked critical.
-   * @param  secondsBeforeExpiration  The length of time in seconds until the
-   *                                  user's password expires, or -1 if the
-   *                                  user's password will not expire or the
-   *                                  expiration time is unknown.
+   * @param  isCritical  Indicates whether this control should be
+   *                     considered critical in processing the
+   *                     request.
+   * @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 is
+   *                               expired.
+   * @param  remainingGraceLogins  The number of grace logins remaining.  A
+   *                               value of zero indicates that there are none
+   *                               remaining.  A value of -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 -1 indicates
+   *                               that the account will not be automatically
+   *                               unlocked and must be reset by an
+   *                               administrator.
    */
-  public AccountUsableResponseControl(String oid, boolean isCritical,
-                                      int secondsBeforeExpiration)
+  public AccountUsableResponseControl(boolean isCritical, boolean isInactive,
+                                      boolean isReset,
+                                      boolean isExpired,
+                                      int remainingGraceLogins,
+                                      boolean isLocked, int secondsBeforeUnlock)
   {
-    super(oid, isCritical, encodeValue(secondsBeforeExpiration));
+    super(OID_ACCOUNT_USABLE_CONTROL, isCritical);
 
 
-    this.secondsBeforeExpiration = secondsBeforeExpiration;
+    this.isInactive           = isInactive;
+    this.isReset              = isReset;
+    this.isExpired            = isExpired;
+    this.remainingGraceLogins = remainingGraceLogins;
+    this.isLocked             = isLocked;
+    this.secondsBeforeUnlock  = secondsBeforeUnlock;
 
-    isUsable             = true;
-    isInactive           = false;
-    isReset              = false;
-    isExpired            = false;
-    remainingGraceLogins = -1;
-    isLocked             = false;
-    secondsBeforeUnlock  = 0;
+    isUsable                = false;
+    secondsBeforeExpiration = -1;
   }
 
-
-
   /**
    * Creates a new account usability response control that may be used to
    * indicate that the account is not available and provide information about
@@ -253,342 +388,63 @@
                                       int remainingGraceLogins,
                                       boolean isLocked, int secondsBeforeUnlock)
   {
-    super(OID_ACCOUNT_USABLE_CONTROL, false,
-          encodeValue(isInactive, isReset, isExpired, remainingGraceLogins,
-                      isLocked, secondsBeforeUnlock));
-
-
-    this.isInactive           = isInactive;
-    this.isReset              = isReset;
-    this.isExpired            = isExpired;
-    this.remainingGraceLogins = remainingGraceLogins;
-    this.isLocked             = isLocked;
-    this.secondsBeforeUnlock  = secondsBeforeUnlock;
-
-    isUsable                = false;
-    secondsBeforeExpiration = -1;
+    this(false, isInactive, isReset, isExpired, remainingGraceLogins,
+        isLocked, secondsBeforeUnlock);
   }
 
-
-
   /**
-   * 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.
+   * Writes this control's value to an ASN.1 writer. The value (if any) must be
+   * written as an ASN1OctetString.
    *
-   * @param  oid                   The OID for this account usability response
-   *                               control.
-   * @param  isCritical            Indicates whether this control should be
-   *                               marked critical.
-   * @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 is
-   *                               expired.
-   * @param  remainingGraceLogins  The number of grace logins remaining.  A
-   *                               value of zero indicates that there are none
-   *                               remaining.  A value of -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 -1 indicates
-   *                               that the account will not be automatically
-   *                               unlocked and must be reset by an
-   *                               administrator.
+   * @param writer The ASN.1 output stream to write to.
+   * @throws IOException If a problem occurs while writing to the stream.
    */
-  public AccountUsableResponseControl(String oid, boolean isCritical,
-                                      boolean isInactive, boolean isReset,
-                                      boolean isExpired,
-                                      int remainingGraceLogins,
-                                      boolean isLocked, int secondsBeforeUnlock)
-  {
-    super(oid, isCritical,
-          encodeValue(isInactive, isReset, isExpired, remainingGraceLogins,
-                      isLocked, secondsBeforeUnlock));
+  public void writeValue(ASN1Writer writer) throws IOException {
+    writer.writeStartSequence(UNIVERSAL_OCTET_STRING_TYPE);
 
-
-    this.isInactive           = isInactive;
-    this.isReset              = isReset;
-    this.isExpired            = isExpired;
-    this.remainingGraceLogins = remainingGraceLogins;
-    this.isLocked             = isLocked;
-    this.secondsBeforeUnlock  = secondsBeforeUnlock;
-
-    isUsable                = false;
-    secondsBeforeExpiration = -1;
-  }
-
-
-
-  /**
-   * Creates a new account usability response control using the provided
-   * information.  This version of the constructor is only intended for internal
-   * use.
-   *
-   * @param  oid                      The OID for this account usability
-   *                                  response control.
-   * @param  isCritical               Indicates whether this control should be
-   *                                  marked critical.
-   * @param  isAvailable              Indicates whether the user's account is
-   *                                  available for use.
-   * @param  secondsBeforeExpiration  The length of time in seconds until the
-   *                                  user's password expires, or -1 if the
-   *                                  user's password will not expire or the
-   *                                  expiration time is unknown.
-   * @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 is
-   *                                  expired.
-   * @param  remainingGraceLogins     The number of grace logins remaining.  A
-   *                                  value of zero indicates that there are
-   *                                  none remaining.  A value of -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 -1
-   *                                  indicates that the account will not be
-   *                                  automatically unlocked and must be reset
-   *                                  by an administrator.
-   * @param  encodedValue             The pre-encoded value for this account
-   *                                  usable response control.
-   */
-  private AccountUsableResponseControl(String oid, boolean isCritical,
-                                             boolean isAvailable,
-                                             int secondsBeforeExpiration,
-                                             boolean isInactive,
-                                             boolean isReset, boolean isExpired,
-                                             int remainingGraceLogins,
-                                             boolean isLocked,
-                                             int secondsBeforeUnlock,
-                                             ASN1OctetString encodedValue)
-  {
-    super(oid, isCritical, encodedValue);
-
-
-    this.isUsable                = isAvailable;
-    this.secondsBeforeExpiration = secondsBeforeExpiration;
-    this.isInactive              = isInactive;
-    this.isReset                 = isReset;
-    this.isExpired               = isExpired;
-    this.remainingGraceLogins    = remainingGraceLogins;
-    this.isLocked                = isLocked;
-    this.secondsBeforeUnlock     = secondsBeforeUnlock;
-  }
-
-
-
-  /**
-   * Encodes the provided information into an ASN.1 octet string suitable for
-   * use as the value for an account usable response control in which the use's
-   * account is available.
-   *
-   * @param  secondsBeforeExpiration  The length of time in seconds until the
-   *                                  user's password expires, or -1 if the
-   *                                  user's password will not expire or the
-   *                                  expiration time is unknown.
-   *
-   * @return  An ASN.1 octet string containing the encoded control value.
-   */
-  private static ASN1OctetString encodeValue(int secondsBeforeExpiration)
-  {
-    ASN1Integer sbeInteger = new ASN1Integer(TYPE_SECONDS_BEFORE_EXPIRATION,
-                                             secondsBeforeExpiration);
-
-    return new ASN1OctetString(sbeInteger.encode());
-  }
-
-
-
-  /**
-   * Encodes the provided information into an ASN.1 octet string suitable for
-   * use as the value for an account usable response control in which the user's
-   * account is not available.
-   *
-   *
-   * @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 is
-   *                               expired.
-   * @param  remainingGraceLogins  The number of grace logins remaining.  A
-   *                               value of zero indicates that there are none
-   *                               remaining.  A value of -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 -1 indicates
-   *                               that the account will not be automatically
-   *                               unlocked and must be reset by an
-   *                               administrator.
-   *
-   * @return  An ASN.1 octet string containing the encoded control value.
-   */
-  private static ASN1OctetString encodeValue(boolean isInactive,
-                                             boolean isReset, boolean isExpired,
-                                             int remainingGraceLogins,
-                                             boolean isLocked,
-                                             int secondsBeforeUnlock)
-  {
-    ArrayList<ASN1Element> elements = new ArrayList<ASN1Element>(5);
-
-    if (isInactive)
+    if(secondsBeforeExpiration < 0)
     {
-      elements.add(new ASN1Boolean(TYPE_INACTIVE, true));
+      writer.writeInteger(TYPE_SECONDS_BEFORE_EXPIRATION,
+          secondsBeforeExpiration);
     }
-
-    if (isReset)
+    else
     {
-      elements.add(new ASN1Boolean(TYPE_RESET, true));
-    }
-
-    if (isExpired)
-    {
-      elements.add(new ASN1Boolean(TYPE_EXPIRED, true));
-
-      if (remainingGraceLogins >= 0)
+      writer.writeStartSequence(TYPE_MORE_INFO);
+      if (isInactive)
       {
-        elements.add(new ASN1Integer(TYPE_REMAINING_GRACE_LOGINS,
-                                     remainingGraceLogins));
-      }
-    }
-
-    if (isLocked)
-    {
-      elements.add(new ASN1Integer(TYPE_SECONDS_BEFORE_UNLOCK,
-                                   secondsBeforeUnlock));
-    }
-
-    ASN1Sequence moreInfoSequence = new ASN1Sequence(TYPE_MORE_INFO,
-                                                     elements);
-    return new ASN1OctetString(moreInfoSequence.encode());
-  }
-
-
-
-  /**
-   * Creates a new account usable response control from the contents of the
-   * provided control.
-   *
-   * @param  control  The generic control containing the information to use to
-   *                  create this account usable response control.
-   *
-   * @return  The account usable response control decoded from the provided
-   *          control.
-   *
-   * @throws  LDAPException  If this control cannot be decoded as a valid
-   *                         account usable response control.
-   */
-  public static AccountUsableResponseControl decodeControl(Control control)
-         throws LDAPException
-  {
-    ASN1OctetString controlValue = control.getValue();
-    if (controlValue == null)
-    {
-      // The response control must always have a value.
-      Message message = ERR_ACCTUSABLERES_NO_CONTROL_VALUE.get();
-      throw new LDAPException(LDAPResultCode.PROTOCOL_ERROR, message);
-    }
-
-
-    try
-    {
-      ASN1Element valueElement = ASN1Element.decode(controlValue.value());
-      switch (valueElement.getType())
-      {
-        case TYPE_SECONDS_BEFORE_EXPIRATION:
-          int secondsBeforeExpiration =
-                   valueElement.decodeAsInteger().intValue();
-          return new AccountUsableResponseControl(control.getOID(),
-                                                  control.isCritical(), true,
-                                                  secondsBeforeExpiration,
-                                                  false, false, false, -1,
-                                                  false, 0, controlValue);
-        case TYPE_MORE_INFO:
-          boolean isInactive = false;
-          boolean isReset = false;
-          boolean isExpired = false;
-          boolean isLocked = false;
-          int     remainingGraceLogins = -1;
-          int     secondsBeforeUnlock = 0;
-
-          for (ASN1Element e : valueElement.decodeAsSequence().elements())
-          {
-            switch (e.getType())
-            {
-              case TYPE_INACTIVE:
-                isInactive = e.decodeAsBoolean().booleanValue();
-                break;
-              case TYPE_RESET:
-                isReset = e.decodeAsBoolean().booleanValue();
-                break;
-              case TYPE_EXPIRED:
-                isExpired = e.decodeAsBoolean().booleanValue();
-                break;
-              case TYPE_REMAINING_GRACE_LOGINS:
-                remainingGraceLogins = e.decodeAsInteger().intValue();
-                break;
-              case TYPE_SECONDS_BEFORE_UNLOCK:
-                isLocked = true;
-                secondsBeforeUnlock = e.decodeAsInteger().intValue();
-                break;
-              default:
-                Message message = ERR_ACCTUSABLERES_UNKNOWN_UNAVAILABLE_TYPE.
-                    get(byteToHex(e.getType()));
-                throw new LDAPException(LDAPResultCode.PROTOCOL_ERROR, message);
-            }
-          }
-
-          return new AccountUsableResponseControl(control.getOID(),
-                                                  control.isCritical(), false,
-                                                  -1, isInactive, isReset,
-                                                  isExpired,
-                                                  remainingGraceLogins,
-                                                  isLocked, secondsBeforeUnlock,
-                                                  controlValue);
-
-        default:
-          Message message = ERR_ACCTUSABLERES_UNKNOWN_VALUE_ELEMENT_TYPE.get(
-              byteToHex(valueElement.getType()));
-          throw new LDAPException(LDAPResultCode.PROTOCOL_ERROR, message);
-      }
-    }
-    catch (LDAPException le)
-    {
-      throw le;
-    }
-    catch (ASN1Exception ae)
-    {
-      if (debugEnabled())
-      {
-        TRACER.debugCaught(DebugLogLevel.ERROR, ae);
+        writer.writeBoolean(TYPE_INACTIVE, true);
       }
 
-      Message message = ERR_ACCTUSABLERES_DECODE_ERROR.get(ae.getMessage());
-      throw new LDAPException(LDAPResultCode.PROTOCOL_ERROR, message);
-    }
-    catch (Exception e)
-    {
-      if (debugEnabled())
+      if (isReset)
       {
-        TRACER.debugCaught(DebugLogLevel.ERROR, e);
+        writer.writeBoolean(TYPE_RESET, true);
       }
 
-      Message message =
-          ERR_ACCTUSABLERES_DECODE_ERROR.get(getExceptionMessage(e));
-      throw new LDAPException(LDAPResultCode.PROTOCOL_ERROR, message);
+      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();
     }
+
+    writer.writeEndSequence();
   }
 
 
 
+
   /**
    * Indicates whether the associated user account is available for use.
    *
@@ -703,20 +559,6 @@
 
 
   /**
-   * Retrieves a string representation of this password policy response control.
-   *
-   * @return  A string representation of this password policy response control.
-   */
-  public String toString()
-  {
-    StringBuilder buffer = new StringBuilder();
-    toString(buffer);
-    return buffer.toString();
-  }
-
-
-
-  /**
    * Appends a string representation of this password policy response control to
    * the provided buffer.
    *
diff --git a/opends/src/server/org/opends/server/controls/AuthorizationIdentityResponseControl.java b/opends/src/server/org/opends/server/controls/AuthorizationIdentityResponseControl.java
index d180db2..81c7e0b 100644
--- a/opends/src/server/org/opends/server/controls/AuthorizationIdentityResponseControl.java
+++ b/opends/src/server/org/opends/server/controls/AuthorizationIdentityResponseControl.java
@@ -29,15 +29,13 @@
 
 
 
-import org.opends.server.protocols.asn1.ASN1OctetString;
-import org.opends.server.protocols.ldap.LDAPResultCode;
-import org.opends.server.types.Control;
-import org.opends.server.types.DN;
-import org.opends.server.types.LDAPException;
+import org.opends.server.protocols.asn1.ASN1Writer;
+import org.opends.server.types.*;
 
 import static org.opends.messages.ProtocolMessages.*;
 import static org.opends.server.util.ServerConstants.*;
 
+import java.io.IOException;
 
 
 /**
@@ -49,7 +47,50 @@
 public class AuthorizationIdentityResponseControl
        extends Control
 {
+  /**
+   * ControlDecoder implentation to decode this control from a ByteString.
+   */
+  private final static class Decoder
+      implements ControlDecoder<AuthorizationIdentityResponseControl>
+  {
+    /**
+     * {@inheritDoc}
+     */
+    public AuthorizationIdentityResponseControl decode(boolean isCritical,
+                                                       ByteString value)
+        throws DirectoryException
+    {
+      if (value == null)
+      {
+        Message message = ERR_AUTHZIDRESP_NO_CONTROL_VALUE.get();
+        throw new DirectoryException(ResultCode.PROTOCOL_ERROR, message);
+      }
 
+      try
+      {
+        String authID = value.toString();
+        return new AuthorizationIdentityResponseControl(isCritical,
+            authID);
+      }
+      catch(Exception e)
+      {
+        // TODO: message.
+        throw new DirectoryException(ResultCode.PROTOCOL_ERROR, Message.EMPTY);
+      }
+    }
+
+    public String getOID()
+    {
+      return OID_AUTHZID_RESPONSE;
+    }
+
+  }
+
+  /**
+   * The Control Decoder that can be used to decode this control.
+   */
+  public static final ControlDecoder<AuthorizationIdentityResponseControl>
+      DECODER = new Decoder();
 
 
   // The authorization ID for this control.
@@ -63,8 +104,20 @@
    */
   public AuthorizationIdentityResponseControl()
   {
-    super(OID_AUTHZID_RESPONSE, false, new ASN1OctetString());
+    this(false);
+  }
 
+  /**
+   * Creates a new authorization identity response control using the default
+   * settings to indicate an anonymous authentication.
+   *
+   * @param  isCritical  Indicates whether this control should be
+   *                     considered critical in processing the
+   *                     request.
+   */
+  public AuthorizationIdentityResponseControl(boolean isCritical)
+  {
+    super(OID_AUTHZID_RESPONSE, isCritical);
   }
 
 
@@ -77,7 +130,23 @@
    */
   public AuthorizationIdentityResponseControl(String authorizationID)
   {
-    super(OID_AUTHZID_RESPONSE, false, encodeValue(authorizationID));
+    this(false, authorizationID);
+  }
+
+
+  /**
+   * Creates a new authorization identity response control with the provided
+   * information.
+   *
+   * @param  isCritical  Indicates whether this control should be
+   *                     considered critical in processing the
+   *                     request.
+   * @param  authorizationID  The authorization ID for this control.
+   */
+  public AuthorizationIdentityResponseControl(boolean isCritical,
+                                              String authorizationID)
+  {
+    super(OID_AUTHZID_RESPONSE, isCritical);
 
 
     this.authorizationID = authorizationID;
@@ -85,6 +154,7 @@
 
 
 
+
   /**
    * Creates a new authorization identity response control with the provided
    * information.
@@ -93,7 +163,7 @@
    */
   public AuthorizationIdentityResponseControl(DN authorizationDN)
   {
-    super(OID_AUTHZID_RESPONSE, false, encodeValue(authorizationDN));
+    super(OID_AUTHZID_RESPONSE, false);
 
 
     if (authorizationDN == null)
@@ -109,142 +179,14 @@
 
 
   /**
-   * Creates a new authorization identity response control with the provided
-   * information.
+   * Writes this control's value to an ASN.1 writer. The value (if any) must be
+   * written as an ASN1OctetString.
    *
-   * @param  oid              The OID to use for this control.
-   * @param  isCritical       Indicates whether this control should be
-   *                          considered a critical part of the response
-   *                          processing.
-   * @param  authorizationID  The authorization ID for this control.
+   * @param writer The ASN.1 output stream to write to.
+   * @throws IOException If a problem occurs while writing to the stream.
    */
-  public AuthorizationIdentityResponseControl(String oid, boolean isCritical,
-                                              String authorizationID)
-  {
-    super(oid, isCritical, encodeValue(authorizationID));
-
-
-    this.authorizationID = authorizationID;
-  }
-
-
-
-  /**
-   * Creates a new authorization identity response control with the provided
-   * information.
-   *
-   * @param  oid              The OID to use for this control.
-   * @param  isCritical       Indicates whether this control should be
-   *                          considered a critical part of the response
-   *                          processing.
-   * @param  authorizationDN  The authorization DN for this control.
-   */
-  public AuthorizationIdentityResponseControl(String oid, boolean isCritical,
-                                              DN authorizationDN)
-  {
-    super(oid, isCritical, encodeValue(authorizationDN));
-
-
-    if (authorizationDN == null)
-    {
-      this.authorizationID = "dn:";
-    }
-    else
-    {
-      this.authorizationID = "dn:" + authorizationDN.toString();
-    }
-  }
-
-
-
-  /**
-   * Creates a new authorization identity response control with the provided
-   * information.
-   *
-   * @param  oid              The OID to use for this control.
-   * @param  isCritical       Indicates whether this control should be
-   *                          considered a critical part of the response
-   *                          processing.
-   * @param  authorizationID  The authorization ID for this control.
-   * @param  encodedValue     The encoded value for the control.
-   */
-  private AuthorizationIdentityResponseControl(String oid, boolean isCritical,
-                                               String authorizationID,
-                                               ASN1OctetString encodedValue)
-  {
-    super(oid, isCritical, encodedValue);
-
-
-    this.authorizationID = authorizationID;
-  }
-
-
-
-  /**
-   * Encodes the provided information into an ASN.1 octet string suitable for
-   * use as the control value.
-   *
-   * @param  authorizationID  The authorization ID for this authorization ID
-   *                          response control.
-   *
-   * @return  An ASN.1 octet string containing the encoded information.
-   */
-  private static ASN1OctetString encodeValue(String authorizationID)
-  {
-    return new ASN1OctetString(authorizationID);
-  }
-
-
-
-  /**
-   * Encodes the provided information into an ASN.1 octet string suitable for
-   * use as the control value.
-   *
-   * @param  authorizationDN  The authorization DN for this authorization ID
-   *                          response control.
-   *
-   * @return  An ASN.1 octet string containing the encoded information.
-   */
-  private static ASN1OctetString encodeValue(DN authorizationDN)
-  {
-    if (authorizationDN == null)
-    {
-      return new ASN1OctetString("dn:");
-    }
-    else
-    {
-      return new ASN1OctetString("dn:" + authorizationDN.toString());
-    }
-  }
-
-
-
-  /**
-   * Creates a new authorization identity response control from the contents of
-   * the provided control.
-   *
-   * @param  control  The generic control containing the information to use to
-   *                  create this authorization identity response control.
-   *
-   * @return  The authorization identity response control decoded from the
-   *          provided control.
-   *
-   * @throws  LDAPException  If this control cannot be decoded as a valid
-   *                         authorization identity response control.
-   */
-  public static AuthorizationIdentityResponseControl decodeControl(
-                                                          Control control)
-         throws LDAPException
-  {
-    if (! control.hasValue())
-    {
-      Message message = ERR_AUTHZIDRESP_NO_CONTROL_VALUE.get();
-      throw new LDAPException(LDAPResultCode.PROTOCOL_ERROR, message);
-    }
-
-    return new AuthorizationIdentityResponseControl(control.getOID(),
-                    control.isCritical(), control.getValue().stringValue(),
-                    control.getValue());
+  public void writeValue(ASN1Writer writer) throws IOException {
+    writer.writeOctetString(authorizationID);
   }
 
 
@@ -264,37 +206,6 @@
 
 
   /**
-   * Specifies the authorization ID for this authorization identity response
-   * control.
-   *
-   * @param  authorizationID  The authorization ID for this authorization
-   *                          identity response control.
-   */
-  public void setAuthorizationID(String authorizationID)
-  {
-    this.authorizationID = authorizationID;
-    setValue(encodeValue(authorizationID));
-  }
-
-
-
-  /**
-   * Retrieves a string representation of this authorization identity response
-   * control.
-   *
-   * @return  A string representation of this authorization identity response
-   *          control.
-   */
-  public String toString()
-  {
-    StringBuilder buffer = new StringBuilder();
-    toString(buffer);
-    return buffer.toString();
-  }
-
-
-
-  /**
    * Appends a string representation of this authorization identity response
    * control to the provided buffer.
    *
diff --git a/opends/src/server/org/opends/server/controls/ControlDecoder.java b/opends/src/server/org/opends/server/controls/ControlDecoder.java
new file mode 100644
index 0000000..c9724c7
--- /dev/null
+++ b/opends/src/server/org/opends/server/controls/ControlDecoder.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 2008 Sun Microsystems, Inc.
+ */
+package org.opends.server.controls;
+
+
+
+import org.opends.server.types.ByteString;
+import org.opends.server.types.Control;
+import org.opends.server.types.DirectoryException;
+
+
+
+/**
+ * An interface for decoding controls.
+ *
+ * @param <T>
+ *          The type of control decoded by this decoder.
+ */
+public interface ControlDecoder<T extends Control>
+{
+
+  /**
+   * Decodes the provided control.
+   *
+   * @param isCritical
+   *          Indicates whether the control should be considered
+   *          critical.
+   * @param value
+   *          The value for the control.
+   * @return The decoded control.
+   * @throws DirectoryException
+   *           If the control could not be decoded.
+   */
+  T decode(boolean isCritical, ByteString value) throws DirectoryException;
+
+
+
+  /**
+   * Gets the OID of the control decoded by this decoded.
+   *
+   * @return The OID of the control decoded by this decoded.
+   */
+  String getOID();
+}
diff --git a/opends/src/server/org/opends/server/controls/EntryChangeNotificationControl.java b/opends/src/server/org/opends/server/controls/EntryChangeNotificationControl.java
index 951d972..ef01791 100644
--- a/opends/src/server/org/opends/server/controls/EntryChangeNotificationControl.java
+++ b/opends/src/server/org/opends/server/controls/EntryChangeNotificationControl.java
@@ -28,20 +28,12 @@
 import org.opends.messages.Message;
 
 
+import java.io.IOException;
 
-import java.util.ArrayList;
-
-import org.opends.server.protocols.asn1.ASN1Constants;
-import org.opends.server.protocols.asn1.ASN1Element;
-import org.opends.server.protocols.asn1.ASN1Enumerated;
-import org.opends.server.protocols.asn1.ASN1Long;
-import org.opends.server.protocols.asn1.ASN1OctetString;
-import org.opends.server.protocols.asn1.ASN1Sequence;
-import org.opends.server.protocols.ldap.LDAPResultCode;
-import org.opends.server.types.Control;
-import org.opends.server.types.DN;
-import org.opends.server.types.DebugLogLevel;
-import org.opends.server.types.LDAPException;
+import org.opends.server.protocols.asn1.*;
+import static org.opends.server.protocols.asn1.ASN1Constants.
+    UNIVERSAL_OCTET_STRING_TYPE;
+import org.opends.server.types.*;
 
 import static org.opends.server.loggers.debug.DebugLogger.*;
 import org.opends.server.loggers.debug.DebugTracer;
@@ -60,6 +52,94 @@
        extends Control
 {
   /**
+   * ControlDecoder implentation to decode this control from a ByteString.
+   */
+  private final static class Decoder
+      implements ControlDecoder<EntryChangeNotificationControl>
+  {
+    /**
+     * {@inheritDoc}
+     */
+    public EntryChangeNotificationControl decode(
+        boolean isCritical, ByteString value) throws DirectoryException
+    {
+      if (value == null)
+      {
+        Message message = ERR_ECN_NO_CONTROL_VALUE.get();
+        throw new DirectoryException(ResultCode.PROTOCOL_ERROR, message);
+      }
+
+
+      DN                         previousDN   = null;
+      long                       changeNumber = -1;
+      PersistentSearchChangeType changeType;
+      ASN1Reader reader = ASN1.getReader(value);
+      try
+      {
+        reader.readStartSequence();
+
+        int changeTypeValue = (int)reader.readInteger();
+        changeType = PersistentSearchChangeType.valueOf(changeTypeValue);
+
+        while(reader.hasNextElement()) {
+          switch(reader.peekType()) {
+            case ASN1Constants.UNIVERSAL_OCTET_STRING_TYPE :
+              if (changeType != PersistentSearchChangeType.MODIFY_DN)
+              {
+                Message message =
+                    ERR_ECN_ILLEGAL_PREVIOUS_DN.get(String.valueOf(changeType));
+                throw new DirectoryException(
+                    ResultCode.PROTOCOL_ERROR, message);
+              }
+
+              previousDN = DN.decode(reader.readOctetStringAsString());
+              break;
+            case ASN1Constants.UNIVERSAL_INTEGER_TYPE :
+              changeNumber = reader.readInteger();
+              break;
+            default :
+              Message message =
+                  ERR_ECN_INVALID_ELEMENT_TYPE.get(
+                      byteToHex(reader.peekType()));
+              throw new DirectoryException(ResultCode.PROTOCOL_ERROR, message);
+          }
+        }
+      }
+      catch (DirectoryException de)
+      {
+        throw de;
+      }
+      catch (Exception e)
+      {
+        if (debugEnabled())
+        {
+          TRACER.debugCaught(DebugLogLevel.ERROR, e);
+        }
+
+        Message message =
+            ERR_ECN_CANNOT_DECODE_VALUE.get(getExceptionMessage(e));
+        throw new DirectoryException(ResultCode.PROTOCOL_ERROR, message, e);
+      }
+
+
+      return new EntryChangeNotificationControl(isCritical, changeType,
+          previousDN, changeNumber);
+    }
+
+    public String getOID()
+    {
+      return OID_ENTRY_CHANGE_NOTIFICATION;
+    }
+
+  }
+
+  /**
+   * The Control Decoder that can be used to decode this control.
+   */
+  public static final ControlDecoder<EntryChangeNotificationControl> DECODER =
+    new Decoder();
+
+  /**
    * The tracer object for the debug logger.
    */
   private static final DebugTracer TRACER = getTracer();
@@ -77,20 +157,22 @@
   private PersistentSearchChangeType changeType;
 
 
-
   /**
    * Creates a new entry change notification control with the provided
    * information.
    *
+   * @param  isCritical  Indicates whether this control should be
+   *                     considered critical in processing the
+   *                     request.
    * @param  changeType    The change type for this change notification control.
    * @param  changeNumber  The change number for the associated change, or a
    *                       negative value if no change number is available.
    */
-  public EntryChangeNotificationControl(PersistentSearchChangeType changeType,
+  public EntryChangeNotificationControl(boolean isCritical,
+                                        PersistentSearchChangeType changeType,
                                         long changeNumber)
   {
-    super(OID_ENTRY_CHANGE_NOTIFICATION, false,
-          encodeValue(changeType, null, changeNumber));
+    super(OID_ENTRY_CHANGE_NOTIFICATION, isCritical);
 
 
     this.changeType   = changeType;
@@ -105,6 +187,49 @@
    * Creates a new entry change notification control with the provided
    * information.
    *
+   * @param  isCritical  Indicates whether this control should be
+   *                     considered critical in processing the
+   *                     request.
+   * @param  changeType    The change type for this change notification control.
+   * @param  previousDN    The DN 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.
+   */
+  public EntryChangeNotificationControl(boolean isCritical,
+                                        PersistentSearchChangeType changeType,
+                                        DN previousDN, long changeNumber)
+  {
+    super(OID_ENTRY_CHANGE_NOTIFICATION, isCritical);
+
+
+    this.changeType   = changeType;
+    this.previousDN   = previousDN;
+    this.changeNumber = changeNumber;
+  }
+
+
+  /**
+   * Creates a new entry change notification control with the provided
+   * information.
+   *
+   * @param  changeType    The change type for this change notification control.
+   * @param  changeNumber  The change number for the associated change, or a
+   *                       negative value if no change number is available.
+   */
+  public EntryChangeNotificationControl(PersistentSearchChangeType changeType,
+                                        long changeNumber)
+  {
+    this(false, changeType, changeNumber);
+  }
+
+
+
+  /**
+   * Creates a new entry change notification control with the provided
+   * information.
+   *
    * @param  changeType    The change type for this change notification control.
    * @param  previousDN    The DN that the entry had prior to a modify DN
    *                       operation, or <CODE>null</CODE> if the operation was
@@ -115,213 +240,36 @@
   public EntryChangeNotificationControl(PersistentSearchChangeType changeType,
                                         DN previousDN, long changeNumber)
   {
-    super(OID_ENTRY_CHANGE_NOTIFICATION, false,
-          encodeValue(changeType, previousDN, changeNumber));
-
-
-    this.changeType   = changeType;
-    this.previousDN   = previousDN;
-    this.changeNumber = changeNumber;
+    this(false, changeType, previousDN, changeNumber);
   }
 
 
 
   /**
-   * Creates a new entry change notification control with the provided
-   * information.
+   * Writes this control's value to an ASN.1 writer. The value (if any) must be
+   * written as an ASN1OctetString.
    *
-   * @param  oid           The OID to use for this control.
-   * @param  isCritical    Indicates whether this control should be considered
-   *                       critical to the operation processing.
-   * @param  changeType    The change type for this change notification control.
-   * @param  previousDN    The DN 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.
+   * @param writer The ASN.1 output stream to write to.
+   * @throws IOException If a problem occurs while writing to the stream.
    */
-  public EntryChangeNotificationControl(String oid, boolean isCritical,
-                                        PersistentSearchChangeType changeType,
-                                        DN previousDN, long changeNumber)
-  {
-    super(oid, isCritical, encodeValue(changeType, previousDN, changeNumber));
+  public void writeValue(ASN1Writer writer) throws IOException {
+    writer.writeStartSequence(UNIVERSAL_OCTET_STRING_TYPE);
 
-
-    this.changeType   = changeType;
-    this.previousDN   = previousDN;
-    this.changeNumber = changeNumber;
-  }
-
-
-
-  /**
-   * Creates a new entry change notification control with the provided
-   * information.
-   *
-   * @param  oid           The OID to use for this control.
-   * @param  isCritical    Indicates whether this control should be considered
-   *                       critical to the operation processing.
-   * @param  changeType    The change type for this change notification control.
-   * @param  previousDN    The DN 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.
-   * @param  encodedValue  The pre-encoded value for this change notification
-   *                       control.
-   */
-  private EntryChangeNotificationControl(String oid, boolean isCritical,
-                                         PersistentSearchChangeType changeType,
-                                         DN previousDN, long changeNumber,
-                                         ASN1OctetString encodedValue)
-  {
-    super(oid, isCritical, encodedValue);
-
-
-    this.changeType   = changeType;
-    this.previousDN   = previousDN;
-    this.changeNumber = changeNumber;
-  }
-
-
-
-  /**
-   * Encodes the provided information into an ASN.1 octet string suitable for
-   * use as the control value.
-   *
-   * @param  changeType    The change type for this change notification control.
-   * @param  previousDN    The DN 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  An ASN.1 octet string containing the encoded information.
-   */
-  private static ASN1OctetString encodeValue(PersistentSearchChangeType
-                                                  changeType,
-                                             DN previousDN, long changeNumber)
-  {
-    ArrayList<ASN1Element> elements =
-         new ArrayList<ASN1Element>(3);
-    elements.add(new ASN1Enumerated(changeType.intValue()));
+    writer.writeStartSequence();
+    writer.writeInteger(changeType.intValue());
 
     if (previousDN != null)
     {
-      elements.add(new ASN1OctetString(previousDN.toString()));
+      writer.writeOctetString(previousDN.toString());
     }
 
     if (changeNumber > 0)
     {
-      elements.add(new ASN1Long(changeNumber));
+      writer.writeInteger(changeNumber);
     }
+    writer.writeEndSequence();
 
-
-    return new ASN1OctetString(new ASN1Sequence(elements).encode());
-  }
-
-
-
-  /**
-   * Creates a new entry change notification control from the contents of the
-   * provided control.
-   *
-   * @param  control  The generic control containing the information to use to
-   *                  create this entry change notification control.
-   *
-   * @return  The entry change notification control decoded from the provided
-   *          control.
-   *
-   * @throws  LDAPException  If this control cannot be decoded as a valid
-   *                         entry change notification control.
-   */
-  public static EntryChangeNotificationControl decodeControl(Control control)
-         throws LDAPException
-  {
-    if (! control.hasValue())
-    {
-      Message message = ERR_ECN_NO_CONTROL_VALUE.get();
-      throw new LDAPException(LDAPResultCode.PROTOCOL_ERROR, message);
-    }
-
-
-    DN                         previousDN   = null;
-    long                       changeNumber = -1;
-    PersistentSearchChangeType changeType;
-    try
-    {
-      ArrayList<ASN1Element> elements =
-           ASN1Sequence.decodeAsSequence(control.getValue().value()).elements();
-      if ((elements.size() < 1) || (elements.size() > 3))
-      {
-        Message message = ERR_ECN_INVALID_ELEMENT_COUNT.get(elements.size());
-        throw new LDAPException(LDAPResultCode.PROTOCOL_ERROR, message);
-      }
-
-      int changeTypeValue = elements.get(0).decodeAsEnumerated().intValue();
-      changeType = PersistentSearchChangeType.valueOf(changeTypeValue);
-
-      if (elements.size() == 2)
-      {
-        ASN1Element e = elements.get(1);
-        if (e.getType() == ASN1Constants.UNIVERSAL_OCTET_STRING_TYPE)
-        {
-          if (changeType != PersistentSearchChangeType.MODIFY_DN)
-          {
-            Message message =
-                ERR_ECN_ILLEGAL_PREVIOUS_DN.get(String.valueOf(changeType));
-            throw new LDAPException(LDAPResultCode.PROTOCOL_ERROR, message);
-          }
-
-          ASN1OctetString rawPreviousDN = e.decodeAsOctetString();
-          previousDN = DN.decode(rawPreviousDN);
-        }
-        else if (e.getType() == ASN1Constants.UNIVERSAL_INTEGER_TYPE)
-        {
-          changeNumber = e.decodeAsLong().longValue();
-        }
-        else
-        {
-          Message message =
-              ERR_ECN_INVALID_ELEMENT_TYPE.get(byteToHex(e.getType()));
-          throw new LDAPException(LDAPResultCode.PROTOCOL_ERROR, message);
-        }
-      }
-      else if (elements.size() == 3)
-      {
-        if (changeType != PersistentSearchChangeType.MODIFY_DN)
-        {
-          Message message =
-              ERR_ECN_ILLEGAL_PREVIOUS_DN.get(String.valueOf(changeType));
-          throw new LDAPException(LDAPResultCode.PROTOCOL_ERROR, message);
-        }
-
-        ASN1OctetString rawPreviousDN = elements.get(1).decodeAsOctetString();
-        previousDN = DN.decode(rawPreviousDN);
-
-        changeNumber = elements.get(2).decodeAsLong().longValue();
-      }
-    }
-    catch (LDAPException le)
-    {
-      throw le;
-    }
-    catch (Exception e)
-    {
-      if (debugEnabled())
-      {
-        TRACER.debugCaught(DebugLogLevel.ERROR, e);
-      }
-
-      Message message = ERR_ECN_CANNOT_DECODE_VALUE.get(getExceptionMessage(e));
-      throw new LDAPException(LDAPResultCode.PROTOCOL_ERROR, message, e);
-    }
-
-
-    return new EntryChangeNotificationControl(control.getOID(),
-                                              control.isCritical(), changeType,
-                                              previousDN, changeNumber,
-                                              control.getValue());
+    writer.writeEndSequence();
   }
 
 
@@ -337,22 +285,6 @@
   }
 
 
-
-  /**
-   * Sets the change type for this entry change notification control.
-   *
-   * @param  changeType  The change type for this entry change notification
-   *                     control.
-   */
-  public void setChangeType(PersistentSearchChangeType changeType)
-  {
-    this.changeType = changeType;
-
-    setValue(encodeValue(changeType, previousDN, changeNumber));
-  }
-
-
-
   /**
    * Retrieves the previous DN for this entry change notification control.
    *
@@ -367,21 +299,6 @@
 
 
   /**
-   * Specifies the previous DN for this entry change notification control.
-   *
-   * @param  previousDN  The previous DN for this entry change notification
-   *                     control.
-   */
-  public void setPreviousDN(DN previousDN)
-  {
-    this.previousDN = previousDN;
-
-    setValue(encodeValue(changeType, previousDN, changeNumber));
-  }
-
-
-
-  /**
    * Retrieves the change number for this entry change notification control.
    *
    * @return  The change number for this entry change notification control, or a
@@ -395,36 +312,6 @@
 
 
   /**
-   * Specifies the change number for this entry change notification control.
-   *
-   * @param  changeNumber  The change number for this entry change notification
-   *                       control.
-   */
-  public void setChangeNumber(long changeNumber)
-  {
-    this.changeNumber = changeNumber;
-
-    setValue(encodeValue(changeType, previousDN, changeNumber));
-  }
-
-
-
-  /**
-   * Retrieves a string representation of this entry change notification
-   * control.
-   *
-   * @return  A string representation of this entry change notification control.
-   */
-  public String toString()
-  {
-    StringBuilder buffer = new StringBuilder();
-    toString(buffer);
-    return buffer.toString();
-  }
-
-
-
-  /**
    * Appends a string representation of this entry change notification control
    * to the provided buffer.
    *
diff --git a/opends/src/server/org/opends/server/controls/GetEffectiveRights.java b/opends/src/server/org/opends/server/controls/GetEffectiveRights.java
deleted file mode 100644
index 1ab28b8..0000000
--- a/opends/src/server/org/opends/server/controls/GetEffectiveRights.java
+++ /dev/null
@@ -1,249 +0,0 @@
-/*
- * CDDL HEADER START
- *
- * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
- *
- * You can obtain a copy of the license at
- * trunk/opends/resource/legal-notices/OpenDS.LICENSE
- * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
- * See the License for the specific language governing permissions
- * and limitations under the License.
- *
- * When distributing Covered Code, include this CDDL HEADER in each
- * file and include the License file at
- * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
- * add the following below this CDDL 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.server.controls;
-import org.opends.messages.Message;
-
-import org.opends.server.types.*;
-import org.opends.server.protocols.asn1.ASN1OctetString;
-import org.opends.server.protocols.asn1.ASN1Element;
-import org.opends.server.protocols.asn1.ASN1Exception;
-import org.opends.server.protocols.ldap.LDAPResultCode;
-import static org.opends.server.util.ServerConstants.OID_GET_EFFECTIVE_RIGHTS;
-import static org.opends.server.util.Validator.ensureNotNull;
-import static org.opends.server.util.StaticUtils.toLowerCase;
-import org.opends.server.core.DirectoryServer;
-import static org.opends.messages.ProtocolMessages.*;
-import static org.opends.server.loggers.debug.DebugLogger.*;
-import org.opends.server.loggers.debug.DebugTracer;
-
-import java.util.List;
-import java.util.ArrayList;
-import java.util.LinkedList;
-
-/**
- * This class partially implements the geteffectiverights control as defined
- * in draft-ietf-ldapext-acl-model-08.txt. The main differences are:
- *
- *  - The response control is not supported. Instead the dseecompat
- *    geteffectiverights control implementation creates attributes containing
- *    right information strings and adds those attributes to the
- *    entry being returned. The attribute type names are dynamically created;
- *    see the dseecompat's AciGetEffectiveRights class for details.
- *
- *  - The dseecompat implementation allows additional attribute types
- *    in the request control for which rights information can be returned.
- *    These are known as the specified attribute types.
- *
- * The dseecompat request control value is the following:
- *
- * <BR>
- * <PRE>
- *  GetRightsControl ::= SEQUENCE {
- *    authzId    authzId
- *    attributes  SEQUENCE OF AttributeType
- *  }
- *
- *   -- Only the "dn:DN form is supported.
- *
- * </PRE>
- *
- **/
-public class GetEffectiveRights extends Control {
-  /**
-   * The tracer object for the debug logger.
-   */
-  private static final DebugTracer TRACER = getTracer();
-
-
-  //The DN representing the authzId. May be null.
-  private DN authzDN=null;
-
-  //The list of additional attribute types to return rights for. May be null.
-  private List<AttributeType> attrs=null;
-
-  /**
-   *  Create a new geteffectiverights control with null authzDN and null
-   *  attribute list.
-   */
-  public GetEffectiveRights() {
-    super(OID_GET_EFFECTIVE_RIGHTS, true, null);
-  }
-
-  /**
-   * Create a new geteffectiverights control with the specified raw octet
-   * string, an authzDN and an attribute list.
-   *
-   * @param val  The octet string repsentation of the control value.
-   *
-   * @param authzDN  The authzDN.
-   *
-   * @param attrs  The list of additional attributes to be returned.
-   */
-  public GetEffectiveRights(ASN1OctetString val, DN authzDN,
-                            List<AttributeType> attrs) {
-    super(OID_GET_EFFECTIVE_RIGHTS, true, val);
-    this.authzDN=authzDN;
-    this.attrs=attrs;
-  }
-
-  /**
-   * Return the authzDN parsed from the control.
-   *
-   * @return The DN representing the authzId.
-   */
-  public DN getAuthzDN () {
-    return authzDN;
-  }
-
-  /**
-   * Return the requested additional attributes parsed from the control. Known
-   * as the specified attributes.
-   *
-   * @return  The list containing any additional attributes to return rights
-   *          about.
-   */
-  public List<AttributeType> getAttributes() {
-    return attrs;
-  }
-
-
-  /**
-   * Decodes the provided ASN1 element.  Assume that it is a ASN1 sequence
-   * of attributetypes.
-   *
-   * @param attributeElement   The ASN1 element to be decoded.
-   *
-   * @return  A list of attribute types to process rights of.
-   *
-   * @throws ASN1Exception If the attribute element cannot be decoded as a
-   *                       sequence.
-   */
-  private static
-  List<AttributeType> decodeAttributeSequence(ASN1Element attributeElement)
-          throws ASN1Exception {
-    List<AttributeType>  attributeList = new LinkedList<AttributeType>();
-    //Decode the sequence element and put the individual elements in array.
-    ArrayList<ASN1Element> attrElems =
-            attributeElement.decodeAsSequence().elements();
-    int numAttrElements = attrElems.size();
-    for(int i=0; i < numAttrElements; i++) {
-      //Decode as an octet string.
-      ASN1OctetString tmp=attrElems.get(i).decodeAsOctetString();
-      //Get an attribute type for it and add to the list.
-      AttributeType attributeType;
-      if((attributeType =
-              DirectoryServer.getAttributeType(tmp.toString())) == null)
-        attributeType =
-                DirectoryServer.getDefaultAttributeType(tmp.toString());
-      attributeList.add(attributeType);
-    }
-    return attributeList;
-  }
-
-  /**
-   * Decodes the request control's value octet string into a GetEffectiveRights
-   * class. It assumes that it is an ASN1 sequence as described in class
-   * description.
-   *
-   * @param val The octet string repsentation of the control value.
-   *
-   * @return  A decoded GetEffectiveRights class representing the request
-   *          control.
-   *
-   * @throws LDAPException   If the request control's value contains errors
-   *                         causing a valid GetEffectiveRights class to not
-   *                         be created.
-   */
-  private static
-  GetEffectiveRights decodeValueSequence(ASN1OctetString val )
-          throws LDAPException {
-    DN authzDN;
-    List<AttributeType> attrs=null;
-    String authzIDString="";
-    try {
-      ASN1Element sequence = ASN1Element.decode(val.value());
-      ArrayList<ASN1Element> elements =
-              sequence.decodeAsSequence().elements();
-      ASN1OctetString authzID = elements.get(0).decodeAsOctetString();
-      //There is an sequence containing an attribute list, try to decode it.
-      if(elements.size() == 2)
-        attrs=decodeAttributeSequence(elements.get(1));
-      authzIDString = authzID.stringValue();
-      String lowerAuthzIDString = toLowerCase(authzIDString);
-      //Make sure authzId starts with "dn:" and is a valid DN.
-      if (lowerAuthzIDString.startsWith("dn:"))
-         authzDN = DN.decode(authzIDString.substring(3));
-      else {
-         Message message = INFO_GETEFFECTIVERIGHTS_INVALID_AUTHZID.get(
-                 String.valueOf(authzID));
-         throw new LDAPException(LDAPResultCode.PROTOCOL_ERROR, message);
-      }
-    } catch (ASN1Exception e) {
-         if (debugEnabled()) {
-            TRACER.debugCaught(DebugLogLevel.ERROR, e);
-         }
-
-         Message message =
-             INFO_GETEFFECTIVERIGHTS_DECODE_ERROR.get(e.getMessage());
-         throw new LDAPException(LDAPResultCode.PROTOCOL_ERROR, message);
-    } catch (DirectoryException de) {
-        if (debugEnabled()) {
-          TRACER.debugCaught(DebugLogLevel.ERROR, de);
-        }
-
-        Message message = INFO_CANNOT_DECODE_GETEFFECTIVERIGHTS_AUTHZID_DN.get(
-            authzIDString.substring(3), de.getMessageObject());
-        throw new LDAPException(LDAPResultCode.PROTOCOL_ERROR, message);
-    }
-    return new GetEffectiveRights(val, authzDN, attrs);
-  }
-
-  /**
-   * Decodes the request control's value into a GetEffectiveRights class.
-   *
-   * @param control  The control class representing the request control.
-   *
-   * @return  A decoded GetEffectiveRights class representing the request
-   *          control.
-   *
-   * @throws LDAPException   If the request control's value contains errors
-   *                         causing a valid GetEffectiveRights class to not
-   *                         be created.
-   */
-  public static
-  GetEffectiveRights decodeControl(Control control) throws LDAPException {
-    ensureNotNull(control);
-    ASN1OctetString value=control.getValue();
-    //If the value is null create a GetEffectiveRights class with null
-    //authzDN and attribute list, else try to decode the value.
-    if(value == null)
-      return new GetEffectiveRights();
-    else
-      return GetEffectiveRights.decodeValueSequence(value);
-  }
-}
diff --git a/opends/src/server/org/opends/server/controls/GetEffectiveRightsRequestControl.java b/opends/src/server/org/opends/server/controls/GetEffectiveRightsRequestControl.java
new file mode 100644
index 0000000..03b216a
--- /dev/null
+++ b/opends/src/server/org/opends/server/controls/GetEffectiveRightsRequestControl.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 2009 Sun Microsystems, Inc.
+ */
+
+package org.opends.server.controls;
+import org.opends.messages.Message;
+
+import org.opends.server.types.*;
+import org.opends.server.protocols.asn1.*;
+import static org.opends.server.protocols.asn1.ASN1Constants.
+    UNIVERSAL_OCTET_STRING_TYPE;
+import static org.opends.server.util.ServerConstants.OID_GET_EFFECTIVE_RIGHTS;
+import org.opends.server.core.DirectoryServer;
+import static org.opends.messages.ProtocolMessages.*;
+import static org.opends.server.loggers.debug.DebugLogger.*;
+import org.opends.server.loggers.debug.DebugTracer;
+
+import java.util.List;
+import java.util.LinkedList;
+import java.io.IOException;
+
+/**
+ * This class partially implements the geteffectiverights control as defined
+ * in draft-ietf-ldapext-acl-model-08.txt. The main differences are:
+ *
+ *  - The response control is not supported. Instead the dseecompat
+ *    geteffectiverights control implementation creates attributes containing
+ *    right information strings and adds those attributes to the
+ *    entry being returned. The attribute type names are dynamically created;
+ *    see the dseecompat's AciGetEffectiveRights class for details.
+ *
+ *  - The dseecompat implementation allows additional attribute types
+ *    in the request control for which rights information can be returned.
+ *    These are known as the specified attribute types.
+ *
+ * The dseecompat request control value is the following:
+ *
+ * <BR>
+ * <PRE>
+ *  GetRightsControl ::= SEQUENCE {
+ *    authzId    authzId
+ *    attributes  SEQUENCE OF AttributeType
+ *  }
+ *
+ *   -- Only the "dn:DN form is supported.
+ *
+ * </PRE>
+ *
+ **/
+public class GetEffectiveRightsRequestControl extends Control
+{
+  /**
+   * ControlDecoder implentation to decode this control from a ByteString.
+   */
+  private static final class Decoder
+      implements ControlDecoder<GetEffectiveRightsRequestControl>
+  {
+    /**
+     * {@inheritDoc}
+     */
+    public GetEffectiveRightsRequestControl decode(boolean isCritical,
+        ByteString value) throws DirectoryException
+    {
+      // If the value is null create a GetEffectiveRightsRequestControl
+      // class with null authzDN and attribute list, else try to
+      // decode the value.
+      if (value == null)
+        return new GetEffectiveRightsRequestControl(isCritical, (DN)null,
+            (List<AttributeType>)null);
+      else
+      {
+        ASN1Reader reader = ASN1.getReader(value);
+        DN authzDN;
+        List<AttributeType> attrs=null;
+        String authzIDString="";
+        try {
+          reader.readStartSequence();
+          authzIDString = reader.readOctetStringAsString();
+          String lowerAuthzIDString = authzIDString.toLowerCase();
+          //Make sure authzId starts with "dn:" and is a valid DN.
+          if (lowerAuthzIDString.startsWith("dn:"))
+            authzDN = DN.decode(authzIDString.substring(3));
+          else {
+            Message message = INFO_GETEFFECTIVERIGHTS_INVALID_AUTHZID.get(
+                lowerAuthzIDString);
+            throw new DirectoryException(ResultCode.PROTOCOL_ERROR, message);
+          }
+          //There is an sequence containing an attribute list, try to decode it.
+          if(reader.hasNextElement()) {
+            AttributeType attributeType;
+            attrs = new LinkedList<AttributeType>();
+            reader.readStartSequence();
+            while(reader.hasNextElement()) {
+              //Decode as an octet string.
+              String attrStr = reader.readOctetStringAsString();
+              //Get an attribute type for it and add to the list.
+              if((attributeType =
+                  DirectoryServer.getAttributeType(attrStr)) == null)
+                attributeType =
+                    DirectoryServer.getDefaultAttributeType(attrStr);
+              attrs.add(attributeType);
+            }
+            reader.readEndSequence();
+          }
+          reader.readEndSequence();
+        } catch (ASN1Exception e) {
+          if (debugEnabled()) {
+            TRACER.debugCaught(DebugLogLevel.ERROR, e);
+          }
+
+          Message message =
+              INFO_GETEFFECTIVERIGHTS_DECODE_ERROR.get(e.getMessage());
+          throw new DirectoryException(ResultCode.PROTOCOL_ERROR, message);
+        }
+
+        return new GetEffectiveRightsRequestControl(isCritical,
+            authzDN, attrs);
+      }
+    }
+
+    public String getOID()
+    {
+      return OID_GET_EFFECTIVE_RIGHTS;
+    }
+
+  }
+
+  /**
+   * The Control Decoder that can be used to decode this control.
+   */
+  public static final ControlDecoder<GetEffectiveRightsRequestControl> DECODER =
+    new Decoder();
+
+  /**
+   * The tracer object for the debug logger.
+   */
+  private static final DebugTracer TRACER = getTracer();
+
+  //The DN representing the authzId. May be null.
+  private DN authzDN=null;
+
+  //The raw DN representing the authzId. May be null.
+  private String rawAuthzDN=null;
+
+  //The list of additional attribute types to return rights for. May be null.
+  private List<AttributeType> attrs=null;
+
+  //The raw DN representing the authzId. May be null.
+  private List<String> rawAttrs=null;
+
+  /**
+   * Create a new geteffectiverights control with the specified authzDN and
+   * an attribute list.
+   *
+   * @param authzDN  The authzDN.
+   *
+   * @param attrs  The list of additional attributes to be returned.
+   */
+  public GetEffectiveRightsRequestControl(DN authzDN,
+                            List<AttributeType> attrs) {
+    this(true, authzDN, attrs);
+  }
+
+  /**
+   * Create a new geteffectiverights control with the specified authzDN and
+   * an attribute list.
+   *
+   * @param  isCritical  Indicates whether this control should be
+   *                     considered critical in processing the
+   *                     request.
+   * @param authzDN  The authzDN.
+   * @param attrs  The list of additional attributes to be returned.
+   */
+  public GetEffectiveRightsRequestControl(boolean isCritical, DN authzDN,
+                                          List<AttributeType> attrs) {
+    super(OID_GET_EFFECTIVE_RIGHTS, isCritical);
+    this.authzDN=authzDN;
+    this.attrs=attrs;
+  }
+
+  /**
+   * Create a new geteffectiverights control with the specified raw
+   * authzDN and an attribute list.
+   *
+   * @param  isCritical  Indicates whether this control should be
+   *                     considered critical in processing the
+   *                     request.
+   * @param authzDN  The authzDN.
+   * @param attrs  The list of additional attributes to be returned.
+   */
+  public GetEffectiveRightsRequestControl(boolean isCritical,
+                                          String authzDN,
+                                          List<String> attrs)
+  {
+    super(OID_GET_EFFECTIVE_RIGHTS, isCritical);
+    this.rawAuthzDN=authzDN;
+    this.rawAttrs=attrs;
+  }
+
+  /**
+   * Writes this control's value to an ASN.1 writer. The value (if any) must be
+   * written as an ASN1OctetString.
+   *
+   * @param writer The ASN.1 output stream to write to.
+   * @throws IOException If a problem occurs while writing to the stream.
+   */
+  @Override
+  public void writeValue(ASN1Writer writer) throws IOException {
+    writer.writeStartSequence(UNIVERSAL_OCTET_STRING_TYPE);
+
+    writer.writeStartSequence();
+    if(authzDN != null)
+    {
+      writer.writeOctetString("dn:" + authzDN.toString());
+    }
+    else if(rawAuthzDN != null)
+    {
+      writer.writeOctetString("dn:" + rawAuthzDN);
+    }
+
+    if(attrs != null)
+    {
+      writer.writeStartSequence();
+      for(AttributeType attr : attrs)
+      {
+        writer.writeOctetString(attr.getNameOrOID());
+      }
+      writer.writeEndSequence();
+    }
+    else if(rawAttrs != null)
+    {
+      writer.writeStartSequence();
+      for(String attr : rawAttrs)
+      {
+        writer.writeOctetString(attr);
+      }
+      writer.writeEndSequence();
+    }
+    writer.writeEndSequence();
+
+    writer.writeEndSequence();
+  }
+
+  /**
+   * Return the authzDN parsed from the control.
+   *
+   * @return The DN representing the authzId.
+   */
+  public DN getAuthzDN () {
+    return authzDN;
+    // TODO: what if rawAuthzDN is not null?
+  }
+
+  /**
+   * Return the requested additional attributes parsed from the control. Known
+   * as the specified attributes.
+   *
+   * @return  The list containing any additional attributes to return rights
+   *          about.
+   */
+  public List<AttributeType> getAttributes() {
+    return attrs;
+  }
+}
diff --git a/opends/src/server/org/opends/server/controls/LDAPAssertionRequestControl.java b/opends/src/server/org/opends/server/controls/LDAPAssertionRequestControl.java
index 3dc798d..864efad 100644
--- a/opends/src/server/org/opends/server/controls/LDAPAssertionRequestControl.java
+++ b/opends/src/server/org/opends/server/controls/LDAPAssertionRequestControl.java
@@ -28,23 +28,16 @@
 import org.opends.messages.Message;
 
 
-
-import org.opends.server.protocols.asn1.ASN1Element;
-import org.opends.server.protocols.asn1.ASN1Exception;
-import org.opends.server.protocols.asn1.ASN1OctetString;
+import org.opends.server.protocols.asn1.*;
+import static org.opends.server.protocols.asn1.ASN1Constants.
+    UNIVERSAL_OCTET_STRING_TYPE;
 import org.opends.server.protocols.ldap.LDAPFilter;
-import org.opends.server.protocols.ldap.LDAPResultCode;
-import org.opends.server.types.Control;
-import org.opends.server.types.DirectoryException;
-import org.opends.server.types.DebugLogLevel;
-import org.opends.server.types.LDAPException;
-import org.opends.server.types.SearchFilter;
+import org.opends.server.types.*;
 
-import static org.opends.server.loggers.debug.DebugLogger.*;
-import org.opends.server.loggers.debug.DebugTracer;
 import static org.opends.messages.ProtocolMessages.*;
 import static org.opends.server.util.ServerConstants.*;
 
+import java.io.IOException;
 
 
 /**
@@ -55,13 +48,54 @@
  * control.
  */
 public class LDAPAssertionRequestControl
-       extends Control
+    extends Control
 {
   /**
-   * The tracer object for the debug logger.
+   * ControlDecoder implentation to decode this control from a ByteString.
    */
-  private static final DebugTracer TRACER = getTracer();
+  private final static class Decoder
+      implements ControlDecoder<LDAPAssertionRequestControl>
+  {
+    /**
+     * {@inheritDoc}
+     */
+    public LDAPAssertionRequestControl decode(boolean isCritical,
+                                              ByteString value)
+        throws DirectoryException
+    {
+      if (value == null)
+      {
+        Message message = ERR_LDAPASSERT_NO_CONTROL_VALUE.get();
+        throw new DirectoryException(ResultCode.PROTOCOL_ERROR, message);
+      }
 
+      ASN1Reader reader = ASN1.getReader(value);
+      LDAPFilter filter;
+      try
+      {
+        filter = LDAPFilter.decode(reader);
+      }
+      catch (LDAPException e)
+      {
+        throw new DirectoryException(ResultCode.valueOf(e.getResultCode()), e
+            .getMessageObject(), e.getCause());
+      }
+
+      return new LDAPAssertionRequestControl(isCritical, filter);
+    }
+
+    public String getOID()
+    {
+      return OID_LDAP_ASSERTION;
+    }
+
+  }
+
+  /**
+   * The Control Decoder that can be used to decode this control.
+   */
+  public static final ControlDecoder<LDAPAssertionRequestControl> DECODER =
+    new Decoder();
 
 
 
@@ -84,8 +118,7 @@
    */
   public LDAPAssertionRequestControl(boolean isCritical, LDAPFilter rawFilter)
   {
-    super(OID_LDAP_ASSERTION, isCritical,
-          new ASN1OctetString(rawFilter.encode().encode()));
+    super(OID_LDAP_ASSERTION, isCritical);
 
 
     this.rawFilter = rawFilter;
@@ -96,98 +129,17 @@
 
 
   /**
-   * Creates a new instance of this LDAP assertion request control with the
-   * provided information.
+   * Writes this control's value to an ASN.1 writer. The value (if any) must be
+   * written as an ASN1OctetString.
    *
-   * @param  oid         The OID to use for this control.
-   * @param  isCritical  Indicates whether support for this control should be
-   *                     considered a critical part of the server processing.
-   * @param  rawFilter   The unparsed LDAP search filter contained in the
-   *                     request from the client.
+   * @param writer The ASN.1 output stream to write to.
+   * @throws IOException If a problem occurs while writing to the stream.
    */
-  public LDAPAssertionRequestControl(String oid, boolean isCritical,
-                                     LDAPFilter rawFilter)
-  {
-    super(oid, isCritical, new ASN1OctetString(rawFilter.encode().encode()));
-
-
-    this.rawFilter = rawFilter;
-
-    filter = null;
-  }
-
-
-
-  /**
-   * Creates a new instance of this LDAP assertion request control with the
-   * provided information.
-   *
-   * @param  oid           The OID to use for this control.
-   * @param  isCritical    Indicates whether support for this control should be
-   *                       considered a critical part of the server processing.
-   * @param  rawFilter     The unparsed LDAP search filter contained in the
-   *                       request from the client.
-   * @param  encodedValue  The pre-encoded value for this control.
-   */
-  private LDAPAssertionRequestControl(String oid, boolean isCritical,
-                                      LDAPFilter rawFilter,
-                                      ASN1OctetString encodedValue)
-  {
-    super(oid, isCritical, encodedValue);
-
-
-    this.rawFilter = rawFilter;
-
-    filter = null;
-  }
-
-
-
-  /**
-   * Creates a new LDAP assertion request control from the contents of the
-   * provided control.
-   *
-   * @param  control  The generic control containing the information to use to
-   *                  create this LDAP assertion request control.
-   *
-   * @return  The LDAP assertion control decoded from the provided control.
-   *
-   * @throws  LDAPException  If this control cannot be decoded as a valid LDAP
-   *                         assertion control.
-   */
-  public static LDAPAssertionRequestControl decodeControl(Control control)
-         throws LDAPException
-  {
-    if (! control.hasValue())
-    {
-      Message message = ERR_LDAPASSERT_NO_CONTROL_VALUE.get();
-      throw new LDAPException(LDAPResultCode.PROTOCOL_ERROR, message);
-    }
-
-
-    ASN1Element valueElement;
-    try
-    {
-      valueElement = ASN1Element.decode(control.getValue().value());
-    }
-    catch (ASN1Exception ae)
-    {
-      if (debugEnabled())
-      {
-        TRACER.debugCaught(DebugLogLevel.ERROR, ae);
-      }
-
-      Message message =
-          ERR_LDAPASSERT_INVALID_CONTROL_VALUE.get(ae.getMessage());
-      throw new LDAPException(LDAPResultCode.PROTOCOL_ERROR, message,
-                              ae);
-    }
-
-
-    return new LDAPAssertionRequestControl(control.getOID(),
-                                           control.isCritical(),
-                                           LDAPFilter.decode(valueElement),
-                                           control.getValue());
+  @Override
+  public void writeValue(ASN1Writer writer) throws IOException {
+    writer.writeStartSequence(UNIVERSAL_OCTET_STRING_TYPE);
+    rawFilter.write(writer);
+    writer.writeEndSequence();
   }
 
 
@@ -203,23 +155,6 @@
   }
 
 
-
-  /**
-   * Sets the raw, unparsed filter from the request control.  This method should
-   * only be called by pre-parse plugins.
-   *
-   * @param  rawFilter  The raw, unparsed filter from the request control.
-   */
-  public void setRawFilter(LDAPFilter rawFilter)
-  {
-    this.rawFilter = rawFilter;
-    this.filter    = null;
-
-    setValue(new ASN1OctetString(rawFilter.encode().encode()));
-  }
-
-
-
   /**
    * Retrieves the processed search filter for this control.
    *
@@ -242,25 +177,12 @@
 
 
   /**
-   * Retrieves a string representation of this LDAP assertion request control.
-   *
-   * @return  A string representation of this LDAP assertion request control.
-   */
-  public String toString()
-  {
-    StringBuilder buffer = new StringBuilder();
-    toString(buffer);
-    return buffer.toString();
-  }
-
-
-
-  /**
    * Appends a string representation of this LDAP assertion request control to
    * the provided buffer.
    *
    * @param  buffer  The buffer to which the information should be appended.
    */
+  @Override
   public void toString(StringBuilder buffer)
   {
     buffer.append("LDAPAssertionRequestControl(criticality=");
diff --git a/opends/src/server/org/opends/server/controls/LDAPPostReadRequestControl.java b/opends/src/server/org/opends/server/controls/LDAPPostReadRequestControl.java
index 6af567a..508f661 100644
--- a/opends/src/server/org/opends/server/controls/LDAPPostReadRequestControl.java
+++ b/opends/src/server/org/opends/server/controls/LDAPPostReadRequestControl.java
@@ -28,25 +28,19 @@
 import org.opends.messages.Message;
 
 
-
-import java.util.ArrayList;
 import java.util.Iterator;
 import java.util.LinkedHashSet;
+import java.util.Set;
+import java.io.IOException;
 
 import org.opends.server.core.DirectoryServer;
-import org.opends.server.protocols.asn1.ASN1Element;
-import org.opends.server.protocols.asn1.ASN1Exception;
-import org.opends.server.protocols.asn1.ASN1OctetString;
-import org.opends.server.protocols.asn1.ASN1Sequence;
-import org.opends.server.protocols.ldap.LDAPResultCode;
-import org.opends.server.types.AttributeType;
-import org.opends.server.types.Control;
-import org.opends.server.types.LDAPException;
-import org.opends.server.types.ObjectClass;
-
+import org.opends.server.protocols.asn1.*;
+import static org.opends.server.protocols.asn1.ASN1Constants.
+    UNIVERSAL_OCTET_STRING_TYPE;
 import static org.opends.server.loggers.debug.DebugLogger.*;
 import org.opends.server.loggers.debug.DebugTracer;
-import org.opends.server.types.DebugLogLevel;
+import org.opends.server.types.*;
+
 import static org.opends.messages.ProtocolMessages.*;
 import static org.opends.server.util.ServerConstants.*;
 
@@ -63,6 +57,68 @@
        extends Control
 {
   /**
+   * ControlDecoder implentation to decode this control from a ByteString.
+   */
+  private final static class Decoder
+      implements ControlDecoder<LDAPPostReadRequestControl>
+  {
+    /**
+     * {@inheritDoc}
+     */
+    public LDAPPostReadRequestControl decode(boolean isCritical,
+                                             ByteString value)
+        throws DirectoryException
+    {
+      if (value == null)
+      {
+        Message message = ERR_POSTREADREQ_NO_CONTROL_VALUE.get();
+        throw new DirectoryException(ResultCode.PROTOCOL_ERROR, message);
+      }
+
+
+      ASN1Reader reader = ASN1.getReader(value);
+      LinkedHashSet<String> rawAttributes = new LinkedHashSet<String>();
+      try
+      {
+        reader.readStartSequence();
+        while(reader.hasNextElement())
+        {
+          rawAttributes.add(reader.readOctetStringAsString());
+        }
+        reader.readEndSequence();
+      }
+      catch (Exception ae)
+      {
+        if (debugEnabled())
+        {
+          TRACER.debugCaught(DebugLogLevel.ERROR, ae);
+        }
+
+        Message message =
+            ERR_POSTREADREQ_CANNOT_DECODE_VALUE.get(ae.getMessage());
+        throw new DirectoryException(ResultCode.PROTOCOL_ERROR, message,
+            ae);
+      }
+
+
+      return new LDAPPostReadRequestControl(isCritical,
+          rawAttributes);
+    }
+
+    public String getOID()
+    {
+      return OID_LDAP_READENTRY_POSTREAD;
+    }
+
+  }
+
+  /**
+   * The Control Decoder that can be used to decode this control.
+   */
+  public static final ControlDecoder<LDAPPostReadRequestControl> DECODER =
+    new Decoder();
+
+  /**
    * The tracer object for the debug logger.
    */
   private static final DebugTracer TRACER = getTracer();
@@ -79,10 +135,10 @@
   private boolean returnAllUserAttrs;
 
   // The set of raw attributes to return in the entry.
-  private LinkedHashSet<String> rawAttributes;
+  private Set<String> rawAttributes;
 
   // The set of processed attributes to return in the entry.
-  private LinkedHashSet<AttributeType> requestedAttributes;
+  private Set<AttributeType> requestedAttributes;
 
 
 
@@ -97,10 +153,9 @@
    *                        attributes should be returned.
    */
   public LDAPPostReadRequestControl(boolean isCritical,
-                                    LinkedHashSet<String> rawAttributes)
+                                    Set<String> rawAttributes)
   {
-    super(OID_LDAP_READENTRY_POSTREAD, isCritical,
-          encodeAttributes(rawAttributes));
+    super(OID_LDAP_READENTRY_POSTREAD, isCritical);
 
 
     if (rawAttributes == null)
@@ -131,9 +186,9 @@
    *                        attributes should be returned.
    */
   public LDAPPostReadRequestControl(String oid, boolean isCritical,
-                                    LinkedHashSet<String> rawAttributes)
+                                    Set<String> rawAttributes)
   {
-    super(oid, isCritical, encodeAttributes(rawAttributes));
+    super(oid, isCritical);
 
 
     if (rawAttributes == null)
@@ -150,126 +205,31 @@
     returnAllUserAttrs        = false;
   }
 
-
-
   /**
-   * Creates a new instance of this LDAP post-read request control with the
-   * provided information.
+   * Writes this control's value to an ASN.1 writer. The value (if any) must be
+   * written as an ASN1OctetString.
    *
-   * @param  oid            The OID to use for this control.
-   * @param  isCritical     Indicates whether support for this control should be
-   *                        considered a critical part of the server processing.
-   * @param  rawAttributes  The set of raw attributes to return in the entry.
-   *                        A null or empty set will indicates that all user
-   *                        attributes should be returned.
-   * @param  encodedValue   The post-encoded value for this control.
+   * @param writer The ASN.1 output stream to write to.
+   * @throws IOException If a problem occurs while writing to the stream.
    */
-  private LDAPPostReadRequestControl(String oid, boolean isCritical,
-                                     LinkedHashSet<String> rawAttributes,
-                                     ASN1OctetString encodedValue)
-  {
-    super(oid, isCritical, encodedValue);
+  @Override
+  public void writeValue(ASN1Writer writer) throws IOException {
+    writer.writeStartSequence(UNIVERSAL_OCTET_STRING_TYPE);
 
-
-    if (rawAttributes == null)
+    writer.writeStartSequence();
+    if (rawAttributes != null)
     {
-      this.rawAttributes = new LinkedHashSet<String>(0);
-    }
-    else
-    {
-      this.rawAttributes = rawAttributes;
-    }
-
-    requestedAttributes       = null;
-    returnAllOperationalAttrs = false;
-    returnAllUserAttrs        = false;
-  }
-
-
-
-  /**
-   * Creates a new LDAP post-read request control from the contents of the
-   * provided control.
-   *
-   * @param  control  The generic control containing the information to use to
-   *                  create this LDAP post-read request control.
-   *
-   * @return  The LDAP post-read request control decoded from the provided
-   *          control.
-   *
-   * @throws  LDAPException  If this control cannot be decoded as a valid LDAP
-   *                         post-read request control.
-   */
-  public static LDAPPostReadRequestControl decodeControl(Control control)
-         throws LDAPException
-  {
-    if (! control.hasValue())
-    {
-      Message message = ERR_POSTREADREQ_NO_CONTROL_VALUE.get();
-      throw new LDAPException(LDAPResultCode.PROTOCOL_ERROR, message);
-    }
-
-
-    LinkedHashSet<String> rawAttributes = new LinkedHashSet<String>();
-    try
-    {
-      ASN1Sequence attrSequence =
-           ASN1Sequence.decodeAsSequence(control.getValue().value());
-      for (ASN1Element e : attrSequence.elements())
+      for (String attr : rawAttributes)
       {
-        rawAttributes.add(e.decodeAsOctetString().stringValue());
+        writer.writeOctetString(attr);
       }
     }
-    catch (ASN1Exception ae)
-    {
-      if (debugEnabled())
-      {
-        TRACER.debugCaught(DebugLogLevel.ERROR, ae);
-      }
+    writer.writeEndSequence();
 
-      Message message =
-          ERR_POSTREADREQ_CANNOT_DECODE_VALUE.get(ae.getMessage());
-      throw new LDAPException(LDAPResultCode.PROTOCOL_ERROR, message,
-                              ae);
-    }
-
-
-    return new LDAPPostReadRequestControl(control.getOID(),
-                                          control.isCritical(),
-                                          rawAttributes, control.getValue());
+    writer.writeEndSequence();
   }
 
 
-
-  /**
-   * Encodes the provided set of raw, unprocessed attribute names to an
-   * ASN.1 octet string suitable for use as the value of this control.
-   *
-   * @param  rawAttributes  The set of attributes to encoded in the encoded
-   *                        control value.
-   *
-   * @return  The ASN.1 octet string containing the encoded attribute set.
-   */
-  private static ASN1OctetString encodeAttributes(LinkedHashSet<String>
-                                                       rawAttributes)
-  {
-    if (rawAttributes == null)
-    {
-      return new ASN1OctetString(new ASN1Sequence().encode());
-    }
-
-    ArrayList<ASN1Element> elements =
-         new ArrayList<ASN1Element>(rawAttributes.size());
-    for (String attr : rawAttributes)
-    {
-      elements.add(new ASN1OctetString(attr));
-    }
-
-    return new ASN1OctetString(new ASN1Sequence(elements).encode());
-  }
-
-
-
   /**
    * Retrieves the raw, unprocessed set of requested attributes.  It must not
    * be altered by the caller without calling <CODE>setRawAttributes</CODE> with
@@ -277,36 +237,12 @@
    *
    * @return  The raw, unprocessed set of attributes.
    */
-  public LinkedHashSet<String> getRawAttributes()
+  public Set<String> getRawAttributes()
   {
     return rawAttributes;
   }
 
 
-
-  /**
-   * Specifies the raw, unprocessed set of requested attributes.  A null or
-   * empty set indicates that all user attributes should be returned.
-   *
-   * @param  rawAttributes  The raw, unprocessed set of requested attributes.
-   */
-  public void setRawAttributes(LinkedHashSet<String> rawAttributes)
-  {
-    if (rawAttributes == null)
-    {
-      this.rawAttributes = new LinkedHashSet<String>();
-    }
-    else
-    {
-      this.rawAttributes = rawAttributes;
-    }
-
-    setValue(encodeAttributes(rawAttributes));
-    requestedAttributes = null;
-  }
-
-
-
   /**
    * Retrieves the set of processed attributes that have been requested for
    * inclusion in the entry that is returned.
@@ -314,7 +250,7 @@
    * @return  The set of processed attributes that have been requested for
    *          inclusion in the entry that is returned.
    */
-  public LinkedHashSet<AttributeType> getRequestedAttributes()
+  public Set<AttributeType> getRequestedAttributes()
   {
     if (requestedAttributes == null)
     {
@@ -441,25 +377,12 @@
 
 
   /**
-   * Retrieves a string representation of this LDAP post-read request control.
-   *
-   * @return  A string representation of this LDAP post-read request control.
-   */
-  public String toString()
-  {
-    StringBuilder buffer = new StringBuilder();
-    toString(buffer);
-    return buffer.toString();
-  }
-
-
-
-  /**
    * Appends a string representation of this LDAP post-read request control to
    * the provided buffer.
    *
    * @param  buffer  The buffer to which the information should be appended.
    */
+  @Override
   public void toString(StringBuilder buffer)
   {
     buffer.append("LDAPPostReadRequestControl(criticality=");
diff --git a/opends/src/server/org/opends/server/controls/LDAPPostReadResponseControl.java b/opends/src/server/org/opends/server/controls/LDAPPostReadResponseControl.java
index 9f68b0e..973211a 100644
--- a/opends/src/server/org/opends/server/controls/LDAPPostReadResponseControl.java
+++ b/opends/src/server/org/opends/server/controls/LDAPPostReadResponseControl.java
@@ -28,22 +28,18 @@
 import org.opends.messages.Message;
 
 
-
-import org.opends.server.protocols.asn1.ASN1Element;
-import org.opends.server.protocols.asn1.ASN1Exception;
-import org.opends.server.protocols.asn1.ASN1OctetString;
-import org.opends.server.protocols.ldap.LDAPResultCode;
-import org.opends.server.protocols.ldap.SearchResultEntryProtocolOp;
-import org.opends.server.types.Control;
-import org.opends.server.types.SearchResultEntry;
-import org.opends.server.types.DebugLogLevel;
-import org.opends.server.types.LDAPException;
+import org.opends.server.protocols.asn1.*;
+import static org.opends.server.protocols.asn1.ASN1Constants.
+    UNIVERSAL_OCTET_STRING_TYPE;
+import org.opends.server.protocols.ldap.*;
+import org.opends.server.types.*;
 
 import static org.opends.server.loggers.debug.DebugLogger.*;
 import org.opends.server.loggers.debug.DebugTracer;
 import static org.opends.messages.ProtocolMessages.*;
 import static org.opends.server.util.ServerConstants.*;
 
+import java.io.IOException;
 
 
 /**
@@ -52,9 +48,68 @@
  * entry immediately before an add, modify, or modify DN operation.
  */
 public class LDAPPostReadResponseControl
-       extends Control
+    extends Control
 {
   /**
+   * ControlDecoder implentation to decode this control from a ByteString.
+   */
+  private final static class Decoder
+      implements ControlDecoder<LDAPPostReadResponseControl>
+  {
+    /**
+     * {@inheritDoc}
+     */
+    public LDAPPostReadResponseControl decode(boolean isCritical,
+                                              ByteString value)
+        throws DirectoryException
+    {
+      if (value == null)
+      {
+        Message message = ERR_POSTREADRESP_NO_CONTROL_VALUE.get();
+        throw new DirectoryException(ResultCode.PROTOCOL_ERROR, message);
+      }
+
+
+      ASN1Reader reader = ASN1.getReader(value);
+      SearchResultEntry searchEntry;
+      try
+      {
+        SearchResultEntryProtocolOp searchResultEntryProtocolOp =
+            LDAPReader.readSearchEntry(reader);
+        searchEntry = searchResultEntryProtocolOp.toSearchResultEntry();
+      }
+      catch (LDAPException le)
+      {
+        if (debugEnabled())
+        {
+          TRACER.debugCaught(DebugLogLevel.ERROR, le);
+        }
+
+        Message message =
+            ERR_POSTREADRESP_CANNOT_DECODE_VALUE.get(le.getMessage());
+        throw new DirectoryException(ResultCode.PROTOCOL_ERROR, message,
+            le);
+      }
+
+      return new LDAPPostReadResponseControl(isCritical, searchEntry);
+    }
+
+    public String getOID()
+    {
+      return OID_LDAP_READENTRY_POSTREAD;
+    }
+
+  }
+
+  /**
+   * The Control Decoder that can be used to decode this control.
+   */
+  public static final ControlDecoder<LDAPPostReadResponseControl> DECODER =
+    new Decoder();
+
+
+
+  /**
    * The tracer object for the debug logger.
    */
   private static final DebugTracer TRACER = getTracer();
@@ -76,11 +131,7 @@
    */
   public LDAPPostReadResponseControl(SearchResultEntry searchEntry)
   {
-    super(OID_LDAP_READENTRY_POSTREAD, false,
-          encodeEntry(searchEntry));
-
-
-    this.searchEntry = searchEntry;
+    this(false, searchEntry);
   }
 
 
@@ -89,122 +140,36 @@
    * Creates a new instance of this LDAP post-read response control with the
    * provided information.
    *
-   * @param  oid          The OID to use for this control.
-   * @param  isCritical   Indicates whether support for this control should be
-   *                      considered a critical part of the server processing.
-   * @param  searchEntry  The search result entry to include in the response
-   *                      control.
-   */
-  public LDAPPostReadResponseControl(String oid, boolean isCritical,
-                                    SearchResultEntry searchEntry)
-  {
-    super(oid, isCritical, encodeEntry(searchEntry));
-
-
-    this.searchEntry = searchEntry;
-  }
-
-
-
-  /**
-   * Creates a new instance of this LDAP post-read response control with the
-   * provided information.
-   *
-   * @param  oid           The OID to use for this control.
    * @param  isCritical    Indicates whether support for this control should be
    *                       considered a critical part of the server processing.
    * @param  searchEntry   The search result entry to include in the response
    *                       control.
-   * @param  encodedValue  The pre-encoded value for this control.
    */
-  private LDAPPostReadResponseControl(String oid, boolean isCritical,
-                                      SearchResultEntry searchEntry,
-                                      ASN1OctetString encodedValue)
+  public LDAPPostReadResponseControl(boolean isCritical,
+                                     SearchResultEntry searchEntry)
   {
-    super(oid, isCritical, encodedValue);
+    super(OID_LDAP_READENTRY_POSTREAD, isCritical);
 
 
     this.searchEntry = searchEntry;
   }
 
-
-
   /**
-   * Creates a new LDAP post-read response control from the contents of the
-   * provided control.
+   * Writes this control's value to an ASN.1 writer. The value (if any) must be
+   * written as an ASN1OctetString.
    *
-   * @param  control  The generic control containing the information to use to
-   *                  create this LDAP post-read response control.
-   *
-   * @return  The LDAP post-read response control decoded from the provided
-   *          control.
-   *
-   * @throws  LDAPException  If this control cannot be decoded as a valid LDAP
-   *                         post-read response control.
+   * @param writer The ASN.1 output stream to write to.
+   * @throws IOException If a problem occurs while writing to the stream.
    */
-  public static LDAPPostReadResponseControl decodeControl(Control control)
-         throws LDAPException
-  {
-    if (! control.hasValue())
-    {
-      Message message = ERR_POSTREADRESP_NO_CONTROL_VALUE.get();
-      throw new LDAPException(LDAPResultCode.PROTOCOL_ERROR, message);
-    }
+  @Override
+  public void writeValue(ASN1Writer writer) throws IOException {
+    writer.writeStartSequence(UNIVERSAL_OCTET_STRING_TYPE);
 
-
-    ASN1OctetString controlValue = control.getValue();
-    SearchResultEntry searchEntry;
-    try
-    {
-      ASN1Element element = ASN1Element.decode(controlValue.value());
-      SearchResultEntryProtocolOp searchResultEntryProtocolOp =
-           SearchResultEntryProtocolOp.decodeSearchEntry(element);
-      searchEntry = searchResultEntryProtocolOp.toSearchResultEntry();
-    }
-    catch (ASN1Exception ae)
-    {
-      if (debugEnabled())
-      {
-        TRACER.debugCaught(DebugLogLevel.ERROR, ae);
-      }
-
-      Message message =
-          ERR_POSTREADRESP_CANNOT_DECODE_VALUE.get(ae.getMessage());
-      throw new LDAPException(LDAPResultCode.PROTOCOL_ERROR, message,
-                              ae);
-    }
-    catch (LDAPException le)
-    {
-      if (debugEnabled())
-      {
-        TRACER.debugCaught(DebugLogLevel.ERROR, le);
-      }
-
-      Message message =
-          ERR_POSTREADRESP_CANNOT_DECODE_VALUE.get(le.getMessage());
-      throw new LDAPException(LDAPResultCode.PROTOCOL_ERROR, message,
-                              le);
-    }
-
-    return new LDAPPostReadResponseControl(control.getOID(),
-                                           control.isCritical(), searchEntry,
-                                           controlValue);
-  }
-
-
-
-  /**
-   * Encodes the provided search result entry for use as an attribute value.
-   *
-   * @param  searchEntry  The search result entry to be encoded.
-   *
-   * @return  The ASN.1 octet string containing the encoded control value.
-   */
-  private static ASN1OctetString encodeEntry(SearchResultEntry searchEntry)
-  {
     SearchResultEntryProtocolOp protocolOp =
-         new SearchResultEntryProtocolOp(searchEntry);
-    return new ASN1OctetString(protocolOp.encode().encode());
+        new SearchResultEntryProtocolOp(searchEntry);
+    protocolOp.write(writer);
+
+    writer.writeEndSequence();
   }
 
 
@@ -224,40 +189,12 @@
 
 
   /**
-   * Specifies the search result entry for use with this post-read response
-   * control.
-   *
-   * @param  searchEntry  The search result entry for use with this post-read
-   *                      response control.
-   */
-  public void setSearchEntry(SearchResultEntry searchEntry)
-  {
-    this.searchEntry = searchEntry;
-    setValue(encodeEntry(searchEntry));
-  }
-
-
-
-  /**
-   * Retrieves a string representation of this LDAP post-read response control.
-   *
-   * @return  A string representation of this LDAP post-read response control.
-   */
-  public String toString()
-  {
-    StringBuilder buffer = new StringBuilder();
-    toString(buffer);
-    return buffer.toString();
-  }
-
-
-
-  /**
    * Appends a string representation of this LDAP post-read response control to
    * the provided buffer.
    *
    * @param  buffer  The buffer to which the information should be appended.
    */
+  @Override
   public void toString(StringBuilder buffer)
   {
     buffer.append("LDAPPostReadResponseControl(criticality=");
diff --git a/opends/src/server/org/opends/server/controls/LDAPPreReadRequestControl.java b/opends/src/server/org/opends/server/controls/LDAPPreReadRequestControl.java
index d6ee485..a5827a7 100644
--- a/opends/src/server/org/opends/server/controls/LDAPPreReadRequestControl.java
+++ b/opends/src/server/org/opends/server/controls/LDAPPreReadRequestControl.java
@@ -28,22 +28,16 @@
 import org.opends.messages.Message;
 
 
-
-import java.util.ArrayList;
 import java.util.Iterator;
 import java.util.LinkedHashSet;
+import java.util.Set;
+import java.io.IOException;
 
 import org.opends.server.core.DirectoryServer;
-import org.opends.server.protocols.asn1.ASN1Element;
-import org.opends.server.protocols.asn1.ASN1Exception;
-import org.opends.server.protocols.asn1.ASN1OctetString;
-import org.opends.server.protocols.asn1.ASN1Sequence;
-import org.opends.server.protocols.ldap.LDAPResultCode;
-import org.opends.server.types.AttributeType;
-import org.opends.server.types.Control;
-import org.opends.server.types.ObjectClass;
-import org.opends.server.types.DebugLogLevel;
-import org.opends.server.types.LDAPException;
+import org.opends.server.protocols.asn1.*;
+import static org.opends.server.protocols.asn1.ASN1Constants.
+    UNIVERSAL_OCTET_STRING_TYPE;
+import org.opends.server.types.*;
 
 import static org.opends.server.loggers.debug.DebugLogger.*;
 import org.opends.server.loggers.debug.DebugTracer;
@@ -63,6 +57,67 @@
        extends Control
 {
   /**
+   * ControlDecoder implentation to decode this control from a ByteString.
+   */
+  private final static class Decoder
+      implements ControlDecoder<LDAPPreReadRequestControl>
+  {
+    /**
+     * {@inheritDoc}
+     */
+    public LDAPPreReadRequestControl decode(boolean isCritical,
+                                            ByteString value)
+        throws DirectoryException
+    {
+     if (value == null)
+      {
+        Message message = ERR_PREREADREQ_NO_CONTROL_VALUE.get();
+        throw new DirectoryException(ResultCode.PROTOCOL_ERROR, message);
+      }
+
+      ASN1Reader reader = ASN1.getReader(value);
+      LinkedHashSet<String> rawAttributes = new LinkedHashSet<String>();
+      try
+      {
+        reader.readStartSequence();
+        while(reader.hasNextElement())
+        {
+          rawAttributes.add(reader.readOctetStringAsString());
+        }
+        reader.readEndSequence();
+      }
+      catch (Exception ae)
+      {
+        if (debugEnabled())
+        {
+          TRACER.debugCaught(DebugLogLevel.ERROR, ae);
+        }
+
+        Message message =
+            ERR_PREREADREQ_CANNOT_DECODE_VALUE.get(ae.getMessage());
+        throw new DirectoryException(ResultCode.PROTOCOL_ERROR, message,
+            ae);
+      }
+
+
+      return new LDAPPreReadRequestControl(isCritical,
+          rawAttributes);
+    }
+
+    public String getOID()
+    {
+      return OID_LDAP_READENTRY_PREREAD;
+    }
+
+  }
+
+  /**
+   * The Control Decoder that can be used to decode this control.
+   */
+  public static final ControlDecoder<LDAPPreReadRequestControl> DECODER =
+    new Decoder();
+
+  /**
    * The tracer object for the debug logger.
    */
   private static final DebugTracer TRACER = getTracer();
@@ -79,10 +134,10 @@
   private boolean returnAllUserAttrs;
 
   // The set of raw attributes to return in the entry.
-  private LinkedHashSet<String> rawAttributes;
+  private Set<String> rawAttributes;
 
   // The set of processed attributes to return in the entry.
-  private LinkedHashSet<AttributeType> requestedAttributes;
+  private Set<AttributeType> requestedAttributes;
 
 
 
@@ -97,10 +152,9 @@
    *                        attributes should be returned.
    */
   public LDAPPreReadRequestControl(boolean isCritical,
-                                   LinkedHashSet<String> rawAttributes)
+                                   Set<String> rawAttributes)
   {
-    super(OID_LDAP_READENTRY_PREREAD, isCritical,
-          encodeAttributes(rawAttributes));
+    super(OID_LDAP_READENTRY_PREREAD, isCritical);
 
 
     if (rawAttributes == null)
@@ -120,150 +174,27 @@
 
 
   /**
-   * Creates a new instance of this LDAP pre-read request control with the
-   * provided information.
+   * Writes this control's value to an ASN.1 writer. The value (if any) must be
+   * written as an ASN1OctetString.
    *
-   * @param  oid            The OID to use for this control.
-   * @param  isCritical     Indicates whether support for this control should be
-   *                        considered a critical part of the server processing.
-   * @param  rawAttributes  The set of raw attributes to return in the entry.
-   *                        A null or empty set will indicates that all user
-   *                        attributes should be returned.
+   * @param writer The ASN.1 output stream to write to.
+   * @throws IOException If a problem occurs while writing to the stream.
    */
-  public LDAPPreReadRequestControl(String oid, boolean isCritical,
-                                   LinkedHashSet<String> rawAttributes)
-  {
-    super(oid, isCritical, encodeAttributes(rawAttributes));
+  @Override
+  public void writeValue(ASN1Writer writer) throws IOException {
+    writer.writeStartSequence(UNIVERSAL_OCTET_STRING_TYPE);
 
-
-    if (rawAttributes == null)
+    writer.writeStartSequence();
+    if (rawAttributes != null)
     {
-      this.rawAttributes = new LinkedHashSet<String>(0);
-    }
-    else
-    {
-      this.rawAttributes = rawAttributes;
-    }
-
-    requestedAttributes       = null;
-    returnAllOperationalAttrs = false;
-    returnAllUserAttrs        = false;
-  }
-
-
-
-  /**
-   * Creates a new instance of this LDAP pre-read request control with the
-   * provided information.
-   *
-   * @param  oid            The OID to use for this control.
-   * @param  isCritical     Indicates whether support for this control should be
-   *                        considered a critical part of the server processing.
-   * @param  rawAttributes  The set of raw attributes to return in the entry.
-   *                        A null or empty set will indicates that all user
-   *                        attributes should be returned.
-   * @param  encodedValue   The pre-encoded value for this control.
-   */
-  private LDAPPreReadRequestControl(String oid, boolean isCritical,
-                                    LinkedHashSet<String> rawAttributes,
-                                    ASN1OctetString encodedValue)
-  {
-    super(oid, isCritical, encodedValue);
-
-
-    if (rawAttributes == null)
-    {
-      this.rawAttributes = new LinkedHashSet<String>(0);
-    }
-    else
-    {
-      this.rawAttributes = rawAttributes;
-    }
-
-    requestedAttributes       = null;
-    returnAllOperationalAttrs = false;
-    returnAllUserAttrs        = false;
-  }
-
-
-
-  /**
-   * Creates a new LDAP pre-read request control from the contents of the
-   * provided control.
-   *
-   * @param  control  The generic control containing the information to use to
-   *                  create this LDAP pre-read request control.
-   *
-   * @return  The LDAP pre-read request control decoded from the provided
-   *          control.
-   *
-   * @throws  LDAPException  If this control cannot be decoded as a valid LDAP
-   *                         pre-read request control.
-   */
-  public static LDAPPreReadRequestControl decodeControl(Control control)
-         throws LDAPException
-  {
-    if (! control.hasValue())
-    {
-      Message message = ERR_PREREADREQ_NO_CONTROL_VALUE.get();
-      throw new LDAPException(LDAPResultCode.PROTOCOL_ERROR, message);
-    }
-
-
-    LinkedHashSet<String> rawAttributes = new LinkedHashSet<String>();
-    try
-    {
-      ASN1Sequence attrSequence =
-           ASN1Sequence.decodeAsSequence(control.getValue().value());
-      for (ASN1Element e : attrSequence.elements())
+      for (String attr : rawAttributes)
       {
-        rawAttributes.add(e.decodeAsOctetString().stringValue());
+        writer.writeOctetString(attr);
       }
     }
-    catch (ASN1Exception ae)
-    {
-      if (debugEnabled())
-      {
-        TRACER.debugCaught(DebugLogLevel.ERROR, ae);
-      }
+    writer.writeEndSequence();
 
-      Message message = ERR_PREREADREQ_CANNOT_DECODE_VALUE.get(ae.getMessage());
-      throw new LDAPException(LDAPResultCode.PROTOCOL_ERROR, message,
-                              ae);
-    }
-
-
-    return new LDAPPreReadRequestControl(control.getOID(), control.isCritical(),
-                                         rawAttributes, control.getValue());
-  }
-
-
-
-  /**
-   * Encodes the provided set of raw, unprocessed attribute names to an
-   * ASN.1 octet string suitable for use as the value of this control.
-   *
-   * @param  rawAttributes  The set of attributes to encoded in the encoded
-   *                        control value.
-   *
-   * @return  The ASN.1 octet string containing the encoded attribute set.
-   */
-  private static ASN1OctetString encodeAttributes(LinkedHashSet<String>
-                                                       rawAttributes)
-  {
-    if (rawAttributes == null)
-    {
-      return new ASN1OctetString(new ASN1Sequence().encode());
-    }
-
-    ArrayList<ASN1Element> elements =
-         new ArrayList<ASN1Element>(rawAttributes.size());
-    for (String attr : rawAttributes)
-    {
-      elements.add(new ASN1OctetString(attr));
-    }
-
-    return new ASN1OctetString(new ASN1Sequence(elements).encode());
+    writer.writeEndSequence();
   }
 
 
@@ -275,7 +206,7 @@
    *
    * @return  The raw, unprocessed set of attributes.
    */
-  public LinkedHashSet<String> getRawAttributes()
+  public Set<String> getRawAttributes()
   {
     return rawAttributes;
   }
@@ -283,36 +214,13 @@
 
 
   /**
-   * Specifies the raw, unprocessed set of requested attributes.  A null or
-   * empty set indicates that all user attributes should be returned.
-   *
-   * @param  rawAttributes  The raw, unprocessed set of requested attributes.
-   */
-  public void setRawAttributes(LinkedHashSet<String> rawAttributes)
-  {
-    if (rawAttributes == null)
-    {
-      this.rawAttributes = new LinkedHashSet<String>();
-    }
-    else
-    {
-      this.rawAttributes = rawAttributes;
-    }
-
-    setValue(encodeAttributes(rawAttributes));
-    requestedAttributes = null;
-  }
-
-
-
-  /**
    * Retrieves the set of processed attributes that have been requested for
    * inclusion in the entry that is returned.
    *
    * @return  The set of processed attributes that have been requested for
    *          inclusion in the entry that is returned.
    */
-  public LinkedHashSet<AttributeType> getRequestedAttributes()
+  public Set<AttributeType> getRequestedAttributes()
   {
     if (requestedAttributes == null)
     {
@@ -439,25 +347,12 @@
 
 
   /**
-   * Retrieves a string representation of this LDAP pre-read request control.
-   *
-   * @return  A string representation of this LDAP pre-read request control.
-   */
-  public String toString()
-  {
-    StringBuilder buffer = new StringBuilder();
-    toString(buffer);
-    return buffer.toString();
-  }
-
-
-
-  /**
    * Appends a string representation of this LDAP pre-read request control to
    * the provided buffer.
    *
    * @param  buffer  The buffer to which the information should be appended.
    */
+  @Override
   public void toString(StringBuilder buffer)
   {
     buffer.append("LDAPPreReadRequestControl(criticality=");
diff --git a/opends/src/server/org/opends/server/controls/LDAPPreReadResponseControl.java b/opends/src/server/org/opends/server/controls/LDAPPreReadResponseControl.java
index c58c4a6..f9cbb53 100644
--- a/opends/src/server/org/opends/server/controls/LDAPPreReadResponseControl.java
+++ b/opends/src/server/org/opends/server/controls/LDAPPreReadResponseControl.java
@@ -28,22 +28,19 @@
 import org.opends.messages.Message;
 
 
-
-import org.opends.server.protocols.asn1.ASN1Element;
-import org.opends.server.protocols.asn1.ASN1Exception;
-import org.opends.server.protocols.asn1.ASN1OctetString;
-import org.opends.server.protocols.ldap.LDAPResultCode;
+import org.opends.server.protocols.asn1.*;
+import static org.opends.server.protocols.asn1.ASN1Constants.
+    UNIVERSAL_OCTET_STRING_TYPE;
 import org.opends.server.protocols.ldap.SearchResultEntryProtocolOp;
-import org.opends.server.types.Control;
-import org.opends.server.types.SearchResultEntry;
-import org.opends.server.types.DebugLogLevel;
-import org.opends.server.types.LDAPException;
+import org.opends.server.protocols.ldap.LDAPReader;
+import org.opends.server.types.*;
 
 import static org.opends.server.loggers.debug.DebugLogger.*;
 import org.opends.server.loggers.debug.DebugTracer;
 import static org.opends.messages.ProtocolMessages.*;
 import static org.opends.server.util.ServerConstants.*;
 
+import java.io.IOException;
 
 
 /**
@@ -55,6 +52,63 @@
        extends Control
 {
   /**
+   * ControlDecoder implentation to decode this control from a ByteString.
+   */
+  private final static class Decoder
+      implements ControlDecoder<LDAPPreReadResponseControl>
+  {
+    /**
+     * {@inheritDoc}
+     */
+    public LDAPPreReadResponseControl decode(boolean isCritical,
+                                             ByteString value)
+        throws DirectoryException
+    {
+     if (value == null)
+      {
+        Message message = ERR_PREREADRESP_NO_CONTROL_VALUE.get();
+        throw new DirectoryException(ResultCode.PROTOCOL_ERROR, message);
+      }
+
+
+      ASN1Reader reader = ASN1.getReader(value);
+      SearchResultEntry searchEntry;
+      try
+      {
+        SearchResultEntryProtocolOp searchResultEntryProtocolOp =
+            LDAPReader.readSearchEntry(reader);
+        searchEntry = searchResultEntryProtocolOp.toSearchResultEntry();
+      }
+      catch (LDAPException le)
+      {
+        if (debugEnabled())
+        {
+          TRACER.debugCaught(DebugLogLevel.ERROR, le);
+        }
+
+        Message message =
+            ERR_PREREADRESP_CANNOT_DECODE_VALUE.get(le.getMessage());
+        throw new DirectoryException(ResultCode.PROTOCOL_ERROR, message,
+            le);
+      }
+
+      return new LDAPPreReadResponseControl(isCritical, searchEntry);
+    }
+
+    public String getOID()
+    {
+      return OID_LDAP_READENTRY_PREREAD;
+    }
+
+  }
+
+  /**
+   * The Control Decoder that can be used to decode this control.
+   */
+  public static final ControlDecoder<LDAPPreReadResponseControl> DECODER =
+    new Decoder();
+
+  /**
    * The tracer object for the debug logger.
    */
   private static final DebugTracer TRACER = getTracer();
@@ -76,11 +130,7 @@
    */
   public LDAPPreReadResponseControl(SearchResultEntry searchEntry)
   {
-    super(OID_LDAP_READENTRY_PREREAD, false,
-          encodeEntry(searchEntry));
-
-
-    this.searchEntry = searchEntry;
+    this(false, searchEntry);
   }
 
 
@@ -89,16 +139,15 @@
    * Creates a new instance of this LDAP pre-read response control with the
    * provided information.
    *
-   * @param  oid          The OID to use for this control.
    * @param  isCritical   Indicates whether support for this control should be
    *                      considered a critical part of the server processing.
    * @param  searchEntry  The search result entry to include in the response
    *                      control.
    */
-  public LDAPPreReadResponseControl(String oid, boolean isCritical,
+  public LDAPPreReadResponseControl(boolean isCritical,
                                     SearchResultEntry searchEntry)
   {
-    super(oid, isCritical, encodeEntry(searchEntry));
+    super(OID_LDAP_READENTRY_PREREAD, isCritical);
 
 
     this.searchEntry = searchEntry;
@@ -107,104 +156,21 @@
 
 
   /**
-   * Creates a new instance of this LDAP pre-read response control with the
-   * provided information.
+   * Writes this control's value to an ASN.1 writer. The value (if any) must be
+   * written as an ASN1OctetString.
    *
-   * @param  oid           The OID to use for this control.
-   * @param  isCritical    Indicates whether support for this control should be
-   *                       considered a critical part of the server processing.
-   * @param  searchEntry   The search result entry to include in the response
-   *                       control.
-   * @param  encodedValue  The pre-encoded value for this control.
+   * @param writer The ASN.1 output stream to write to.
+   * @throws IOException If a problem occurs while writing to the stream.
    */
-  private LDAPPreReadResponseControl(String oid, boolean isCritical,
-                                     SearchResultEntry searchEntry,
-                                     ASN1OctetString encodedValue)
-  {
-    super(oid, isCritical, encodedValue);
+  @Override
+  public void writeValue(ASN1Writer writer) throws IOException {
+    writer.writeStartSequence(UNIVERSAL_OCTET_STRING_TYPE);
 
-
-    this.searchEntry = searchEntry;
-  }
-
-
-
-  /**
-   * Creates a new LDAP pre-read response control from the contents of the
-   * provided control.
-   *
-   * @param  control  The generic control containing the information to use to
-   *                  create this LDAP pre-read response control.
-   *
-   * @return  The LDAP pre-read response control decoded from the provided
-   *          control.
-   *
-   * @throws  LDAPException  If this control cannot be decoded as a valid LDAP
-   *                         pre-read response control.
-   */
-  public static LDAPPreReadResponseControl decodeControl(Control control)
-         throws LDAPException
-  {
-    if (! control.hasValue())
-    {
-      Message message = ERR_PREREADRESP_NO_CONTROL_VALUE.get();
-      throw new LDAPException(LDAPResultCode.PROTOCOL_ERROR, message);
-    }
-
-
-    ASN1OctetString controlValue = control.getValue();
-    SearchResultEntry searchEntry;
-    try
-    {
-      ASN1Element element = ASN1Element.decode(controlValue.value());
-      SearchResultEntryProtocolOp searchResultEntryProtocolOp =
-           SearchResultEntryProtocolOp.decodeSearchEntry(element);
-      searchEntry = searchResultEntryProtocolOp.toSearchResultEntry();
-    }
-    catch (ASN1Exception ae)
-    {
-      if (debugEnabled())
-      {
-        TRACER.debugCaught(DebugLogLevel.ERROR, ae);
-      }
-
-      Message message =
-          ERR_PREREADRESP_CANNOT_DECODE_VALUE.get(ae.getMessage());
-      throw new LDAPException(LDAPResultCode.PROTOCOL_ERROR, message,
-                              ae);
-    }
-    catch (LDAPException le)
-    {
-      if (debugEnabled())
-      {
-        TRACER.debugCaught(DebugLogLevel.ERROR, le);
-      }
-
-      Message message =
-          ERR_PREREADRESP_CANNOT_DECODE_VALUE.get(le.getMessage());
-      throw new LDAPException(LDAPResultCode.PROTOCOL_ERROR, message,
-                              le);
-    }
-
-    return new LDAPPreReadResponseControl(control.getOID(),
-                                          control.isCritical(), searchEntry,
-                                          controlValue);
-  }
-
-
-
-  /**
-   * Encodes the provided search result entry for use as an attribute value.
-   *
-   * @param  searchEntry  The search result entry to be encoded.
-   *
-   * @return  The ASN.1 octet string containing the encoded control value.
-   */
-  private static ASN1OctetString encodeEntry(SearchResultEntry searchEntry)
-  {
     SearchResultEntryProtocolOp protocolOp =
-         new SearchResultEntryProtocolOp(searchEntry);
-    return new ASN1OctetString(protocolOp.encode().encode());
+        new SearchResultEntryProtocolOp(searchEntry);
+
+    protocolOp.write(writer);
+    writer.writeEndSequence();
   }
 
 
@@ -224,40 +190,12 @@
 
 
   /**
-   * Specifies the search result entry for use with this pre-read response
-   * control.
-   *
-   * @param  searchEntry  The search result entry for use with this pre-read
-   *                      response control.
-   */
-  public void setSearchEntry(SearchResultEntry searchEntry)
-  {
-    this.searchEntry = searchEntry;
-    setValue(encodeEntry(searchEntry));
-  }
-
-
-
-  /**
-   * Retrieves a string representation of this LDAP pre-read response control.
-   *
-   * @return  A string representation of this LDAP pre-read response control.
-   */
-  public String toString()
-  {
-    StringBuilder buffer = new StringBuilder();
-    toString(buffer);
-    return buffer.toString();
-  }
-
-
-
-  /**
    * Appends a string representation of this LDAP pre-read response control to
    * the provided buffer.
    *
    * @param  buffer  The buffer to which the information should be appended.
    */
+  @Override
   public void toString(StringBuilder buffer)
   {
     buffer.append("LDAPPreReadResponseControl(criticality=");
diff --git a/opends/src/server/org/opends/server/controls/MatchedValuesControl.java b/opends/src/server/org/opends/server/controls/MatchedValuesControl.java
index 3959a21..ee3e444 100644
--- a/opends/src/server/org/opends/server/controls/MatchedValuesControl.java
+++ b/opends/src/server/org/opends/server/controls/MatchedValuesControl.java
@@ -30,16 +30,12 @@
 
 
 import java.util.ArrayList;
+import java.io.IOException;
 
-import org.opends.server.protocols.asn1.ASN1Element;
-import org.opends.server.protocols.asn1.ASN1OctetString;
-import org.opends.server.protocols.asn1.ASN1Sequence;
-import org.opends.server.protocols.ldap.LDAPResultCode;
-import org.opends.server.types.AttributeType;
-import org.opends.server.types.AttributeValue;
-import org.opends.server.types.Control;
-import org.opends.server.types.DebugLogLevel;
-import org.opends.server.types.LDAPException;
+import org.opends.server.protocols.asn1.*;
+import static org.opends.server.protocols.asn1.ASN1Constants.
+    UNIVERSAL_OCTET_STRING_TYPE;
+import org.opends.server.types.*;
 
 import static org.opends.server.loggers.debug.DebugLogger.*;
 import org.opends.server.loggers.debug.DebugTracer;
@@ -59,6 +55,75 @@
        extends Control
 {
   /**
+   * ControlDecoder implentation to decode this control from a ByteString.
+   */
+  private final static class Decoder
+      implements ControlDecoder<MatchedValuesControl>
+  {
+    /**
+     * {@inheritDoc}
+     */
+    public MatchedValuesControl decode(boolean isCritical, ByteString value)
+        throws DirectoryException
+    {
+      ArrayList<MatchedValuesFilter> filters;
+      if (value == null)
+      {
+        Message message = ERR_MATCHEDVALUES_NO_CONTROL_VALUE.get();
+        throw new DirectoryException(ResultCode.PROTOCOL_ERROR, message);
+      }
+
+      ASN1Reader reader = ASN1.getReader(value);
+      try
+      {
+        reader.readStartSequence();
+        if (!reader.hasNextElement())
+        {
+          Message message = ERR_MATCHEDVALUES_NO_FILTERS.get();
+          throw new DirectoryException(ResultCode.PROTOCOL_ERROR, message);
+        }
+
+        filters = new ArrayList<MatchedValuesFilter>();
+        while(reader.hasNextElement())
+        {
+          filters.add(MatchedValuesFilter.decode(reader));
+        }
+        reader.readEndSequence();
+      }
+      catch (DirectoryException e)
+      {
+        throw e;
+      }
+      catch (Exception e)
+      {
+        if (debugEnabled())
+        {
+          TRACER.debugCaught(DebugLogLevel.ERROR, e);
+        }
+
+        Message message = ERR_MATCHEDVALUES_CANNOT_DECODE_VALUE_AS_SEQUENCE.get(
+            getExceptionMessage(e));
+        throw new DirectoryException(ResultCode.PROTOCOL_ERROR, message);
+      }
+
+      return new MatchedValuesControl(isCritical,filters);
+    }
+
+
+    public String getOID()
+    {
+      return OID_MATCHED_VALUES;
+    }
+
+  }
+
+  /**
+   * The Control Decoder that can be used to decode this control.
+   */
+  public static final ControlDecoder<MatchedValuesControl> DECODER =
+    new Decoder();
+
+  /**
    * The tracer object for the debug logger.
    */
   private static final DebugTracer TRACER = getTracer();
@@ -67,7 +132,7 @@
 
 
   // The set of matched values filters for this control.
-  ArrayList<MatchedValuesFilter> filters;
+  private final ArrayList<MatchedValuesFilter> filters;
 
 
 
@@ -83,7 +148,7 @@
   public MatchedValuesControl(boolean isCritical,
                               ArrayList<MatchedValuesFilter> filters)
   {
-    super(OID_MATCHED_VALUES, isCritical, encodeValue(filters));
+    super(OID_MATCHED_VALUES, isCritical);
 
 
     this.filters = filters;
@@ -92,136 +157,27 @@
 
 
   /**
-   * Creates a new matched values control using the default OID and the provided
-   * criticality and set of filters.
+   * Writes this control's value to an ASN.1 writer. The value (if any) must be
+   * written as an ASN1OctetString.
    *
-   * @param  oid         The OID for this matched values control.
-   * @param  isCritical  Indicates whether this control should be considered
-   *                     critical to the operation processing.
-   * @param  filters     The set of filters to use to determine which values to
-   *                     return.
+   * @param writer The ASN.1 output stream to write to.
+   * @throws IOException If a problem occurs while writing to the stream.
    */
-  public MatchedValuesControl(String oid, boolean isCritical,
-                              ArrayList<MatchedValuesFilter> filters)
-  {
-    super(oid, isCritical, encodeValue(filters));
+  @Override
+  public void writeValue(ASN1Writer writer) throws IOException {
+    writer.writeStartSequence(UNIVERSAL_OCTET_STRING_TYPE);
 
-
-    this.filters = filters;
-  }
-
-
-
-  /**
-   * Creates a new matched values control using the default OID and the provided
-   * criticality and set of filters.
-   *
-   * @param  oid           The OID for this matched values control.
-   * @param  isCritical    Indicates whether this control should be considered
-   *                       critical to the operation processing.
-   * @param  filters       The set of filters to use to determine which values
-   *                       to return.
-   * @param  encodedValue  The pre-encoded value for this matched values
-   *                       control.
-   */
-  private MatchedValuesControl(String oid, boolean isCritical,
-                               ArrayList<MatchedValuesFilter> filters,
-                               ASN1OctetString encodedValue)
-  {
-    super(oid, isCritical, encodedValue);
-
-
-    this.filters = filters;
-  }
-
-
-
-  /**
-   * Encodes the provided information into an ASN.1 octet string suitable for
-   * use as the control value.
-   *
-   * @param  filters  The set of filters to include in the control value.
-   *
-   * @return  An ASN.1 octet string containing the encoded information.
-   */
-  private static ASN1OctetString
-                      encodeValue(ArrayList<MatchedValuesFilter> filters)
-  {
-    ArrayList<ASN1Element> elements =
-         new ArrayList<ASN1Element>(filters.size());
+    writer.writeStartSequence();
     for (MatchedValuesFilter f : filters)
     {
-      elements.add(f.encode());
+      f.encode(writer);
     }
+    writer.writeEndSequence();
 
-
-    return new ASN1OctetString(new ASN1Sequence(elements).encode());
+    writer.writeEndSequence();
   }
 
 
-
-  /**
-   * Creates a new matched values control from the contents of the provided
-   * control.
-   *
-   * @param  control  The generic control containing the information to use to
-   *                  create this matched values control.
-   *
-   * @return  The matched values control decoded from the provided control.
-   *
-   * @throws  LDAPException  If this control cannot be decoded as a valid
-   *                         matched values control.
-   */
-  public static MatchedValuesControl decodeControl(Control control)
-         throws LDAPException
-  {
-    if (! control.hasValue())
-    {
-      Message message = ERR_MATCHEDVALUES_NO_CONTROL_VALUE.get();
-      throw new LDAPException(LDAPResultCode.PROTOCOL_ERROR, message);
-    }
-
-
-    ArrayList<ASN1Element> elements;
-    try
-    {
-      elements =
-           ASN1Sequence.decodeAsSequence(control.getValue().value()).elements();
-    }
-    catch (Exception e)
-    {
-      if (debugEnabled())
-      {
-        TRACER.debugCaught(DebugLogLevel.ERROR, e);
-      }
-
-      Message message = ERR_MATCHEDVALUES_CANNOT_DECODE_VALUE_AS_SEQUENCE.get(
-          getExceptionMessage(e));
-      throw new LDAPException(LDAPResultCode.PROTOCOL_ERROR, message);
-    }
-
-
-    if (elements.isEmpty())
-    {
-      Message message = ERR_MATCHEDVALUES_NO_FILTERS.get();
-      throw new LDAPException(LDAPResultCode.PROTOCOL_ERROR, message);
-    }
-
-
-    ArrayList<MatchedValuesFilter> filters =
-         new ArrayList<MatchedValuesFilter>(elements.size());
-    for (ASN1Element e : elements)
-    {
-      filters.add(MatchedValuesFilter.decode(e));
-    }
-
-
-    return new MatchedValuesControl(control.getOID(), control.isCritical(),
-                                    filters, control.getValue());
-  }
-
-
-
   /**
    * Retrieves the set of filters associated with this matched values control.
    *
@@ -271,27 +227,12 @@
 
 
   /**
-   * Retrieves a string representation of this authorization identity response
-   * control.
-   *
-   * @return  A string representation of this authorization identity response
-   *          control.
-   */
-  public String toString()
-  {
-    StringBuilder buffer = new StringBuilder();
-    toString(buffer);
-    return buffer.toString();
-  }
-
-
-
-  /**
    * Appends a string representation of this authorization identity response
    * control to the provided buffer.
    *
    * @param  buffer  The buffer to which the information should be appended.
    */
+  @Override
   public void toString(StringBuilder buffer)
   {
     if (filters.size() == 1)
diff --git a/opends/src/server/org/opends/server/controls/MatchedValuesFilter.java b/opends/src/server/org/opends/server/controls/MatchedValuesFilter.java
index 6795d07..bde20fe 100644
--- a/opends/src/server/org/opends/server/controls/MatchedValuesFilter.java
+++ b/opends/src/server/org/opends/server/controls/MatchedValuesFilter.java
@@ -31,6 +31,7 @@
 
 import java.util.ArrayList;
 import java.util.List;
+import java.io.IOException;
 
 import org.opends.server.api.ApproximateMatchingRule;
 import org.opends.server.api.EqualityMatchingRule;
@@ -38,21 +39,13 @@
 import org.opends.server.api.OrderingMatchingRule;
 import org.opends.server.api.SubstringMatchingRule;
 import org.opends.server.core.DirectoryServer;
-import org.opends.server.protocols.asn1.ASN1Element;
-import org.opends.server.protocols.asn1.ASN1OctetString;
-import org.opends.server.protocols.asn1.ASN1Sequence;
+import org.opends.server.protocols.asn1.*;
 import org.opends.server.protocols.ldap.LDAPResultCode;
-import org.opends.server.types.AttributeType;
-import org.opends.server.types.AttributeValue;
-import org.opends.server.types.ByteString;
-import org.opends.server.types.ConditionResult;
-import org.opends.server.types.LDAPException;
-import org.opends.server.types.RawFilter;
 import org.opends.server.util.Validator;
 
 import static org.opends.server.loggers.debug.DebugLogger.*;
 import org.opends.server.loggers.debug.DebugTracer;
-import org.opends.server.types.DebugLogLevel;
+import org.opends.server.types.*;
 import static org.opends.messages.ProtocolMessages.*;
 import static org.opends.server.protocols.ldap.LDAPConstants.*;
 import static org.opends.server.util.StaticUtils.*;
@@ -130,19 +123,19 @@
   private ApproximateMatchingRule approximateMatchingRule;
 
   // The normalized subFinal value for this matched values filter.
-  private ASN1OctetString normalizedSubFinal;
+  private ByteString normalizedSubFinal;
 
   // The normalized subInitial value for this matched values filter.
-  private ASN1OctetString normalizedSubInitial;
+  private ByteString normalizedSubInitial;
 
   // The raw, unprocessed assertion value for this matched values filter.
-  private ByteString rawAssertionValue;
+  private final ByteString rawAssertionValue;
 
   // The subFinal value for this matched values filter.
-  private ByteString subFinal;
+  private final ByteString subFinal;
 
   // The subInitial value for this matched values filter.
-  private ByteString subInitial;
+  private final ByteString subInitial;
 
   // The processed attribute type for this matched values filter.
   private AttributeType attributeType;
@@ -155,16 +148,16 @@
   private boolean decoded;
 
   // The match type for this matched values filter.
-  private byte matchType;
+  private final byte matchType;
 
   // The equality matching rule for this matched values filter.
   private EqualityMatchingRule equalityMatchingRule;
 
   // The set of normalized subAny values for this matched values filter.
-  private List<ASN1OctetString> normalizedSubAny;
+  private List<ByteString> normalizedSubAny;
 
   // The set of subAny values for this matched values filter.
-  private List<ByteString> subAny;
+  private final List<ByteString> subAny;
 
   // The matching rule for this matched values filter.
   private MatchingRule matchingRule;
@@ -173,10 +166,10 @@
   private OrderingMatchingRule orderingMatchingRule;
 
   // The matching rule ID for this matched values filter.
-  private String matchingRuleID;
+  private final String matchingRuleID;
 
   // The raw, unprocessed attribute type for this matched values filter.
-  private String rawAttributeType;
+  private final String rawAttributeType;
 
   // The substring matching rule for this matched values filter.
   private SubstringMatchingRule substringMatchingRule;
@@ -256,8 +249,7 @@
   {
     Validator.ensureNotNull(attributeType, assertionValue);
     String rawAttributeType = attributeType.getNameOrOID();
-    ASN1OctetString rawAssertionValue = assertionValue.getValue()
-        .toASN1OctetString();
+    ByteString rawAssertionValue = assertionValue.getValue();
 
     MatchedValuesFilter filter =
          new MatchedValuesFilter(EQUALITY_MATCH_TYPE, rawAttributeType,
@@ -357,8 +349,7 @@
     Validator.ensureNotNull(attributeType, assertionValue);
 
     String          rawAttributeType  = attributeType.getNameOrOID();
-    ASN1OctetString rawAssertionValue =
-         assertionValue.getValue().toASN1OctetString();
+    ByteString rawAssertionValue = assertionValue.getValue();
 
     MatchedValuesFilter filter =
          new MatchedValuesFilter(GREATER_OR_EQUAL_TYPE, rawAttributeType,
@@ -405,8 +396,7 @@
     Validator.ensureNotNull(attributeType, assertionValue);
 
     String          rawAttributeType = attributeType.getNameOrOID();
-    ASN1OctetString rawAssertionValue =
-         assertionValue.getValue().toASN1OctetString();
+    ByteString rawAssertionValue = assertionValue.getValue();
 
     MatchedValuesFilter filter =
          new MatchedValuesFilter(LESS_OR_EQUAL_TYPE, rawAttributeType,
@@ -492,8 +482,7 @@
   {
     Validator.ensureNotNull(attributeType,assertionValue);
     String          rawAttributeType  = attributeType.getNameOrOID();
-    ASN1OctetString rawAssertionValue =
-         assertionValue.getValue().toASN1OctetString();
+    ByteString rawAssertionValue = assertionValue.getValue();
 
     MatchedValuesFilter filter =
          new MatchedValuesFilter(APPROXIMATE_MATCH_TYPE, rawAttributeType,
@@ -546,8 +535,7 @@
     Validator.ensureNotNull(attributeType, matchingRule, assertionValue);
     String rawAttributeType = attributeType.getNameOrOID();
     String matchingRuleID = matchingRule.getOID();
-    ASN1OctetString rawAssertionValue =
-         assertionValue.getValue().toASN1OctetString();
+    ByteString rawAssertionValue = assertionValue.getValue();
 
     MatchedValuesFilter filter =
          new MatchedValuesFilter(EXTENSIBLE_MATCH_TYPE, rawAttributeType,
@@ -651,14 +639,13 @@
     }
   }
 
-
-
   /**
    * Encodes this matched values filter as an ASN.1 element.
    *
-   * @return  The ASN.1 element containing the encoded matched values filter.
+   * @param writer The ASN1Writer to use to encode this matched values filter.
+   * @throws IOException if an error occurs while encoding.
    */
-  public ASN1Element encode()
+  public void encode(ASN1Writer writer) throws IOException
   {
     switch (matchType)
     {
@@ -667,89 +654,90 @@
       case LESS_OR_EQUAL_TYPE:
       case APPROXIMATE_MATCH_TYPE:
         // These will all be encoded in the same way.
-        ArrayList<ASN1Element> elements = new ArrayList<ASN1Element>(2);
-        elements.add(new ASN1OctetString(rawAttributeType));
-        elements.add(rawAssertionValue.toASN1OctetString());
-        return new ASN1Sequence(matchType, elements);
-
+        writer.writeStartSequence(matchType);
+        writer.writeOctetString(rawAttributeType);
+        writer.writeOctetString(rawAssertionValue);
+        writer.writeEndSequence();
+        return;
 
       case SUBSTRINGS_TYPE:
-        ArrayList<ASN1Element> subElements = new ArrayList<ASN1Element>();
+        writer.writeStartSequence(matchType);
+        writer.writeOctetString(rawAttributeType);
+
+        writer.writeStartSequence();
         if (subInitial != null)
         {
-          ASN1OctetString subInitialOS = subInitial.toASN1OctetString();
-          subInitialOS.setType(TYPE_SUBINITIAL);
-          subElements.add(subInitialOS);
+          writer.writeOctetString(TYPE_SUBINITIAL, subInitial);
         }
 
         if (subAny != null)
         {
           for (ByteString s : subAny)
           {
-            ASN1OctetString os = s.toASN1OctetString();
-            os.setType(TYPE_SUBANY);
-            subElements.add(os);
+            writer.writeOctetString(TYPE_SUBANY, s);
           }
         }
 
         if (subFinal != null)
         {
-          ASN1OctetString subFinalOS = subFinal.toASN1OctetString();
-          subFinalOS.setType(TYPE_SUBFINAL);
-          subElements.add(subFinalOS);
+          writer.writeOctetString(TYPE_SUBFINAL, subFinal);
         }
+        writer.writeEndSequence();
 
-        elements = new ArrayList<ASN1Element>(2);
-        elements.add(new ASN1OctetString(rawAttributeType));
-        elements.add(new ASN1Sequence(subElements));
-        return new ASN1Sequence(matchType, elements);
-
+        writer.writeEndSequence();
+        return;
 
       case PRESENT_TYPE:
-        return new ASN1OctetString(matchType, rawAttributeType);
-
+        writer.writeOctetString(matchType, rawAttributeType);
+        return;
 
       case EXTENSIBLE_MATCH_TYPE:
-        elements = new ArrayList<ASN1Element>(3);
+        writer.writeStartSequence(matchType);
         if (matchingRuleID != null)
         {
-          elements.add(new ASN1OctetString(TYPE_MATCHING_RULE_ID,
-                                           matchingRuleID));
+          writer.writeOctetString(TYPE_MATCHING_RULE_ID, matchingRuleID);
         }
 
         if (rawAttributeType != null)
         {
-          elements.add(new ASN1OctetString(TYPE_MATCHING_RULE_TYPE,
-                                           rawAttributeType));
+          writer.writeOctetString(TYPE_MATCHING_RULE_TYPE, rawAttributeType);
         }
-
-        ASN1OctetString valueOS = rawAssertionValue.toASN1OctetString();
-        valueOS.setType(TYPE_MATCHING_RULE_VALUE);
-        elements.add(valueOS);
-        return new ASN1Sequence(matchType, elements);
+        writer.writeOctetString(TYPE_MATCHING_RULE_VALUE, rawAssertionValue);
+        writer.writeEndSequence();
+        return;
 
 
       default:
-        return null;
     }
   }
 
-
-
-  /**
+    /**
    * Decodes the provided ASN.1 element as a matched values filter item.
    *
-   * @param  element  The ASN.1 element to be decoded.
+   * @param  reader The ASN.1 reader.
    *
    * @return  The decoded matched values filter.
    *
    * @throws  LDAPException  If a problem occurs while attempting to decode the
    *                         filter item.
    */
-  public static MatchedValuesFilter decode(ASN1Element element)
+  public static MatchedValuesFilter decode(ASN1Reader reader)
          throws LDAPException
   {
-    switch (element.getType())
+    byte type;
+    try
+    {
+      type = reader.peekType();
+    }
+    catch(Exception e)
+    {
+      // TODO: Need a better message.
+      Message message =
+          ERR_MVFILTER_INVALID_ELEMENT_TYPE.get(e.toString());
+      throw new LDAPException(LDAPResultCode.PROTOCOL_ERROR, message);
+    }
+
+    switch (type)
     {
       case EQUALITY_MATCH_TYPE:
       case GREATER_OR_EQUAL_TYPE:
@@ -759,25 +747,12 @@
         // sequence consisting of the attribute type and assertion value.
         try
         {
-          ArrayList<ASN1Element> elements =
-               element.decodeAsSequence().elements();
-          if (elements.size() != 2)
-          {
-            Message message =
-                ERR_MVFILTER_INVALID_AVA_SEQUENCE_SIZE.get(elements.size());
-            throw new LDAPException(LDAPResultCode.PROTOCOL_ERROR, message);
-          }
-
-          String rawAttributeType =
-                      elements.get(0).decodeAsOctetString().stringValue();
-
-          return new MatchedValuesFilter(element.getType(), rawAttributeType,
-                                         elements.get(1).decodeAsOctetString(),
-                                         null, null, null, null);
-        }
-        catch (LDAPException le)
-        {
-          throw le;
+          reader.readStartSequence();
+          String rawAttributeType = reader.readOctetStringAsString();
+          ByteString rawAssertionValue = reader.readOctetString();
+          reader.readEndSequence();
+          return new MatchedValuesFilter(type, rawAttributeType,
+              rawAssertionValue, null, null, null, null);
         }
         catch (Exception e)
         {
@@ -798,37 +773,27 @@
         // sequence of substring types.
         try
         {
-          ArrayList<ASN1Element> elements =
-               element.decodeAsSequence().elements();
-          if (elements.size() != 2)
-          {
-            Message message = ERR_MVFILTER_INVALID_SUBSTRING_SEQUENCE_SIZE.get(
-                elements.size());
-            throw new LDAPException(LDAPResultCode.PROTOCOL_ERROR, message);
-          }
+          reader.readStartSequence();
+          String rawAttributeType = reader.readOctetStringAsString();
 
-          ArrayList<ASN1Element> subElements =
-               elements.get(1).decodeAsSequence().elements();
-          if (subElements.isEmpty())
+          reader.readStartSequence();
+          if(!reader.hasNextElement())
           {
             Message message = ERR_MVFILTER_NO_SUBSTRING_ELEMENTS.get();
             throw new LDAPException(LDAPResultCode.PROTOCOL_ERROR, message);
           }
 
-          String rawAttributeType =
-                      elements.get(0).decodeAsOctetString().stringValue();
-
           ByteString subInitial        = null;
           ArrayList<ByteString> subAny = null;
           ByteString subFinal          = null;
-          for (ASN1Element e : subElements)
+          while(reader.hasNextElement())
           {
-            switch (e.getType())
+            switch(reader.peekType())
             {
-              case TYPE_SUBINITIAL:
+             case TYPE_SUBINITIAL:
                 if (subInitial == null)
                 {
-                  subInitial = e.decodeAsOctetString();
+                  subInitial = reader.readOctetString();
                 }
                 else
                 {
@@ -844,13 +809,13 @@
                   subAny = new ArrayList<ByteString>();
                 }
 
-                subAny.add(e.decodeAsOctetString());
+                subAny.add(reader.readOctetString());
                 break;
 
               case TYPE_SUBFINAL:
                 if (subFinal == null)
                 {
-                  subFinal = e.decodeAsOctetString();
+                  subFinal = reader.readOctetString();
                 }
                 else
                 {
@@ -862,12 +827,15 @@
 
               default:
                 Message message = ERR_MVFILTER_INVALID_SUBSTRING_ELEMENT_TYPE.
-                    get(byteToHex(e.getType()));
+                    get(byteToHex(reader.peekType()));
                 throw new LDAPException(LDAPResultCode.PROTOCOL_ERROR, message);
             }
           }
+          reader.readEndSequence();
 
-          return new MatchedValuesFilter(element.getType(), rawAttributeType,
+          reader.readEndSequence();
+
+          return new MatchedValuesFilter(type, rawAttributeType,
                                          null, subInitial, subAny, subFinal,
                                          null);
         }
@@ -893,9 +861,9 @@
         // The element must be an ASN.1 octet string holding the attribute type.
         try
         {
-          String rawAttributeType = element.decodeAsOctetString().stringValue();
+          String rawAttributeType = reader.readOctetStringAsString();
 
-          return new MatchedValuesFilter(element.getType(), rawAttributeType,
+          return new MatchedValuesFilter(type, rawAttributeType,
                                          null, null, null, null, null);
         }
         catch (Exception e)
@@ -918,27 +886,19 @@
         // the first element(s).
         try
         {
-          ArrayList<ASN1Element> elements =
-               element.decodeAsSequence().elements();
-          if ((elements.size() < 2) || (elements.size() > 3))
-          {
-            Message message = ERR_MVFILTER_INVALID_EXTENSIBLE_SEQUENCE_SIZE.get(
-                elements.size());
-            throw new LDAPException(LDAPResultCode.PROTOCOL_ERROR, message);
-          }
-
+          reader.readStartSequence();
 
           String          rawAttributeType  = null;
           String          matchingRuleID    = null;
-          ASN1OctetString rawAssertionValue = null;
-          for (ASN1Element e : elements)
+          ByteString rawAssertionValue = null;
+          while(reader.hasNextElement())
           {
-            switch (e.getType())
+            switch (reader.peekType())
             {
               case TYPE_MATCHING_RULE_ID:
                 if (matchingRuleID == null)
                 {
-                  matchingRuleID = e.decodeAsOctetString().stringValue();
+                  matchingRuleID = reader.readOctetStringAsString();
                 }
                 else
                 {
@@ -952,7 +912,7 @@
               case TYPE_MATCHING_RULE_TYPE:
                 if (rawAttributeType == null)
                 {
-                  rawAttributeType = e.decodeAsOctetString().stringValue();
+                  rawAttributeType = reader.readOctetStringAsString();
                 }
                 else
                 {
@@ -965,7 +925,7 @@
               case TYPE_MATCHING_RULE_VALUE:
                 if (rawAssertionValue == null)
                 {
-                  rawAssertionValue = e.decodeAsOctetString();
+                  rawAssertionValue = reader.readOctetString();
                 }
                 else
                 {
@@ -978,13 +938,13 @@
 
               default:
                 Message message = ERR_MVFILTER_INVALID_EXTENSIBLE_ELEMENT_TYPE.
-                    get(byteToHex(e.getType()));
+                    get(byteToHex(reader.peekType()));
                 throw new LDAPException(LDAPResultCode.PROTOCOL_ERROR, message);
             }
           }
+          reader.readEndSequence();
 
-
-          return new MatchedValuesFilter(element.getType(), rawAttributeType,
+          return new MatchedValuesFilter(type, rawAttributeType,
                                          rawAssertionValue, null, null, null,
                                          matchingRuleID);
         }
@@ -1008,7 +968,7 @@
 
       default:
         Message message =
-            ERR_MVFILTER_INVALID_ELEMENT_TYPE.get(byteToHex(element.getType()));
+            ERR_MVFILTER_INVALID_ELEMENT_TYPE.get(byteToHex(type));
         throw new LDAPException(LDAPResultCode.PROTOCOL_ERROR, message);
     }
   }
@@ -1040,28 +1000,6 @@
   }
 
 
-
-  /**
-   * Specifies the raw, unprocessed attribute type for this matched values
-   * filter.
-   *
-   * @param  rawAttributeType  The raw, unprocessed attribute type for this
-   *                           matched values filter.
-   */
-  public void setRawAttributeType(String rawAttributeType)
-  {
-    this.rawAttributeType = rawAttributeType;
-
-    decoded                 = false;
-    attributeType           = null;
-    approximateMatchingRule = null;
-    equalityMatchingRule    = null;
-    orderingMatchingRule    = null;
-    substringMatchingRule   = null;
-  }
-
-
-
   /**
    * Retrieves the attribute type for this matched values filter.
    *
@@ -1088,34 +1026,6 @@
   }
 
 
-
-  /**
-   * Specifies the attribute type for this matched values filter.
-   *
-   * @param  attributeType  The attribute type for this matched values filter.
-   */
-  public void setAttributeType(AttributeType attributeType)
-  {
-    this.attributeType = attributeType;
-
-    if (attributeType == null)
-    {
-      rawAttributeType = null;
-    }
-    else
-    {
-      rawAttributeType = attributeType.getNameOrOID();
-    }
-
-    decoded                 = false;
-    approximateMatchingRule = null;
-    equalityMatchingRule    = null;
-    orderingMatchingRule    = null;
-    substringMatchingRule   = null;
-  }
-
-
-
   /**
    * Retrieves the raw, unprocessed assertion value for this matched values
    * filter.
@@ -1131,23 +1041,6 @@
 
 
   /**
-   * Specifies the raw, unprocessed assertion value for this matched values
-   * filter.
-   *
-   * @param  rawAssertionValue  The raw, unprocessed assertion value for this
-   *                            matched values filter.
-   */
-  public void setRawAssertionValue(ByteString rawAssertionValue)
-  {
-    this.rawAssertionValue = rawAssertionValue;
-
-    decoded        = false;
-    assertionValue = null;
-  }
-
-
-
-  /**
    * Retrieves the assertion value for this matched values filter.
    *
    * @return  The assertion value for this matched values filter, or
@@ -1159,8 +1052,8 @@
     {
       if (rawAssertionValue != null)
       {
-        assertionValue = new AttributeValue(getAttributeType(),
-                                            rawAssertionValue);
+        assertionValue = AttributeValues.create(
+            getAttributeType(), rawAssertionValue);
       }
     }
 
@@ -1170,29 +1063,6 @@
 
 
   /**
-   * Specifies the assertion value for this matched values filter.
-   *
-   * @param  assertionValue  The assertion value for this matched values filter.
-   */
-  public void setAssertionValue(AttributeValue assertionValue)
-  {
-    this.assertionValue = assertionValue;
-
-    if (assertionValue == null)
-    {
-      rawAssertionValue = null;
-    }
-    else
-    {
-      rawAssertionValue = assertionValue.getValue().toASN1OctetString();
-    }
-
-    decoded = false;
-  }
-
-
-
-  /**
    * Retrieves the subInitial element for this matched values filter.
    *
    * @return  The subInitial element for this matched values filter, or
@@ -1205,18 +1075,7 @@
 
 
 
-  /**
-   * Specifies the subInitial element for this matched values filter.
-   *
-   * @param  subInitial  The subInitial element for this matched values filter.
-   */
-  public void setSubInitialElement(ByteString subInitial)
-  {
-    this.subInitial = subInitial;
 
-    decoded              = false;
-    normalizedSubInitial = null;
-  }
 
 
 
@@ -1226,7 +1085,7 @@
    * @return  The normalized form of the subInitial element, or
    *          <CODE>null</CODE> if there is none.
    */
-  public ASN1OctetString getNormalizedSubInitialElement()
+  public ByteString getNormalizedSubInitialElement()
   {
     if (normalizedSubInitial == null)
     {
@@ -1235,8 +1094,7 @@
         try
         {
           normalizedSubInitial =
-               getSubstringMatchingRule().normalizeSubstring(subInitial).
-                    toASN1OctetString();
+               getSubstringMatchingRule().normalizeSubstring(subInitial);
         }
         catch (Exception e)
         {
@@ -1268,21 +1126,6 @@
 
 
   /**
-   * Specifies the set of subAny elements for this matched values filter.
-   *
-   * @param  subAny  The set of subAny elements for this matched values filter.
-   */
-  public void setSubAnyElements(List<ByteString> subAny)
-  {
-    this.subAny = subAny;
-
-    decoded          = false;
-    normalizedSubAny = null;
-  }
-
-
-
-  /**
    * Retrieves the set of normalized subAny elements for this matched values
    * filter.
    *
@@ -1291,13 +1134,13 @@
    *          problem occurs while attempting to perform the normalization, then
    *          <CODE>null</CODE> will be returned.
    */
-  public List<ASN1OctetString> getNormalizedSubAnyElements()
+  public List<ByteString> getNormalizedSubAnyElements()
   {
     if (normalizedSubAny == null)
     {
       if ((subAny == null) || (subAny.isEmpty()))
       {
-        normalizedSubAny = new ArrayList<ASN1OctetString>(0);
+        normalizedSubAny = new ArrayList<ByteString>(0);
       }
       else
       {
@@ -1306,14 +1149,13 @@
           return null;
         }
 
-        normalizedSubAny = new ArrayList<ASN1OctetString>();
+        normalizedSubAny = new ArrayList<ByteString>();
         try
         {
           for (ByteString s : subAny)
           {
             normalizedSubAny.add(
-                 substringMatchingRule.normalizeSubstring(s).
-                      toASN1OctetString());
+                 substringMatchingRule.normalizeSubstring(s));
           }
         }
         catch (Exception e)
@@ -1347,27 +1189,12 @@
 
 
   /**
-   * Specifies the subFinal element for this matched values filter.
-   *
-   * @param  subFinal  The subFinal element for this matched values filter.
-   */
-  public void setSubFinalElement(ByteString subFinal)
-  {
-    this.subFinal = subFinal;
-
-    decoded            = false;
-    normalizedSubFinal = null;
-  }
-
-
-
-  /**
    * Retrieves the normalized form of the subFinal element.
    *
    * @return  The normalized form of the subFinal element, or <CODE>null</CODE>
    *          if there is none.
    */
-  public ASN1OctetString getNormalizedSubFinalElement()
+  public ByteString getNormalizedSubFinalElement()
   {
     if (normalizedSubFinal == null)
     {
@@ -1376,8 +1203,7 @@
         try
         {
           normalizedSubFinal =
-               getSubstringMatchingRule().normalizeSubstring(subFinal).
-                    toASN1OctetString();
+               getSubstringMatchingRule().normalizeSubstring(subFinal);
         }
         catch (Exception e)
         {
@@ -1408,22 +1234,6 @@
 
 
   /**
-   * Specifies the matching rule ID for this matched values filter.
-   *
-   * @param  matchingRuleID  The matching rule ID for this matched values
-   *                         filter.
-   */
-  public void setMatchingRuleID(String matchingRuleID)
-  {
-    this.matchingRuleID = matchingRuleID;
-
-    decoded      = false;
-    matchingRule = null;
-  }
-
-
-
-  /**
    * Retrieves the matching rule for this matched values filter.
    *
    * @return  The matching rule for this matched values filter, or
@@ -1446,29 +1256,6 @@
 
 
   /**
-   * Specifies the matching rule for this matched values filter.
-   *
-   * @param  matchingRule  The matching rule for this matched values filter.
-   */
-  public void setMatchingRule(MatchingRule matchingRule)
-  {
-    this.matchingRule = matchingRule;
-
-    if (matchingRule == null)
-    {
-      matchingRuleID = null;
-    }
-    else
-    {
-      matchingRuleID = matchingRule.getNameOrOID();
-    }
-
-    decoded = false;
-  }
-
-
-
-  /**
    * Retrieves the approximate matching rule that should be used for this
    * matched values filter.
    *
@@ -1635,8 +1422,8 @@
         {
           try
           {
-            ArrayList<ByteString> normalizedSubAnyBS =
-                 new ArrayList<ByteString>(normalizedSubAny);
+            ArrayList<ByteSequence> normalizedSubAnyBS =
+                 new ArrayList<ByteSequence>(normalizedSubAny);
 
             return substringMatchingRule.valueMatchesSubstring(
                  value.getNormalizedValue(), normalizedSubInitial,
@@ -1762,12 +1549,10 @@
 
           try
           {
-            ASN1OctetString nv1 =
-                 matchingRule.normalizeValue(value.getValue()).
-                      toASN1OctetString();
-            ASN1OctetString nv2 =
-                 matchingRule.normalizeValue(assertionValue.getValue()).
-                      toASN1OctetString();
+            ByteString nv1 =
+                 matchingRule.normalizeValue(value.getValue());
+            ByteString nv2 =
+                 matchingRule.normalizeValue(assertionValue.getValue());
 
             return (matchingRule.valuesMatch(nv1, nv2) == ConditionResult.TRUE);
           }
@@ -1819,6 +1604,7 @@
    *
    * @return  A string representation of this matched values filter.
    */
+  @Override
   public String toString()
   {
     StringBuilder buffer = new StringBuilder();
diff --git a/opends/src/server/org/opends/server/controls/PagedResultsControl.java b/opends/src/server/org/opends/server/controls/PagedResultsControl.java
index 26220a3..cd35248 100644
--- a/opends/src/server/org/opends/server/controls/PagedResultsControl.java
+++ b/opends/src/server/org/opends/server/controls/PagedResultsControl.java
@@ -29,19 +29,15 @@
 
 import static org.opends.server.loggers.debug.DebugLogger.*;
 import org.opends.server.loggers.debug.DebugTracer;
-import org.opends.server.types.DebugLogLevel;
 import static org.opends.messages.ProtocolMessages.*;
-import static org.opends.server.protocols.ldap.LDAPResultCode.PROTOCOL_ERROR;
 import static org.opends.server.util.ServerConstants.OID_PAGED_RESULTS_CONTROL;
 
-import org.opends.server.protocols.asn1.ASN1Element;
-import org.opends.server.protocols.asn1.ASN1Integer;
-import org.opends.server.protocols.asn1.ASN1OctetString;
-import org.opends.server.protocols.asn1.ASN1Sequence;
-import org.opends.server.types.Control;
-import org.opends.server.types.LDAPException;
+import org.opends.server.protocols.asn1.*;
+import static org.opends.server.protocols.asn1.ASN1Constants.
+    UNIVERSAL_OCTET_STRING_TYPE;
+import org.opends.server.types.*;
 
-import java.util.ArrayList;
+import java.io.IOException;
 
 /**
  * This class represents a paged results control value as defined in
@@ -61,6 +57,107 @@
 public class PagedResultsControl extends Control
 {
   /**
+   * ControlDecoder implentation to decode this control from a ByteString.
+   */
+  private final static class Decoder
+      implements ControlDecoder<PagedResultsControl>
+  {
+    /**
+     * {@inheritDoc}
+     */
+    public PagedResultsControl decode(boolean isCritical, ByteString value)
+        throws DirectoryException
+    {
+      if (value == null)
+      {
+        Message message = ERR_LDAP_PAGED_RESULTS_DECODE_NULL.get();
+        throw new DirectoryException(ResultCode.PROTOCOL_ERROR, message);
+      }
+
+      ASN1Reader reader = ASN1.getReader(value);
+      try
+      {
+        reader.readStartSequence();
+      }
+      catch (Exception e)
+      {
+        if (debugEnabled())
+        {
+          TRACER.debugCaught(DebugLogLevel.ERROR, e);
+        }
+
+        Message message =
+            ERR_LDAP_PAGED_RESULTS_DECODE_SEQUENCE.get(String.valueOf(e));
+        throw new DirectoryException(ResultCode.PROTOCOL_ERROR, message, e);
+      }
+
+      int size;
+      try
+      {
+        size = (int)reader.readInteger();
+      }
+      catch (Exception e)
+      {
+        if (debugEnabled())
+        {
+          TRACER.debugCaught(DebugLogLevel.ERROR, e);
+        }
+
+        Message message =
+            ERR_LDAP_PAGED_RESULTS_DECODE_SIZE.get(String.valueOf(e));
+        throw new DirectoryException(ResultCode.PROTOCOL_ERROR, message, e);
+      }
+
+      ByteString cookie;
+      try
+      {
+        cookie = reader.readOctetString();
+      }
+      catch (Exception e)
+      {
+        if (debugEnabled())
+        {
+          TRACER.debugCaught(DebugLogLevel.ERROR, e);
+        }
+
+        Message message =
+            ERR_LDAP_PAGED_RESULTS_DECODE_COOKIE.get(String.valueOf(e));
+        throw new DirectoryException(ResultCode.PROTOCOL_ERROR, message, e);
+      }
+
+      try
+      {
+        reader.readEndSequence();
+      }
+      catch (Exception e)
+      {
+        if (debugEnabled())
+        {
+          TRACER.debugCaught(DebugLogLevel.ERROR, e);
+        }
+
+        Message message =
+            ERR_LDAP_PAGED_RESULTS_DECODE_SEQUENCE.get(String.valueOf(e));
+        throw new DirectoryException(ResultCode.PROTOCOL_ERROR, message, e);
+      }
+
+      return new PagedResultsControl(isCritical, size, cookie);
+    }
+
+    public String getOID()
+    {
+      return OID_PAGED_RESULTS_CONTROL;
+    }
+
+  }
+
+  /**
+   * The Control Decoder that can be used to decode this control.
+   */
+  public static final  ControlDecoder<PagedResultsControl> DECODER =
+    new Decoder();
+
+  /**
    * The tracer object for the debug logger.
    */
   private static final DebugTracer TRACER = getTracer();
@@ -77,7 +174,7 @@
   /**
    * The control value cookie element.
    */
-  private ASN1OctetString cookie;
+  private ByteString cookie;
 
 
   /**
@@ -89,112 +186,36 @@
    * @param  cookie      The cookie element.
    */
   public PagedResultsControl(boolean isCritical, int size,
-                             ASN1OctetString cookie)
+                             ByteString cookie)
   {
     super(OID_PAGED_RESULTS_CONTROL, isCritical);
 
 
     this.size   = size;
-    this.cookie = cookie;
-
-    this.setValue(encode());
+    if(cookie == null)
+        this.cookie=ByteString.empty();
+    else
+        this.cookie = cookie;
   }
 
 
   /**
-   * Creates a new paged results control by decoding the given information.
+   * Writes this control's value to an ASN.1 writer. The value (if any) must be
+   * written as an ASN1OctetString.
    *
-   * @param  isCritical  Indicates whether the control is considered
-   *                     critical in processing the request.
-   * @param  value       The value of the control.
-   *
-   * @throws  LDAPException  If a problem occurs while attempting to decode the
-   *                         provided information as a paged results control.
+   * @param writer The ASN.1 output stream to write to.
+   * @throws IOException If a problem occurs while writing to the stream.
    */
-  public PagedResultsControl(boolean isCritical, ASN1OctetString value)
-       throws LDAPException
-  {
-    super(OID_PAGED_RESULTS_CONTROL, isCritical, value);
+  @Override
+  public void writeValue(ASN1Writer writer) throws IOException {
+    writer.writeStartSequence(UNIVERSAL_OCTET_STRING_TYPE);
 
-    if (value == null)
-    {
-      Message message = ERR_LDAP_PAGED_RESULTS_DECODE_NULL.get();
-      throw new LDAPException(PROTOCOL_ERROR, message);
-    }
+    writer.writeStartSequence();
+    writer.writeInteger(size);
+    writer.writeOctetString(cookie);
+    writer.writeEndSequence();
 
-    ArrayList<ASN1Element> elements;
-    try
-    {
-      ASN1Element sequence = ASN1Element.decode(value.value());
-      elements = sequence.decodeAsSequence().elements();
-    }
-    catch (Exception e)
-    {
-      if (debugEnabled())
-      {
-        TRACER.debugCaught(DebugLogLevel.ERROR, e);
-      }
-
-      Message message =
-          ERR_LDAP_PAGED_RESULTS_DECODE_SEQUENCE.get(String.valueOf(e));
-      throw new LDAPException(PROTOCOL_ERROR, message, e);
-    }
-
-    int numElements = elements.size();
-    if (numElements != 2)
-    {
-      Message message =
-          ERR_LDAP_PAGED_RESULTS_DECODE_INVALID_ELEMENT_COUNT.get(numElements);
-      throw new LDAPException(PROTOCOL_ERROR, message);
-    }
-
-    try
-    {
-      size = elements.get(0).decodeAsInteger().intValue();
-    }
-    catch (Exception e)
-    {
-      if (debugEnabled())
-      {
-        TRACER.debugCaught(DebugLogLevel.ERROR, e);
-      }
-
-      Message message =
-          ERR_LDAP_PAGED_RESULTS_DECODE_SIZE.get(String.valueOf(e));
-      throw new LDAPException(PROTOCOL_ERROR, message, e);
-    }
-
-    try
-    {
-      cookie = elements.get(1).decodeAsOctetString();
-    }
-    catch (Exception e)
-    {
-      if (debugEnabled())
-      {
-        TRACER.debugCaught(DebugLogLevel.ERROR, e);
-      }
-
-      Message message =
-          ERR_LDAP_PAGED_RESULTS_DECODE_COOKIE.get(String.valueOf(e));
-      throw new LDAPException(PROTOCOL_ERROR, message, e);
-    }
-  }
-
-
-  /**
-   * Encodes this control value to an ASN.1 element.
-   *
-   * @return  The ASN.1 element containing the encoded control value.
-   */
-  public ASN1OctetString encode()
-  {
-    ArrayList<ASN1Element> elements = new ArrayList<ASN1Element>(2);
-    elements.add(new ASN1Integer(size));
-    elements.add(cookie);
-
-    ASN1Sequence sequence = new ASN1Sequence(elements);
-    return new ASN1OctetString(sequence.encode());
+    writer.writeEndSequence();
   }
 
 
@@ -214,7 +235,7 @@
    * Get the control value cookie element.
    * @return The control value cookie element.
    */
-  public ASN1OctetString getCookie()
+  public ByteString getCookie()
   {
     return cookie;
   }
diff --git a/opends/src/server/org/opends/server/controls/PasswordExpiredControl.java b/opends/src/server/org/opends/server/controls/PasswordExpiredControl.java
index 9e40d01..5691f2d 100644
--- a/opends/src/server/org/opends/server/controls/PasswordExpiredControl.java
+++ b/opends/src/server/org/opends/server/controls/PasswordExpiredControl.java
@@ -29,14 +29,16 @@
 
 
 
-import org.opends.server.protocols.asn1.ASN1OctetString;
-import org.opends.server.protocols.ldap.LDAPResultCode;
+import org.opends.server.protocols.asn1.ASN1Writer;
+import org.opends.server.types.ByteString;
 import org.opends.server.types.Control;
-import org.opends.server.types.LDAPException;
+import org.opends.server.types.DirectoryException;
+import org.opends.server.types.ResultCode;
 
 import static org.opends.messages.ProtocolMessages.*;
 import static org.opends.server.util.ServerConstants.*;
 
+import java.io.IOException;
 
 
 /**
@@ -48,75 +50,77 @@
        extends Control
 {
   /**
+   * ControlDecoder implentation to decode this control from a ByteString.
+   */
+  private final static class Decoder
+      implements ControlDecoder<PasswordExpiredControl>
+  {
+    /**
+     * {@inheritDoc}
+     */
+    public PasswordExpiredControl decode(boolean isCritical, ByteString value)
+        throws DirectoryException
+    {
+      if (value != null)
+      {
+        try
+        {
+          Integer.parseInt(value.toString());
+        }
+        catch (Exception e)
+        {
+          Message message = ERR_PWEXPIRED_CONTROL_INVALID_VALUE.get();
+          throw new DirectoryException(ResultCode.PROTOCOL_ERROR, message);
+        }
+      }
+
+      return new PasswordExpiredControl(isCritical);
+    }
+
+    public String getOID()
+    {
+      return OID_NS_PASSWORD_EXPIRED;
+    }
+
+  }
+
+  /**
+   * The Control Decoder that can be used to decode this control.
+   */
+  public static final ControlDecoder<PasswordExpiredControl> DECODER =
+    new Decoder();
+
+  /**
    * Creates a new instance of the password expired control with the default
    * settings.
    */
   public PasswordExpiredControl()
   {
-    super(OID_NS_PASSWORD_EXPIRED, false, new ASN1OctetString("0"));
+    this(false);
   }
 
-
-
   /**
    * Creates a new instance of the password expired control with the provided
    * information.
    *
-   * @param  oid         The OID to use for this control.
    * @param  isCritical  Indicates whether support for this control should be
    *                     considered a critical part of the client processing.
    */
-  public PasswordExpiredControl(String oid, boolean isCritical)
+  public PasswordExpiredControl(boolean isCritical)
   {
-    super(oid, isCritical, new ASN1OctetString("0"));
+    super(OID_NS_PASSWORD_EXPIRED, isCritical);
   }
 
-
-
   /**
-   * Creates a new password expired control from the contents of the provided
-   * control.
+   * Writes this control's value to an ASN.1 writer. The value (if any) must be
+   * written as an ASN1OctetString.
    *
-   * @param  control  The generic control containing the information to use to
-   *                  create this password expired control.
-   *
-   * @return  The password expired control decoded from the provided control.
-   *
-   * @throws  LDAPException  If this control cannot be decoded as a valid
-   *                         password expired control.
+   * @param writer The ASN.1 output stream to write to.
+   * @throws IOException If a problem occurs while writing to the stream.
    */
-  public static PasswordExpiredControl decodeControl(Control control)
-         throws LDAPException
-  {
-    if (control.hasValue())
-    {
-      String valueStr = control.getValue().stringValue();
-      try
-      {
-        Integer.parseInt(valueStr);
-      }
-      catch (Exception e)
-      {
-        Message message = ERR_PWEXPIRED_CONTROL_INVALID_VALUE.get();
-        throw new LDAPException(LDAPResultCode.PROTOCOL_ERROR, message);
-      }
-    }
-
-    return new PasswordExpiredControl(control.getOID(), control.isCritical());
-  }
-
-
-
-  /**
-   * Retrieves a string representation of this password expired control.
-   *
-   * @return  A string representation of this password expired control.
-   */
-  public String toString()
-  {
-    StringBuilder buffer = new StringBuilder();
-    toString(buffer);
-    return buffer.toString();
+  @Override
+  public void writeValue(ASN1Writer writer) throws IOException {
+    writer.writeOctetString("0");
   }
 
 
@@ -127,6 +131,7 @@
    *
    * @param  buffer  The buffer to which the information should be appended.
    */
+  @Override
   public void toString(StringBuilder buffer)
   {
     buffer.append("PasswordExpiredControl()");
diff --git a/opends/src/server/org/opends/server/controls/PasswordExpiringControl.java b/opends/src/server/org/opends/server/controls/PasswordExpiringControl.java
index f090fab..9055941 100644
--- a/opends/src/server/org/opends/server/controls/PasswordExpiringControl.java
+++ b/opends/src/server/org/opends/server/controls/PasswordExpiringControl.java
@@ -29,11 +29,8 @@
 
 
 
-import org.opends.server.protocols.asn1.ASN1OctetString;
-import org.opends.server.protocols.ldap.LDAPResultCode;
-import org.opends.server.types.Control;
-import org.opends.server.types.DebugLogLevel;
-import org.opends.server.types.LDAPException;
+import org.opends.server.protocols.asn1.ASN1Writer;
+import org.opends.server.types.*;
 
 import static org.opends.server.loggers.debug.DebugLogger.*;
 import org.opends.server.loggers.debug.DebugTracer;
@@ -41,6 +38,7 @@
 import static org.opends.server.util.ServerConstants.*;
 import static org.opends.server.util.StaticUtils.*;
 
+import java.io.IOException;
 
 
 /**
@@ -53,6 +51,60 @@
        extends Control
 {
   /**
+   * ControlDecoder implentation to decode this control from a ByteString.
+   */
+  private final static class Decoder
+      implements ControlDecoder<PasswordExpiringControl>
+  {
+    /**
+     * {@inheritDoc}
+     */
+    public PasswordExpiringControl decode(boolean isCritical, ByteString value)
+        throws DirectoryException
+    {
+      if (value == null)
+      {
+        Message message = ERR_PWEXPIRING_NO_CONTROL_VALUE.get();
+        throw new DirectoryException(ResultCode.PROTOCOL_ERROR, message);
+      }
+
+      int secondsUntilExpiration;
+      try
+      {
+        secondsUntilExpiration =
+            Integer.parseInt(value.toString());
+      }
+      catch (Exception e)
+      {
+        if (debugEnabled())
+        {
+          TRACER.debugCaught(DebugLogLevel.ERROR, e);
+        }
+
+        Message message = ERR_PWEXPIRING_CANNOT_DECODE_SECONDS_UNTIL_EXPIRATION.
+            get(getExceptionMessage(e));
+        throw new DirectoryException(ResultCode.PROTOCOL_ERROR, message);
+      }
+
+
+      return new PasswordExpiringControl(isCritical,
+          secondsUntilExpiration);
+    }
+
+    public String getOID()
+    {
+      return OID_NS_PASSWORD_EXPIRING;
+    }
+
+  }
+
+  /**
+   * The Control Decoder that can be used to decode this control.
+   */
+  public static final ControlDecoder<PasswordExpiringControl> DECODER =
+    new Decoder();
+
+  /**
    * The tracer object for the debug logger.
    */
   private static final DebugTracer TRACER = getTracer();
@@ -74,11 +126,7 @@
    */
   public PasswordExpiringControl(int secondsUntilExpiration)
   {
-    super(OID_NS_PASSWORD_EXPIRING, false,
-          new ASN1OctetString(String.valueOf(secondsUntilExpiration)));
-
-
-    this.secondsUntilExpiration = secondsUntilExpiration;
+    this(false, secondsUntilExpiration);
   }
 
 
@@ -87,93 +135,31 @@
    * Creates a new instance of the password expiring control with the provided
    * information.
    *
-   * @param  oid                     The OID to use for this control.
    * @param  isCritical              Indicates whether support for this control
    *                                 should be considered a critical part of the
    *                                 client processing.
    * @param  secondsUntilExpiration  The length of time in seconds until the
    *                                 password actually expires.
    */
-  public PasswordExpiringControl(String oid, boolean isCritical,
-                                 int secondsUntilExpiration)
+  public PasswordExpiringControl(boolean isCritical, int secondsUntilExpiration)
   {
-    super(oid, isCritical,
-          new ASN1OctetString(String.valueOf(secondsUntilExpiration)));
+    super(OID_NS_PASSWORD_EXPIRING, isCritical);
 
 
     this.secondsUntilExpiration = secondsUntilExpiration;
   }
 
 
-
   /**
-   * Creates a new instance of the password expiring control with the provided
-   * information.
+   * Writes this control's value to an ASN.1 writer. The value (if any) must be
+   * written as an ASN1OctetString.
    *
-   * @param  oid                     The OID to use for this control.
-   * @param  isCritical              Indicates whether support for this control
-   *                                 should be considered a critical part of the
-   *                                 client processing.
-   * @param  secondsUntilExpiration  The length of time in seconds until the
-   *                                 password actually expires.
-   * @param  encodedValue            The pre-encoded value for this control.
+   * @param writer The ASN.1 output stream to write to.
+   * @throws IOException If a problem occurs while writing to the stream.
    */
-  private PasswordExpiringControl(String oid, boolean isCritical,
-                                  int secondsUntilExpiration,
-                                  ASN1OctetString encodedValue)
-  {
-    super(oid, isCritical, encodedValue);
-
-
-    this.secondsUntilExpiration = secondsUntilExpiration;
-  }
-
-
-
-  /**
-   * Creates a new password expiring control from the contents of the provided
-   * control.
-   *
-   * @param  control  The generic control containing the information to use to
-   *                  create this password expiring control.
-   *
-   * @return  The password expiring control decoded from the provided control.
-   *
-   * @throws  LDAPException  If this control cannot be decoded as a valid
-   *                         password expiring control.
-   */
-  public static PasswordExpiringControl decodeControl(Control control)
-         throws LDAPException
-  {
-    if (! control.hasValue())
-    {
-      Message message = ERR_PWEXPIRING_NO_CONTROL_VALUE.get();
-      throw new LDAPException(LDAPResultCode.PROTOCOL_ERROR, message);
-    }
-
-
-    int secondsUntilExpiration;
-    try
-    {
-      secondsUntilExpiration =
-           Integer.parseInt(control.getValue().stringValue());
-    }
-    catch (Exception e)
-    {
-      if (debugEnabled())
-      {
-        TRACER.debugCaught(DebugLogLevel.ERROR, e);
-      }
-
-      Message message = ERR_PWEXPIRING_CANNOT_DECODE_SECONDS_UNTIL_EXPIRATION.
-          get(getExceptionMessage(e));
-      throw new LDAPException(LDAPResultCode.PROTOCOL_ERROR, message);
-    }
-
-
-    return new PasswordExpiringControl(control.getOID(), control.isCritical(),
-                                       secondsUntilExpiration,
-                                       control.getValue());
+  @Override
+  public void writeValue(ASN1Writer writer) throws IOException {
+    writer.writeOctetString(String.valueOf(secondsUntilExpiration));
   }
 
 
@@ -192,25 +178,12 @@
 
 
   /**
-   * Retrieves a string representation of this password expiring control.
-   *
-   * @return  A string representation of this password expiring control.
-   */
-  public String toString()
-  {
-    StringBuilder buffer = new StringBuilder();
-    toString(buffer);
-    return buffer.toString();
-  }
-
-
-
-  /**
    * Appends a string representation of this password expiring control to the
    * provided buffer.
    *
    * @param  buffer  The buffer to which the information should be appended.
    */
+  @Override
   public void toString(StringBuilder buffer)
   {
     buffer.append("PasswordExpiringControl(secondsUntilExpiration=");
diff --git a/opends/src/server/org/opends/server/controls/PasswordPolicyRequestControl.java b/opends/src/server/org/opends/server/controls/PasswordPolicyRequestControl.java
index 79b2728..fd8b54e 100644
--- a/opends/src/server/org/opends/server/controls/PasswordPolicyRequestControl.java
+++ b/opends/src/server/org/opends/server/controls/PasswordPolicyRequestControl.java
@@ -29,13 +29,16 @@
 
 
 
-import org.opends.server.protocols.ldap.LDAPResultCode;
+import org.opends.server.protocols.asn1.ASN1Writer;
+import org.opends.server.types.ByteString;
 import org.opends.server.types.Control;
-import org.opends.server.types.LDAPException;
+import org.opends.server.types.DirectoryException;
+import org.opends.server.types.ResultCode;
 
 import static org.opends.messages.ProtocolMessages.*;
 import static org.opends.server.util.ServerConstants.*;
 
+import java.io.IOException;
 
 
 /**
@@ -45,8 +48,42 @@
 public class PasswordPolicyRequestControl
        extends Control
 {
+  /**
+   * ControlDecoder implentation to decode this control from a ByteString.
+   */
+  private final static class Decoder
+      implements ControlDecoder<PasswordPolicyRequestControl>
+  {
+    /**
+     * {@inheritDoc}
+     */
+    public PasswordPolicyRequestControl decode(boolean isCritical,
+                                               ByteString value)
+        throws DirectoryException
+    {
+      if (value != null)
+      {
+        Message message = ERR_PWPOLICYREQ_CONTROL_HAS_VALUE.get();
+        throw new DirectoryException(ResultCode.PROTOCOL_ERROR, message);
+      }
 
 
+      return new PasswordPolicyRequestControl(isCritical);
+    }
+
+    public String getOID()
+    {
+      return OID_PASSWORD_POLICY_CONTROL;
+    }
+
+  }
+
+  /**
+   * The Control Decoder that can be used to decode this control.
+   */
+  public static final ControlDecoder<PasswordPolicyRequestControl> DECODER =
+    new Decoder();
+
 
   /**
    * Creates a new instance of the password policy request control with the
@@ -54,7 +91,7 @@
    */
   public PasswordPolicyRequestControl()
   {
-    super(OID_PASSWORD_POLICY_CONTROL, false);
+    this(false);
 
   }
 
@@ -64,57 +101,27 @@
    * Creates a new instance of the password policy request control with the
    * provided information.
    *
-   * @param  oid         The OID to use for this control.
    * @param  isCritical  Indicates whether support for this control should be
    *                     considered a critical part of the client processing.
    */
-  public PasswordPolicyRequestControl(String oid, boolean isCritical)
+  public PasswordPolicyRequestControl(boolean isCritical)
   {
-    super(oid, isCritical);
+    super(OID_PASSWORD_POLICY_CONTROL, isCritical);
 
   }
 
 
 
   /**
-   * Creates a new password policy request control from the contents of the
-   * provided control.
+   * Writes this control's value to an ASN.1 writer. The value (if any) must be
+   * written as an ASN1OctetString.
    *
-   * @param  control  The generic control containing the information to use to
-   *                  create this password policy request control.
-   *
-   * @return  The password policy request control decoded from the provided
-   *          control.
-   *
-   * @throws  LDAPException  If this control cannot be decoded as a valid
-   *                         password policy request control.
+   * @param writer The ASN.1 output stream to write to.
+   * @throws IOException If a problem occurs while writing to the stream.
    */
-  public static PasswordPolicyRequestControl decodeControl(Control control)
-         throws LDAPException
-  {
-    if (control.hasValue())
-    {
-      Message message = ERR_PWPOLICYREQ_CONTROL_HAS_VALUE.get();
-      throw new LDAPException(LDAPResultCode.PROTOCOL_ERROR, message);
-    }
-
-
-    return new PasswordPolicyRequestControl(control.getOID(),
-                                            control.isCritical());
-  }
-
-
-
-  /**
-   * Retrieves a string representation of this password policy request control.
-   *
-   * @return  A string representation of this password policy request control.
-   */
-  public String toString()
-  {
-    StringBuilder buffer = new StringBuilder();
-    toString(buffer);
-    return buffer.toString();
+  @Override
+  public void writeValue(ASN1Writer writer) throws IOException {
+    // No value element.
   }
 
 
@@ -125,6 +132,7 @@
    *
    * @param  buffer  The buffer to which the information should be appended.
    */
+  @Override
   public void toString(StringBuilder buffer)
   {
     buffer.append("PasswordPolicyRequestControl()");
diff --git a/opends/src/server/org/opends/server/controls/PasswordPolicyResponseControl.java b/opends/src/server/org/opends/server/controls/PasswordPolicyResponseControl.java
index 96b46cb..ae6cc4e 100644
--- a/opends/src/server/org/opends/server/controls/PasswordPolicyResponseControl.java
+++ b/opends/src/server/org/opends/server/controls/PasswordPolicyResponseControl.java
@@ -29,21 +29,15 @@
 
 
 
-import java.util.ArrayList;
+import java.io.IOException;
 
-import org.opends.server.protocols.asn1.ASN1Element;
-import org.opends.server.protocols.asn1.ASN1Enumerated;
-import org.opends.server.protocols.asn1.ASN1Exception;
-import org.opends.server.protocols.asn1.ASN1Integer;
-import org.opends.server.protocols.asn1.ASN1OctetString;
-import org.opends.server.protocols.asn1.ASN1Sequence;
-import org.opends.server.protocols.ldap.LDAPResultCode;
-import org.opends.server.types.Control;
-import org.opends.server.types.LDAPException;
-
+import org.opends.server.protocols.asn1.*;
+import static org.opends.server.protocols.asn1.ASN1Constants.
+    UNIVERSAL_OCTET_STRING_TYPE;
 import static org.opends.server.loggers.debug.DebugLogger.*;
 import org.opends.server.loggers.debug.DebugTracer;
-import org.opends.server.types.DebugLogLevel;
+import org.opends.server.types.*;
+
 import static org.opends.messages.ProtocolMessages.*;
 import static org.opends.server.util.ServerConstants.*;
 import static org.opends.server.util.StaticUtils.*;
@@ -59,6 +53,112 @@
        extends Control
 {
   /**
+   * ControlDecoder implentation to decode this control from a ByteString.
+   */
+  private final static class Decoder
+      implements ControlDecoder<PasswordPolicyResponseControl>
+  {
+    /**
+     * {@inheritDoc}
+     */
+    public PasswordPolicyResponseControl decode(boolean isCritical,
+                                                ByteString value)
+        throws DirectoryException
+    {
+      if (value == null)
+      {
+        // The response control must always have a value.
+        Message message = ERR_PWPOLICYRES_NO_CONTROL_VALUE.get();
+        throw new DirectoryException(ResultCode.PROTOCOL_ERROR, message);
+      }
+
+      ASN1Reader reader = ASN1.getReader(value);
+      try
+      {
+        PasswordPolicyWarningType warningType  = null;
+        PasswordPolicyErrorType   errorType    = null;
+        int                       warningValue = -1;
+
+        reader.readStartSequence();
+
+        while(reader.hasNextElement())
+        {
+          switch (reader.peekType())
+          {
+            case TYPE_WARNING_ELEMENT:
+              // Its a CHOICE element. Read as sequence to retrieve
+              // nested element.
+              reader.readStartSequence();
+              warningType =
+                  PasswordPolicyWarningType.valueOf(reader.peekType());
+              warningValue = (int)reader.readInteger();
+              if (warningType == null)
+              {
+                Message message = ERR_PWPOLICYRES_INVALID_WARNING_TYPE.get(
+                    byteToHex(reader.peekType()));
+                throw new DirectoryException(ResultCode.PROTOCOL_ERROR,
+                    message);
+              }
+              reader.readEndSequence();
+              break;
+
+            case TYPE_ERROR_ELEMENT:
+              int errorValue = (int)reader.readInteger();
+              errorType = PasswordPolicyErrorType.valueOf(errorValue);
+              if (errorType == null)
+              {
+                Message message =
+                    ERR_PWPOLICYRES_INVALID_ERROR_TYPE.get(errorValue);
+                throw new DirectoryException(ResultCode.PROTOCOL_ERROR,
+                    message);
+              }
+              break;
+
+            default:
+              Message message = ERR_PWPOLICYRES_INVALID_ELEMENT_TYPE.get(
+                  byteToHex(reader.peekType()));
+              throw new DirectoryException(ResultCode.PROTOCOL_ERROR, message);
+          }
+        }
+
+        reader.readEndSequence();
+
+        return new PasswordPolicyResponseControl(isCritical,
+            warningType, warningValue,
+            errorType);
+      }
+      catch (DirectoryException de)
+      {
+        throw de;
+      }
+      catch (Exception e)
+      {
+        if (debugEnabled())
+        {
+          TRACER.debugCaught(DebugLogLevel.ERROR, e);
+        }
+
+        Message message =
+            ERR_PWPOLICYRES_DECODE_ERROR.get(getExceptionMessage(e));
+        throw new DirectoryException(ResultCode.PROTOCOL_ERROR, message);
+      }
+    }
+
+
+    public String getOID()
+    {
+      return OID_ACCOUNT_USABLE_CONTROL;
+    }
+
+  }
+
+  /**
+   * The Control Decoder that can be used to decode this control.
+   */
+  public static final ControlDecoder<PasswordPolicyResponseControl> DECODER =
+    new Decoder();
+
+  /**
    * The tracer object for the debug logger.
    */
   private static final DebugTracer TRACER = getTracer();
@@ -97,7 +197,7 @@
    */
   public PasswordPolicyResponseControl()
   {
-    super(OID_PASSWORD_POLICY_CONTROL, false, encodeValue(null, -1, null));
+    super(OID_PASSWORD_POLICY_CONTROL, false);
 
 
     warningType  = null;
@@ -125,13 +225,7 @@
                                        int warningValue,
                                        PasswordPolicyErrorType errorType)
   {
-    super(OID_PASSWORD_POLICY_CONTROL, false,
-          encodeValue(warningType, warningValue, errorType));
-
-
-    this.warningType  = warningType;
-    this.warningValue = warningValue;
-    this.errorType    = errorType;
+    this(false, warningType, warningValue, errorType);
   }
 
 
@@ -140,7 +234,6 @@
    * Creates a new instance of the password policy request control with the
    * provided information.
    *
-   * @param  oid           The OID to use for this control.
    * @param  isCritical    Indicates whether support for this control should be
    *                       considered a critical part of the client processing.
    * @param  warningType   The warning type to use for this password policy
@@ -152,13 +245,12 @@
    *                       response control, or <CODE>null</CODE> if there
    *                       should not be an error flag.
    */
-  public PasswordPolicyResponseControl(String oid, boolean isCritical,
+  public PasswordPolicyResponseControl(boolean isCritical,
                                        PasswordPolicyWarningType warningType,
                                        int warningValue,
                                        PasswordPolicyErrorType errorType)
   {
-    super(oid, isCritical, encodeValue(warningType, warningValue, errorType));
-
+    super(OID_PASSWORD_POLICY_CONTROL, isCritical);
 
     this.warningType  = warningType;
     this.warningValue = warningValue;
@@ -168,182 +260,35 @@
 
 
   /**
-   * Creates a new instance of the password policy request control with the
-   * provided information.
+   * Writes this control's value to an ASN.1 writer. The value (if any) must be
+   * written as an ASN1OctetString.
    *
-   * @param  oid           The OID to use for this control.
-   * @param  isCritical    Indicates whether support for this control should be
-   *                       considered a critical part of the client processing.
-   * @param  warningType   The warning type to use for this password policy
-   *                       response control, or <CODE>null</CODE> if there
-   *                       should not be a warning flag.
-   * @param  warningValue  The warning value to use for this password policy
-   *                       response control, if applicable.
-   * @param  errorType     The error type to use for this password policy
-   *                       response control, or <CODE>null</CODE> if there
-   *                       should not be an error flag.
-   * @param  encodedValue  The pre-encoded value to use for this control.
+   * @param writer The ASN.1 writer to use.
+   * @throws IOException If a problem occurs while writing to the stream.
    */
-  private PasswordPolicyResponseControl(String oid, boolean isCritical,
-                                        PasswordPolicyWarningType warningType,
-                                        int warningValue,
-                                        PasswordPolicyErrorType errorType,
-                                        ASN1OctetString encodedValue)
-  {
-    super(oid, isCritical, encodedValue);
+  @Override
+  protected void writeValue(ASN1Writer writer) throws IOException {
+    writer.writeStartSequence(UNIVERSAL_OCTET_STRING_TYPE);
 
-
-    this.warningType  = warningType;
-    this.warningValue = warningValue;
-    this.errorType    = errorType;
-  }
-
-
-
-  /**
-   * Encodes the provided information into an ASN.1 octet string suitable for
-   * use as the value for this control.
-   *
-   * @param  warningType   The warning type to use for this password policy
-   *                       response control, or <CODE>null</CODE> if there
-   *                       should not be a warning flag.
-   * @param  warningValue  The warning value to use for this password policy
-   *                       response control, if applicable.
-   * @param  errorType     The error type to use for this password policy
-   *                       response control, or <CODE>null</CODE> if there
-   *                       should not be an error flag.
-   *
-   * @return  An ASN.1 octet string containing the encoded control value.
-   */
-  private static ASN1OctetString encodeValue(
-                                      PasswordPolicyWarningType warningType,
-                                      int warningValue,
-                                      PasswordPolicyErrorType errorType)
-  {
-    ArrayList<ASN1Element> elements = new ArrayList<ASN1Element>(2);
-
+    writer.writeStartSequence();
     if (warningType != null)
     {
-      ASN1Integer warningInteger = new ASN1Integer(warningType.getType(),
-                                                   warningValue);
-      elements.add(new ASN1Element(TYPE_WARNING_ELEMENT,
-                                   warningInteger.encode()));
+      // Just write the CHOICE element as a single element SEQUENCE.
+      writer.writeStartSequence(TYPE_WARNING_ELEMENT);
+      writer.writeInteger(warningType.getType(), warningValue);
+      writer.writeEndSequence();
     }
 
     if (errorType != null)
     {
-      elements.add(new ASN1Enumerated(TYPE_ERROR_ELEMENT,
-                                      errorType.intValue()));
+      writer.writeInteger(TYPE_ERROR_ELEMENT, errorType.intValue());
     }
+    writer.writeEndSequence();
 
-    ASN1Sequence valueSequence = new ASN1Sequence(elements);
-    return new ASN1OctetString(valueSequence.encode());
+    writer.writeEndSequence();
   }
 
 
-
-  /**
-   * Creates a new password policy response control from the contents of the
-   * provided control.
-   *
-   * @param  control  The generic control containing the information to use to
-   *                  create this password policy response control.
-   *
-   * @return  The password policy response control decoded from the provided
-   *          control.
-   *
-   * @throws  LDAPException  If this control cannot be decoded as a valid
-   *                         password policy response control.
-   */
-  public static PasswordPolicyResponseControl decodeControl(Control control)
-         throws LDAPException
-  {
-    ASN1OctetString controlValue = control.getValue();
-    if (controlValue == null)
-    {
-      // The response control must always have a value.
-      Message message = ERR_PWPOLICYRES_NO_CONTROL_VALUE.get();
-      throw new LDAPException(LDAPResultCode.PROTOCOL_ERROR, message);
-    }
-
-
-    try
-    {
-      PasswordPolicyWarningType warningType  = null;
-      PasswordPolicyErrorType   errorType    = null;
-      int                       warningValue = -1;
-
-      ASN1Sequence valueSequence =
-           ASN1Sequence.decodeAsSequence(controlValue.value());
-      for (ASN1Element e : valueSequence.elements())
-      {
-        switch (e.getType())
-        {
-          case TYPE_WARNING_ELEMENT:
-            ASN1Integer integerElement = ASN1Integer.decodeAsInteger(e.value());
-            warningValue = integerElement.intValue();
-            warningType =
-                 PasswordPolicyWarningType.valueOf(integerElement.getType());
-            if (warningType == null)
-            {
-              Message message = ERR_PWPOLICYRES_INVALID_WARNING_TYPE.get(
-                  byteToHex(integerElement.getType()));
-              throw new LDAPException(LDAPResultCode.PROTOCOL_ERROR, message);
-            }
-            break;
-
-          case TYPE_ERROR_ELEMENT:
-            int errorValue = e.decodeAsEnumerated().intValue();
-            errorType = PasswordPolicyErrorType.valueOf(errorValue);
-            if (errorType == null)
-            {
-              Message message =
-                  ERR_PWPOLICYRES_INVALID_ERROR_TYPE.get(errorValue);
-              throw new LDAPException(LDAPResultCode.PROTOCOL_ERROR, message);
-            }
-            break;
-
-          default:
-            Message message = ERR_PWPOLICYRES_INVALID_ELEMENT_TYPE.get(
-                byteToHex(e.getType()));
-            throw new LDAPException(LDAPResultCode.PROTOCOL_ERROR, message);
-        }
-      }
-
-      return new PasswordPolicyResponseControl(control.getOID(),
-                                               control.isCritical(),
-                                               warningType, warningValue,
-                                               errorType, controlValue);
-    }
-    catch (LDAPException le)
-    {
-      throw le;
-    }
-    catch (ASN1Exception ae)
-    {
-      if (debugEnabled())
-      {
-        TRACER.debugCaught(DebugLogLevel.ERROR, ae);
-      }
-
-      Message message = ERR_PWPOLICYRES_DECODE_ERROR.get(ae.getMessage());
-      throw new LDAPException(LDAPResultCode.PROTOCOL_ERROR, message);
-    }
-    catch (Exception e)
-    {
-      if (debugEnabled())
-      {
-        TRACER.debugCaught(DebugLogLevel.ERROR, e);
-      }
-
-      Message message =
-          ERR_PWPOLICYRES_DECODE_ERROR.get(getExceptionMessage(e));
-      throw new LDAPException(LDAPResultCode.PROTOCOL_ERROR, message);
-    }
-  }
-
-
-
   /**
    * Retrieves the password policy warning type contained in this control.
    *
@@ -384,25 +329,12 @@
 
 
   /**
-   * Retrieves a string representation of this password policy response control.
-   *
-   * @return  A string representation of this password policy response control.
-   */
-  public String toString()
-  {
-    StringBuilder buffer = new StringBuilder();
-    toString(buffer);
-    return buffer.toString();
-  }
-
-
-
-  /**
    * Appends a string representation of this password policy response control to
    * the provided buffer.
    *
    * @param  buffer  The buffer to which the information should be appended.
    */
+  @Override
   public void toString(StringBuilder buffer)
   {
     buffer.append("PasswordPolicyResponseControl(");
diff --git a/opends/src/server/org/opends/server/controls/PersistentSearchControl.java b/opends/src/server/org/opends/server/controls/PersistentSearchControl.java
index 984c7a9..40f2477 100644
--- a/opends/src/server/org/opends/server/controls/PersistentSearchControl.java
+++ b/opends/src/server/org/opends/server/controls/PersistentSearchControl.java
@@ -28,22 +28,16 @@
 import org.opends.messages.Message;
 
 
-
-import java.util.ArrayList;
 import java.util.Set;
+import java.io.IOException;
 
-import org.opends.server.protocols.asn1.ASN1Boolean;
-import org.opends.server.protocols.asn1.ASN1Element;
-import org.opends.server.protocols.asn1.ASN1Integer;
-import org.opends.server.protocols.asn1.ASN1OctetString;
-import org.opends.server.protocols.asn1.ASN1Sequence;
-import org.opends.server.protocols.ldap.LDAPResultCode;
-import org.opends.server.types.Control;
-import org.opends.server.types.LDAPException;
-
+import org.opends.server.protocols.asn1.*;
+import static org.opends.server.protocols.asn1.ASN1Constants.
+    UNIVERSAL_OCTET_STRING_TYPE;
 import static org.opends.server.loggers.debug.DebugLogger.*;
 import org.opends.server.loggers.debug.DebugTracer;
-import org.opends.server.types.DebugLogLevel;
+import org.opends.server.types.*;
+
 import static org.opends.messages.ProtocolMessages.*;
 import static org.opends.server.util.ServerConstants.*;
 import static org.opends.server.util.StaticUtils.*;
@@ -59,6 +53,74 @@
        extends Control
 {
   /**
+   * ControlDecoder implentation to decode this control from a ByteString.
+   */
+  private final static class Decoder
+      implements ControlDecoder<PersistentSearchControl>
+  {
+    /**
+     * {@inheritDoc}
+     */
+    public PersistentSearchControl decode(boolean isCritical, ByteString value)
+        throws DirectoryException
+    {
+      if (value == null)
+      {
+        Message message = ERR_PSEARCH_NO_CONTROL_VALUE.get();
+        throw new DirectoryException(ResultCode.PROTOCOL_ERROR, message);
+      }
+
+      ASN1Reader reader = ASN1.getReader(value);
+      boolean                         changesOnly;
+      boolean                         returnECs;
+      Set<PersistentSearchChangeType> changeTypes;
+      try
+      {
+        reader.readStartSequence();
+
+        int changeTypesValue = (int)reader.readInteger();
+        changeTypes = PersistentSearchChangeType.intToTypes(changeTypesValue);
+        changesOnly = reader.readBoolean();
+        returnECs   = reader.readBoolean();
+
+        reader.readEndSequence();
+      }
+      catch (LDAPException le)
+      {
+        throw new DirectoryException(ResultCode.valueOf(le.getResultCode()), le
+            .getMessageObject());
+      }
+      catch (Exception e)
+      {
+        if (debugEnabled())
+        {
+          TRACER.debugCaught(DebugLogLevel.ERROR, e);
+        }
+
+        Message message =
+            ERR_PSEARCH_CANNOT_DECODE_VALUE.get(getExceptionMessage(e));
+        throw new DirectoryException(ResultCode.PROTOCOL_ERROR, message, e);
+      }
+
+
+      return new PersistentSearchControl(isCritical,
+          changeTypes, changesOnly, returnECs);
+    }
+
+    public String getOID()
+    {
+      return OID_PERSISTENT_SEARCH;
+    }
+
+  }
+
+  /**
+   * The Control Decoder that can be used to decode this control.
+   */
+  public static final ControlDecoder<PersistentSearchControl> DECODER =
+    new Decoder();
+
+  /**
    * The tracer object for the debug logger.
    */
   private static final DebugTracer TRACER = getTracer();
@@ -94,13 +156,7 @@
   public PersistentSearchControl(Set<PersistentSearchChangeType> changeTypes,
                                  boolean changesOnly, boolean returnECs)
   {
-    super(OID_PERSISTENT_SEARCH, true,
-          encodeValue(changeTypes, changesOnly, returnECs));
-
-
-    this.changeTypes = changeTypes;
-    this.changesOnly = changesOnly;
-    this.returnECs   = returnECs;
+    this(true, changeTypes, changesOnly, returnECs);
   }
 
 
@@ -108,7 +164,6 @@
   /**
    * Creates a new persistent search control with the provided information.
    *
-   * @param  oid          The OID to use for the control.
    * @param  isCritical   Indicates whether the control should be considered
    *                      critical for the operation processing.
    * @param  changeTypes  The set of change types for which to provide
@@ -120,11 +175,11 @@
    *                      notification control in updated entries that match the
    *                      associated search criteria.
    */
-  public PersistentSearchControl(String oid, boolean isCritical,
+  public PersistentSearchControl(boolean isCritical,
                                  Set<PersistentSearchChangeType> changeTypes,
                                  boolean changesOnly, boolean returnECs)
   {
-    super(oid, isCritical, encodeValue(changeTypes, changesOnly, returnECs));
+    super(OID_PERSISTENT_SEARCH, isCritical);
 
 
     this.changeTypes = changeTypes;
@@ -135,130 +190,24 @@
 
 
   /**
-   * Creates a new persistent search control with the provided information.
+   * Writes this control's value to an ASN.1 writer. The value (if any) must be
+   * written as an ASN1OctetString.
    *
-   * @param  oid           The OID to use for the control.
-   * @param  isCritical    Indicates whether the control should be considered
-   *                       critical for the operation processing.
-   * @param  changeTypes   The set of change types for which to provide
-   *                       notification to the client.
-   * @param  changesOnly   Indicates whether to only return changes that match
-   *                       the associated search criteria, or to also return all
-   *                       existing entries that match the filter.
-   * @param  returnECs     Indicates whether to include the entry change
-   *                       notification control in updated entries that match
-   *                       the associated search criteria.
-   * @param  encodedValue  The pre-encoded value for the control.
+   * @param writer The ASN.1 writer to use.
+   * @throws IOException If a problem occurs while writing to the stream.
    */
-  private PersistentSearchControl(String oid, boolean isCritical,
-                                  Set<PersistentSearchChangeType> changeTypes,
-                                  boolean changesOnly, boolean returnECs,
-                                  ASN1OctetString encodedValue)
-  {
-    super(oid, isCritical, encodedValue);
+  @Override
+  protected void writeValue(ASN1Writer writer) throws IOException {
+    writer.writeStartSequence(UNIVERSAL_OCTET_STRING_TYPE);
 
+    writer.writeStartSequence();
+    writer.writeInteger(
+        PersistentSearchChangeType.changeTypesToInt(changeTypes));
+    writer.writeBoolean(changesOnly);
+    writer.writeBoolean(returnECs);
+    writer.writeEndSequence();
 
-    this.changeTypes = changeTypes;
-    this.changesOnly = changesOnly;
-    this.returnECs   = returnECs;
-  }
-
-
-
-  /**
-   * Encodes the provided information into an ASN.1 octet string suitable for
-   * use as the control value.
-   *
-   * @param  changeTypes  The set of change types for which to provide
-   *                      notification to the client.
-   * @param  changesOnly  Indicates whether to only return changes that match
-   *                      the associated search criteria, or to also return all
-   *                      existing entries that match the filter.
-   * @param  returnECs    Indicates whether to include the entry change
-   *                      notification control in updated entries that match the
-   *                      associated search criteria.
-   *
-   * @return  An ASN.1 octet string containing the encoded information.
-   */
-  private static ASN1OctetString encodeValue(Set<PersistentSearchChangeType>
-                                                  changeTypes,
-                                             boolean changesOnly,
-                                             boolean returnECs)
-  {
-    ArrayList<ASN1Element> elements =
-         new ArrayList<ASN1Element>(3);
-    elements.add(new ASN1Integer(
-         PersistentSearchChangeType.changeTypesToInt(changeTypes)));
-    elements.add(new ASN1Boolean(changesOnly));
-    elements.add(new ASN1Boolean(returnECs));
-
-
-    return new ASN1OctetString(new ASN1Sequence(elements).encode());
-  }
-
-
-
-  /**
-   * Creates a new persistent search control from the contents of the provided
-   * control.
-   *
-   * @param  control  The generic control containing the information to use to
-   *                  create this persistent search control.
-   *
-   * @return  The persistent search control decoded from the provided control.
-   *
-   * @throws  LDAPException  If this control cannot be decoded as a valid
-   *                         persistent search control.
-   */
-  public static PersistentSearchControl decodeControl(Control control)
-         throws LDAPException
-  {
-    if (! control.hasValue())
-    {
-      Message message = ERR_PSEARCH_NO_CONTROL_VALUE.get();
-      throw new LDAPException(LDAPResultCode.PROTOCOL_ERROR, message);
-    }
-
-
-    boolean                         changesOnly;
-    boolean                         returnECs;
-    Set<PersistentSearchChangeType> changeTypes;
-    try
-    {
-      ArrayList<ASN1Element> elements =
-           ASN1Sequence.decodeAsSequence(control.getValue().value()).elements();
-      if (elements.size() != 3)
-      {
-        Message message =
-            ERR_PSEARCH_INVALID_ELEMENT_COUNT.get(elements.size());
-        throw new LDAPException(LDAPResultCode.PROTOCOL_ERROR, message);
-      }
-
-      int changeTypesValue = elements.get(0).decodeAsInteger().intValue();
-      changeTypes = PersistentSearchChangeType.intToTypes(changeTypesValue);
-      changesOnly = elements.get(1).decodeAsBoolean().booleanValue();
-      returnECs   = elements.get(2).decodeAsBoolean().booleanValue();
-    }
-    catch (LDAPException le)
-    {
-      throw le;
-    }
-    catch (Exception e)
-    {
-      if (debugEnabled())
-      {
-        TRACER.debugCaught(DebugLogLevel.ERROR, e);
-      }
-
-      Message message =
-          ERR_PSEARCH_CANNOT_DECODE_VALUE.get(getExceptionMessage(e));
-      throw new LDAPException(LDAPResultCode.PROTOCOL_ERROR, message, e);
-    }
-
-
-    return new PersistentSearchControl(control.getOID(), control.isCritical(),
-                                       changeTypes, changesOnly, returnECs,
-                                       control.getValue());
+    writer.writeEndSequence();
   }
 
 
@@ -276,21 +225,6 @@
 
 
   /**
-   * Specifies the set of change types for this persistent search control.
-   *
-   * @param  changeTypes  The set of change types for this persistent search
-   *                      control.
-   */
-  public void setChangeTypes(Set<PersistentSearchChangeType> changeTypes)
-  {
-    this.changeTypes = changeTypes;
-
-    setValue(encodeValue(changeTypes, changesOnly, returnECs));
-  }
-
-
-
-  /**
    * Indicates whether to only return changes that match the associated search
    * criteria, or to also return all existing entries that match the filter.
    *
@@ -306,23 +240,6 @@
 
 
   /**
-   * Specifies whether to only return changes that match teh associated search
-   * criteria, or to also return all existing entries that match the filter.
-   *
-   * @param  changesOnly  Indicates whether to only return changes that match
-   *                      the associated search criteria, or to also return all
-   *                      existing entries that match the filter.
-   */
-  public void setChangesOnly(boolean changesOnly)
-  {
-    this.changesOnly = changesOnly;
-
-    setValue(encodeValue(changeTypes, changesOnly, returnECs));
-  }
-
-
-
-  /**
    * Indicates whether to include the entry change notification control in
    * entries returned to the client as the result of a change in the Directory
    * Server data.
@@ -338,43 +255,12 @@
 
 
   /**
-   * Specifies whether to include the entry change notification control in
-   * entries returned to the client as a result of a change in the Directory
-   * Server data.
-   *
-   * @param  returnECs  Indicates whether to include the entry change
-   *                    notification control in updated entries that match the
-   *                    associated search criteria.
-   */
-  public void setReturnECs(boolean returnECs)
-  {
-    this.returnECs = returnECs;
-
-    setValue(encodeValue(changeTypes, changesOnly, returnECs));
-  }
-
-
-
-  /**
-   * Retrieves a string representation of this persistent search control.
-   *
-   * @return  A string representation of this persistent search control.
-   */
-  public String toString()
-  {
-    StringBuilder buffer = new StringBuilder();
-    toString(buffer);
-    return buffer.toString();
-  }
-
-
-
-  /**
    * Appends a string representation of this persistent search control to the
    * provided buffer.
    *
    * @param  buffer  The buffer to which the information should be appended.
    */
+  @Override
   public void toString(StringBuilder buffer)
   {
     buffer.append("PersistentSearchControl(changeTypes=\"");
diff --git a/opends/src/server/org/opends/server/controls/ProxiedAuthV1Control.java b/opends/src/server/org/opends/server/controls/ProxiedAuthV1Control.java
index 5122226..54ab358 100644
--- a/opends/src/server/org/opends/server/controls/ProxiedAuthV1Control.java
+++ b/opends/src/server/org/opends/server/controls/ProxiedAuthV1Control.java
@@ -28,31 +28,21 @@
 import org.opends.messages.Message;
 
 
-
-import java.util.ArrayList;
 import java.util.concurrent.locks.Lock;
+import java.io.IOException;
 
 import org.opends.server.core.DirectoryServer;
 import org.opends.server.core.PasswordPolicyState;
-import org.opends.server.protocols.asn1.ASN1Element;
-import org.opends.server.protocols.asn1.ASN1OctetString;
-import org.opends.server.protocols.asn1.ASN1Sequence;
-import org.opends.server.protocols.ldap.LDAPResultCode;
-import org.opends.server.types.Control;
-import org.opends.server.types.DirectoryException;
-import org.opends.server.types.DN;
-import org.opends.server.types.Entry;
-import org.opends.server.types.LDAPException;
-import org.opends.server.types.LockManager;
-import org.opends.server.types.ResultCode;
-
+import org.opends.server.protocols.asn1.*;
+import static org.opends.server.protocols.asn1.ASN1Constants.
+    UNIVERSAL_OCTET_STRING_TYPE;
 import static org.opends.server.loggers.debug.DebugLogger.*;
 import org.opends.server.loggers.debug.DebugTracer;
-import org.opends.server.types.DebugLogLevel;
+import org.opends.server.types.*;
+
 import static org.opends.messages.ProtocolMessages.*;
 import static org.opends.server.util.ServerConstants.*;
 import static org.opends.server.util.StaticUtils.*;
-import static org.opends.server.util.Validator.*;
 
 
 
@@ -69,6 +59,66 @@
        extends Control
 {
   /**
+   * ControlDecoder implentation to decode this control from a ByteString.
+   */
+  private final static class Decoder
+      implements ControlDecoder<ProxiedAuthV1Control>
+  {
+    /**
+     * {@inheritDoc}
+     */
+    public ProxiedAuthV1Control decode(boolean isCritical, ByteString value)
+        throws DirectoryException
+    {
+      if (!isCritical)
+      {
+        Message message = ERR_PROXYAUTH1_CONTROL_NOT_CRITICAL.get();
+        throw new DirectoryException(ResultCode.PROTOCOL_ERROR, message);
+      }
+
+      if (value == null)
+      {
+        Message message = ERR_PROXYAUTH1_NO_CONTROL_VALUE.get();
+        throw new DirectoryException(ResultCode.PROTOCOL_ERROR, message);
+      }
+
+      ASN1Reader reader = ASN1.getReader(value);
+      DN authorizationDN;
+      try
+      {
+        reader.readStartSequence();
+        authorizationDN = DN.decode(reader.readOctetString());
+        reader.readEndSequence();
+      }
+      catch (Exception e)
+      {
+        if (debugEnabled())
+        {
+          TRACER.debugCaught(DebugLogLevel.ERROR, e);
+        }
+
+        Message message =
+            ERR_PROXYAUTH1_CANNOT_DECODE_VALUE.get(getExceptionMessage(e));
+        throw new DirectoryException(ResultCode.PROTOCOL_ERROR, message, e);
+      }
+
+      return new ProxiedAuthV1Control(isCritical, authorizationDN);
+    }
+
+    public String getOID()
+    {
+      return OID_PROXIED_AUTH_V1;
+    }
+
+  }
+
+  /**
+   * The Control Decoder that can be used to decode this control.
+   */
+  public static final ControlDecoder<ProxiedAuthV1Control> DECODER =
+    new Decoder();
+
+  /**
    * The tracer object for the debug logger.
    */
   private static final DebugTracer TRACER = getTracer();
@@ -77,7 +127,7 @@
 
 
   // The raw, unprocessed authorization DN from the control value.
-  private ASN1OctetString rawAuthorizationDN;
+  private ByteString rawAuthorizationDN;
 
   // The processed authorization DN from the control value.
   private DN authorizationDN;
@@ -91,14 +141,9 @@
    * @param  rawAuthorizationDN  The raw, unprocessed authorization DN from the
    *                             control value.  It must not be {@code null}.
    */
-  public ProxiedAuthV1Control(ASN1OctetString rawAuthorizationDN)
+  public ProxiedAuthV1Control(ByteString rawAuthorizationDN)
   {
-    super(OID_PROXIED_AUTH_V1, true, encodeValue(rawAuthorizationDN));
-
-
-    this.rawAuthorizationDN = rawAuthorizationDN;
-
-    authorizationDN = null;
+    this(true, rawAuthorizationDN);
   }
 
 
@@ -112,13 +157,7 @@
    */
   public ProxiedAuthV1Control(DN authorizationDN)
   {
-    super(OID_PROXIED_AUTH_V1, true,
-          encodeValue(new ASN1OctetString(authorizationDN.toString())));
-
-
-    this.authorizationDN = authorizationDN;
-
-    rawAuthorizationDN = new ASN1OctetString(authorizationDN.toString());
+    this(true, authorizationDN);
   }
 
 
@@ -127,19 +166,15 @@
    * Creates a new instance of the proxied authorization v1 control with the
    * provided information.
    *
-   * @param  oid                 The OID to use for this control.
    * @param  isCritical          Indicates whether support for this control
    *                             should be considered a critical part of the
    *                             server processing.
-   * @param  controlValue        The encoded value for this control.
    * @param  rawAuthorizationDN  The raw, unprocessed authorization DN from the
    *                             control value.
    */
-  private ProxiedAuthV1Control(String oid, boolean isCritical,
-                             ASN1OctetString controlValue,
-                             ASN1OctetString rawAuthorizationDN)
+  public ProxiedAuthV1Control(boolean isCritical, ByteString rawAuthorizationDN)
   {
-    super(oid, isCritical, controlValue);
+    super(OID_PROXIED_AUTH_V1, isCritical);
 
 
     this.rawAuthorizationDN = rawAuthorizationDN;
@@ -150,91 +185,43 @@
 
 
   /**
-   * Generates an encoded value for this control containing the provided raw
-   * authorization DN.
+   * Creates a new instance of the proxied authorization v1 control with the
+   * provided information.
    *
-   * @param  rawAuthorizationDN  The raw, unprocessed authorization DN to use in
-   *                             the control value.  It must not be
-   *                             {@code null}.
-   *
-   * @return  The encoded control value.
+   * @param  isCritical          Indicates whether support for this control
+   *                             should be considered a critical part of the
+   *                             server processing.
+   * @param  authorizationDN     The authorization DN from the control value.
+   *                             It must not be {@code null}.
    */
-  private static ASN1OctetString encodeValue(ASN1OctetString rawAuthorizationDN)
+  public ProxiedAuthV1Control(boolean isCritical, DN authorizationDN)
   {
-    ensureNotNull(rawAuthorizationDN);
+    super(OID_PROXIED_AUTH_V1, isCritical);
 
-    ArrayList<ASN1Element> elements = new ArrayList<ASN1Element>(1);
-    elements.add(rawAuthorizationDN);
 
-    return new ASN1OctetString(new ASN1Sequence(elements).encode());
+    this.authorizationDN = authorizationDN;
+
+    rawAuthorizationDN = ByteString.valueOf(authorizationDN.toString());
   }
 
 
 
   /**
-   * Creates a new proxied authorization v1 control from the contents of the
-   * provided control.
+   * Writes this control's value to an ASN.1 writer. The value (if any) must be
+   * written as an ASN1OctetString.
    *
-   * @param  control  The generic control containing the information to use to
-   *                  create this proxied authorization v1 control.  It must not
-   *                  be {@code null}.
-   *
-   * @return  The proxied authorization v1 control decoded from the provided
-   *          control.
-   *
-   * @throws  LDAPException  If this control cannot be decoded as a valid
-   *                         proxied authorization v1 control.
+   * @param writer The ASN.1 writer to use.
+   * @throws IOException If a problem occurs while writing to the stream.
    */
-  public static ProxiedAuthV1Control decodeControl(Control control)
-         throws LDAPException
-  {
-    ensureNotNull(control);
+  @Override
+  protected void writeValue(ASN1Writer writer) throws IOException {
+    writer.writeStartSequence(UNIVERSAL_OCTET_STRING_TYPE);
 
-    if (! control.isCritical())
-    {
-      Message message = ERR_PROXYAUTH1_CONTROL_NOT_CRITICAL.get();
-      throw new LDAPException(LDAPResultCode.PROTOCOL_ERROR, message);
-    }
+    writer.writeStartSequence();
+    writer.writeOctetString(rawAuthorizationDN);
+    writer.writeEndSequence();
 
-    if (! control.hasValue())
-    {
-      Message message = ERR_PROXYAUTH1_NO_CONTROL_VALUE.get();
-      throw new LDAPException(LDAPResultCode.PROTOCOL_ERROR, message);
-    }
-
-
-    ASN1OctetString rawAuthorizationDN;
-    try
-    {
-      ArrayList<ASN1Element> elements =
-           ASN1Sequence.decodeAsSequence(control.getValue().value()).elements();
-      if (elements.size() != 1)
-      {
-        Message message =
-            ERR_PROXYAUTH1_INVALID_ELEMENT_COUNT.get(elements.size());
-        throw new LDAPException(LDAPResultCode.PROTOCOL_ERROR, message);
-      }
-
-      rawAuthorizationDN = elements.get(0).decodeAsOctetString();
-    }
-    catch (LDAPException le)
-    {
-      throw le;
-    }
-    catch (Exception e)
-    {
-      if (debugEnabled())
-      {
-        TRACER.debugCaught(DebugLogLevel.ERROR, e);
-      }
-
-      Message message =
-          ERR_PROXYAUTH1_CANNOT_DECODE_VALUE.get(getExceptionMessage(e));
-      throw new LDAPException(LDAPResultCode.PROTOCOL_ERROR, message, e);
-    }
-
-    return new ProxiedAuthV1Control(control.getOID(), control.isCritical(),
-                                    control.getValue(), rawAuthorizationDN);
+    writer.writeEndSequence();
   }
 
 
@@ -244,7 +231,7 @@
    *
    * @return  The raw, unprocessed authorization DN from the control value.
    */
-  public ASN1OctetString getRawAuthorizationDN()
+  public ByteString getRawAuthorizationDN()
   {
     return rawAuthorizationDN;
   }
@@ -252,23 +239,6 @@
 
 
   /**
-   * Specifies the raw, unprocessed authorization DN for this proxied auth
-   * control.
-   *
-   * @param  rawAuthorizationDN  The raw, unprocessed authorization DN for this
-   *                             proxied auth control.
-   */
-  public void setRawAuthorizationDN(ASN1OctetString rawAuthorizationDN)
-  {
-    this.rawAuthorizationDN = rawAuthorizationDN;
-
-    setValue(encodeValue(rawAuthorizationDN));
-    authorizationDN = null;
-  }
-
-
-
-  /**
    * Retrieves the authorization DN from the control value.
    *
    * @return  The authorization DN from the control value.
@@ -290,24 +260,6 @@
 
 
   /**
-   * Specifies the authorization DN for this proxied auth control.
-   *
-   * @param  authorizationDN  The authorizationDN for this proxied auth control.
-   *                          It must not be {@code null}.
-   */
-  public void setAuthorizationDN(DN authorizationDN)
-  {
-    ensureNotNull(authorizationDN);
-
-    this.authorizationDN = authorizationDN;
-
-    rawAuthorizationDN = new ASN1OctetString(authorizationDN.toString());
-    setValue(encodeValue(rawAuthorizationDN));
-  }
-
-
-
-  /**
    * Retrieves the authorization entry for this proxied authorization V1
    * control.  It will also perform any necessary password policy checks to
    * ensure that the associated user account is suitable for use in performing
@@ -396,29 +348,16 @@
 
 
   /**
-   * Retrieves a string representation of this proxied auth v1 control.
-   *
-   * @return  A string representation of this proxied auth v1 control.
-   */
-  public String toString()
-  {
-    StringBuilder buffer = new StringBuilder();
-    toString(buffer);
-    return buffer.toString();
-  }
-
-
-
-  /**
    * Appends a string representation of this proxied auth v1 control to the
    * provided buffer.
    *
    * @param  buffer  The buffer to which the information should be appended.
    */
+  @Override
   public void toString(StringBuilder buffer)
   {
     buffer.append("ProxiedAuthorizationV1Control(authorizationDN=\"");
-    rawAuthorizationDN.toString(buffer);
+    buffer.append(rawAuthorizationDN);
     buffer.append("\")");
   }
 }
diff --git a/opends/src/server/org/opends/server/controls/ProxiedAuthV2Control.java b/opends/src/server/org/opends/server/controls/ProxiedAuthV2Control.java
index 197f6bf..d5f576d 100644
--- a/opends/src/server/org/opends/server/controls/ProxiedAuthV2Control.java
+++ b/opends/src/server/org/opends/server/controls/ProxiedAuthV2Control.java
@@ -30,29 +30,20 @@
 
 
 import java.util.concurrent.locks.Lock;
+import java.io.IOException;
 
 import org.opends.server.api.IdentityMapper;
 import org.opends.server.core.DirectoryServer;
 import org.opends.server.core.PasswordPolicyState;
-import org.opends.server.protocols.asn1.ASN1Exception;
-import org.opends.server.protocols.asn1.ASN1OctetString;
-import org.opends.server.protocols.ldap.LDAPResultCode;
-import org.opends.server.types.Control;
-import org.opends.server.types.DirectoryException;
-import org.opends.server.types.DN;
-import org.opends.server.types.Entry;
-import org.opends.server.types.LDAPException;
-import org.opends.server.types.LockManager;
-import org.opends.server.types.ResultCode;
-
+import org.opends.server.protocols.asn1.*;
 import static org.opends.server.loggers.debug.DebugLogger.*;
 import org.opends.server.loggers.debug.DebugTracer;
-import org.opends.server.types.DebugLogLevel;
+import org.opends.server.types.*;
+
 import static org.opends.messages.ProtocolMessages.*;
 import static org.opends.server.util.ServerConstants.*;
 import static org.opends.server.util.StaticUtils.*;
-import static org.opends.server.util.Validator.*;
-
+import static org.opends.server.util.Validator.ensureNotNull;
 
 
 /**
@@ -67,6 +58,74 @@
        extends Control
 {
   /**
+   * ControlDecoder implentation to decode this control from a ByteString.
+   */
+  private static final class Decoder
+      implements ControlDecoder<ProxiedAuthV2Control>
+  {
+    /**
+     * {@inheritDoc}
+     */
+    public ProxiedAuthV2Control decode(boolean isCritical, ByteString value)
+        throws DirectoryException
+    {
+      if (!isCritical)
+      {
+        Message message = ERR_PROXYAUTH2_CONTROL_NOT_CRITICAL.get();
+        throw new DirectoryException(ResultCode.PROTOCOL_ERROR, message);
+      }
+
+      if (value == null)
+      {
+        Message message = ERR_PROXYAUTH2_NO_CONTROL_VALUE.get();
+        throw new DirectoryException(ResultCode.PROTOCOL_ERROR, message);
+      }
+
+      ASN1Reader reader = ASN1.getReader(value);
+      ByteString authorizationID;
+      try
+      {
+        // Try the legacy encoding where the value is wrapped by an
+        // extra octet string
+        authorizationID = reader.readOctetString();
+      }
+      catch (Exception e)
+      {
+        // Try just getting the value.
+        authorizationID = value;
+        String lowerAuthZIDStr = toLowerCase(authorizationID.toString());
+        if (!lowerAuthZIDStr.startsWith("dn:") &&
+            !lowerAuthZIDStr.startsWith("u:"))
+        {
+          if (debugEnabled())
+          {
+            TRACER.debugCaught(DebugLogLevel.ERROR, e);
+          }
+
+          Message message =
+              ERR_PROXYAUTH2_CANNOT_DECODE_VALUE.get(getExceptionMessage(e));
+          throw new DirectoryException(ResultCode.PROTOCOL_ERROR, message,
+              e);
+        }
+      }
+
+      return new ProxiedAuthV2Control(isCritical, authorizationID);
+    }
+
+    public String getOID()
+    {
+      return OID_PROXIED_AUTH_V2;
+    }
+
+  }
+
+  /**
+   * The Control Decoder that can be used to decode this control.
+   */
+  public static final ControlDecoder<ProxiedAuthV2Control> DECODER =
+    new Decoder();
+
+  /**
    * The tracer object for the debug logger.
    */
   private static final DebugTracer TRACER = getTracer();
@@ -75,7 +134,7 @@
 
 
   // The authorization ID from the control value.
-  private ASN1OctetString authorizationID;
+  private ByteString authorizationID;
 
 
 
@@ -85,13 +144,9 @@
    *
    * @param  authorizationID  The authorization ID from the control value.
    */
-  public ProxiedAuthV2Control(ASN1OctetString authorizationID)
+  public ProxiedAuthV2Control(ByteString authorizationID)
   {
-    super(OID_PROXIED_AUTH_V2, true, authorizationID);
-
-
-    ensureNotNull(authorizationID);
-    this.authorizationID = authorizationID;
+    this(true, authorizationID);
   }
 
 
@@ -100,17 +155,16 @@
    * Creates a new instance of the proxied authorization v2 control with the
    * provided information.
    *
-   * @param  oid              The OID to use for this control.
    * @param  isCritical       Indicates whether support for this control
    *                          should be considered a critical part of the
    *                          server processing.
    * @param  authorizationID  The authorization ID from the control value.
    */
-  private ProxiedAuthV2Control(String oid, boolean isCritical,
-                             ASN1OctetString authorizationID)
+  public ProxiedAuthV2Control(boolean isCritical, ByteString authorizationID)
   {
-    super(oid, isCritical, authorizationID);
+    super(OID_PROXIED_AUTH_V2, isCritical);
 
+    ensureNotNull(authorizationID);
 
     this.authorizationID = authorizationID;
   }
@@ -118,76 +172,15 @@
 
 
   /**
-   * Creates a new proxied authorization v2 control from the contents of the
-   * provided control.
+   * Writes this control's value to an ASN.1 writer. The value (if any) must be
+   * written as an ASN1OctetString.
    *
-   * @param  control  The generic control containing the information to use to
-   *                  create this proxied authorization v2 control.  It must not
-   *                  be {@code null}.
-   *
-   * @return  The proxied authorization v2 control decoded from the provided
-   *          control.
-   *
-   * @throws  LDAPException  If this control cannot be decoded as a valid
-   *                         proxied authorization v2 control.
+   * @param writer The ASN.1 writer to use.
+   * @throws IOException If a problem occurs while writing to the stream.
    */
-  public static ProxiedAuthV2Control decodeControl(Control control)
-         throws LDAPException
-  {
-    ensureNotNull(control);
-
-    if (! control.isCritical())
-    {
-      Message message = ERR_PROXYAUTH2_CONTROL_NOT_CRITICAL.get();
-      throw new LDAPException(LDAPResultCode.PROTOCOL_ERROR, message);
-    }
-
-    if (! control.hasValue())
-    {
-      Message message = ERR_PROXYAUTH2_NO_CONTROL_VALUE.get();
-      throw new LDAPException(LDAPResultCode.PROTOCOL_ERROR, message);
-    }
-
-    ASN1OctetString authorizationID;
-    try
-    {
-      authorizationID =
-           ASN1OctetString.decodeAsOctetString(control.getValue().value());
-    }
-    catch (ASN1Exception ae)
-    {
-      String lowerAuthZIDStr = toLowerCase(control.getValue().stringValue());
-      if (lowerAuthZIDStr.startsWith("dn:") || lowerAuthZIDStr.startsWith("u:"))
-      {
-        authorizationID = control.getValue();
-      }
-      else
-      {
-        if (debugEnabled())
-        {
-          TRACER.debugCaught(DebugLogLevel.ERROR, ae);
-        }
-
-        Message message =
-            ERR_PROXYAUTH2_CANNOT_DECODE_VALUE.get(getExceptionMessage(ae));
-        throw new LDAPException(LDAPResultCode.PROTOCOL_ERROR, message,
-                                ae);
-      }
-    }
-    catch (Exception e)
-    {
-      if (debugEnabled())
-      {
-        TRACER.debugCaught(DebugLogLevel.ERROR, e);
-      }
-
-      Message message =
-          ERR_PROXYAUTH2_CANNOT_DECODE_VALUE.get(getExceptionMessage(e));
-      throw new LDAPException(LDAPResultCode.PROTOCOL_ERROR, message, e);
-    }
-
-    return new ProxiedAuthV2Control(control.getOID(), control.isCritical(),
-                                    authorizationID);
+  @Override
+  protected void writeValue(ASN1Writer writer) throws IOException {
+    writer.writeOctetString(authorizationID);
   }
 
 
@@ -197,7 +190,7 @@
    *
    * @return  The authorization ID for this proxied authorization V2 control.
    */
-  public ASN1OctetString getAuthorizationID()
+  public ByteString getAuthorizationID()
   {
     return authorizationID;
   }
@@ -205,28 +198,6 @@
 
 
   /**
-   * Specifies the authorization ID for this proxied authorization V2 control.
-   *
-   * @param  authorizationID  The authorization ID for this proxied
-   *                          authorization V2 control.
-   */
-  public void setAuthorizationID(ASN1OctetString authorizationID)
-  {
-    if (authorizationID == null)
-    {
-      this.authorizationID = new ASN1OctetString();
-      setValue(this.authorizationID);
-    }
-    else
-    {
-      this.authorizationID = authorizationID;
-      setValue(authorizationID);
-    }
-  }
-
-
-
-  /**
    * Retrieves the authorization entry for this proxied authorization V2
    * control.  It will also perform any necessary password policy checks to
    * ensure that the associated user account is suitable for use in performing
@@ -244,7 +215,7 @@
          throws DirectoryException
   {
     // Check for a zero-length value, which would be for an anonymous user.
-    if (authorizationID.value().length == 0)
+    if (authorizationID.length() == 0)
     {
       return null;
     }
@@ -252,13 +223,12 @@
 
     // Get a lowercase string representation.  It must start with either "dn:"
     // or "u:".
-    String authzID = authorizationID.stringValue();
-    String lowerAuthzID = toLowerCase(authzID);
+    String lowerAuthzID = toLowerCase(authorizationID.toString());
     if (lowerAuthzID.startsWith("dn:"))
     {
       // It's a DN, so decode it and see if it exists.  If it's the null DN,
       // then just assume that it does.
-      DN authzDN = DN.decode(authzID.substring(3));
+      DN authzDN = DN.decode(lowerAuthzID.substring(3));
       if (authzDN.isNullDN())
       {
         return null;
@@ -297,7 +267,7 @@
           if (userEntry == null)
           {
             // The requested user does not exist.
-            Message message = ERR_PROXYAUTH2_NO_SUCH_USER.get(authzID);
+            Message message = ERR_PROXYAUTH2_NO_SUCH_USER.get(lowerAuthzID);
             throw new DirectoryException(ResultCode.AUTHORIZATION_DENIED,
                                          message);
           }
@@ -339,7 +309,7 @@
 
       // Use the proxied authorization identity mapper to resolve the username
       // to an entry.
-      IdentityMapper proxyMapper =
+      IdentityMapper<?> proxyMapper =
            DirectoryServer.getProxiedAuthorizationIdentityMapper();
       if (proxyMapper == null)
       {
@@ -347,10 +317,10 @@
         throw new DirectoryException(ResultCode.AUTHORIZATION_DENIED, message);
       }
 
-      Entry userEntry = proxyMapper.getEntryForID(authzID.substring(2));
+      Entry userEntry = proxyMapper.getEntryForID(lowerAuthzID.substring(2));
       if (userEntry == null)
       {
-        Message message = ERR_PROXYAUTH2_NO_SUCH_USER.get(authzID);
+        Message message = ERR_PROXYAUTH2_NO_SUCH_USER.get(lowerAuthzID);
         throw new DirectoryException(ResultCode.AUTHORIZATION_DENIED, message);
       }
       else
@@ -376,7 +346,7 @@
     }
     else
     {
-      Message message = ERR_PROXYAUTH2_INVALID_AUTHZID.get(authzID);
+      Message message = ERR_PROXYAUTH2_INVALID_AUTHZID.get(lowerAuthzID);
       throw new DirectoryException(ResultCode.PROTOCOL_ERROR, message);
     }
   }
@@ -384,29 +354,16 @@
 
 
   /**
-   * Retrieves a string representation of this proxied auth v2 control.
-   *
-   * @return  A string representation of this proxied auth v2 control.
-   */
-  public String toString()
-  {
-    StringBuilder buffer = new StringBuilder();
-    toString(buffer);
-    return buffer.toString();
-  }
-
-
-
-  /**
    * Appends a string representation of this proxied auth v2 control to the
    * provided buffer.
    *
    * @param  buffer  The buffer to which the information should be appended.
    */
+  @Override
   public void toString(StringBuilder buffer)
   {
     buffer.append("ProxiedAuthorizationV2Control(authzID=\"");
-    authorizationID.toString(buffer);
+    buffer.append(authorizationID);
     buffer.append("\")");
   }
 }
diff --git a/opends/src/server/org/opends/server/controls/ServerSideSortRequestControl.java b/opends/src/server/org/opends/server/controls/ServerSideSortRequestControl.java
index 068a14a..2c71b03 100644
--- a/opends/src/server/org/opends/server/controls/ServerSideSortRequestControl.java
+++ b/opends/src/server/org/opends/server/controls/ServerSideSortRequestControl.java
@@ -31,19 +31,15 @@
 
 import java.util.ArrayList;
 import java.util.StringTokenizer;
+import java.io.IOException;
 
 import org.opends.server.api.OrderingMatchingRule;
 import org.opends.server.core.DirectoryServer;
-import org.opends.server.protocols.asn1.ASN1Boolean;
-import org.opends.server.protocols.asn1.ASN1Element;
-import org.opends.server.protocols.asn1.ASN1OctetString;
-import org.opends.server.protocols.asn1.ASN1Sequence;
+import org.opends.server.protocols.asn1.*;
+import static org.opends.server.protocols.asn1.ASN1Constants.
+    UNIVERSAL_OCTET_STRING_TYPE;
 import org.opends.server.protocols.ldap.LDAPResultCode;
-import org.opends.server.types.AttributeType;
-import org.opends.server.types.Control;
-import org.opends.server.types.LDAPException;
-import org.opends.server.types.SortKey;
-import org.opends.server.types.SortOrder;
+import org.opends.server.types.*;
 
 import static org.opends.messages.ProtocolMessages.*;
 import static org.opends.server.util.ServerConstants.*;
@@ -53,7 +49,10 @@
 
 /**
  * This class implements the server-side sort request control as defined in RFC
- * 2891 section 1.1.  The ASN.1 description for the control value is:
+ * 2891 section 1.1. The subclass ServerSideSortRequestControl.ClientRequest
+ * should be used when encoding this control from a sort order string. This is
+ * suitable for client tools that want to encode this control without a
+ * SortOrder object. The ASN.1 description for the control value is:
  * <BR><BR>
  * <PRE>
  * SortKeyList ::= SEQUENCE OF SEQUENCE {
@@ -63,7 +62,7 @@
  * </PRE>
  */
 public class ServerSideSortRequestControl
-       extends Control
+    extends Control
 {
   /**
    * The BER type to use when encoding the orderingRule element.
@@ -78,140 +77,165 @@
   private static final byte TYPE_REVERSE_ORDER = (byte) 0x81;
 
 
+  /**
+   * ControlDecoder implentation to decode this control from a ByteString.
+   */
+  private final static class Decoder
+      implements ControlDecoder<ServerSideSortRequestControl>
+  {
+    /**
+     * {@inheritDoc}
+     */
+    public ServerSideSortRequestControl decode(boolean isCritical,
+                                               ByteString value)
+        throws DirectoryException
+    {
+      if (value == null)
+      {
+        Message message = INFO_SORTREQ_CONTROL_NO_VALUE.get();
+        throw new DirectoryException(ResultCode.PROTOCOL_ERROR, message);
+      }
+
+      ASN1Reader reader = ASN1.getReader(value);
+      try
+      {
+        reader.readStartSequence();
+        if (!reader.hasNextElement())
+        {
+          Message message = INFO_SORTREQ_CONTROL_NO_SORT_KEYS.get();
+          throw new DirectoryException(ResultCode.PROTOCOL_ERROR, message);
+        }
+
+        ArrayList<SortKey> sortKeys = new ArrayList<SortKey>();
+        while(reader.hasNextElement())
+        {
+          reader.readStartSequence();
+          String attrName = toLowerCase(reader.readOctetStringAsString());
+          AttributeType attrType =
+              DirectoryServer.getAttributeType(attrName, false);
+          if (attrType == null)
+          {
+            Message message = INFO_SORTREQ_CONTROL_UNDEFINED_ATTR.get(attrName);
+            throw new DirectoryException(ResultCode.PROTOCOL_ERROR, message);
+          }
+
+          OrderingMatchingRule orderingRule = null;
+          boolean ascending = true;
+
+          while(reader.hasNextElement())
+          {
+            switch (reader.peekType())
+            {
+              case TYPE_ORDERING_RULE_ID:
+                String orderingRuleID =
+                               toLowerCase(reader.readOctetStringAsString());
+                orderingRule =
+                    DirectoryServer.getOrderingMatchingRule(orderingRuleID);
+                if (orderingRule == null)
+                {
+                  Message message =
+                      INFO_SORTREQ_CONTROL_UNDEFINED_ORDERING_RULE.
+                          get(orderingRuleID);
+                  throw new DirectoryException(ResultCode.PROTOCOL_ERROR,
+                      message);
+                }
+                break;
+
+              case TYPE_REVERSE_ORDER:
+                ascending = ! reader.readBoolean();
+                break;
+
+              default:
+                Message message = INFO_SORTREQ_CONTROL_INVALID_SEQ_ELEMENT_TYPE.
+                    get(byteToHex(reader.peekType()));
+                throw new DirectoryException(ResultCode.PROTOCOL_ERROR,
+                    message);
+            }
+          }
+
+          if ((orderingRule == null) &&
+              (attrType.getOrderingMatchingRule() == null))
+          {
+            Message message =
+                INFO_SORTREQ_CONTROL_NO_ORDERING_RULE_FOR_ATTR.get(attrName);
+            throw new DirectoryException(ResultCode.CONSTRAINT_VIOLATION,
+                message);
+          }
+
+          sortKeys.add(new SortKey(attrType, ascending, orderingRule));
+        }
+
+        return new ServerSideSortRequestControl(isCritical,
+            new SortOrder(sortKeys.toArray(new SortKey[0])));
+      }
+      catch (DirectoryException de)
+      {
+        throw de;
+      }
+      catch (Exception e)
+      {
+        Message message =
+            INFO_SORTREQ_CONTROL_CANNOT_DECODE_VALUE.get(
+                getExceptionMessage(e));
+        throw new DirectoryException(ResultCode.PROTOCOL_ERROR, message, e);
+      }
+    }
+
+    public String getOID()
+    {
+      return OID_SERVER_SIDE_SORT_REQUEST_CONTROL;
+    }
+
+  }
+
+  /**
+   * The Control Decoder that can be used to decode this control.
+   */
+  public static final ControlDecoder<ServerSideSortRequestControl> DECODER =
+      new Decoder();
+
+  // The sort order associated with this control represented by strings.
+  private ArrayList<String[]> decodedKeyList;
 
   // The sort order associated with this control.
   private SortOrder sortOrder;
 
-
-
   /**
-   * Creates a new server-side sort request control based on the provided sort
-   * order.
+   * Creates a new server-side sort request control based on the definition in
+   * the provided sort order string.
    *
-   * @param  sortOrder  The sort order to use for this control.
+   * @param  sortOrderString  The string representation of the sort order to
+   *                          use for the control.
+   * @throws LDAPException If the provided sort order string could not be
+   *                       decoded.
    */
-  public ServerSideSortRequestControl(SortOrder sortOrder)
+  public ServerSideSortRequestControl(String sortOrderString)
+      throws LDAPException
   {
-    super(OID_SERVER_SIDE_SORT_REQUEST_CONTROL, false,
-          encodeControlValue(sortOrder));
-
-    this.sortOrder = sortOrder;
+    this(false, sortOrderString);
   }
 
-
-
   /**
    * Creates a new server-side sort request control based on the definition in
-   * the provided sort order string.  This is only intended for client-side use,
-   * and controls created with this constructor should not attempt to use the
-   * generated sort order for any purpose.
+   * the provided sort order string.
    *
-   * @param  sortOrderString  The string representation of the sort order to use
-   *                          for the control.
-   *
-   * @throws  LDAPException  If the provided sort order string could not be
-   *                         decoded.
+   * @param  isCritical    Indicates whether support for this control
+   *                       should be considered a critical part of the
+   *                       server processing.
+   * @param  sortOrderString  The string representation of the sort order to
+   *                          use for the control.
+   * @throws LDAPException If the provided sort order string could not be
+   *                       decoded.
    */
-  public ServerSideSortRequestControl(String sortOrderString)
-         throws LDAPException
+  public ServerSideSortRequestControl(boolean isCritical,
+                                      String sortOrderString)
+      throws LDAPException
   {
-    super(OID_SERVER_SIDE_SORT_REQUEST_CONTROL, false,
-          encodeControlValue(sortOrderString));
+    super(OID_SERVER_SIDE_SORT_REQUEST_CONTROL, isCritical);
 
-    this.sortOrder = null;
-  }
-
-
-
-  /**
-   * Creates a new server-side sort request control with the provided
-   * information.
-   *
-   * @param  oid           The OID to use for this control.
-   * @param  isCritical    Indicates whether support for this control should be
-   *                       considered a critical part of the server processing.
-   * @param  controlValue  The encoded value for this control.
-   * @param  sortOrder     sort order associated with this server-side sort
-   *                       control.
-   */
-  private ServerSideSortRequestControl(String oid, boolean isCritical,
-                                       ASN1OctetString controlValue,
-                                       SortOrder sortOrder)
-  {
-    super(oid, isCritical, controlValue);
-
-    this.sortOrder = sortOrder;
-  }
-
-
-
-  /**
-   * Retrieves the sort order for this server-side sort request control.
-   *
-   * @return  The sort order for this server-side sort request control.
-   */
-  public SortOrder getSortOrder()
-  {
-    return sortOrder;
-  }
-
-
-
-  /**
-   * Encodes the provided sort order object in a manner suitable for use as the
-   * value of this control.
-   *
-   * @param  sortOrder  The sort order to be encoded.
-   *
-   * @return  The ASN.1 octet string containing the encoded sort order.
-   */
-  private static ASN1OctetString encodeControlValue(SortOrder sortOrder)
-  {
-    SortKey[] sortKeys = sortOrder.getSortKeys();
-    ArrayList<ASN1Element> keyList =
-         new ArrayList<ASN1Element>(sortKeys.length);
-    for (SortKey sortKey : sortKeys)
-    {
-      ArrayList<ASN1Element> elementList = new ArrayList<ASN1Element>(3);
-      elementList.add(new ASN1OctetString(
-                               sortKey.getAttributeType().getNameOrOID()));
-
-      if (sortKey.getOrderingRule() != null)
-      {
-        elementList.add(new ASN1OctetString(TYPE_ORDERING_RULE_ID,
-                                 sortKey.getOrderingRule().getNameOrOID()));
-      }
-
-      if (! sortKey.ascending())
-      {
-        elementList.add(new ASN1Boolean(TYPE_REVERSE_ORDER, true));
-      }
-
-      keyList.add(new ASN1Sequence(elementList));
-    }
-
-    return new ASN1OctetString(new ASN1Sequence(keyList).encode());
-  }
-
-
-
-  /**
-   * Encodes the provided sort order string in a manner suitable for use as the
-   * value of this control.
-   *
-   * @param  sortOrderString  The sort order string to be encoded.
-   *
-   * @return  The ASN.1 octet string containing the encoded sort order.
-   *
-   * @throws  LDAPException  If the provided sort order string cannot be decoded
-   *                         to create the control value.
-   */
-  private static ASN1OctetString encodeControlValue(String sortOrderString)
-          throws LDAPException
-  {
     StringTokenizer tokenizer = new StringTokenizer(sortOrderString, ",");
 
-    ArrayList<ASN1Element> keyList = new ArrayList<ASN1Element>();
+    decodedKeyList = new ArrayList<String[]>();
     while (tokenizer.hasMoreTokens())
     {
       String token = tokenizer.nextToken().trim();
@@ -238,16 +262,11 @@
 
         if (reverseOrder)
         {
-          ArrayList<ASN1Element> elementList = new ArrayList<ASN1Element>(2);
-          elementList.add(new ASN1OctetString(token));
-          elementList.add(new ASN1Boolean(TYPE_REVERSE_ORDER, reverseOrder));
-          keyList.add(new ASN1Sequence(elementList));
+          decodedKeyList.add(new String[]{token, null, "r"});
         }
         else
         {
-          ArrayList<ASN1Element> elementList = new ArrayList<ASN1Element>(1);
-          elementList.add(new ASN1OctetString(token));
-          keyList.add(new ASN1Sequence(elementList));
+          decodedKeyList.add(new String[]{token, null, null});
         }
       }
       else if (colonPos == 0)
@@ -269,160 +288,91 @@
 
         if (reverseOrder)
         {
-          ArrayList<ASN1Element> elementList = new ArrayList<ASN1Element>(3);
-          elementList.add(new ASN1OctetString(attrName));
-          elementList.add(new ASN1OctetString(TYPE_ORDERING_RULE_ID, ruleID));
-          elementList.add(new ASN1Boolean(TYPE_REVERSE_ORDER, reverseOrder));
-          keyList.add(new ASN1Sequence(elementList));
+          decodedKeyList.add(new String[]{attrName, ruleID, "r"});
         }
         else
         {
-          ArrayList<ASN1Element> elementList = new ArrayList<ASN1Element>(2);
-          elementList.add(new ASN1OctetString(attrName));
-          elementList.add(new ASN1OctetString(TYPE_ORDERING_RULE_ID, ruleID));
-          keyList.add(new ASN1Sequence(elementList));
+          decodedKeyList.add(new String[]{attrName, ruleID, null});
         }
       }
     }
 
-    if (keyList.isEmpty())
+    if (decodedKeyList.isEmpty())
     {
       Message message = INFO_SORTREQ_CONTROL_NO_SORT_KEYS.get();
       throw new LDAPException(LDAPResultCode.PROTOCOL_ERROR, message);
     }
-
-    return new ASN1OctetString(new ASN1Sequence(keyList).encode());
   }
 
 
-
   /**
-   * Creates a new server-side sort request control from the contents of the
-   * provided control.
+   * Creates a new server-side sort request control based on the provided sort
+   * order.
    *
-   * @param  control  The generic control containing the information to use to
-   *                  create this server-side sort request control.  It must not
-   *                  be {@code null}.
-   *
-   * @return  The server-side sort request control decoded from the provided
-   *          control.
-   *
-   * @throws  LDAPException  If this control cannot be decoded as a valid
-   *                         server-side sort request control.
+   * @param  sortOrder  The sort order to use for this control.
    */
-  public static ServerSideSortRequestControl decodeControl(Control control)
-         throws LDAPException
+  public ServerSideSortRequestControl(SortOrder sortOrder)
   {
-    ASN1OctetString controlValue = control.getValue();
-    if (controlValue == null)
-    {
-      Message message = INFO_SORTREQ_CONTROL_NO_VALUE.get();
-      throw new LDAPException(LDAPResultCode.PROTOCOL_ERROR, message);
-    }
-
-    try
-    {
-      ASN1Sequence orderSequence =
-           ASN1Sequence.decodeAsSequence(controlValue.value());
-      ArrayList<ASN1Element> orderElements = orderSequence.elements();
-      SortKey[] sortKeys = new SortKey[orderElements.size()];
-      if (sortKeys.length == 0)
-      {
-        Message message = INFO_SORTREQ_CONTROL_NO_SORT_KEYS.get();
-        throw new LDAPException(LDAPResultCode.PROTOCOL_ERROR, message);
-      }
-
-      for (int i=0; i < sortKeys.length; i++)
-      {
-        ASN1Sequence keySequence = orderElements.get(i).decodeAsSequence();
-        ArrayList<ASN1Element> keyElements = keySequence.elements();
-
-        String attrName =
-             keyElements.get(0).decodeAsOctetString().stringValue().
-                  toLowerCase();
-        AttributeType attrType = DirectoryServer.getAttributeType(attrName,
-                                                                  false);
-        if (attrType == null)
-        {
-          Message message = INFO_SORTREQ_CONTROL_UNDEFINED_ATTR.get(attrName);
-          throw new LDAPException(LDAPResultCode.PROTOCOL_ERROR, message);
-        }
-
-        OrderingMatchingRule orderingRule = null;
-        boolean ascending = true;
-
-        for (int j=1; j < keyElements.size(); j++)
-        {
-          ASN1Element e = keyElements.get(j);
-          switch (e.getType())
-          {
-            case TYPE_ORDERING_RULE_ID:
-              String orderingRuleID =
-                   e.decodeAsOctetString().stringValue().toLowerCase();
-              orderingRule =
-                   DirectoryServer.getOrderingMatchingRule(orderingRuleID);
-              if (orderingRule == null)
-              {
-                Message message = INFO_SORTREQ_CONTROL_UNDEFINED_ORDERING_RULE.
-                    get(orderingRuleID);
-                throw new LDAPException(LDAPResultCode.PROTOCOL_ERROR, message);
-              }
-              break;
-
-            case TYPE_REVERSE_ORDER:
-              ascending = ! e.decodeAsBoolean().booleanValue();
-              break;
-
-            default:
-              Message message = INFO_SORTREQ_CONTROL_INVALID_SEQ_ELEMENT_TYPE.
-                  get(byteToHex(e.getType()));
-              throw new LDAPException(LDAPResultCode.PROTOCOL_ERROR, message);
-          }
-        }
-
-        if ((orderingRule == null) &&
-            (attrType.getOrderingMatchingRule() == null))
-        {
-          Message message =
-              INFO_SORTREQ_CONTROL_NO_ORDERING_RULE_FOR_ATTR.get(attrName);
-          throw new LDAPException(LDAPResultCode.CONSTRAINT_VIOLATION, message);
-        }
-
-        sortKeys[i] = new SortKey(attrType, ascending, orderingRule);
-      }
-
-      return new ServerSideSortRequestControl(control.getOID(),
-                                              control.isCritical(),
-                                              controlValue,
-                                              new SortOrder(sortKeys));
-    }
-    catch (LDAPException le)
-    {
-      throw le;
-    }
-    catch (Exception e)
-    {
-      Message message =
-          INFO_SORTREQ_CONTROL_CANNOT_DECODE_VALUE.get(getExceptionMessage(e));
-      throw new LDAPException(LDAPResultCode.PROTOCOL_ERROR, message, e);
-    }
+    this(false, sortOrder);
   }
 
+  /**
+   * Creates a new server-side sort request control with the provided
+   * information.
+   *
+   * @param  isCritical    Indicates whether support for this control should be
+   *                       considered a critical part of the server processing.
+   * @param  sortOrder     sort order associated with this server-side sort
+   *                       control.
+   */
+  public ServerSideSortRequestControl(boolean isCritical, SortOrder sortOrder)
+  {
+    super(OID_SERVER_SIDE_SORT_REQUEST_CONTROL, isCritical);
+
+    this.sortOrder = sortOrder;
+  }
 
 
   /**
-   * Retrieves a string representation of this server-side sort request control.
+   * Retrieves the sort order for this server-side sort request control.
    *
-   * @return  A string representation of this server-side sort request control.
+   * @return  The sort order for this server-side sort request control.
+   * @throws  DirectoryException if an error occurs while retriving the
+   *          sort order.
    */
-  public String toString()
+  public SortOrder getSortOrder() throws DirectoryException
   {
-    StringBuilder buffer = new StringBuilder();
-    toString(buffer);
-    return buffer.toString();
+    if(sortOrder == null)
+    {
+      sortOrder = decodeSortOrderFromString();
+    }
+
+    return sortOrder;
   }
 
+  /**
+   * Writes this control's value to an ASN.1 writer. The value (if any) must
+   * be written as an ASN1OctetString.
+   *
+   * @param writer The ASN.1 writer to use.
+   * @throws IOException If a problem occurs while writing to the stream.
 
+   */
+  @Override
+  protected void writeValue(ASN1Writer writer) throws IOException {
+    if(decodedKeyList != null)
+    {
+      // This control was created with a sort order string so encode using
+      // that.
+      writeValueFromString(writer);
+    }
+    else
+    {
+      // This control must have been created with a typed sort order object
+      // so encode using that.
+      writeValueFromSortOrder(writer);
+    }
+  }
 
   /**
    * Appends a string representation of this server-side sort request control
@@ -430,16 +380,160 @@
    *
    * @param  buffer  The buffer to which the information should be appended.
    */
+  @Override
   public void toString(StringBuilder buffer)
   {
     buffer.append("ServerSideSortRequestControl(");
+    if(sortOrder == null)
+    {
+      buffer.append("SortOrder(");
 
-    if (sortOrder != null)
+      if (decodedKeyList.size() > 0)
+      {
+        decodedKeyToString(decodedKeyList.get(0), buffer);
+
+        for (int i=1; i < decodedKeyList.size(); i++)
+        {
+          buffer.append(",");
+          decodedKeyToString(decodedKeyList.get(i), buffer);
+        }
+      }
+      buffer.append(")");
+    }
+    else
     {
       buffer.append(sortOrder);
     }
+    buffer.append(")");
+  }
+
+  private void decodedKeyToString(String[] decodedKey, StringBuilder buffer)
+  {
+    buffer.append("SortKey(");
+    if (decodedKey[2] == null)
+    {
+      buffer.append("+");
+    }
+    else
+    {
+      buffer.append("-");
+    }
+    buffer.append(decodedKey[0]);
+
+    if (decodedKey[1] != null)
+    {
+      buffer.append(":");
+      buffer.append(decodedKey[1]);
+    }
 
     buffer.append(")");
   }
+
+  private SortOrder decodeSortOrderFromString() throws DirectoryException
+  {
+    ArrayList<SortKey> sortKeys = new ArrayList<SortKey>();
+    for(String[] decodedKey : decodedKeyList)
+    {
+      AttributeType attrType =
+          DirectoryServer.getAttributeType(decodedKey[0].toLowerCase(), false);
+      if (attrType == null)
+      {
+        Message message =
+            INFO_SORTREQ_CONTROL_UNDEFINED_ATTR.get(decodedKey[0]);
+        throw new DirectoryException(ResultCode.PROTOCOL_ERROR, message);
+      }
+
+      OrderingMatchingRule orderingRule = null;
+      if(decodedKey[1] != null)
+      {
+        orderingRule =
+            DirectoryServer.getOrderingMatchingRule(
+                decodedKey[1].toLowerCase());
+        if (orderingRule == null)
+        {
+          Message message =
+              INFO_SORTREQ_CONTROL_UNDEFINED_ORDERING_RULE.
+                  get(decodedKey[1]);
+          throw new DirectoryException(ResultCode.PROTOCOL_ERROR,
+              message);
+        }
+      }
+
+      boolean ascending = true;
+      if(decodedKey[2] != null && decodedKey[2].equals("r"))
+      {
+        ascending = false;
+      }
+
+      if ((orderingRule == null) &&
+          (attrType.getOrderingMatchingRule() == null))
+      {
+        Message message =
+            INFO_SORTREQ_CONTROL_NO_ORDERING_RULE_FOR_ATTR.get(
+                decodedKey[0]);
+        throw new DirectoryException(ResultCode.CONSTRAINT_VIOLATION,
+            message);
+      }
+
+      sortKeys.add(new SortKey(attrType, ascending, orderingRule));
+    }
+
+    return new SortOrder(sortKeys.toArray(new SortKey[0]));
+  }
+
+  private void writeValueFromString(ASN1Writer writer) throws IOException
+  {
+    writer.writeStartSequence(UNIVERSAL_OCTET_STRING_TYPE);
+
+    writer.writeStartSequence();
+    for(String[] strs : decodedKeyList)
+    {
+      writer.writeStartSequence();
+      // Attr name will always be present
+      writer.writeOctetString(strs[0]);
+      // Rule ID might not be present
+      if(strs[1] != null)
+      {
+        writer.writeOctetString(TYPE_ORDERING_RULE_ID, strs[1]);
+      }
+      // Reverse if present
+      if(strs[2] != null)
+      {
+        writer.writeBoolean(TYPE_REVERSE_ORDER, true);
+      }
+      writer.writeEndSequence();
+    }
+    writer.writeEndSequence();
+
+    writer.writeEndSequence();
+  }
+
+  private void writeValueFromSortOrder(ASN1Writer writer) throws IOException
+  {
+    writer.writeStartSequence(UNIVERSAL_OCTET_STRING_TYPE);
+
+    writer.writeStartSequence();
+    for (SortKey sortKey : sortOrder.getSortKeys())
+    {
+      writer.writeStartSequence();
+      writer.writeOctetString(sortKey.getAttributeType().getNameOrOID());
+
+      if (sortKey.getOrderingRule() != null)
+      {
+        writer.writeOctetString(TYPE_ORDERING_RULE_ID,
+            sortKey.getOrderingRule().getNameOrOID());
+      }
+
+      if (! sortKey.ascending())
+      {
+        writer.writeBoolean(TYPE_REVERSE_ORDER, true);
+      }
+
+      writer.writeEndSequence();
+    }
+    writer.writeEndSequence();
+
+    writer.writeEndSequence();
+  }
 }
 
diff --git a/opends/src/server/org/opends/server/controls/ServerSideSortResponseControl.java b/opends/src/server/org/opends/server/controls/ServerSideSortResponseControl.java
index 4a59c7e..427b477 100644
--- a/opends/src/server/org/opends/server/controls/ServerSideSortResponseControl.java
+++ b/opends/src/server/org/opends/server/controls/ServerSideSortResponseControl.java
@@ -28,16 +28,15 @@
 import org.opends.messages.Message;
 
 
+import java.io.IOException;
 
-import java.util.ArrayList;
-
-import org.opends.server.protocols.asn1.ASN1Element;
-import org.opends.server.protocols.asn1.ASN1Enumerated;
-import org.opends.server.protocols.asn1.ASN1OctetString;
-import org.opends.server.protocols.asn1.ASN1Sequence;
-import org.opends.server.protocols.ldap.LDAPResultCode;
+import org.opends.server.protocols.asn1.*;
+import static org.opends.server.protocols.asn1.ASN1Constants.
+    UNIVERSAL_OCTET_STRING_TYPE;
 import org.opends.server.types.Control;
-import org.opends.server.types.LDAPException;
+import org.opends.server.types.DirectoryException;
+import org.opends.server.types.ByteString;
+import org.opends.server.types.ResultCode;
 
 import static org.opends.messages.ProtocolMessages.*;
 import static org.opends.server.util.ServerConstants.*;
@@ -79,6 +78,63 @@
        extends Control
 {
   /**
+   * ControlDecoder implentation to decode this control from a ByteString.
+   */
+  private final static class Decoder
+      implements ControlDecoder<ServerSideSortResponseControl>
+  {
+    /**
+     * {@inheritDoc}
+     */
+    public ServerSideSortResponseControl decode(boolean isCritical,
+                                                ByteString value)
+        throws DirectoryException
+    {
+      if (value == null)
+      {
+        Message message = INFO_SORTRES_CONTROL_NO_VALUE.get();
+        throw new DirectoryException(ResultCode.PROTOCOL_ERROR, message);
+      }
+
+      ASN1Reader reader = ASN1.getReader(value);
+      try
+      {
+        reader.readStartSequence();
+        int resultCode = (int)reader.readInteger();
+
+        String attributeType = null;
+        if(reader.hasNextElement())
+        {
+          attributeType = reader.readOctetStringAsString();
+        }
+
+        return new ServerSideSortResponseControl(isCritical,
+            resultCode,
+            attributeType);
+      }
+      catch (Exception e)
+      {
+        Message message =
+            INFO_SORTRES_CONTROL_CANNOT_DECODE_VALUE.get(
+                getExceptionMessage(e));
+        throw new DirectoryException(ResultCode.PROTOCOL_ERROR, message, e);
+      }
+    }
+
+    public String getOID()
+    {
+      return OID_SERVER_SIDE_SORT_RESPONSE_CONTROL;
+    }
+
+  }
+
+  /**
+   * The Control Decoder that can be used to decode this control.
+   */
+  public static final ControlDecoder<ServerSideSortResponseControl> DECODER =
+    new Decoder();
+
+  /**
    * The BER type to use when encoding the attribute type element.
    */
   private static final byte TYPE_ATTRIBUTE_TYPE = (byte) 0x80;
@@ -103,11 +159,7 @@
    */
   public ServerSideSortResponseControl(int resultCode, String attributeType)
   {
-    super(OID_SERVER_SIDE_SORT_RESPONSE_CONTROL, false,
-          encodeControlValue(resultCode, attributeType));
-
-    this.resultCode    = resultCode;
-    this.attributeType = attributeType;
+    this(false, resultCode, attributeType);
   }
 
 
@@ -116,19 +168,16 @@
    * Creates a new server-side sort response control with the provided
    * information.
    *
-   * @param  oid            The OID to use for this control.
    * @param  isCritical     Indicates whether support for this control should be
    *                        considered a critical part of the server processing.
-   * @param  controlValue   The encoded value for this control.
    * @param  resultCode     The result code for the sort result.
    * @param  attributeType  The attribute type for the sort result.
    */
-  private ServerSideSortResponseControl(String oid, boolean isCritical,
-                                        ASN1OctetString controlValue,
-                                        int resultCode,
-                                        String attributeType)
+  public ServerSideSortResponseControl(boolean isCritical,
+                                       int resultCode,
+                                       String attributeType)
   {
-    super(oid, isCritical, controlValue);
+    super(OID_SERVER_SIDE_SORT_RESPONSE_CONTROL, isCritical);
 
     this.resultCode    = resultCode;
     this.attributeType = attributeType;
@@ -162,93 +211,25 @@
 
 
   /**
-   * Encodes the provided set of result codes and attribute types in a manner
-   * suitable for use as the value of this control.
+   * Writes this control's value to an ASN.1 writer. The value (if any) must be
+   * written as an ASN1OctetString.
    *
-   * @param  resultCode     The result code for the sort result.
-   * @param  attributeType  The attribute type for the sort result, or
-   *                        {@code null} if there is none.
-   *
-   * @return  The ASN.1 octet string containing the encoded sort result.
+   * @param writer The ASN.1 writer to use.
+   * @throws IOException If a problem occurs while writing to the stream.
    */
-  private static ASN1OctetString encodeControlValue(int resultCode,
-                                                    String attributeType)
-  {
-    ArrayList<ASN1Element> elements = new ArrayList<ASN1Element>(2);
-    elements.add(new ASN1Enumerated(resultCode));
+  @Override
+  protected void writeValue(ASN1Writer writer) throws IOException {
+    writer.writeStartSequence(UNIVERSAL_OCTET_STRING_TYPE);
 
+    writer.writeStartSequence();
+    writer.writeInteger(resultCode);
     if (attributeType != null)
     {
-      elements.add(new ASN1OctetString(TYPE_ATTRIBUTE_TYPE, attributeType));
+      writer.writeOctetString(TYPE_ATTRIBUTE_TYPE, attributeType);
     }
+    writer.writeEndSequence();
 
-    return new ASN1OctetString(new ASN1Sequence(elements).encode());
-  }
-
-
-
-  /**
-   * Creates a new server-side sort response control from the contents of the
-   * provided control.
-   *
-   * @param  control  The generic control containing the information to use to
-   *                  create this server-side sort response control.  It must
-   *                  not be {@code null}.
-   *
-   * @return  The server-side sort response control decoded from the provided
-   *          control.
-   *
-   * @throws  LDAPException  If this control cannot be decoded as a valid
-   *                         server-side sort response control.
-   */
-  public static ServerSideSortResponseControl decodeControl(Control control)
-         throws LDAPException
-  {
-    ASN1OctetString controlValue = control.getValue();
-    if (controlValue == null)
-    {
-      Message message = INFO_SORTRES_CONTROL_NO_VALUE.get();
-      throw new LDAPException(LDAPResultCode.PROTOCOL_ERROR, message);
-    }
-
-    try
-    {
-      ArrayList<ASN1Element> elements =
-           ASN1Sequence.decodeAsSequence(control.getValue().value()).elements();
-      int resultCode = elements.get(0).decodeAsEnumerated().intValue();
-
-      String attributeType = null;
-      if (elements.size() > 1)
-      {
-        attributeType = elements.get(1).decodeAsOctetString().stringValue();
-      }
-
-      return new ServerSideSortResponseControl(control.getOID(),
-                                               control.isCritical(),
-                                               control.getValue(), resultCode,
-                                               attributeType);
-    }
-    catch (Exception e)
-    {
-      Message message =
-          INFO_SORTRES_CONTROL_CANNOT_DECODE_VALUE.get(getExceptionMessage(e));
-      throw new LDAPException(LDAPResultCode.PROTOCOL_ERROR, message, e);
-    }
-  }
-
-
-
-  /**
-   * Retrieves a string representation of this server-side sort response
-   * control.
-   *
-   * @return  A string representation of this server-side sort response control.
-   */
-  public String toString()
-  {
-    StringBuilder buffer = new StringBuilder();
-    toString(buffer);
-    return buffer.toString();
+    writer.writeEndSequence();
   }
 
 
@@ -259,6 +240,7 @@
    *
    * @param  buffer  The buffer to which the information should be appended.
    */
+  @Override
   public void toString(StringBuilder buffer)
   {
     buffer.append("ServerSideSortResponseControl(resultCode=");
diff --git a/opends/src/server/org/opends/server/controls/SubtreeDeleteControl.java b/opends/src/server/org/opends/server/controls/SubtreeDeleteControl.java
index 1b440f2..185a593 100644
--- a/opends/src/server/org/opends/server/controls/SubtreeDeleteControl.java
+++ b/opends/src/server/org/opends/server/controls/SubtreeDeleteControl.java
@@ -26,21 +26,103 @@
  */
 package org.opends.server.controls;
 
-import org.opends.server.types.Control;
+
+
+import static org.opends.messages.ProtocolMessages.*;
 import static org.opends.server.util.ServerConstants.*;
 
+import java.io.IOException;
+
+import org.opends.messages.Message;
+import org.opends.server.protocols.asn1.ASN1Writer;
+import org.opends.server.types.ByteString;
+import org.opends.server.types.Control;
+import org.opends.server.types.DirectoryException;
+import org.opends.server.types.ResultCode;
+
+
+
 /**
- * This class implements the subtree delete control.
+ * This class implements the subtree delete control defined in
+ * draft-armijo-ldap-treedelete. It makes it possible for clients to
+ * delete subtrees of entries.
  */
 public class SubtreeDeleteControl extends Control
 {
   /**
-   * Creates a new instance of Subtree Delete control with the
-   * default settings.
+   * ControlDecoder implementation to decode this control from a
+   * ByteString.
    */
-  public SubtreeDeleteControl()
+  private final static class Decoder implements
+      ControlDecoder<SubtreeDeleteControl>
   {
-    super(OID_SUBTREE_DELETE_CONTROL, false);
+    /**
+     * {@inheritDoc}
+     */
+    public SubtreeDeleteControl decode(boolean isCritical,
+        ByteString value) throws DirectoryException
+    {
+      if (value != null)
+      {
+        Message message =
+            ERR_SUBTREE_DELETE_INVALID_CONTROL_VALUE.get();
+        throw new DirectoryException(ResultCode.PROTOCOL_ERROR, message);
+      }
+
+      return new SubtreeDeleteControl(isCritical);
+    }
+
+
+
+    public String getOID()
+    {
+      return OID_SUBTREE_DELETE_CONTROL;
+    }
+
+  }
+
+
+
+  /**
+   * The Control Decoder that can be used to decode this control.
+   */
+  public static final ControlDecoder<SubtreeDeleteControl> DECODER =
+      new Decoder();
+
+
+
+  /**
+   * Creates a new subtree delete control.
+   *
+   * @param isCritical
+   *          Indicates whether the control should be considered
+   *          critical for the operation processing.
+   */
+  public SubtreeDeleteControl(boolean isCritical)
+  {
+    super(OID_SUBTREE_DELETE_CONTROL, isCritical);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  protected void writeValue(ASN1Writer writer) throws IOException
+  {
+    // Nothing to do.
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public void toString(StringBuilder buffer)
+  {
+    buffer.append("SubtreeDeleteControl()");
   }
 
 }
diff --git a/opends/src/server/org/opends/server/controls/VLVRequestControl.java b/opends/src/server/org/opends/server/controls/VLVRequestControl.java
index 7bb2801..e9860f3 100644
--- a/opends/src/server/org/opends/server/controls/VLVRequestControl.java
+++ b/opends/src/server/org/opends/server/controls/VLVRequestControl.java
@@ -28,17 +28,15 @@
 import org.opends.messages.Message;
 
 
+import java.io.IOException;
 
-import java.util.ArrayList;
-
-import org.opends.server.protocols.asn1.ASN1Element;
-import org.opends.server.protocols.asn1.ASN1Integer;
-import org.opends.server.protocols.asn1.ASN1OctetString;
-import org.opends.server.protocols.asn1.ASN1Sequence;
-import org.opends.server.protocols.ldap.LDAPResultCode;
-import org.opends.server.types.ByteString;
+import org.opends.server.protocols.asn1.*;
+import static org.opends.server.protocols.asn1.ASN1Constants.
+    UNIVERSAL_OCTET_STRING_TYPE;
 import org.opends.server.types.Control;
-import org.opends.server.types.LDAPException;
+import org.opends.server.types.DirectoryException;
+import org.opends.server.types.ByteString;
+import org.opends.server.types.ResultCode;
 
 import static org.opends.messages.ProtocolMessages.*;
 import static org.opends.server.util.ServerConstants.*;
@@ -67,6 +65,95 @@
        extends Control
 {
   /**
+   * ControlDecoder implentation to decode this control from a ByteString.
+   */
+  private final static class Decoder
+      implements ControlDecoder<VLVRequestControl>
+  {
+    /**
+     * {@inheritDoc}
+     */
+    public VLVRequestControl decode(boolean isCritical, ByteString value)
+        throws DirectoryException
+    {
+      if (value == null)
+      {
+        Message message = INFO_VLVREQ_CONTROL_NO_VALUE.get();
+        throw new DirectoryException(ResultCode.PROTOCOL_ERROR, message);
+      }
+
+      ASN1Reader reader = ASN1.getReader(value);
+      try
+      {
+        reader.readStartSequence();
+
+        int beforeCount = (int)reader.readInteger();
+        int afterCount  = (int)reader.readInteger();
+
+        int offset = 0;
+        int contentCount = 0;
+        ByteString greaterThanOrEqual = null;
+        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:
+            greaterThanOrEqual = reader.readOctetString();
+            break;
+
+          default:
+            Message message = INFO_VLVREQ_CONTROL_INVALID_TARGET_TYPE.get(
+                byteToHex(targetType));
+            throw new DirectoryException(ResultCode.PROTOCOL_ERROR, message);
+        }
+
+        ByteString contextID = null;
+        if (reader.hasNextElement())
+        {
+          contextID = reader.readOctetString();
+        }
+
+        if(targetType == TYPE_TARGET_BYOFFSET)
+        {
+          return new VLVRequestControl(isCritical, beforeCount,
+              afterCount, offset, contentCount, contextID);
+        }
+
+        return new VLVRequestControl(isCritical, beforeCount,
+            afterCount, greaterThanOrEqual, contextID);
+      }
+      catch (DirectoryException de)
+      {
+        throw de;
+      }
+      catch (Exception e)
+      {
+        Message message =
+            INFO_VLVREQ_CONTROL_CANNOT_DECODE_VALUE.get(getExceptionMessage(e));
+        throw new DirectoryException(ResultCode.PROTOCOL_ERROR, message, e);
+      }
+    }
+
+    public String getOID()
+    {
+      return OID_VLV_REQUEST_CONTROL;
+    }
+
+  }
+
+  /**
+   * The Control Decoder that can be used to decode this control.
+   */
+  public static final ControlDecoder<VLVRequestControl> DECODER =
+    new Decoder();
+
+  /**
    * The BER type to use when encoding the byOffset target element.
    */
   public static final byte TYPE_TARGET_BYOFFSET = (byte) 0xA0;
@@ -119,7 +206,7 @@
   public VLVRequestControl(int beforeCount, int afterCount, int offset,
                            int contentCount)
   {
-    this(beforeCount, afterCount, offset, contentCount, null);
+    this(false, beforeCount, afterCount, offset, contentCount, null);
   }
 
 
@@ -127,6 +214,7 @@
   /**
    * Creates a new VLV request control with the provided information.
    *
+   * @param  isCritical    Indicates whether or not the control is critical.
    * @param  beforeCount   The number of entries before the target offset to
    *                       retrieve in the results page.
    * @param  afterCount    The number of entries after the target offset to
@@ -142,12 +230,10 @@
    *                       the server did not include a context ID in the
    *                       last response.
    */
-  public VLVRequestControl(int beforeCount, int afterCount, int offset,
-                           int contentCount, ByteString contextID)
+  public VLVRequestControl(boolean isCritical, int beforeCount, int afterCount,
+                           int offset, int contentCount, ByteString contextID)
   {
-    super(OID_VLV_REQUEST_CONTROL, false,
-          encodeControlValue(beforeCount, afterCount, offset, contentCount,
-                             contextID));
+    super(OID_VLV_REQUEST_CONTROL, isCritical);
 
     this.beforeCount  = beforeCount;
     this.afterCount   = afterCount;
@@ -174,7 +260,7 @@
   public VLVRequestControl(int beforeCount, int afterCount,
                            ByteString greaterThanOrEqual)
   {
-    this(beforeCount, afterCount, greaterThanOrEqual, null);
+    this(false, beforeCount, afterCount, greaterThanOrEqual, null);
   }
 
 
@@ -182,6 +268,8 @@
   /**
    * Creates a new VLV request control with the provided information.
    *
+   * @param  isCritical          Indicates whether the control should be
+   *                             considered critical.
    * @param  beforeCount         The number of entries before the target
    *                             assertion value.
    * @param  afterCount          The number of entries after the target
@@ -195,13 +283,11 @@
    *                             response or the server did not include a
    *                             context ID in the last response.
    */
-  public VLVRequestControl(int beforeCount, int afterCount,
+  public VLVRequestControl(boolean isCritical, int beforeCount, int afterCount,
                            ByteString greaterThanOrEqual,
                            ByteString contextID)
   {
-    super(OID_VLV_REQUEST_CONTROL, false,
-          encodeControlValue(beforeCount, afterCount, greaterThanOrEqual,
-                             contextID));
+    super(OID_VLV_REQUEST_CONTROL, isCritical);
 
     this.beforeCount        = beforeCount;
     this.afterCount         = afterCount;
@@ -214,46 +300,6 @@
 
 
   /**
-   * Creates a new VLV request control with the provided information.
-   *
-   * @param  oid                 The OID for the control.
-   * @param  isCritical          Indicates whether the control should be
-   *                             considered critical.
-   * @param  controlValue        The pre-encoded value for the control.
-   * @param  beforeCount         The number of entries before the target
-   *                             assertion value.
-   * @param  afterCount          The number of entries after the target
-   *                             assertion value.
-   * @param  greaterThanOrEqual  The greaterThanOrEqual target assertion value
-   *                             that indicates where to start the page of
-   *                             results.
-   * @param  contextID           The context ID provided by the server in the
-   *                             last VLV response for the same set of criteria,
-   *                             or {@code null} if there was no previous VLV
-   *                             response or the server did not include a
-   *                             context ID in the last response.
-   */
-  private VLVRequestControl(String oid, boolean isCritical,
-                            ASN1OctetString controlValue, int beforeCount,
-                            int afterCount, byte targetType,
-                            int offset, int contentCount,
-                            ByteString greaterThanOrEqual,
-                            ByteString contextID)
-  {
-    super(oid, isCritical, controlValue);
-
-    this.beforeCount        = beforeCount;
-    this.afterCount         = afterCount;
-    this.targetType         = targetType;
-    this.offset             = offset;
-    this.contentCount       = contentCount;
-    this.greaterThanOrEqual = greaterThanOrEqual;
-    this.contextID          = contextID;
-  }
-
-
-
-  /**
    * Retrieves the number of entries before the target offset or assertion value
    * to include in the results page.
    *
@@ -358,188 +404,38 @@
 
 
   /**
-   * Encodes the provided information in a manner suitable for use as the value
-   * of this control.
+   * Writes this control's value to an ASN.1 writer. The value (if any) must be
+   * written as an ASN1OctetString.
    *
-   * @param  beforeCount   The number of entries before the target offset to
-   *                       retrieve in the results page.
-   * @param  afterCount    The number of entries after the target offset to
-   *                       retrieve in the results page.
-   * @param  offset        The offset in the result set to target for the
-   *                       beginning of the page of results.
-   * @param  contentCount  The content count returned by the server in the last
-   *                       phase of the VLV request, or zero for a new VLV
-   *                       request session.
-   * @param  contextID     The context ID provided by the server in the last
-   *                       VLV response for the same set of criteria, or
-   *                       {@code null} if there was no previous VLV response or
-   *                       the server did not include a context ID in the
-   *                       last response.
-   *
-   * @return  The ASN.1 octet string containing the encoded sort order.
+   * @param writer The ASN.1 writer to use.
+   * @throws IOException If a problem occurs while writing to the stream.
    */
-  private static ASN1OctetString encodeControlValue(int beforeCount,
-                                      int afterCount, int offset,
-                                      int contentCount, ByteString contextID)
-  {
-    ArrayList<ASN1Element> vlvElements = new ArrayList<ASN1Element>(4);
-    vlvElements.add(new ASN1Integer(beforeCount));
-    vlvElements.add(new ASN1Integer(afterCount));
+  @Override
+  protected void writeValue(ASN1Writer writer) throws IOException {
+    writer.writeStartSequence(UNIVERSAL_OCTET_STRING_TYPE);
 
-    ArrayList<ASN1Element> targetElements = new ArrayList<ASN1Element>(2);
-    targetElements.add(new ASN1Integer(offset));
-    targetElements.add(new ASN1Integer(contentCount));
-    vlvElements.add(new ASN1Sequence(TYPE_TARGET_BYOFFSET, targetElements));
-
+    writer.writeStartSequence();
+    writer.writeInteger(beforeCount);
+    writer.writeInteger(afterCount);
+    if(targetType == TYPE_TARGET_BYOFFSET)
+    {
+      writer.writeStartSequence(TYPE_TARGET_BYOFFSET);
+      writer.writeInteger(offset);
+      writer.writeInteger(contentCount);
+      writer.writeEndSequence();
+    }
+    else
+    {
+      writer.writeOctetString(TYPE_TARGET_GREATERTHANOREQUAL,
+          greaterThanOrEqual);
+    }
     if (contextID != null)
     {
-      vlvElements.add(contextID.toASN1OctetString());
+      writer.writeOctetString(contextID);
     }
+    writer.writeEndSequence();
 
-    return new ASN1OctetString(new ASN1Sequence(vlvElements).encode());
-  }
-
-
-
-  /**
-   * Encodes the provided information in a manner suitable for use as the value
-   * of this control.
-   *
-   * @param  beforeCount         The number of entries before the target
-   *                             assertion value.
-   * @param  afterCount          The number of entries after the target
-   *                             assertion value.
-   * @param  greaterThanOrEqual  The greaterThanOrEqual target assertion value
-   *                             that indicates where to start the page of
-   *                             results.
-   * @param  contextID           The context ID provided by the server in the
-   *                             last VLV response for the same set of criteria,
-   *                             or {@code null} if there was no previous VLV
-   *                             response or the server did not include a
-   *                             context ID in the last response.
-   *
-   * @return  The ASN.1 octet string containing the encoded sort order.
-   */
-  private static ASN1OctetString encodeControlValue(int beforeCount,
-                                      int afterCount,
-                                      ByteString greaterThanOrEqual,
-                                      ByteString contextID)
-  {
-    ArrayList<ASN1Element> vlvElements = new ArrayList<ASN1Element>(4);
-    vlvElements.add(new ASN1Integer(beforeCount));
-    vlvElements.add(new ASN1Integer(afterCount));
-
-    vlvElements.add(new ASN1OctetString(TYPE_TARGET_GREATERTHANOREQUAL,
-                                        greaterThanOrEqual.value()));
-
-    if (contextID != null)
-    {
-      vlvElements.add(contextID.toASN1OctetString());
-    }
-
-    return new ASN1OctetString(new ASN1Sequence(vlvElements).encode());
-  }
-
-
-
-  /**
-   * Creates a new VLV request control from the contents of the provided
-   * control.
-   *
-   * @param  control  The generic control containing the information to use to
-   *                  create this VLV request control.  It must not be
-   *                  {@code null}.
-   *
-   * @return  The VLV request control decoded from the provided control.
-   *
-   * @throws  LDAPException  If this control cannot be decoded as a valid VLV
-   *                         request control.
-   */
-  public static VLVRequestControl decodeControl(Control control)
-         throws LDAPException
-  {
-    ASN1OctetString controlValue = control.getValue();
-    if (controlValue == null)
-    {
-      Message message = INFO_VLVREQ_CONTROL_NO_VALUE.get();
-      throw new LDAPException(LDAPResultCode.PROTOCOL_ERROR, message);
-    }
-
-    try
-    {
-      ASN1Sequence vlvSequence =
-           ASN1Sequence.decodeAsSequence(controlValue.value());
-      ArrayList<ASN1Element> elements = vlvSequence.elements();
-
-      if ((elements.size() < 3) || (elements.size() > 4))
-      {
-        Message message =
-            INFO_VLVREQ_CONTROL_INVALID_ELEMENT_COUNT.get(elements.size());
-        throw new LDAPException(LDAPResultCode.PROTOCOL_ERROR, message);
-      }
-
-      int beforeCount = elements.get(0).decodeAsInteger().intValue();
-      int afterCount  = elements.get(1).decodeAsInteger().intValue();
-
-      ASN1Element targetElement = elements.get(2);
-      int offset = 0;
-      int contentCount = 0;
-      ASN1OctetString greaterThanOrEqual = null;
-      byte targetType = targetElement.getType();
-      switch (targetType)
-      {
-        case TYPE_TARGET_BYOFFSET:
-          ArrayList<ASN1Element> targetElements =
-               targetElement.decodeAsSequence().elements();
-          offset = targetElements.get(0).decodeAsInteger().intValue();
-          contentCount = targetElements.get(1).decodeAsInteger().intValue();
-          break;
-
-        case TYPE_TARGET_GREATERTHANOREQUAL:
-          greaterThanOrEqual = targetElement.decodeAsOctetString();
-          break;
-
-        default:
-          Message message = INFO_VLVREQ_CONTROL_INVALID_TARGET_TYPE.get(
-              byteToHex(targetType));
-          throw new LDAPException(LDAPResultCode.PROTOCOL_ERROR, message);
-      }
-
-      ASN1OctetString contextID = null;
-      if (elements.size() == 4)
-      {
-        contextID = elements.get(3).decodeAsOctetString();
-      }
-
-      return new VLVRequestControl(control.getOID(), control.isCritical(),
-                                   controlValue, beforeCount, afterCount,
-                                   targetType, offset, contentCount,
-                                   greaterThanOrEqual, contextID);
-    }
-    catch (LDAPException le)
-    {
-      throw le;
-    }
-    catch (Exception e)
-    {
-      Message message =
-          INFO_VLVREQ_CONTROL_CANNOT_DECODE_VALUE.get(getExceptionMessage(e));
-      throw new LDAPException(LDAPResultCode.PROTOCOL_ERROR, message, e);
-    }
-  }
-
-
-
-  /**
-   * Retrieves a string representation of this VLV request control.
-   *
-   * @return  A string representation of this VLV request control.
-   */
-  public String toString()
-  {
-    StringBuilder buffer = new StringBuilder();
-    toString(buffer);
-    return buffer.toString();
+    writer.writeEndSequence();
   }
 
 
@@ -550,6 +446,7 @@
    *
    * @param  buffer  The buffer to which the information should be appended.
    */
+  @Override
   public void toString(StringBuilder buffer)
   {
     buffer.append("VLVRequestControl(beforeCount=");
diff --git a/opends/src/server/org/opends/server/controls/VLVResponseControl.java b/opends/src/server/org/opends/server/controls/VLVResponseControl.java
index ec56131..8256b92 100644
--- a/opends/src/server/org/opends/server/controls/VLVResponseControl.java
+++ b/opends/src/server/org/opends/server/controls/VLVResponseControl.java
@@ -28,18 +28,12 @@
 import org.opends.messages.Message;
 
 
+import java.io.IOException;
 
-import java.util.ArrayList;
-
-import org.opends.server.protocols.asn1.ASN1Element;
-import org.opends.server.protocols.asn1.ASN1Enumerated;
-import org.opends.server.protocols.asn1.ASN1Integer;
-import org.opends.server.protocols.asn1.ASN1OctetString;
-import org.opends.server.protocols.asn1.ASN1Sequence;
-import org.opends.server.protocols.ldap.LDAPResultCode;
-import org.opends.server.types.ByteString;
-import org.opends.server.types.Control;
-import org.opends.server.types.LDAPException;
+import org.opends.server.protocols.asn1.*;
+import static org.opends.server.protocols.asn1.ASN1Constants.
+    UNIVERSAL_OCTET_STRING_TYPE;
+import org.opends.server.types.*;
 
 import static org.opends.messages.ProtocolMessages.*;
 import static org.opends.server.util.ServerConstants.*;
@@ -75,6 +69,65 @@
 public class VLVResponseControl
        extends Control
 {
+  /**
+   * ControlDecoder implentation to decode this control from a ByteString.
+   */
+  private final static class Decoder
+      implements ControlDecoder<VLVResponseControl>
+  {
+    /**
+     * {@inheritDoc}
+     */
+    public VLVResponseControl decode(boolean isCritical, ByteString value)
+        throws DirectoryException
+    {
+      if (value == null)
+      {
+        Message message = INFO_VLVRES_CONTROL_NO_VALUE.get();
+        throw new DirectoryException(ResultCode.PROTOCOL_ERROR, message);
+      }
+
+      ASN1Reader reader = ASN1.getReader(value);
+      try
+      {
+        reader.readStartSequence();
+
+        int targetPosition = (int)reader.readInteger();
+        int contentCount   = (int)reader.readInteger();
+        int vlvResultCode  = (int)reader.readInteger();
+
+        ByteString contextID = null;
+        if (reader.hasNextElement())
+        {
+          contextID = reader.readOctetString();
+        }
+
+        return new VLVResponseControl(isCritical, targetPosition,
+            contentCount, vlvResultCode, contextID);
+      }
+      catch (Exception e)
+      {
+        Message message =
+            INFO_VLVRES_CONTROL_CANNOT_DECODE_VALUE.get(getExceptionMessage(e));
+        throw new DirectoryException(ResultCode.PROTOCOL_ERROR, message, e);
+      }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public String getOID()
+    {
+      return OID_VLV_RESPONSE_CONTROL;
+    }
+  }
+
+  /**
+   * The Control Decoder that can be used to decode this control.
+   */
+  public static final ControlDecoder<VLVResponseControl> DECODER =
+    new Decoder();
+
   // The context ID for this VLV response control.
   private ByteString contextID;
 
@@ -100,7 +153,7 @@
   public VLVResponseControl(int targetPosition, int contentCount,
                             int vlvResultCode)
   {
-    this(targetPosition, contentCount, vlvResultCode, null);
+    this(false, targetPosition, contentCount, vlvResultCode, null);
   }
 
 
@@ -108,46 +161,19 @@
   /**
    * Creates a new VLV response control with the provided information.
    *
-   * @param  targetPosition  The position of the target entry in the result set.
-   * @param  contentCount    The content count estimating the total number of
-   *                         entries in the result set.
-   * @param  vlvResultCode   The result code for the VLV operation.
-   * @param  contextID       The context ID for this VLV response control.
-   */
-  public VLVResponseControl(int targetPosition, int contentCount,
-                            int vlvResultCode, ByteString contextID)
-  {
-    super(OID_VLV_RESPONSE_CONTROL, false,
-          encodeControlValue(targetPosition, contentCount, vlvResultCode,
-                             contextID));
-
-    this.targetPosition = targetPosition;
-    this.contentCount   = contentCount;
-    this.vlvResultCode  = vlvResultCode;
-    this.contextID      = contextID;
-  }
-
-
-
-  /**
-   * Creates a new VLV response control with the provided information.
-   *
-   * @param  oid             The OID for the control.
    * @param  isCritical      Indicates whether the control should be considered
    *                         critical.
-   * @param  controlValue    The pre-encoded value for the control.
    * @param  targetPosition  The position of the target entry in the result set.
    * @param  contentCount    The content count estimating the total number of
    *                         entries in the result set.
    * @param  vlvResultCode   The result code for the VLV operation.
    * @param  contextID       The context ID for this VLV response control.
    */
-  private VLVResponseControl(String oid, boolean isCritical,
-                             ASN1OctetString controlValue, int targetPosition,
+  public VLVResponseControl(boolean isCritical, int targetPosition,
                              int contentCount, int vlvResultCode,
                              ByteString contextID)
   {
-    super(oid, isCritical, controlValue);
+    super(OID_VLV_RESPONSE_CONTROL, isCritical);
 
     this.targetPosition = targetPosition;
     this.contentCount   = contentCount;
@@ -209,110 +235,27 @@
 
 
   /**
-   * Encodes the provided information in a manner suitable for use as the value
-   * of this control.
+   * Writes this control's value to an ASN.1 writer. The value (if any) must be
+   * written as an ASN1OctetString.
    *
-   * @param  targetPosition  The position of the target entry in the result set.
-   * @param  contentCount    The content count estimating the total number of
-   *                         entries in the result set.
-   * @param  vlvResultCode   The result code for the VLV operation.
-   * @param  contextID       The context ID for this VLV response control.
-   *
-   * @return  The ASN.1 octet string containing the encoded sort order.
+   * @param writer The ASN.1 writer to use.
+   * @throws IOException If a problem occurs while writing to the stream.
    */
-  private static ASN1OctetString encodeControlValue(int targetPosition,
-                                      int contentCount, int vlvResultCode,
-                                      ByteString contextID)
-  {
-    ArrayList<ASN1Element> vlvElements = new ArrayList<ASN1Element>(4);
-    vlvElements.add(new ASN1Integer(targetPosition));
-    vlvElements.add(new ASN1Integer(contentCount));
-    vlvElements.add(new ASN1Enumerated(vlvResultCode));
+  @Override
+  protected void writeValue(ASN1Writer writer) throws IOException {
+    writer.writeStartSequence(UNIVERSAL_OCTET_STRING_TYPE);
 
+    writer.writeStartSequence();
+    writer.writeInteger(targetPosition);
+    writer.writeInteger(contentCount);
+    writer.writeInteger(vlvResultCode);
     if (contextID != null)
     {
-      vlvElements.add(contextID.toASN1OctetString());
+      writer.writeOctetString(contextID);
     }
+    writer.writeEndSequence();
 
-    return new ASN1OctetString(new ASN1Sequence(vlvElements).encode());
-  }
-
-
-
-  /**
-   * Creates a new VLV response control from the contents of the provided
-   * control.
-   *
-   * @param  control  The generic control containing the information to use to
-   *                  create this VLV response control.  It must not be
-   *                  {@code null}.
-   *
-   * @return  The VLV response control decoded from the provided control.
-   *
-   * @throws  LDAPException  If this control cannot be decoded as a valid VLV
-   *                         response control.
-   */
-  public static VLVResponseControl decodeControl(Control control)
-         throws LDAPException
-  {
-    ASN1OctetString controlValue = control.getValue();
-    if (controlValue == null)
-    {
-      Message message = INFO_VLVRES_CONTROL_NO_VALUE.get();
-      throw new LDAPException(LDAPResultCode.PROTOCOL_ERROR, message);
-    }
-
-    try
-    {
-      ASN1Sequence vlvSequence =
-           ASN1Sequence.decodeAsSequence(controlValue.value());
-      ArrayList<ASN1Element> elements = vlvSequence.elements();
-
-      if ((elements.size() < 3) || (elements.size() > 4))
-      {
-        Message message =
-            INFO_VLVRES_CONTROL_INVALID_ELEMENT_COUNT.get(elements.size());
-        throw new LDAPException(LDAPResultCode.PROTOCOL_ERROR, message);
-      }
-
-      int targetPosition = elements.get(0).decodeAsInteger().intValue();
-      int contentCount   = elements.get(1).decodeAsInteger().intValue();
-      int vlvResultCode  = elements.get(2).decodeAsEnumerated().intValue();
-
-      ASN1OctetString contextID = null;
-      if (elements.size() == 4)
-      {
-        contextID = elements.get(3).decodeAsOctetString();
-      }
-
-      return new VLVResponseControl(control.getOID(), control.isCritical(),
-                                    controlValue, targetPosition, contentCount,
-                                    vlvResultCode, contextID);
-    }
-    catch (LDAPException le)
-    {
-      throw le;
-    }
-    catch (Exception e)
-    {
-      Message message =
-          INFO_VLVRES_CONTROL_CANNOT_DECODE_VALUE.get(getExceptionMessage(e));
-      throw new LDAPException(LDAPResultCode.PROTOCOL_ERROR, message, e);
-    }
-  }
-
-
-
-  /**
-   * Retrieves a string representation of this VLV request control.
-   *
-   * @return  A string representation of this VLV request control.
-   */
-  public String toString()
-  {
-    StringBuilder buffer = new StringBuilder();
-    toString(buffer);
-    return buffer.toString();
+    writer.writeEndSequence();
   }
 
 
@@ -323,6 +266,7 @@
    *
    * @param  buffer  The buffer to which the information should be appended.
    */
+  @Override
   public void toString(StringBuilder buffer)
   {
     buffer.append("VLVResponseControl(targetPosition=");
diff --git a/opends/src/server/org/opends/server/core/AddOperation.java b/opends/src/server/org/opends/server/core/AddOperation.java
index c6157bd..7d32cca 100644
--- a/opends/src/server/org/opends/server/core/AddOperation.java
+++ b/opends/src/server/org/opends/server/core/AddOperation.java
@@ -29,13 +29,7 @@
 import java.util.List;
 import java.util.Map;
 
-import org.opends.server.types.Attribute;
-import org.opends.server.types.AttributeType;
-import org.opends.server.types.ByteString;
-import org.opends.server.types.DN;
-import org.opends.server.types.ObjectClass;
-import org.opends.server.types.Operation;
-import org.opends.server.types.RawAttribute;
+import org.opends.server.types.*;
 
 /**
  * This interface defines an operation that may be used to add a new entry to
diff --git a/opends/src/server/org/opends/server/core/AddOperationBasis.java b/opends/src/server/org/opends/server/core/AddOperationBasis.java
index 7280815..0667056 100644
--- a/opends/src/server/org/opends/server/core/AddOperationBasis.java
+++ b/opends/src/server/org/opends/server/core/AddOperationBasis.java
@@ -52,7 +52,6 @@
 import org.opends.server.core.networkgroups.NetworkGroup;
 import org.opends.server.loggers.debug.DebugLogger;
 import org.opends.server.loggers.debug.DebugTracer;
-import org.opends.server.protocols.asn1.ASN1OctetString;
 import org.opends.server.protocols.ldap.LDAPAttribute;
 import org.opends.server.types.*;
 import org.opends.server.types.operation.PostResponseAddOperation;
@@ -175,14 +174,14 @@
     this.userAttributes        = userAttributes;
     this.operationalAttributes = operationalAttributes;
 
-    rawEntryDN = new ASN1OctetString(entryDN.toString());
+    rawEntryDN = ByteString.valueOf(entryDN.toString());
 
     rawAttributes = new ArrayList<RawAttribute>();
 
-    ArrayList<ASN1OctetString> ocValues = new ArrayList<ASN1OctetString>();
+    ArrayList<ByteString> ocValues = new ArrayList<ByteString>();
     for (String s : objectClasses.values())
     {
-      ocValues.add(new ASN1OctetString(s));
+      ocValues.add(ByteString.valueOf(s));
     }
 
     LDAPAttribute ocAttr = new LDAPAttribute(ATTR_OBJECTCLASS, ocValues);
diff --git a/opends/src/server/org/opends/server/core/AddOperationWrapper.java b/opends/src/server/org/opends/server/core/AddOperationWrapper.java
index ed1c260..d48f069 100644
--- a/opends/src/server/org/opends/server/core/AddOperationWrapper.java
+++ b/opends/src/server/org/opends/server/core/AddOperationWrapper.java
@@ -29,12 +29,7 @@
 import java.util.List;
 import java.util.Map;
 
-import org.opends.server.types.Attribute;
-import org.opends.server.types.AttributeType;
-import org.opends.server.types.ByteString;
-import org.opends.server.types.DN;
-import org.opends.server.types.ObjectClass;
-import org.opends.server.types.RawAttribute;
+import org.opends.server.types.*;
 
 
 /**
diff --git a/opends/src/server/org/opends/server/core/BindOperation.java b/opends/src/server/org/opends/server/core/BindOperation.java
index 13ee216..3f93ea0 100644
--- a/opends/src/server/org/opends/server/core/BindOperation.java
+++ b/opends/src/server/org/opends/server/core/BindOperation.java
@@ -27,13 +27,7 @@
 package org.opends.server.core;
 import org.opends.messages.Message;
 
-import org.opends.server.protocols.asn1.ASN1OctetString;
-import org.opends.server.types.AuthenticationInfo;
-import org.opends.server.types.AuthenticationType;
-import org.opends.server.types.ByteString;
-import org.opends.server.types.DN;
-import org.opends.server.types.Entry;
-import org.opends.server.types.Operation;
+import org.opends.server.types.*;
 
 
 /**
@@ -132,7 +126,7 @@
    * @return  The SASL credentials for this bind operation, or <CODE>null</CODE>
    *          if there are none or if the bind does not use SASL authentication.
    */
-  public abstract ASN1OctetString getSASLCredentials();
+  public abstract ByteString getSASLCredentials();
 
   /**
    * Specifies the SASL credentials for this bind operation.
@@ -142,7 +136,7 @@
    *                          <CODE>null</CODE> if there are none.
    */
   public abstract void setSASLCredentials(String saslMechanism,
-      ASN1OctetString saslCredentials);
+      ByteString saslCredentials);
 
   /**
    * Retrieves the set of server SASL credentials to include in the bind
@@ -151,7 +145,7 @@
    * @return  The set of server SASL credentials to include in the bind
    *          response, or <CODE>null</CODE> if there are none.
    */
-  public abstract ASN1OctetString getServerSASLCredentials();
+  public abstract ByteString getServerSASLCredentials();
 
   /**
    * Specifies the set of server SASL credentials to include in the bind
@@ -161,7 +155,7 @@
    *                                include in the bind response.
    */
   public abstract void setServerSASLCredentials(
-      ASN1OctetString serverSASLCredentials);
+      ByteString serverSASLCredentials);
 
   /**
    * Retrieves the user entry associated with the SASL authentication attempt.
diff --git a/opends/src/server/org/opends/server/core/BindOperationBasis.java b/opends/src/server/org/opends/server/core/BindOperationBasis.java
index 874aed7..01110df 100644
--- a/opends/src/server/org/opends/server/core/BindOperationBasis.java
+++ b/opends/src/server/org/opends/server/core/BindOperationBasis.java
@@ -52,14 +52,11 @@
 import org.opends.server.core.networkgroups.NetworkGroup;
 import org.opends.server.loggers.debug.DebugLogger;
 import org.opends.server.loggers.debug.DebugTracer;
-import org.opends.server.protocols.asn1.ASN1OctetString;
 import org.opends.server.types.*;
 import org.opends.server.types.operation.PreParseBindOperation;
 import org.opends.server.workflowelement.localbackend.*;
 
 
-
-
 /**
  * This class defines an operation that may be used to authenticate a user to
  * the Directory Server.  Note that for security restrictions, response messages
@@ -80,10 +77,10 @@
   private static final DebugTracer TRACER = DebugLogger.getTracer();
 
   // The credentials used for SASL authentication.
-  private ASN1OctetString saslCredentials;
+  private ByteString saslCredentials;
 
   // The server SASL credentials provided to the client in the response.
-  private ASN1OctetString serverSASLCredentials;
+  private ByteString serverSASLCredentials;
 
   // The authentication info for this bind operation.
   private AuthenticationInfo authInfo = null;
@@ -151,7 +148,7 @@
 
     if (rawBindDN == null)
     {
-      this.rawBindDN = new ASN1OctetString();
+      this.rawBindDN = ByteString.empty();
     }
     else
     {
@@ -160,7 +157,7 @@
 
     if (simplePassword == null)
     {
-      this.simplePassword = new ASN1OctetString();
+      this.simplePassword = ByteString.empty();
     }
     else
     {
@@ -199,7 +196,7 @@
   public BindOperationBasis(ClientConnection clientConnection, long operationID,
                        int messageID, List<Control> requestControls,
                        String protocolVersion, ByteString rawBindDN,
-                       String saslMechanism, ASN1OctetString saslCredentials)
+                       String saslMechanism, ByteString saslCredentials)
   {
     super(clientConnection, operationID, messageID, requestControls);
 
@@ -212,7 +209,7 @@
 
     if (rawBindDN == null)
     {
-      this.rawBindDN = new ASN1OctetString();
+      this.rawBindDN = ByteString.empty();
     }
     else
     {
@@ -262,16 +259,16 @@
 
     if (bindDN == null)
     {
-      rawBindDN = new ASN1OctetString();
+      rawBindDN = ByteString.empty();
     }
     else
     {
-      rawBindDN = new ASN1OctetString(bindDN.toString());
+      rawBindDN = ByteString.valueOf(bindDN.toString());
     }
 
     if (simplePassword == null)
     {
-      this.simplePassword = new ASN1OctetString();
+      this.simplePassword = ByteString.empty();
     }
     else
     {
@@ -308,7 +305,7 @@
   public BindOperationBasis(ClientConnection clientConnection, long operationID,
                        int messageID, List<Control> requestControls,
                        String protocolVersion, DN bindDN,
-                       String saslMechanism, ASN1OctetString saslCredentials)
+                       String saslMechanism, ByteString saslCredentials)
   {
     super(clientConnection, operationID, messageID, requestControls);
 
@@ -322,11 +319,11 @@
 
     if (bindDN == null)
     {
-      rawBindDN = new ASN1OctetString();
+      rawBindDN = ByteString.empty();
     }
     else
     {
-      rawBindDN = new ASN1OctetString(bindDN.toString());
+      rawBindDN = ByteString.valueOf(bindDN.toString());
     }
 
     responseControls       = new ArrayList<Control>(0);
@@ -363,7 +360,7 @@
   {
     if (rawBindDN == null)
     {
-      this.rawBindDN = new ASN1OctetString();
+      this.rawBindDN = ByteString.empty();
     }
     else
     {
@@ -414,7 +411,7 @@
   {
     if (simplePassword == null)
     {
-      this.simplePassword = new ASN1OctetString();
+      this.simplePassword = ByteString.empty();
     }
     else
     {
@@ -437,7 +434,7 @@
   /**
    * {@inheritDoc}
    */
-  public final ASN1OctetString getSASLCredentials()
+  public final ByteString getSASLCredentials()
   {
     return saslCredentials;
   }
@@ -446,7 +443,7 @@
    * {@inheritDoc}
    */
   public final void setSASLCredentials(String saslMechanism,
-                                       ASN1OctetString saslCredentials)
+                                       ByteString saslCredentials)
   {
     this.saslMechanism   = saslMechanism;
     this.saslCredentials = saslCredentials;
@@ -458,7 +455,7 @@
   /**
    * {@inheritDoc}
    */
-  public final ASN1OctetString getServerSASLCredentials()
+  public final ByteString getServerSASLCredentials()
   {
     return serverSASLCredentials;
   }
@@ -466,7 +463,7 @@
   /**
    * {@inheritDoc}
    */
-  public final void setServerSASLCredentials(ASN1OctetString
+  public final void setServerSASLCredentials(ByteString
                                                   serverSASLCredentials)
   {
     this.serverSASLCredentials = serverSASLCredentials;
diff --git a/opends/src/server/org/opends/server/core/BindOperationWrapper.java b/opends/src/server/org/opends/server/core/BindOperationWrapper.java
index 35d1d67..4734dec 100644
--- a/opends/src/server/org/opends/server/core/BindOperationWrapper.java
+++ b/opends/src/server/org/opends/server/core/BindOperationWrapper.java
@@ -28,13 +28,7 @@
 import org.opends.messages.Message;
 
 
-import org.opends.server.protocols.asn1.ASN1OctetString;
-import org.opends.server.types.AuthenticationInfo;
-import org.opends.server.types.AuthenticationType;
-import org.opends.server.types.ByteString;
-import org.opends.server.types.DN;
-import org.opends.server.types.Entry;
-
+import org.opends.server.types.*;
 
 
 /**
@@ -110,7 +104,7 @@
   /**
    * {@inheritDoc}
    */
-  public ASN1OctetString getSASLCredentials()
+  public ByteString getSASLCredentials()
   {
     return bind.getSASLCredentials();
   }
@@ -126,7 +120,7 @@
   /**
    * {@inheritDoc}
    */
-  public ASN1OctetString getServerSASLCredentials()
+  public ByteString getServerSASLCredentials()
   {
     return bind.getServerSASLCredentials();
   }
@@ -190,7 +184,7 @@
    * {@inheritDoc}
    */
   public void setSASLCredentials(String saslMechanism,
-      ASN1OctetString saslCredentials)
+      ByteString saslCredentials)
   {
     bind.setSASLCredentials(saslMechanism, saslCredentials);
   }
@@ -198,7 +192,7 @@
   /**
    * {@inheritDoc}
    */
-  public void setServerSASLCredentials(ASN1OctetString serverSASLCredentials)
+  public void setServerSASLCredentials(ByteString serverSASLCredentials)
   {
     bind.setServerSASLCredentials(serverSASLCredentials);
   }
diff --git a/opends/src/server/org/opends/server/core/CompareOperation.java b/opends/src/server/org/opends/server/core/CompareOperation.java
index 7106d40..27269bf 100644
--- a/opends/src/server/org/opends/server/core/CompareOperation.java
+++ b/opends/src/server/org/opends/server/core/CompareOperation.java
@@ -26,10 +26,7 @@
  */
 package org.opends.server.core;
 
-import org.opends.server.types.AttributeType;
-import org.opends.server.types.ByteString;
-import org.opends.server.types.DN;
-import org.opends.server.types.Operation;
+import org.opends.server.types.*;
 
 
 /**
diff --git a/opends/src/server/org/opends/server/core/CompareOperationBasis.java b/opends/src/server/org/opends/server/core/CompareOperationBasis.java
index 12c3650..bd24447 100644
--- a/opends/src/server/org/opends/server/core/CompareOperationBasis.java
+++ b/opends/src/server/org/opends/server/core/CompareOperationBasis.java
@@ -41,7 +41,6 @@
 import org.opends.server.core.networkgroups.NetworkGroup;
 import org.opends.server.loggers.debug.DebugLogger;
 import org.opends.server.loggers.debug.DebugTracer;
-import org.opends.server.protocols.asn1.ASN1OctetString;
 import org.opends.server.types.*;
 import org.opends.server.types.operation.PostResponseCompareOperation;
 import org.opends.server.types.operation.PreParseCompareOperation;
@@ -151,7 +150,7 @@
     this.assertionValue = assertionValue;
 
     responseControls       = new ArrayList<Control>();
-    rawEntryDN             = new ASN1OctetString(entryDN.toString());
+    rawEntryDN             = ByteString.valueOf(entryDN.toString());
     rawAttributeType       = attributeType.getNameOrOID();
     cancelRequest          = null;
     proxiedAuthorizationDN = null;
diff --git a/opends/src/server/org/opends/server/core/DefaultCompressedSchema.java b/opends/src/server/org/opends/server/core/DefaultCompressedSchema.java
index 6f67cff..d4316bd 100644
--- a/opends/src/server/org/opends/server/core/DefaultCompressedSchema.java
+++ b/opends/src/server/org/opends/server/core/DefaultCompressedSchema.java
@@ -31,7 +31,6 @@
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.FileOutputStream;
-import java.util.ArrayList;
 import java.util.LinkedHashMap;
 import java.util.LinkedHashSet;
 import java.util.Map;
@@ -42,21 +41,10 @@
 import org.opends.messages.Message;
 import org.opends.server.api.CompressedSchema;
 import org.opends.server.loggers.debug.DebugTracer;
-import org.opends.server.protocols.asn1.ASN1Element;
-import org.opends.server.protocols.asn1.ASN1Integer;
-import org.opends.server.protocols.asn1.ASN1OctetString;
 import org.opends.server.protocols.asn1.ASN1Reader;
-import org.opends.server.protocols.asn1.ASN1Sequence;
+import org.opends.server.protocols.asn1.ASN1;
 import org.opends.server.protocols.asn1.ASN1Writer;
-import org.opends.server.types.Attribute;
-import org.opends.server.types.AttributeBuilder;
-import org.opends.server.types.AttributeType;
-import org.opends.server.types.AttributeValue;
-import org.opends.server.types.Attributes;
-import org.opends.server.types.ByteArray;
-import org.opends.server.types.DebugLogLevel;
-import org.opends.server.types.DirectoryException;
-import org.opends.server.types.ObjectClass;
+import org.opends.server.types.*;
 
 import static org.opends.server.config.ConfigConstants.*;
 import static org.opends.server.loggers.debug.DebugLogger.*;
@@ -87,21 +75,22 @@
   private AtomicInteger ocCounter;
 
   // The map between encoded representations and attribute types.
-  private ConcurrentHashMap<ByteArray,AttributeType> atDecodeMap;
+  private ConcurrentHashMap<ByteSequence,AttributeType> atDecodeMap;
 
   // The map between encoded representations and attribute options.
-  private ConcurrentHashMap<ByteArray,Set<String>> aoDecodeMap;
+  private ConcurrentHashMap<ByteSequence,Set<String>> aoDecodeMap;
 
   // The map between encoded representations and object class sets.
-  private ConcurrentHashMap<ByteArray,Map<ObjectClass,String>> ocDecodeMap;
+  private ConcurrentHashMap<ByteSequence,Map<ObjectClass,String>> ocDecodeMap;
 
   // The map between attribute descriptions and their encoded
   // representations.
-  private ConcurrentHashMap<AttributeType,
-               ConcurrentHashMap<Set<String>,ByteArray>> adEncodeMap;
+  private final ConcurrentHashMap<AttributeType,
+                ConcurrentHashMap<Set<String>, ByteSequence>> adEncodeMap;
 
   // The map between object class sets and encoded representations.
-  private ConcurrentHashMap<Map<ObjectClass,String>,ByteArray> ocEncodeMap;
+  private final ConcurrentHashMap<Map<ObjectClass,String>,
+      ByteSequence> ocEncodeMap;
 
 
 
@@ -110,12 +99,14 @@
    */
   public DefaultCompressedSchema()
   {
-    atDecodeMap = new ConcurrentHashMap<ByteArray, AttributeType>();
-    aoDecodeMap = new ConcurrentHashMap<ByteArray, Set<String>>();
-    ocDecodeMap = new ConcurrentHashMap<ByteArray, Map<ObjectClass, String>>();
+    atDecodeMap = new ConcurrentHashMap<ByteSequence, AttributeType>();
+    aoDecodeMap = new ConcurrentHashMap<ByteSequence, Set<String>>();
+    ocDecodeMap =
+        new ConcurrentHashMap<ByteSequence, Map<ObjectClass, String>>();
     adEncodeMap = new ConcurrentHashMap
-      <AttributeType, ConcurrentHashMap<Set<String>, ByteArray>>();
-    ocEncodeMap = new ConcurrentHashMap<Map<ObjectClass, String>, ByteArray>();
+      <AttributeType, ConcurrentHashMap<Set<String>, ByteSequence>>();
+    ocEncodeMap = new ConcurrentHashMap<Map<ObjectClass, String>,
+        ByteSequence>();
 
     adCounter = new AtomicInteger(1);
     ocCounter = new AtomicInteger(1);
@@ -130,7 +121,7 @@
    */
   private void load()
   {
-    ASN1Reader reader = null;
+    FileInputStream inputStream = null;
 
     try
     {
@@ -144,41 +135,40 @@
       {
         return;
       }
-      FileInputStream inputStream = new FileInputStream(path);
-      reader = new ASN1Reader(inputStream);
+      inputStream = new FileInputStream(path);
+      ASN1Reader reader = ASN1.getReader(inputStream);
 
 
       // The first element in the file should be a sequence of object class
       // sets.  Each object class set will itself be a sequence of octet
       // strings, where the first one is the token and the remaining elements
       // are the names of the associated object classes.
-      ASN1Sequence ocSequence = reader.readElement().decodeAsSequence();
-      for (ASN1Element element : ocSequence.elements())
+      reader.readStartSequence();
+      while(reader.hasNextElement())
       {
-        ArrayList<ASN1Element> elements = element.decodeAsSequence().elements();
-        ASN1OctetString os = elements.get(0).decodeAsOctetString();
-        ByteArray token = new ByteArray(os.value());
+        reader.readStartSequence();
+        ByteSequence token = reader.readOctetString();
 
         LinkedHashMap<ObjectClass,String> ocMap =
-             new LinkedHashMap<ObjectClass,String>(elements.size()-1);
-        for (int i=1; i < elements.size(); i++)
+             new LinkedHashMap<ObjectClass,String>();
+        while(reader.hasNextElement())
         {
-          os = elements.get(i).decodeAsOctetString();
-          String ocName = os.stringValue();
+          String ocName = reader.readOctetStringAsString();
           String lowerName = toLowerCase(ocName);
           ObjectClass oc = DirectoryServer.getObjectClass(lowerName, true);
           ocMap.put(oc, ocName);
         }
+        reader.readEndSequence();
 
         ocEncodeMap.put(ocMap, token);
         ocDecodeMap.put(token, ocMap);
       }
+      reader.readEndSequence();
 
 
       // The second element in the file should be an integer element that holds
       // the value to use to initialize the object class counter.
-      ASN1Element counterElement = reader.readElement();
-      ocCounter.set(counterElement.decodeAsInteger().intValue());
+      ocCounter.set((int)reader.readInteger());
 
 
       // The third element in the file should be a sequence of attribute
@@ -186,35 +176,32 @@
       // itself be a sequence of octet strings, where the first one is the
       // token, the second is the attribute name, and all remaining elements are
       // the attribute options.
-      ASN1Sequence adSequence = reader.readElement().decodeAsSequence();
-      for (ASN1Element element : adSequence.elements())
+      reader.readStartSequence();
+      while(reader.hasNextElement())
       {
-        ArrayList<ASN1Element> elements = element.decodeAsSequence().elements();
-        ASN1OctetString os = elements. get(0).decodeAsOctetString();
-        ByteArray token = new ByteArray(os.value());
-
-        os = elements.get(1).decodeAsOctetString();
-        String attrName = os.stringValue();
+        reader.readStartSequence();
+        ByteSequence token = reader.readOctetString();
+        String attrName = reader.readOctetStringAsString();
         String lowerName = toLowerCase(attrName);
         AttributeType attrType =
-             DirectoryServer.getAttributeType(lowerName, true);
+            DirectoryServer.getAttributeType(lowerName, true);
 
         LinkedHashSet<String> options =
-             new LinkedHashSet<String>(elements.size()-2);
-        for (int i=2; i < elements.size(); i++)
+            new LinkedHashSet<String>();
+        while(reader.hasNextElement())
         {
-          os = elements.get(i).decodeAsOctetString();
-          options.add(os.stringValue());
+          options.add(reader.readOctetStringAsString());
         }
+        reader.readEndSequence();
 
         atDecodeMap.put(token, attrType);
         aoDecodeMap.put(token, options);
 
-        ConcurrentHashMap<Set<String>, ByteArray> map = adEncodeMap
+        ConcurrentHashMap<Set<String>, ByteSequence> map = adEncodeMap
             .get(attrType);
         if (map == null)
         {
-          map = new ConcurrentHashMap<Set<String>, ByteArray>(1);
+          map = new ConcurrentHashMap<Set<String>, ByteSequence>(1);
           map.put(options, token);
           adEncodeMap.put(attrType, map);
         }
@@ -223,12 +210,12 @@
           map.put(options, token);
         }
       }
+      reader.readEndSequence();
 
 
       // The fourth element in the file should be an integer element that holds
       // the value to use to initialize the attribute description counter.
-      counterElement = reader.readElement();
-      adCounter.set(counterElement.decodeAsInteger().intValue());
+      adCounter.set((int)reader.readInteger());
     }
     catch (Exception e)
     {
@@ -244,9 +231,9 @@
     {
       try
       {
-        if (reader != null)
+        if (inputStream != null)
         {
-          reader.close();
+          inputStream.close();
         }
       }
       catch (Exception e)
@@ -270,7 +257,7 @@
   private void save()
           throws DirectoryException
   {
-    ASN1Writer writer = null;
+    FileOutputStream outputStream = null;
     try
     {
       // Determine the location of the "live" compressed schema data file, and
@@ -281,39 +268,34 @@
                     COMPRESSED_SCHEMA_FILE_NAME;
       String tempPath = path + ".tmp";
 
-      FileOutputStream outputStream = new FileOutputStream(tempPath);
-      writer = new ASN1Writer(outputStream);
+      outputStream = new FileOutputStream(tempPath);
+      ASN1Writer writer = ASN1.getWriter(outputStream);
 
 
       // The first element in the file should be a sequence of object class
       // sets.  Each object class set will itself be a sequence of octet
       // strings, where the first one is the token and the remaining elements
       // are the names of the associated object classes.
-      ArrayList<ASN1Element> ocElements =
-           new ArrayList<ASN1Element>(ocDecodeMap.size());
-      for (Map.Entry<ByteArray,Map<ObjectClass,String>> mapEntry :
+      writer.writeStartSequence();
+      for (Map.Entry<ByteSequence,Map<ObjectClass,String>> mapEntry :
            ocDecodeMap.entrySet())
       {
-        ByteArray token = mapEntry.getKey();
+        writer.writeStartSequence();
+        writer.writeOctetString(mapEntry.getKey());
         Map<ObjectClass,String> ocMap = mapEntry.getValue();
 
-        ArrayList<ASN1Element> elements =
-             new ArrayList<ASN1Element>(ocMap.size()+1);
-        elements.add(new ASN1OctetString(token.array()));
-
         for (String ocName : ocMap.values())
         {
-          elements.add(new ASN1OctetString(ocName));
+          writer.writeOctetString(ocName);
         }
-
-        ocElements.add(new ASN1Sequence(elements));
+        writer.writeEndSequence();
       }
-      writer.writeElement(new ASN1Sequence(ocElements));
+      writer.writeEndSequence();
 
 
       // The second element in the file should be an integer element that holds
       // the value to use to initialize the object class counter.
-      writer.writeElement(new ASN1Integer(ocCounter.get()));
+      writer.writeInteger(ocCounter.get());
 
 
       // The third element in the file should be a sequence of attribute
@@ -321,34 +303,31 @@
       // itself be a sequence of octet strings, where the first one is the
       // token, the second is the attribute name, and all remaining elements are
       // the attribute options.
-      ArrayList<ASN1Element> adElements =
-           new ArrayList<ASN1Element>(atDecodeMap.size());
-      for (ByteArray token : atDecodeMap.keySet())
+      writer.writeStartSequence();
+      for (ByteSequence token : atDecodeMap.keySet())
       {
+        writer.writeStartSequence();
         AttributeType attrType = atDecodeMap.get(token);
         Set<String> options = aoDecodeMap.get(token);
 
-        ArrayList<ASN1Element> elements =
-             new ArrayList<ASN1Element>(options.size()+2);
-        elements.add(new ASN1OctetString(token.array()));
-        elements.add(new ASN1OctetString(attrType.getNameOrOID()));
+        writer.writeOctetString(token);
+        writer.writeOctetString(attrType.getNameOrOID());
         for (String option : options)
         {
-          elements.add(new ASN1OctetString(option));
+          writer.writeOctetString(option);
         }
-
-        adElements.add(new ASN1Sequence(elements));
+        writer.writeEndSequence();
       }
-      writer.writeElement(new ASN1Sequence(adElements));
+      writer.writeEndSequence();
 
 
       // The fourth element in the file should be an integer element that holds
       // the value to use to initialize the attribute description counter.
-      writer.writeElement(new ASN1Integer(adCounter.get()));
+      writer.writeInteger(adCounter.get());
 
 
       // Close the writer and swing the temp file into place.
-      writer.close();
+      outputStream.close();
       File liveFile = new File(path);
       File tempFile = new File(tempPath);
 
@@ -379,9 +358,9 @@
     {
       try
       {
-        if (writer != null)
+        if (outputStream != null)
         {
-          writer.close();
+          outputStream.close();
         }
       }
       catch (Exception e)
@@ -400,29 +379,27 @@
    * {@inheritDoc}
    */
   @Override()
-  public byte[] encodeObjectClasses(Map<ObjectClass,String> objectClasses)
+  public void encodeObjectClasses(ByteStringBuilder entryBuffer,
+                                  Map<ObjectClass,String> objectClasses)
          throws DirectoryException
   {
-    ByteArray encodedClasses = ocEncodeMap.get(objectClasses);
+    ByteSequence encodedClasses = ocEncodeMap.get(objectClasses);
     if (encodedClasses == null)
     {
       synchronized (ocEncodeMap)
       {
         int setValue = ocCounter.getAndIncrement();
-        byte[] array = encodeInt(setValue);
 
-        encodedClasses = new ByteArray(array);
+        encodedClasses = ByteString.wrap(encodeInt(setValue));
         ocEncodeMap.put(objectClasses, encodedClasses);
         ocDecodeMap.put(encodedClasses, objectClasses);
 
         save();
-        return array;
       }
     }
-    else
-    {
-      return encodedClasses.array();
-    }
+
+    entryBuffer.appendBERLength(encodedClasses.length());
+    encodedClasses.copyTo(entryBuffer);
   }
 
 
@@ -432,17 +409,17 @@
    */
   @Override()
   public Map<ObjectClass,String> decodeObjectClasses(
-                                      byte[] encodedObjectClasses)
-         throws DirectoryException
+      ByteSequenceReader entryBufferReader) throws DirectoryException
   {
-    ByteArray byteArray = new ByteArray(encodedObjectClasses);
+    int tokenLength = entryBufferReader.getBERLength();
+    ByteSequence byteArray = entryBufferReader.getByteSequence(tokenLength);
     Map<ObjectClass,String> ocMap = ocDecodeMap.get(byteArray);
     if (ocMap == null)
     {
-      Message message = ERR_COMPRESSEDSCHEMA_UNKNOWN_OC_TOKEN.get(
-                             bytesToHex(encodedObjectClasses));
+      Message message = ERR_COMPRESSEDSCHEMA_UNKNOWN_OC_TOKEN.get(byteArray
+          .toByteString().toHex());
       throw new DirectoryException(DirectoryServer.getServerErrorResultCode(),
-                                   message);
+          message);
     }
     else
     {
@@ -456,23 +433,22 @@
    * {@inheritDoc}
    */
   @Override()
-  public byte[] encodeAttribute(Attribute attribute)
-         throws DirectoryException
+  public void encodeAttribute(ByteStringBuilder entryBuffer,
+                              Attribute attribute) throws DirectoryException
   {
     AttributeType type = attribute.getAttributeType();
     Set<String> options = attribute.getOptions();
 
-    ConcurrentHashMap<Set<String>, ByteArray> map = adEncodeMap.get(type);
+    ConcurrentHashMap<Set<String>, ByteSequence> map = adEncodeMap.get(type);
     if (map == null)
     {
-      byte[] array;
+      ByteString byteArray;
       synchronized (adEncodeMap)
       {
-        map = new ConcurrentHashMap<Set<String>,ByteArray>(1);
+        map = new ConcurrentHashMap<Set<String>, ByteSequence>(1);
 
         int intValue = adCounter.getAndIncrement();
-        array = encodeInt(intValue);
-        ByteArray byteArray = new ByteArray(array);
+        byteArray = ByteString.wrap(encodeInt(intValue));
         map.put(options,byteArray);
 
         adEncodeMap.put(type, map);
@@ -481,32 +457,26 @@
         save();
       }
 
-      return encodeAttribute(array, attribute);
+      encodeAttribute(entryBuffer, byteArray, attribute);
     }
     else
     {
-      ByteArray byteArray = map.get(options);
+      ByteSequence byteArray = map.get(options);
       if (byteArray == null)
       {
-        byte[] array;
         synchronized (map)
         {
           int intValue = adCounter.getAndIncrement();
-          array = encodeInt(intValue);
-          byteArray = new ByteArray(array);
+          byteArray = ByteString.wrap(encodeInt(intValue));
           map.put(options,byteArray);
 
           atDecodeMap.put(byteArray, type);
           aoDecodeMap.put(byteArray, options);
           save();
         }
+      }
 
-        return encodeAttribute(array, attribute);
-      }
-      else
-      {
-        return encodeAttribute(byteArray.array(), attribute);
-      }
+      encodeAttribute(entryBuffer, byteArray, attribute);
     }
   }
 
@@ -516,50 +486,27 @@
    * Encodes the information in the provided attribute to a byte
    * array.
    *
+   * @param  buffer     The byte buffer to encode the attribute into.
    * @param  adArray    The byte array that is a placeholder for the
    *                    attribute type and set of options.
    * @param  attribute  The attribute to be encoded.
-   *
-   * @return  An encoded representation of the provided attribute.
    */
-  private byte[] encodeAttribute(byte[] adArray, Attribute attribute)
+  private void encodeAttribute(ByteStringBuilder buffer, ByteSequence adArray,
+                               Attribute attribute)
   {
-    int totalValuesLength = 0;
-    byte[][] subArrays = new  byte[attribute.size()*2][];
-    int pos = 0;
-    for (AttributeValue v : attribute)
+    // Write the length of the adArray followed by the adArray.
+    buffer.appendBERLength(adArray.length());
+    adArray.copyTo(buffer);
+
+    // Write the number of attributes
+    buffer.appendBERLength(attribute.size());
+
+    // Write the attribute values as length / value pairs
+    for(AttributeValue v : attribute)
     {
-      byte[] vBytes = v.getValueBytes();
-      byte[] lBytes = ASN1Element.encodeLength(vBytes.length);
-
-      subArrays[pos++] = lBytes;
-      subArrays[pos++] = vBytes;
-
-      totalValuesLength += lBytes.length + vBytes.length;
+      buffer.appendBERLength(v.getValue().length());
+      buffer.append(v.getValue());
     }
-
-    byte[] adArrayLength = ASN1Element.encodeLength(adArray.length);
-    byte[] countBytes = ASN1Element.encodeLength(attribute.size());
-    int totalLength = adArrayLength.length + adArray.length +
-                      countBytes.length + totalValuesLength;
-    byte[] array = new byte[totalLength];
-
-    System.arraycopy(adArrayLength, 0, array, 0,
-                     adArrayLength.length);
-    pos = adArrayLength.length;
-    System.arraycopy(adArray, 0, array, pos, adArray.length);
-    pos += adArray.length;
-    System.arraycopy(countBytes, 0, array, pos, countBytes.length);
-    pos += countBytes.length;
-
-    for (int i=0; i < subArrays.length; i++)
-    {
-      System.arraycopy(subArrays[i], 0, array, pos,
-                       subArrays[i].length);
-      pos += subArrays[i].length;
-    }
-
-    return array;
   }
 
 
@@ -568,75 +515,43 @@
    * {@inheritDoc}
    */
   @Override()
-  public Attribute decodeAttribute(byte[] encodedEntry, int startPos,
-                                   int length)
+  public Attribute decodeAttribute(ByteSequenceReader entryBufferReader)
          throws DirectoryException
   {
     // Figure out how many bytes are in the token that is the placeholder for
     // the attribute description.
-    int pos = startPos;
-    int adArrayLength = encodedEntry[pos] & 0x7F;
-    if (adArrayLength != encodedEntry[pos++])
-    {
-      int numLengthBytes = adArrayLength;
-      adArrayLength = 0;
-      for (int i=0; i < numLengthBytes; i++, pos++)
-      {
-        adArrayLength = (adArrayLength << 8) | (encodedEntry[pos] & 0xFF);
-      }
-    }
+    int adArrayLength = entryBufferReader.getBERLength();
 
 
     // Get the attribute description token and make sure it resolves to an
     // attribute type and option set.
-    ByteArray adArray = new ByteArray(new byte[adArrayLength]);
-    System.arraycopy(encodedEntry, pos, adArray.array(), 0, adArrayLength);
-    pos += adArrayLength;
+    ByteSequence adArray = entryBufferReader.getByteSequence(adArrayLength);
 
     AttributeType attrType = atDecodeMap.get(adArray);
     Set<String> options = aoDecodeMap.get(adArray);
     if ((attrType == null) || (options == null))
     {
-      Message message = ERR_COMPRESSEDSCHEMA_UNRECOGNIZED_AD_TOKEN.get(
-                             bytesToHex(adArray.array()));
+      Message message = ERR_COMPRESSEDSCHEMA_UNRECOGNIZED_AD_TOKEN.get(adArray
+          .toByteString().toHex());
       throw new DirectoryException(DirectoryServer.getServerErrorResultCode(),
-                                   message);
+          message);
     }
 
 
     // Determine the number of values for the attribute.
-    int numValues = encodedEntry[pos] & 0x7F;
-    if (numValues != encodedEntry[pos++])
-    {
-      int numValuesBytes = numValues;
-      numValues = 0;
-      for (int i=0; i < numValuesBytes; i++, pos++)
-      {
-        numValues = (numValues << 8) | (encodedEntry[pos] & 0xFF);
-      }
-    }
+    int numValues = entryBufferReader.getBERLength();
 
 
     // For the common case of a single value with no options, generate
     // less garbage.
     if (numValues == 1 && options.isEmpty())
     {
-      int valueLength = encodedEntry[pos] & 0x7F;
-      if (valueLength != encodedEntry[pos++])
-      {
-        int valueLengthBytes = valueLength;
-        valueLength = 0;
-        for (int j = 0; j < valueLengthBytes; j++, pos++)
-        {
-          valueLength = (valueLength << 8) | (encodedEntry[pos] & 0xFF);
-        }
-      }
+      int valueLength = entryBufferReader.getBERLength();
 
-      byte[] valueBytes = new byte[valueLength];
-      System.arraycopy(encodedEntry, pos, valueBytes, 0, valueLength);
-
-      return Attributes.create(attrType, new AttributeValue(attrType,
-          new ASN1OctetString(valueBytes)));
+      ByteString valueBytes =
+          entryBufferReader.getByteSequence(valueLength).toByteString();
+      return Attributes.create(attrType,
+          AttributeValues.create(attrType,valueBytes));
     }
     else
     {
@@ -646,22 +561,12 @@
       builder.setInitialCapacity(numValues);
       for (int i = 0; i < numValues; i++)
       {
-        int valueLength = encodedEntry[pos] & 0x7F;
-        if (valueLength != encodedEntry[pos++])
-        {
-          int valueLengthBytes = valueLength;
-          valueLength = 0;
-          for (int j = 0; j < valueLengthBytes; j++, pos++)
-          {
-            valueLength = (valueLength << 8) | (encodedEntry[pos] & 0xFF);
-          }
-        }
+        int valueLength = entryBufferReader.getBERLength();
 
-        byte[] valueBytes = new byte[valueLength];
-        System.arraycopy(encodedEntry, pos, valueBytes, 0, valueLength);
-        pos += valueLength;
-        builder.add(new AttributeValue(attrType,
-            new ASN1OctetString(valueBytes)));
+        ByteString valueBytes =
+            entryBufferReader.getByteSequence(valueLength).toByteString();
+        builder.add(AttributeValues.create(attrType,
+            valueBytes));
       }
 
       return builder.toAttribute();
diff --git a/opends/src/server/org/opends/server/core/DeleteOperationBasis.java b/opends/src/server/org/opends/server/core/DeleteOperationBasis.java
index 2bbd45b..9b9a733 100644
--- a/opends/src/server/org/opends/server/core/DeleteOperationBasis.java
+++ b/opends/src/server/org/opends/server/core/DeleteOperationBasis.java
@@ -47,7 +47,6 @@
 import org.opends.server.core.networkgroups.NetworkGroup;
 import org.opends.server.loggers.debug.DebugLogger;
 import org.opends.server.loggers.debug.DebugTracer;
-import org.opends.server.protocols.asn1.ASN1OctetString;
 import org.opends.server.types.*;
 import org.opends.server.types.operation.PostResponseDeleteOperation;
 import org.opends.server.types.operation.PreParseDeleteOperation;
@@ -137,7 +136,7 @@
 
     this.entryDN = entryDN;
 
-    rawEntryDN       = new ASN1OctetString(entryDN.toString());
+    rawEntryDN       = ByteString.valueOf(entryDN.toString());
     responseControls = new ArrayList<Control>();
     cancelRequest    = null;
     changeNumber     = -1;
diff --git a/opends/src/server/org/opends/server/core/DirectoryServer.java b/opends/src/server/org/opends/server/core/DirectoryServer.java
index 9551fdc..f7dbdc3 100644
--- a/opends/src/server/org/opends/server/core/DirectoryServer.java
+++ b/opends/src/server/org/opends/server/core/DirectoryServer.java
@@ -26,11 +26,60 @@
  */
 package org.opends.server.core;
 
+import static org.opends.messages.ConfigMessages.*;
+import static org.opends.messages.CoreMessages.*;
+import static org.opends.messages.ToolMessages.*;
+import static org.opends.server.config.ConfigConstants.*;
+import static org.opends.server.loggers.AccessLogger.*;
+import static org.opends.server.loggers.ErrorLogger.*;
+import static org.opends.server.loggers.debug.DebugLogger.*;
+import static org.opends.server.schema.SchemaConstants.*;
+import static org.opends.server.util.DynamicConstants.*;
+import static org.opends.server.util.ServerConstants.*;
+import static org.opends.server.util.StaticUtils.*;
+import static org.opends.server.util.Validator.*;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.PrintStream;
+import java.net.InetAddress;
+import java.text.DecimalFormat;
+import java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+import java.util.TreeMap;
+import java.util.TreeSet;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.concurrent.CopyOnWriteArraySet;
+
+import javax.management.MBeanServer;
+import javax.management.MBeanServerFactory;
+
+import org.opends.messages.Message;
+import org.opends.messages.MessageDescriptor;
 import org.opends.server.admin.AdministrationDataSync;
 import org.opends.server.admin.ClassLoaderProvider;
 import org.opends.server.admin.server.ServerManagementContext;
 import org.opends.server.admin.std.meta.GlobalCfgDefn.WorkflowConfigurationMode;
-import org.opends.server.admin.std.server.*;
+import org.opends.server.admin.std.server.AlertHandlerCfg;
+import org.opends.server.admin.std.server.AttributeSyntaxCfg;
+import org.opends.server.admin.std.server.ConnectionHandlerCfg;
+import org.opends.server.admin.std.server.CryptoManagerCfg;
+import org.opends.server.admin.std.server.DirectoryStringAttributeSyntaxCfg;
+import org.opends.server.admin.std.server.MonitorProviderCfg;
+import org.opends.server.admin.std.server.PasswordValidatorCfg;
+import org.opends.server.admin.std.server.RootCfg;
+import org.opends.server.admin.std.server.RootDSEBackendCfg;
+import org.opends.server.admin.std.server.SynchronizationProviderCfg;
+import org.opends.server.api.AccessControlHandler;
 import org.opends.server.api.AccountStatusNotificationHandler;
 import org.opends.server.api.AlertGenerator;
 import org.opends.server.api.AlertHandler;
@@ -53,13 +102,14 @@
 import org.opends.server.api.EqualityMatchingRule;
 import org.opends.server.api.ExportTaskListener;
 import org.opends.server.api.ExtendedOperationHandler;
+import org.opends.server.api.Extension;
 import org.opends.server.api.IdentityMapper;
 import org.opends.server.api.ImportTaskListener;
 import org.opends.server.api.InitializationCompletedListener;
 import org.opends.server.api.InvokableComponent;
 import org.opends.server.api.KeyManagerProvider;
-import org.opends.server.api.Extension;
 import org.opends.server.api.MatchingRule;
+import org.opends.server.api.MatchingRuleFactory;
 import org.opends.server.api.MonitorProvider;
 import org.opends.server.api.OrderingMatchingRule;
 import org.opends.server.api.PasswordGenerator;
@@ -72,14 +122,10 @@
 import org.opends.server.api.SynchronizationProvider;
 import org.opends.server.api.TrustManagerProvider;
 import org.opends.server.api.WorkQueue;
-import org.opends.server.api.AccessControlHandler;
-import org.opends.server.api.plugin.PluginType;
 import org.opends.server.api.plugin.PluginResult;
+import org.opends.server.api.plugin.PluginType;
 import org.opends.server.api.ExtensibleMatchingRule;
 import org.opends.server.backends.RootDSEBackend;
-import static org.opends.server.config.ConfigConstants.DN_CONFIG_ROOT;
-import static org.opends.server.config.ConfigConstants.DN_MONITOR_ROOT;
-import static org.opends.server.config.ConfigConstants.ENV_VAR_INSTALL_ROOT;
 import org.opends.server.config.ConfigEntry;
 import org.opends.server.config.ConfigException;
 import org.opends.server.config.JMXMBean;
@@ -87,22 +133,22 @@
 import org.opends.server.controls.PasswordPolicyResponseControl;
 import org.opends.server.core.networkgroups.NetworkGroup;
 import org.opends.server.core.networkgroups.NetworkGroupConfigManager;
+import org.opends.server.crypto.CryptoManagerImpl;
+import org.opends.server.crypto.CryptoManagerSync;
 import org.opends.server.extensions.ConfigFileHandler;
 import org.opends.server.extensions.JMXAlertHandler;
-import static org.opends.server.loggers.AccessLogger.*;
-import static org.opends.server.loggers.ErrorLogger.*;
-import org.opends.server.loggers.*;
-import static org.opends.server.loggers.debug.DebugLogger.*;
-import org.opends.server.loggers.debug.DebugTracer;
+import org.opends.server.loggers.ErrorLogger;
+import org.opends.server.loggers.RetentionPolicy;
+import org.opends.server.loggers.RotationPolicy;
+import org.opends.server.loggers.TextErrorLogPublisher;
+import org.opends.server.loggers.TextWriter;
 import org.opends.server.loggers.debug.DebugLogger;
+import org.opends.server.loggers.debug.DebugTracer;
 import org.opends.server.loggers.debug.TextDebugLogPublisher;
-
-import org.opends.messages.MessageDescriptor;
-import org.opends.messages.Message;
-import static org.opends.messages.CoreMessages.*;
-import static org.opends.messages.ToolMessages.*;
 import org.opends.server.monitors.BackendMonitor;
 import org.opends.server.monitors.ConnectionHandlerMonitor;
+import org.opends.server.protocols.internal.InternalClientConnection;
+import org.opends.server.protocols.internal.InternalConnectionHandler;
 import org.opends.server.schema.AttributeTypeSyntax;
 import org.opends.server.schema.BinarySyntax;
 import org.opends.server.schema.BooleanEqualityMatchingRuleFactory;
@@ -134,10 +180,10 @@
 import org.opends.server.schema.OctetStringEqualityMatchingRuleFactory;
 import org.opends.server.schema.OctetStringOrderingMatchingRuleFactory;
 import org.opends.server.schema.OctetStringSubstringMatchingRuleFactory;
-import static org.opends.server.schema.SchemaConstants.*;
 import org.opends.server.schema.TelephoneNumberEqualityMatchingRuleFactory;
 import org.opends.server.schema.TelephoneNumberSubstringMatchingRuleFactory;
 import org.opends.server.schema.TelephoneNumberSyntax;
+import org.opends.server.servicetag.ServiceTagRegistration;
 import org.opends.server.tools.ConfigureWindowsService;
 import org.opends.server.types.AbstractOperation;
 import org.opends.server.types.AcceptRejectWarn;
@@ -146,17 +192,18 @@
 import org.opends.server.types.AttributeValue;
 import org.opends.server.types.BackupConfig;
 import org.opends.server.types.Control;
-import org.opends.server.crypto.CryptoManagerImpl;
 import org.opends.server.types.DITContentRule;
 import org.opends.server.types.DITStructureRule;
 import org.opends.server.types.DN;
 import org.opends.server.types.DebugLogLevel;
+import org.opends.server.types.DirectoryEnvironmentConfig;
 import org.opends.server.types.DirectoryException;
 import org.opends.server.types.Entry;
 import org.opends.server.types.HostPort;
 import org.opends.server.types.InitializationException;
 import org.opends.server.types.LDIFExportConfig;
 import org.opends.server.types.LDIFImportConfig;
+import org.opends.server.types.LockManager;
 import org.opends.server.types.MatchingRuleUse;
 import org.opends.server.types.Modification;
 import org.opends.server.types.NameForm;
@@ -170,12 +217,6 @@
 import org.opends.server.types.Schema;
 import org.opends.server.types.VirtualAttributeRule;
 import org.opends.server.types.WritabilityMode;
-import org.opends.server.types.DirectoryEnvironmentConfig;
-import org.opends.server.types.LockManager;
-import static org.opends.server.util.DynamicConstants.*;
-import static org.opends.server.util.ServerConstants.*;
-import static org.opends.server.util.StaticUtils.*;
-import static org.opends.server.util.Validator.ensureNotNull;
 import org.opends.server.util.MultiOutputStream;
 import org.opends.server.util.RuntimeInformation;
 import org.opends.server.util.SetupUtils;
@@ -189,28 +230,8 @@
 import org.opends.server.util.args.StringArgument;
 import org.opends.server.workflowelement.WorkflowElement;
 import org.opends.server.workflowelement.WorkflowElementConfigManager;
-import
-  org.opends.server.workflowelement.localbackend.LocalBackendWorkflowElement;
-import org.opends.server.protocols.internal.InternalConnectionHandler;
-import org.opends.server.protocols.internal.InternalClientConnection;
-import org.opends.server.crypto.CryptoManagerSync;
-import org.opends.server.servicetag.ServiceTagRegistration;
-import static org.opends.messages.ConfigMessages.*;
-
-import javax.management.MBeanServer;
-import javax.management.MBeanServerFactory;
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.OutputStream;
-import java.io.PrintStream;
-import java.net.InetAddress;
-import java.text.DecimalFormat;
-import java.util.*;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.CopyOnWriteArrayList;
-import java.util.concurrent.CopyOnWriteArraySet;
-import org.opends.server.api.MatchingRuleFactory;
+import org.opends.server.workflowelement.
+    localbackend.LocalBackendWorkflowElement;
 
 
 /**
@@ -642,7 +663,7 @@
   private MonitorConfigManager monitorConfigManager;
 
   // The operating system on which the server is running.
-  private OperatingSystem operatingSystem;
+  private final OperatingSystem operatingSystem;
 
   // The configuration handler used to manage the password generators.
   private PasswordGeneratorConfigManager passwordGeneratorConfigManager;
@@ -731,7 +752,7 @@
 
   // The mappings between the names and WorkflowElements
   // registered with the Directory Server
-  private ConcurrentHashMap<String, WorkflowElement> workflowElements =
+  private final ConcurrentHashMap<String, WorkflowElement> workflowElements =
           new ConcurrentHashMap<String, WorkflowElement>();
 
   // The workflow configuration mode (auto or manual).
@@ -2358,7 +2379,7 @@
         workflowID,
         baseDN,
         rootWE.getWorkflowElementID(),
-        (WorkflowElement) rootWE);
+        rootWE);
     workflowImpl.register();
 
     return workflowImpl;
@@ -3044,7 +3065,7 @@
       if (serverRoot != null)
       {
         File instanceRoot =
-          directoryServer.environmentConfig.getInstanceRootFromServerRoot(
+          DirectoryEnvironmentConfig.getInstanceRootFromServerRoot(
               serverRoot);
         if (instanceRoot != null)
         {
@@ -5278,8 +5299,7 @@
       directoryServer.defaultPasswordPolicyConfig = null;
     }
 
-    PasswordPolicyConfig config
-            = directoryServer.passwordPolicies.remove(configEntryDN);
+    directoryServer.passwordPolicies.remove(configEntryDN);
   }
 
 
@@ -8076,9 +8096,8 @@
       directoryServer.shuttingDown = true;
     }
 
-    ConfigEntry rootConfigEntry = null;
     try {
-      rootConfigEntry = directoryServer.configHandler.getConfigRootEntry();
+      directoryServer.configHandler.getConfigRootEntry();
     } catch (Exception e) {
 
     }
@@ -9544,7 +9563,7 @@
   public static DN getMonitorProviderDN(MonitorProvider provider)
   {
     String monitorName = provider.getMonitorInstanceName();
-    AttributeType cnType = getAttributeType(ATTR_COMMON_NAME);
+    getAttributeType(ATTR_COMMON_NAME);
     DN monitorRootDN;
     try
     {
@@ -9848,7 +9867,7 @@
     synchronized (directoryServer)
     {
       if (directoryServer.workflowElements.containsKey(workflowElementID)) {
-        Message message = ERR_REGISTER_WORKFLOW_ELEMENT_ALREADY_EXISTS.get(
+        ERR_REGISTER_WORKFLOW_ELEMENT_ALREADY_EXISTS.get(
                 workflowElementID);
       } else {
         directoryServer.workflowElements.put(workflowElementID, we);
diff --git a/opends/src/server/org/opends/server/core/ExtendedOperation.java b/opends/src/server/org/opends/server/core/ExtendedOperation.java
index 274ac3a..455140c 100644
--- a/opends/src/server/org/opends/server/core/ExtendedOperation.java
+++ b/opends/src/server/org/opends/server/core/ExtendedOperation.java
@@ -26,9 +26,8 @@
  */
 package org.opends.server.core;
 
-import org.opends.server.protocols.asn1.ASN1OctetString;
 import org.opends.server.types.Operation;
-
+import org.opends.server.types.ByteString;
 
 
 /**
@@ -56,7 +55,7 @@
    * @return  The value for the request associated with this extended
    *          operation.
    */
-  public ASN1OctetString getRequestValue();
+  public ByteString getRequestValue();
 
 
 
@@ -84,7 +83,7 @@
    *
    * @return  The value to include in the response to the client.
    */
-  public ASN1OctetString getResponseValue();
+  public ByteString getResponseValue();
 
 
 
@@ -94,7 +93,7 @@
    * @param  responseValue  The value to include in the response to
    *                        the client.
    */
-  public void setResponseValue(ASN1OctetString responseValue);
+  public void setResponseValue(ByteString responseValue);
 
   /**
    * Indicates that the response for this extended operation has been sent from
diff --git a/opends/src/server/org/opends/server/core/ExtendedOperationBasis.java b/opends/src/server/org/opends/server/core/ExtendedOperationBasis.java
index 195ee47..527f19a 100644
--- a/opends/src/server/org/opends/server/core/ExtendedOperationBasis.java
+++ b/opends/src/server/org/opends/server/core/ExtendedOperationBasis.java
@@ -35,7 +35,6 @@
 import org.opends.server.api.ClientConnection;
 import org.opends.server.api.ExtendedOperationHandler;
 import org.opends.server.api.plugin.PluginResult;
-import org.opends.server.protocols.asn1.ASN1OctetString;
 import org.opends.server.types.operation.PostOperationExtendedOperation;
 import org.opends.server.types.operation.PostResponseExtendedOperation;
 import org.opends.server.types.operation.PreOperationExtendedOperation;
@@ -71,10 +70,10 @@
   private static final DebugTracer TRACER = DebugLogger.getTracer();
 
   // The value for the request associated with this extended operation.
-  private ASN1OctetString requestValue;
+  private ByteString requestValue;
 
   // The value for the response associated with this extended operation.
-  private ASN1OctetString responseValue;
+  private ByteString responseValue;
 
   // Indicates whether a response has yet been sent for this operation.
   private boolean responseSent;
@@ -107,7 +106,7 @@
   public ExtendedOperationBasis(ClientConnection clientConnection,
                            long operationID,
                            int messageID, List<Control> requestControls,
-                           String requestOID, ASN1OctetString requestValue)
+                           String requestOID, ByteString requestValue)
   {
     super(clientConnection, operationID, messageID, requestControls);
 
@@ -162,7 +161,7 @@
   /**
    * {@inheritDoc}
    */
-  public final ASN1OctetString getRequestValue()
+  public final ByteString getRequestValue()
   {
     return requestValue;
   }
@@ -176,7 +175,7 @@
    * @param  requestValue  The value for the request associated with this
    *                       extended operation.
    */
-  public final void setRequestValue(ASN1OctetString requestValue)
+  public final void setRequestValue(ByteString requestValue)
   {
     this.requestValue = requestValue;
   }
@@ -206,7 +205,7 @@
   /**
    * {@inheritDoc}
    */
-  public final ASN1OctetString getResponseValue()
+  public final ByteString getResponseValue()
   {
     return responseValue;
   }
@@ -216,7 +215,7 @@
   /**
    * {@inheritDoc}
    */
-  public final void setResponseValue(ASN1OctetString responseValue)
+  public final void setResponseValue(ByteString responseValue)
   {
     this.responseValue = responseValue;
   }
@@ -469,10 +468,10 @@
             pluginConfigManager.invokePreOperationExtendedPlugins(this);
         if(!preOpResult.continueProcessing())
         {
-          setResultCode(preParseResult.getResultCode());
-          appendErrorMessage(preParseResult.getErrorMessage());
-          setMatchedDN(preParseResult.getMatchedDN());
-          setReferralURLs(preParseResult.getReferralURLs());
+          setResultCode(preOpResult.getResultCode());
+          appendErrorMessage(preOpResult.getErrorMessage());
+          setMatchedDN(preOpResult.getMatchedDN());
+          setReferralURLs(preOpResult.getReferralURLs());
           return;
         }
 
diff --git a/opends/src/server/org/opends/server/core/GroupManager.java b/opends/src/server/org/opends/server/core/GroupManager.java
index b7f7687..5eddc18 100644
--- a/opends/src/server/org/opends/server/core/GroupManager.java
+++ b/opends/src/server/org/opends/server/core/GroupManager.java
@@ -49,6 +49,7 @@
 import org.opends.server.loggers.debug.DebugTracer;
 import org.opends.server.protocols.internal.InternalClientConnection;
 import org.opends.server.protocols.internal.InternalSearchOperation;
+import org.opends.server.protocols.ldap.LDAPControl;
 import org.opends.server.types.ConfigChangeResult;
 import org.opends.server.types.Control;
 import org.opends.server.types.DebugLogLevel;
@@ -581,7 +582,7 @@
          InternalClientConnection.getRootConnection();
 
     LinkedList<Control> requestControls = new LinkedList<Control>();
-    requestControls.add(new Control(OID_INTERNAL_GROUP_MEMBERSHIP_UPDATE,
+    requestControls.add(new LDAPControl(OID_INTERNAL_GROUP_MEMBERSHIP_UPDATE,
                                     false));
     for (DN configEntryDN : groupImplementations.keySet())
     {
diff --git a/opends/src/server/org/opends/server/core/ModifyDNOperation.java b/opends/src/server/org/opends/server/core/ModifyDNOperation.java
index 7f6ac9d..9e58c8b 100644
--- a/opends/src/server/org/opends/server/core/ModifyDNOperation.java
+++ b/opends/src/server/org/opends/server/core/ModifyDNOperation.java
@@ -27,12 +27,8 @@
 package org.opends.server.core;
 
 import java.util.List;
-import org.opends.server.types.ByteString;
-import org.opends.server.types.DN;
-import org.opends.server.types.Entry;
-import org.opends.server.types.Modification;
-import org.opends.server.types.Operation;
-import org.opends.server.types.RDN;
+
+import org.opends.server.types.*;
 import org.opends.server.types.operation.SubordinateModifyDNOperation;
 
 /**
diff --git a/opends/src/server/org/opends/server/core/ModifyDNOperationBasis.java b/opends/src/server/org/opends/server/core/ModifyDNOperationBasis.java
index 65db06b..ca97939 100644
--- a/opends/src/server/org/opends/server/core/ModifyDNOperationBasis.java
+++ b/opends/src/server/org/opends/server/core/ModifyDNOperationBasis.java
@@ -22,7 +22,7 @@
  * CDDL HEADER END
  *
  *
- *      Copyright 2006-2008 Sun Microsystems, Inc.
+ *      Copyright 2006-2009 Sun Microsystems, Inc.
  */
 package org.opends.server.core;
 import org.opends.messages.MessageBuilder;
@@ -33,7 +33,6 @@
 import org.opends.server.api.ClientConnection;
 import org.opends.server.api.plugin.PluginResult;
 import org.opends.server.core.networkgroups.NetworkGroup;
-import org.opends.server.protocols.asn1.ASN1OctetString;
 import org.opends.server.types.operation.PostResponseModifyDNOperation;
 import org.opends.server.types.operation.PreParseModifyDNOperation;
 import static org.opends.server.core.CoreConstants.*;
@@ -176,8 +175,8 @@
     this.deleteOldRDN = deleteOldRDN;
     this.newSuperior  = newSuperior;
 
-    rawEntryDN = new ASN1OctetString(entryDN.toString());
-    rawNewRDN  = new ASN1OctetString(newRDN.toString());
+    rawEntryDN = ByteString.valueOf(entryDN.toString());
+    rawNewRDN  = ByteString.valueOf(newRDN.toString());
 
     if (newSuperior == null)
     {
@@ -185,7 +184,7 @@
     }
     else
     {
-      rawNewSuperior = new ASN1OctetString(newSuperior.toString());
+      rawNewSuperior = ByteString.valueOf(newSuperior.toString());
     }
 
     responseControls = new ArrayList<Control>();
@@ -270,7 +269,7 @@
     {
       if (newRDN == null)
       {
-        newRDN = RDN.decode(rawNewRDN.stringValue());
+        newRDN = RDN.decode(rawNewRDN.toString());
       }
     }
     catch (DirectoryException de)
@@ -444,7 +443,7 @@
     }
     else
     {
-      newSuperiorStr = rawNewSuperior.stringValue();
+      newSuperiorStr = rawNewSuperior.toString();
     }
 
     return new String[][]
@@ -572,6 +571,7 @@
    * managing synchronization, and any other work that might need to
    * be done in the course of processing.
    */
+  @Override
   public final void run()
   {
     setResultCode(ResultCode.UNDEFINED);
diff --git a/opends/src/server/org/opends/server/core/ModifyDNOperationWrapper.java b/opends/src/server/org/opends/server/core/ModifyDNOperationWrapper.java
index db948cf..22d8182 100644
--- a/opends/src/server/org/opends/server/core/ModifyDNOperationWrapper.java
+++ b/opends/src/server/org/opends/server/core/ModifyDNOperationWrapper.java
@@ -27,11 +27,8 @@
 package org.opends.server.core;
 
 import java.util.List;
-import org.opends.server.types.ByteString;
-import org.opends.server.types.DN;
-import org.opends.server.types.Entry;
-import org.opends.server.types.Modification;
-import org.opends.server.types.RDN;
+
+import org.opends.server.types.*;
 
 /**
  * This abstract class wraps/decorates a given moddn operation.
diff --git a/opends/src/server/org/opends/server/core/ModifyOperation.java b/opends/src/server/org/opends/server/core/ModifyOperation.java
index 388e1b3..e779c0a 100644
--- a/opends/src/server/org/opends/server/core/ModifyOperation.java
+++ b/opends/src/server/org/opends/server/core/ModifyOperation.java
@@ -28,12 +28,7 @@
 
 import java.util.List;
 
-import org.opends.server.types.ByteString;
-import org.opends.server.types.DN;
-import org.opends.server.types.DirectoryException;
-import org.opends.server.types.Modification;
-import org.opends.server.types.Operation;
-import org.opends.server.types.RawModification;
+import org.opends.server.types.*;
 
 /**
  * This interface defines an operation used to modify an entry in
diff --git a/opends/src/server/org/opends/server/core/ModifyOperationBasis.java b/opends/src/server/org/opends/server/core/ModifyOperationBasis.java
index 43474bd..8a2a229 100644
--- a/opends/src/server/org/opends/server/core/ModifyOperationBasis.java
+++ b/opends/src/server/org/opends/server/core/ModifyOperationBasis.java
@@ -46,7 +46,6 @@
 import org.opends.server.core.networkgroups.NetworkGroup;
 import org.opends.server.loggers.debug.DebugLogger;
 import org.opends.server.loggers.debug.DebugTracer;
-import org.opends.server.protocols.asn1.ASN1OctetString;
 import org.opends.server.protocols.ldap.LDAPAttribute;
 import org.opends.server.protocols.ldap.LDAPModification;
 import org.opends.server.types.*;
@@ -150,7 +149,7 @@
     this.entryDN       = entryDN;
     this.modifications = modifications;
 
-    rawEntryDN = new ASN1OctetString(entryDN.toString());
+    rawEntryDN = ByteString.valueOf(entryDN.toString());
 
     rawModifications = new ArrayList<RawModification>(modifications.size());
     for (Modification m : modifications)
diff --git a/opends/src/server/org/opends/server/core/ModifyOperationWrapper.java b/opends/src/server/org/opends/server/core/ModifyOperationWrapper.java
index 69e14db..d2fd62f 100644
--- a/opends/src/server/org/opends/server/core/ModifyOperationWrapper.java
+++ b/opends/src/server/org/opends/server/core/ModifyOperationWrapper.java
@@ -28,11 +28,8 @@
 
 
 import java.util.List;
-import org.opends.server.types.ByteString;
-import org.opends.server.types.DN;
-import org.opends.server.types.DirectoryException;
-import org.opends.server.types.Modification;
-import org.opends.server.types.RawModification;
+
+import org.opends.server.types.*;
 
 
 /**
diff --git a/opends/src/server/org/opends/server/core/OperationWrapper.java b/opends/src/server/org/opends/server/core/OperationWrapper.java
index 02684d7..e077fa9 100644
--- a/opends/src/server/org/opends/server/core/OperationWrapper.java
+++ b/opends/src/server/org/opends/server/core/OperationWrapper.java
@@ -34,6 +34,7 @@
 
 import org.opends.server.api.ClientConnection;
 import org.opends.server.types.*;
+import org.opends.server.controls.ControlDecoder;
 
 
 /**
@@ -296,6 +297,15 @@
   /**
    * {@inheritDoc}
    */
+  public <T extends Control> T getRequestControl(
+      ControlDecoder<T> d)throws DirectoryException
+  {
+    return operation.getRequestControl(d);
+  }
+
+  /**
+   * {@inheritDoc}
+   */
   public String[][] getRequestLogElements()
   {
     return operation.getRequestLogElements();
diff --git a/opends/src/server/org/opends/server/core/PasswordPolicy.java b/opends/src/server/org/opends/server/core/PasswordPolicy.java
index 86b48ef..9cbd63c 100644
--- a/opends/src/server/org/opends/server/core/PasswordPolicy.java
+++ b/opends/src/server/org/opends/server/core/PasswordPolicy.java
@@ -50,13 +50,8 @@
 import org.opends.server.api.PasswordValidator;
 import org.opends.server.config.ConfigException;
 import org.opends.server.loggers.debug.DebugTracer;
-import org.opends.server.protocols.asn1.ASN1OctetString;
 import org.opends.server.schema.GeneralizedTimeSyntax;
-import org.opends.server.types.AttributeType;
-import org.opends.server.types.ByteString;
-import org.opends.server.types.DebugLogLevel;
-import org.opends.server.types.DN;
-import org.opends.server.types.InitializationException;
+import org.opends.server.types.*;
 
 import static org.opends.messages.CoreMessages.*;
 import static org.opends.server.config.ConfigConstants.*;
@@ -502,7 +497,7 @@
     {
       if (requireChangeBy != null)
       {
-        ByteString valueString = new ASN1OctetString(requireChangeBy);
+        ByteString valueString = ByteString.valueOf(requireChangeBy);
 
         GeneralizedTimeSyntax syntax =
              (GeneralizedTimeSyntax)
diff --git a/opends/src/server/org/opends/server/core/PasswordPolicyState.java b/opends/src/server/org/opends/server/core/PasswordPolicyState.java
index a709199..b8a9c9c 100644
--- a/opends/src/server/org/opends/server/core/PasswordPolicyState.java
+++ b/opends/src/server/org/opends/server/core/PasswordPolicyState.java
@@ -52,31 +52,12 @@
 import org.opends.server.api.PasswordValidator;
 import org.opends.server.loggers.ErrorLogger;
 import org.opends.server.loggers.debug.DebugTracer;
-import org.opends.server.protocols.asn1.ASN1OctetString;
 import org.opends.server.protocols.internal.InternalClientConnection;
 import org.opends.server.protocols.ldap.LDAPAttribute;
 import org.opends.server.schema.AuthPasswordSyntax;
 import org.opends.server.schema.GeneralizedTimeSyntax;
 import org.opends.server.schema.UserPasswordSyntax;
-import org.opends.server.types.AccountStatusNotification;
-import org.opends.server.types.AccountStatusNotificationProperty;
-import org.opends.server.types.AccountStatusNotificationType;
-import org.opends.server.types.Attribute;
-import org.opends.server.types.AttributeBuilder;
-import org.opends.server.types.AttributeType;
-import org.opends.server.types.AttributeValue;
-import org.opends.server.types.Attributes;
-import org.opends.server.types.ByteString;
-import org.opends.server.types.ConditionResult;
-import org.opends.server.types.DebugLogLevel;
-import org.opends.server.types.DirectoryException;
-import org.opends.server.types.DN;
-import org.opends.server.types.Entry;
-import org.opends.server.types.Modification;
-import org.opends.server.types.ModificationType;
-import org.opends.server.types.Operation;
-import org.opends.server.types.RawModification;
-import org.opends.server.types.ResultCode;
+import org.opends.server.types.*;
 import org.opends.server.util.TimeThread;
 
 import static org.opends.server.config.ConfigConstants.*;
@@ -317,12 +298,12 @@
           {
             TRACER.debugError("Could not parse password policy subentry " +
                 "DN %s for user %s: %s",
-                       v.getStringValue(), userDNString,
+                       v.getValue().toString(), userDNString,
                        stackTraceToSingleLineString(e));
           }
 
           Message message = ERR_PWPSTATE_CANNOT_DECODE_SUBENTRY_VALUE_AS_DN.get(
-              v.getStringValue(), userDNString, e.getMessage());
+              v.getValue().toString(), userDNString, e.getMessage());
           if (useDefaultOnError)
           {
             ErrorLogger.logError(message);
@@ -400,7 +381,7 @@
       {
         if (a.isEmpty()) continue;
 
-        stringValue = a.iterator().next().getStringValue();
+        stringValue = a.iterator().next().getValue().toString();
         break ;
       }
     }
@@ -466,12 +447,12 @@
 
             TRACER.debugWarning("Unable to decode value %s for attribute %s " +
                 "in user entry %s: %s",
-                v.getStringValue(), attributeType.getNameOrOID(),
+                v.getValue().toString(), attributeType.getNameOrOID(),
                 userDNString, stackTraceToSingleLineString(e));
           }
 
           Message message = ERR_PWPSTATE_CANNOT_DECODE_GENERALIZED_TIME.
-              get(v.getStringValue(), attributeType.getNameOrOID(),
+              get(v.getValue().toString(), attributeType.getNameOrOID(),
                   userDNString, String.valueOf(e));
           throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX,
                                        message, e);
@@ -534,12 +515,12 @@
 
               TRACER.debugWarning("Unable to decode value %s for attribute %s" +
                   "in user entry %s: %s",
-                  v.getStringValue(), attributeType.getNameOrOID(),
+                  v.getValue().toString(), attributeType.getNameOrOID(),
                   userDNString, stackTraceToSingleLineString(e));
             }
 
             Message message = ERR_PWPSTATE_CANNOT_DECODE_GENERALIZED_TIME.
-                get(v.getStringValue(), attributeType.getNameOrOID(),
+                get(v.getValue().toString(), attributeType.getNameOrOID(),
                     userDNString, String.valueOf(e));
             throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX,
                                          message, e);
@@ -586,7 +567,7 @@
         if (a.isEmpty()) continue;
 
         String valueString
-             = toLowerCase(a.iterator().next().getStringValue());
+             = toLowerCase(a.iterator().next().getValue().toString());
 
         if (valueString.equals("true") || valueString.equals("yes") ||
             valueString.equals("on") || valueString.equals("1"))
@@ -1212,7 +1193,7 @@
             valuesToRemove = new LinkedHashSet<AttributeValue>();
           }
 
-          valuesToRemove.add(new AttributeValue(type,
+          valuesToRemove.add(AttributeValues.create(type,
                                               GeneralizedTimeSyntax.format(l)));
         }
       }
@@ -1231,7 +1212,7 @@
             for (Long l : authFailureTimes)
             {
               builder.add(
-                   new AttributeValue(type, GeneralizedTimeSyntax.format(l)));
+                 AttributeValues.create(type, GeneralizedTimeSyntax.format(l)));
             }
             ArrayList<Attribute> keepList = new ArrayList<Attribute>(1);
             keepList.add(builder.toAttribute());
@@ -1308,13 +1289,14 @@
     AttributeBuilder builder = new AttributeBuilder(type);
     for (Long l : failureTimes)
     {
-      builder.add(new AttributeValue(type, GeneralizedTimeSyntax.format(l)));
+      builder.add(AttributeValues.create(type,
+          GeneralizedTimeSyntax.format(l)));
     }
 
     ArrayList<Attribute> attrList = new ArrayList<Attribute>(1);
     attrList.add(builder.toAttribute());
 
-    Attribute addAttr = Attributes.create(type, new AttributeValue(type,
+    Attribute addAttr = Attributes.create(type, AttributeValues.create(type,
         GeneralizedTimeSyntax.format(highestFailureTime)));
 
     if (updateEntry)
@@ -1374,7 +1356,7 @@
     for (Long l : authFailureTimes)
     {
       builder
-          .add(new AttributeValue(type, GeneralizedTimeSyntax.format(l)));
+          .add(AttributeValues.create(type, GeneralizedTimeSyntax.format(l)));
     }
     Attribute a = builder.toAttribute();
 
@@ -1516,7 +1498,7 @@
                                   OP_ATTR_PWPOLICY_LOCKED_TIME);
     }
 
-    Attribute a = Attributes.create(type, new AttributeValue(type,
+    Attribute a = Attributes.create(type, AttributeValues.create(type,
         GeneralizedTimeSyntax.format(failureLockedTime)));
 
     if (updateEntry)
@@ -1769,7 +1751,7 @@
       {
         if (a.isEmpty()) continue;
 
-        String valueString = a.iterator().next().getStringValue();
+        String valueString = a.iterator().next().getValue().toString();
 
         try
         {
@@ -3011,7 +2993,7 @@
       AttributeBuilder builder = new AttributeBuilder(type);
       for (Long l : graceTimes)
       {
-        builder.add(new AttributeValue(type, GeneralizedTimeSyntax
+        builder.add(AttributeValues.create(type, GeneralizedTimeSyntax
             .format(l)));
       }
 
@@ -3022,7 +3004,7 @@
     }
     else
     {
-      Attribute addAttr = Attributes.create(type, new AttributeValue(
+      Attribute addAttr = Attributes.create(type, AttributeValues.create(
           type, GeneralizedTimeSyntax.format(highestGraceTime)));
 
       modifications.add(new Modification(ModificationType.ADD, addAttr, true));
@@ -3058,7 +3040,7 @@
     for (Long l : graceLoginTimes)
     {
       builder
-          .add(new AttributeValue(type, GeneralizedTimeSyntax.format(l)));
+          .add(AttributeValues.create(type, GeneralizedTimeSyntax.format(l)));
     }
     Attribute a = builder.toAttribute();
 
@@ -3146,12 +3128,12 @@
           if (usesAuthPasswordSyntax)
           {
             pwComponents =
-                 AuthPasswordSyntax.decodeAuthPassword(v.getStringValue());
+                 AuthPasswordSyntax.decodeAuthPassword(v.getValue().toString());
           }
           else
           {
             String[] userPwComponents =
-                 UserPasswordSyntax.decodeUserPassword(v.getStringValue());
+                 UserPasswordSyntax.decodeUserPassword(v.getValue().toString());
             pwComponents = new StringBuilder[userPwComponents.length];
             for (int i = 0; i < userPwComponents.length; ++i)
             {
@@ -3182,7 +3164,7 @@
                                pwComponents[1].toString(),
                                pwComponents[2].toString())
                          : scheme.getPlaintextValue(
-                               new ASN1OctetString(pwComponents[1].toString()));
+                ByteString.valueOf(pwComponents[1].toString()));
             clearPasswords.add(clearValue);
           }
         }
@@ -3244,12 +3226,12 @@
           if (usesAuthPasswordSyntax)
           {
             pwComponents =
-                 AuthPasswordSyntax.decodeAuthPassword(v.getStringValue());
+                 AuthPasswordSyntax.decodeAuthPassword(v.getValue().toString());
           }
           else
           {
             String[] userPwComponents =
-                 UserPasswordSyntax.decodeUserPassword(v.getStringValue());
+                 UserPasswordSyntax.decodeUserPassword(v.getValue().toString());
             pwComponents = new StringBuilder[userPwComponents.length];
             for (int i = 0; i < userPwComponents.length; ++i)
             {
@@ -3278,7 +3260,7 @@
                                                   pwComponents[1].toString(),
                                                   pwComponents[2].toString())
                      : scheme.passwordMatches(password,
-                               new ASN1OctetString(pwComponents[1].toString()));
+              ByteString.valueOf(pwComponents[1].toString()));
           if (passwordMatches)
           {
             if (debugEnabled())
@@ -3493,12 +3475,12 @@
           if (usesAuthPasswordSyntax)
           {
             pwComponents =
-                 AuthPasswordSyntax.decodeAuthPassword(v.getStringValue());
+                 AuthPasswordSyntax.decodeAuthPassword(v.getValue().toString());
           }
           else
           {
             String[] userPwComponents =
-                 UserPasswordSyntax.decodeUserPassword(v.getStringValue());
+                 UserPasswordSyntax.decodeUserPassword(v.getValue().toString());
             pwComponents = new StringBuilder[userPwComponents.length];
             for (int i = 0; i < userPwComponents.length; ++i)
             {
@@ -3527,7 +3509,7 @@
                                                   pwComponents[1].toString(),
                                                   pwComponents[2].toString())
                      : scheme.passwordMatches(password,
-                               new ASN1OctetString(pwComponents[1].toString()));
+              ByteString.valueOf(pwComponents[1].toString()));
           if (passwordMatches)
           {
             if (passwordPolicy.isDefaultStorageScheme(schemeName))
@@ -3591,7 +3573,8 @@
           ByteString encodedPassword = (usesAuthPasswordSyntax)
                                        ? s.encodeAuthPassword(password)
                                        : s.encodePasswordWithScheme(password);
-          AttributeValue v = new AttributeValue(type, encodedPassword);
+          AttributeValue v =
+              AttributeValues.create(type, encodedPassword);
           addedValues.add(v);
           updatedValues.add(v);
         }
@@ -3800,7 +3783,7 @@
       {
         for (AttributeValue v : a)
         {
-          String histStr = v.getStringValue();
+          String histStr = v.getValue().toString();
           int    hashPos = histStr.indexOf('#');
           if (hashPos <= 0)
           {
@@ -3822,7 +3805,7 @@
             {
               long timestamp =
                    GeneralizedTimeSyntax.decodeGeneralizedTimeValue(
-                        new ASN1OctetString(histStr.substring(0, hashPos)));
+                       ByteString.valueOf(histStr.substring(0, hashPos)));
               historyMap.put(timestamp, v);
             }
             catch (Exception e)
@@ -3871,7 +3854,7 @@
     // we only care about the syntax OID and encoded password.
     try
     {
-      String histStr  = historyValue.getStringValue();
+      String histStr  = historyValue.getValue().toString();
       int    hashPos1 = histStr.indexOf('#');
       if (hashPos1 <= 0)
       {
@@ -3935,7 +3918,7 @@
         PasswordStorageScheme<?> scheme =
              DirectoryServer.getPasswordStorageScheme(userPWComponents[0]);
         if (scheme.passwordMatches(password,
-                                   new ASN1OctetString(userPWComponents[1])))
+            ByteString.valueOf(userPWComponents[1])))
         {
           if (debugEnabled())
           {
@@ -4001,7 +3984,7 @@
       {
         for (AttributeValue v : a)
         {
-          addPasswordToHistory(v.getStringValue());
+          addPasswordToHistory(v.getValue().toString());
         }
       }
     }
@@ -4060,8 +4043,8 @@
 
         if (debugEnabled())
         {
-          TRACER.debugInfo("Removing history value " + v.getStringValue() +
-              " to preserve the history count.");
+          TRACER.debugInfo("Removing history value " +
+              v.getValue().toString() + " to preserve the history count.");
         }
       }
 
@@ -4094,7 +4077,8 @@
 
           if (debugEnabled())
           {
-            TRACER.debugInfo("Removing history value " + v.getStringValue() +
+            TRACER.debugInfo("Removing history value " +
+                v.getValue().toString() +
                 " to preserve the history duration.");
           }
         }
@@ -4177,7 +4161,7 @@
       {
         for (AttributeValue v : a)
         {
-          historyValues.add(v.getStringValue());
+          historyValues.add(v.getValue().toString());
         }
       }
     }
@@ -4334,7 +4318,7 @@
     InternalClientConnection conn =
          InternalClientConnection.getRootConnection();
     ModifyOperation internalModify =
-         conn.processModify(new ASN1OctetString(userDNString), modList);
+         conn.processModify(ByteString.valueOf(userDNString), modList);
 
     ResultCode resultCode = internalModify.getResultCode();
     if (resultCode != ResultCode.SUCCESS)
diff --git a/opends/src/server/org/opends/server/core/PluginConfigManager.java b/opends/src/server/org/opends/server/core/PluginConfigManager.java
index 7cc55e2..43bc080 100644
--- a/opends/src/server/org/opends/server/core/PluginConfigManager.java
+++ b/opends/src/server/org/opends/server/core/PluginConfigManager.java
@@ -982,7 +982,7 @@
       {
         DN dn = p.getPluginEntryDN();
         String lowerName =
-             toLowerCase(dn.getRDN().getAttributeValue(0).getStringValue());
+            toLowerCase(dn.getRDN().getAttributeValue(0).getValue().toString());
         if (initialPluginNames.contains(lowerName))
         {
           initialPlugins.put(lowerName, p);
@@ -1002,7 +1002,7 @@
       // the correct category.
       DN dn = plugin.getPluginEntryDN();
       String lowerName =
-           toLowerCase(dn.getRDN().getAttributeValue(0).getStringValue());
+           toLowerCase(dn.getRDN().getAttributeValue(0).getValue().toString());
       if (initialPluginNames.contains(lowerName))
       {
         initialPlugins.put(lowerName, plugin);
diff --git a/opends/src/server/org/opends/server/core/SchemaConfigManager.java b/opends/src/server/org/opends/server/core/SchemaConfigManager.java
index ed00b5e..dfdd846 100644
--- a/opends/src/server/org/opends/server/core/SchemaConfigManager.java
+++ b/opends/src/server/org/opends/server/core/SchemaConfigManager.java
@@ -825,7 +825,7 @@
             }
 
             Message message = WARN_CONFIG_SCHEMA_CANNOT_PARSE_ATTR_TYPE.get(
-                    schemaFile, v.getStringValue() + ":  " +
+                    schemaFile, v.getValue().toString() + ":  " +
                     getExceptionMessage(e));
             if (failOnError)
             {
@@ -920,7 +920,7 @@
 
             Message message = WARN_CONFIG_SCHEMA_CANNOT_PARSE_OC.get(
                     schemaFile,
-                    v.getStringValue() + ":  " + getExceptionMessage(e));
+                    v.getValue().toString() + ":  " + getExceptionMessage(e));
 
             if (failOnError)
             {
@@ -1011,7 +1011,7 @@
             }
 
             Message message = WARN_CONFIG_SCHEMA_CANNOT_PARSE_NAME_FORM.get(
-                    schemaFile,  v.getStringValue() + ":  " +
+                    schemaFile,  v.getValue().toString() + ":  " +
                     getExceptionMessage(e));
 
             if (failOnError)
@@ -1105,7 +1105,7 @@
             }
 
             Message message = WARN_CONFIG_SCHEMA_CANNOT_PARSE_DCR.get(
-                    schemaFile,v.getStringValue() + ":  " +
+                    schemaFile,v.getValue().toString() + ":  " +
                     getExceptionMessage(e));
 
             if (failOnError)
@@ -1199,7 +1199,7 @@
             }
 
             Message message = WARN_CONFIG_SCHEMA_CANNOT_PARSE_DSR.get(
-                    schemaFile, v.getStringValue() + ":  " +
+                    schemaFile, v.getValue().toString() + ":  " +
                                         getExceptionMessage(e));
 
             if (failOnError)
@@ -1294,7 +1294,7 @@
 
             Message message = WARN_CONFIG_SCHEMA_CANNOT_PARSE_MRU.get(
                     schemaFile,
-                    v.getStringValue() + ":  " +
+                    v.getValue().toString() + ":  " +
                     getExceptionMessage(e));
 
             if (failOnError)
diff --git a/opends/src/server/org/opends/server/core/SearchOperation.java b/opends/src/server/org/opends/server/core/SearchOperation.java
index 5f8bb40..ee0edfa 100644
--- a/opends/src/server/org/opends/server/core/SearchOperation.java
+++ b/opends/src/server/org/opends/server/core/SearchOperation.java
@@ -30,18 +30,7 @@
 import java.util.List;
 
 import org.opends.server.controls.MatchedValuesControl;
-import org.opends.server.types.ByteString;
-import org.opends.server.types.Control;
-import org.opends.server.types.DN;
-import org.opends.server.types.DereferencePolicy;
-import org.opends.server.types.DirectoryException;
-import org.opends.server.types.Entry;
-import org.opends.server.types.Operation;
-import org.opends.server.types.RawFilter;
-import org.opends.server.types.SearchFilter;
-import org.opends.server.types.SearchResultEntry;
-import org.opends.server.types.SearchResultReference;
-import org.opends.server.types.SearchScope;
+import org.opends.server.types.*;
 
 /**
  * This interface defines an operation used to search for entries
diff --git a/opends/src/server/org/opends/server/core/SearchOperationBasis.java b/opends/src/server/org/opends/server/core/SearchOperationBasis.java
index 2285719..f31ee88 100644
--- a/opends/src/server/org/opends/server/core/SearchOperationBasis.java
+++ b/opends/src/server/org/opends/server/core/SearchOperationBasis.java
@@ -42,7 +42,6 @@
 import org.opends.server.core.networkgroups.NetworkGroup;
 import org.opends.server.loggers.debug.DebugLogger;
 import org.opends.server.loggers.debug.DebugTracer;
-import org.opends.server.protocols.asn1.ASN1OctetString;
 import org.opends.server.protocols.ldap.LDAPFilter;
 import org.opends.server.types.*;
 import org.opends.server.types.operation.PostResponseSearchOperation;
@@ -300,7 +299,7 @@
       this.attributes  = attributes;
     }
 
-    rawBaseDN = new ASN1OctetString(baseDN.toString());
+    rawBaseDN = ByteString.valueOf(baseDN.toString());
     rawFilter = new LDAPFilter(filter);
 
 
@@ -620,7 +619,7 @@
                 (f.getAttributeType().isObjectClassType()))
             {
               AttributeValue v = f.getAssertionValue();
-              if (toLowerCase(v.getStringValue()).equals("ldapsubentry"))
+              if (toLowerCase(v.getValue().toString()).equals("ldapsubentry"))
               {
                 setReturnLDAPSubentries(true);
               }
@@ -633,7 +632,7 @@
           if (t.isObjectClassType())
           {
             AttributeValue v = filter.getAssertionValue();
-            if (toLowerCase(v.getStringValue()).equals("ldapsubentry"))
+            if (toLowerCase(v.getValue().toString()).equals("ldapsubentry"))
             {
               setReturnLDAPSubentries(true);
             }
@@ -729,8 +728,8 @@
       while (ocIterator.hasNext())
       {
         String ocName = ocIterator.next();
-        AttributeValue v = new AttributeValue(attrType,
-                                              new ASN1OctetString(ocName));
+        AttributeValue v =
+            AttributeValues.create(attrType,ocName);
         if (! matchedValuesControl.valueMatches(attrType, v))
         {
           ocIterator.remove();
diff --git a/opends/src/server/org/opends/server/core/SearchOperationWrapper.java b/opends/src/server/org/opends/server/core/SearchOperationWrapper.java
index c3aa626..ebeb62c 100644
--- a/opends/src/server/org/opends/server/core/SearchOperationWrapper.java
+++ b/opends/src/server/org/opends/server/core/SearchOperationWrapper.java
@@ -30,17 +30,7 @@
 import java.util.LinkedHashSet;
 import java.util.List;
 import org.opends.server.controls.MatchedValuesControl;
-import org.opends.server.types.ByteString;
-import org.opends.server.types.Control;
-import org.opends.server.types.DN;
-import org.opends.server.types.DereferencePolicy;
-import org.opends.server.types.DirectoryException;
-import org.opends.server.types.Entry;
-import org.opends.server.types.RawFilter;
-import org.opends.server.types.SearchFilter;
-import org.opends.server.types.SearchResultEntry;
-import org.opends.server.types.SearchResultReference;
-import org.opends.server.types.SearchScope;
+import org.opends.server.types.*;
 
 
 /**
diff --git a/opends/src/server/org/opends/server/core/UnbindOperationBasis.java b/opends/src/server/org/opends/server/core/UnbindOperationBasis.java
index 4db93c1..60a1d9d 100644
--- a/opends/src/server/org/opends/server/core/UnbindOperationBasis.java
+++ b/opends/src/server/org/opends/server/core/UnbindOperationBasis.java
@@ -26,8 +26,6 @@
  */
 package org.opends.server.core;
 
-
-import java.util.ArrayList;
 import java.util.List;
 
 import org.opends.server.api.ClientConnection;
@@ -67,7 +65,7 @@
    */
   public UnbindOperationBasis(ClientConnection clientConnection,
                          long operationID,
-                         int messageID, ArrayList<Control> requestControls)
+                         int messageID, List<Control> requestControls)
   {
     super(clientConnection, operationID, messageID, requestControls);
 
diff --git a/opends/src/server/org/opends/server/core/networkgroups/NetworkGroup.java b/opends/src/server/org/opends/server/core/networkgroups/NetworkGroup.java
index 60c1f11..3824919 100644
--- a/opends/src/server/org/opends/server/core/networkgroups/NetworkGroup.java
+++ b/opends/src/server/org/opends/server/core/networkgroups/NetworkGroup.java
@@ -719,7 +719,7 @@
   private static String getNameFromConfiguration(NetworkGroupCfg configuration)
   {
     DN dn = configuration.dn();
-    return dn.getRDN().getAttributeValue(0).getStringValue();
+    return dn.getRDN().getAttributeValue(0).toString();
   }
 
 
diff --git a/opends/src/server/org/opends/server/core/networkgroups/ResourceLimitsPolicyFactory.java b/opends/src/server/org/opends/server/core/networkgroups/ResourceLimitsPolicyFactory.java
index 3516a5f..ed5b347 100644
--- a/opends/src/server/org/opends/server/core/networkgroups/ResourceLimitsPolicyFactory.java
+++ b/opends/src/server/org/opends/server/core/networkgroups/ResourceLimitsPolicyFactory.java
@@ -382,7 +382,7 @@
         ByteString subInitialElement = filter.getSubInitialElement();
         if (subInitialElement != null)
         {
-          length += subInitialElement.stringValue().length();
+          length += subInitialElement.length();
         }
         ArrayList<ByteString> subAnyElements =
             filter.getSubAnyElements();
@@ -390,13 +390,13 @@
         {
           for (ByteString element : subAnyElements)
           {
-            length += element.stringValue().length();
+            length += element.length();
           }
         }
         ByteString subFinalElement = filter.getSubFinalElement();
         if (subFinalElement != null)
         {
-          length += subFinalElement.stringValue().length();
+          length += subFinalElement.length();
         }
         return length >= minSearchSubstringLength;
       default:
diff --git a/opends/src/server/org/opends/server/crypto/CryptoManagerImpl.java b/opends/src/server/org/opends/server/crypto/CryptoManagerImpl.java
index be481d5..b5351a6 100644
--- a/opends/src/server/org/opends/server/crypto/CryptoManagerImpl.java
+++ b/opends/src/server/org/opends/server/crypto/CryptoManagerImpl.java
@@ -73,10 +73,8 @@
 import static org.opends.server.util.ServerConstants.OC_TOP;
 import org.opends.server.protocols.internal.InternalClientConnection;
 import org.opends.server.protocols.internal.InternalSearchOperation;
-import org.opends.server.protocols.asn1.ASN1OctetString;
 import org.opends.server.protocols.ldap.ExtendedRequestProtocolOp;
 import org.opends.server.protocols.ldap.LDAPMessage;
-import org.opends.server.protocols.ldap.LDAPControl;
 import org.opends.server.protocols.ldap.ExtendedResponseProtocolOp;
 import org.opends.server.protocols.ldap.LDAPResultCode;
 import org.opends.server.schema.DirectoryStringSyntax;
@@ -499,7 +497,7 @@
   static byte[] getInstanceKeyCertificateFromLocalTruststore()
           throws CryptoManagerException {
     // Construct the key entry DN.
-    final AttributeValue distinguishedValue = new AttributeValue(
+    final AttributeValue distinguishedValue = AttributeValues.create(
             attrKeyID, ConfigConstants.ADS_CERTIFICATE_ALIAS);
     final DN entryDN = localTruststoreDN.concat(
             RDN.create(attrKeyID, distinguishedValue));
@@ -538,7 +536,7 @@
             /* attribute ds-cfg-public-key-certificate is a MUST in
                the schema */
             certificate = e.getAttributeValue(
-                    attrPublicKeyCertificate, BinarySyntax.DECODER);
+                  attrPublicKeyCertificate, BinarySyntax.DECODER).toByteArray();
           }
           break;
         }
@@ -643,7 +641,7 @@
             = getInstanceKeyID(instanceKeyCertificate);
     // Construct the key entry DN.
     final AttributeValue distinguishedValue =
-            new AttributeValue(attrKeyID, instanceKeyID);
+        AttributeValues.create(attrKeyID, instanceKeyID);
     final DN entryDN = instanceKeysDN.concat(
          RDN.create(attrKeyID, distinguishedValue));
     // Construct the search filter.
@@ -682,9 +680,9 @@
         AttributeBuilder builder = new AttributeBuilder(
             attrPublicKeyCertificate);
         builder.setOption("binary");
-        builder.add(new AttributeValue(
+        builder.add(AttributeValues.create(
             attrPublicKeyCertificate,
-            ByteStringFactory.create(instanceKeyCertificate)));
+            ByteString.wrap(instanceKeyCertificate)));
         final Attribute certificateAttr = builder.toAttribute();
         entry.addAttribute(certificateAttr,
                 new ArrayList<AttributeValue>(0));
@@ -763,7 +761,7 @@
         final String keyID = e.getAttributeValue(
                 attrKeyID, DirectoryStringSyntax.DECODER);
         final byte[] certificate = e.getAttributeValue(
-                attrPublicKeyCertificate, BinarySyntax.DECODER);
+                attrPublicKeyCertificate, BinarySyntax.DECODER).toByteArray();
         certificateMap.put(keyID, certificate);
       }
     }
@@ -1091,7 +1089,7 @@
 
             // Send the Get Symmetric Key extended request.
 
-            ASN1OctetString requestValue =
+            ByteString requestValue =
                  GetSymmetricKeyExtendedOperation.encodeRequestValue(
                       symmetricKey, getInstanceKeyID());
 
@@ -1101,8 +1099,8 @@
                            OID_GET_SYMMETRIC_KEY_EXTENDED_OP,
                       requestValue);
 
-            ArrayList<LDAPControl> controls =
-                 new ArrayList<LDAPControl>();
+            ArrayList<Control> controls =
+                 new ArrayList<Control>();
             LDAPMessage requestMessage =
                  new LDAPMessage(nextMessageID.getAndIncrement(),
                                  extendedRequest, controls);
@@ -1115,7 +1113,7 @@
                  LDAPResultCode.SUCCESS)
             {
               // Got our symmetric key value.
-              return extendedResponse.getValue().stringValue();
+              return extendedResponse.getValue().toString();
             }
           }
           finally
@@ -1710,8 +1708,8 @@
     {
       // Construct the key entry DN.
       AttributeValue distinguishedValue =
-           new AttributeValue(attrKeyID,
-                              keyEntry.getKeyID().getStringValue());
+           AttributeValues.create(attrKeyID,
+               keyEntry.getKeyID().getStringValue());
       DN entryDN = secretKeysDN.concat(
            RDN.create(attrKeyID, distinguishedValue));
 
@@ -1735,21 +1733,24 @@
       // Add the transformation name attribute.
       attrList = new ArrayList<Attribute>(1);
       attrList.add(Attributes.create(attrTransformation,
-          new AttributeValue(attrTransformation, keyEntry.getType())));
+          AttributeValues.create(attrTransformation,
+              keyEntry.getType())));
       userAttrs.put(attrTransformation, attrList);
 
       // Add the init vector length attribute.
       attrList = new ArrayList<Attribute>(1);
       attrList.add(Attributes.create(attrInitVectorLength,
-          new AttributeValue(attrInitVectorLength, String.valueOf(keyEntry
+          AttributeValues.create(attrInitVectorLength,
+              String.valueOf(keyEntry
               .getIVLengthBits()))));
       userAttrs.put(attrInitVectorLength, attrList);
 
 
       // Add the key length attribute.
       attrList = new ArrayList<Attribute>(1);
-      attrList.add(Attributes.create(attrKeyLength, new AttributeValue(
-          attrKeyLength, String.valueOf(keyEntry.getKeyLengthBits()))));
+      attrList.add(Attributes.create(attrKeyLength,
+          AttributeValues.create(attrKeyLength,
+              String.valueOf(keyEntry.getKeyLengthBits()))));
       userAttrs.put(attrKeyLength, attrList);
 
 
@@ -1770,7 +1771,7 @@
         String symmetricKey = cryptoManager.encodeSymmetricKeyAttribute(
             mapEntry.getKey(), mapEntry.getValue(), keyEntry.getSecretKey());
 
-        builder.add(new AttributeValue(attrSymmetricKey, symmetricKey));
+        builder.add(AttributeValues.create(attrSymmetricKey, symmetricKey));
       }
       attrList = new ArrayList<Attribute>(1);
       attrList.add(builder.toAttribute());
@@ -2255,7 +2256,7 @@
     {
       // Construct the key entry DN.
       AttributeValue distinguishedValue =
-           new AttributeValue(attrKeyID,
+           AttributeValues.create(attrKeyID,
                               keyEntry.getKeyID().getStringValue());
       DN entryDN = secretKeysDN.concat(
            RDN.create(attrKeyID, distinguishedValue));
@@ -2281,13 +2282,13 @@
       // Add the mac algorithm name attribute.
       attrList = new ArrayList<Attribute>(1);
       attrList.add(Attributes.create(attrMacAlgorithm,
-          new AttributeValue(attrMacAlgorithm, keyEntry.getType())));
+          AttributeValues.create(attrMacAlgorithm, keyEntry.getType())));
       userAttrs.put(attrMacAlgorithm, attrList);
 
 
       // Add the key length attribute.
       attrList = new ArrayList<Attribute>(1);
-      attrList.add(Attributes.create(attrKeyLength, new AttributeValue(
+      attrList.add(Attributes.create(attrKeyLength, AttributeValues.create(
           attrKeyLength, String.valueOf(keyEntry.getKeyLengthBits()))));
       userAttrs.put(attrKeyLength, attrList);
 
@@ -2314,7 +2315,7 @@
                   keyEntry.getSecretKey());
 
         builder.add(
-             new AttributeValue(attrSymmetricKey, symmetricKey));
+            AttributeValues.create(attrSymmetricKey, symmetricKey));
       }
 
       attrList = new ArrayList<Attribute>(1);
@@ -2945,15 +2946,16 @@
 
 
   /** {@inheritDoc} */
-  public int compress(byte[] src, byte[] dst)
+  public int compress(byte[] src, int srcOff, int srcLen,
+                      byte[] dst, int dstOff, int dstLen)
   {
     Deflater deflater = new Deflater();
     try
     {
-      deflater.setInput(src);
+      deflater.setInput(src, srcOff, srcLen);
       deflater.finish();
 
-      int compressedLength = deflater.deflate(dst);
+      int compressedLength = deflater.deflate(dst, dstOff, dstLen);
       if (deflater.finished())
       {
         return compressedLength;
@@ -2971,15 +2973,16 @@
 
 
   /** {@inheritDoc} */
-  public int uncompress(byte[] src, byte[] dst)
+  public int uncompress(byte[] src, int srcOff, int srcLen,
+                        byte[] dst, int dstOff, int dstLen)
          throws DataFormatException
   {
     Inflater inflater = new Inflater();
     try
     {
-      inflater.setInput(src);
+      inflater.setInput(src, srcOff, srcLen);
 
-      int decompressedLength = inflater.inflate(dst);
+      int decompressedLength = inflater.inflate(dst, dstOff, dstLen);
       if (inflater.finished())
       {
         return decompressedLength;
@@ -2990,7 +2993,7 @@
 
         while (! inflater.finished())
         {
-          totalLength += inflater.inflate(dst);
+          totalLength += inflater.inflate(dst, dstOff, dstLen);
         }
 
         return -totalLength;
diff --git a/opends/src/server/org/opends/server/crypto/CryptoManagerSync.java b/opends/src/server/org/opends/server/crypto/CryptoManagerSync.java
index e9b3000..4bd43ef 100644
--- a/opends/src/server/org/opends/server/crypto/CryptoManagerSync.java
+++ b/opends/src/server/org/opends/server/crypto/CryptoManagerSync.java
@@ -49,6 +49,7 @@
 import static org.opends.server.config.ConfigConstants.OC_CRYPTO_MAC_KEY;
 import org.opends.server.protocols.internal.InternalClientConnection;
 import org.opends.server.protocols.internal.InternalSearchOperation;
+import org.opends.server.protocols.ldap.LDAPControl;
 import org.opends.server.controls.PersistentSearchChangeType;
 import org.opends.server.controls.EntryChangeNotificationControl;
 import org.opends.server.core.DirectoryServer;
@@ -299,11 +300,19 @@
         {
           if (c.getOID().equals(OID_ENTRY_CHANGE_NOTIFICATION))
           {
-            ecn = EntryChangeNotificationControl.decodeControl(c);
+            if (c instanceof LDAPControl)
+            {
+              ecn = EntryChangeNotificationControl.DECODER.decode(c
+                  .isCritical(), ((LDAPControl) c).getValue());
+            }
+            else
+            {
+              ecn = (EntryChangeNotificationControl)c;
+            }
           }
         }
       }
-      catch (LDAPException e)
+      catch (DirectoryException e)
       {
         // ignore
       }
diff --git a/opends/src/server/org/opends/server/crypto/GetSymmetricKeyExtendedOperation.java b/opends/src/server/org/opends/server/crypto/GetSymmetricKeyExtendedOperation.java
index ff7aebf..6f8377d 100644
--- a/opends/src/server/org/opends/server/crypto/GetSymmetricKeyExtendedOperation.java
+++ b/opends/src/server/org/opends/server/crypto/GetSymmetricKeyExtendedOperation.java
@@ -36,18 +36,17 @@
 import org.opends.server.config.ConfigException;
 import org.opends.server.core.DirectoryServer;
 import org.opends.server.core.ExtendedOperation;
-import org.opends.server.protocols.asn1.ASN1Sequence;
-import org.opends.server.protocols.asn1.ASN1Element;
-import org.opends.server.protocols.asn1.ASN1Exception;
-import org.opends.server.protocols.asn1.ASN1OctetString;
 import org.opends.server.util.StaticUtils;
 import org.opends.server.util.ServerConstants;
+import org.opends.server.protocols.asn1.ASN1Reader;
+import org.opends.server.protocols.asn1.ASN1;
+import org.opends.server.protocols.asn1.ASN1Exception;
+import org.opends.server.protocols.asn1.ASN1Writer;
 import org.opends.messages.Message;
 import static org.opends.messages.ExtensionMessages.*;
 
 import java.util.Set;
 import java.util.HashSet;
-import java.util.ArrayList;
 
 /**
  * This class implements the get symmetric key extended operation, an OpenDS
@@ -167,29 +166,28 @@
 
     try
     {
-      ASN1Sequence valueSequence =
-           ASN1Sequence.decodeAsSequence(requestValue.value());
-      for (ASN1Element e : valueSequence.elements())
+      ASN1Reader reader = ASN1.getReader(requestValue);
+      reader.readStartSequence();
+      while(reader.hasNextElement())
       {
-        switch (e.getType())
+        switch (reader.peekType())
         {
           case TYPE_SYMMETRIC_KEY_ELEMENT:
-            requestSymmetricKey =
-                 ASN1OctetString.decodeAsOctetString(e).stringValue();
+            requestSymmetricKey = reader.readOctetStringAsString();
             break;
 
           case TYPE_INSTANCE_KEY_ID_ELEMENT:
-            instanceKeyID =
-                 ASN1OctetString.decodeAsOctetString(e).stringValue();
+            instanceKeyID = reader.readOctetStringAsString();
             break;
 
           default:
             Message message = ERR_GET_SYMMETRIC_KEY_INVALID_TYPE.get(
-                 StaticUtils.byteToHex(e.getType()));
+                 StaticUtils.byteToHex(reader.peekType()));
             operation.appendErrorMessage(message);
             return;
         }
       }
+      reader.readEndSequence();
     }
     catch (ASN1Exception ae)
     {
@@ -226,7 +224,7 @@
 
       operation.setResponseOID(
            ServerConstants.OID_GET_SYMMETRIC_KEY_EXTENDED_OP);
-      operation.setResponseValue(new ASN1OctetString(responseSymmetricKey));
+      operation.setResponseValue(ByteString.valueOf(responseSymmetricKey));
       operation.setResultCode(ResultCode.SUCCESS);
     }
     catch (CryptoManagerException e)
@@ -251,23 +249,26 @@
    *
    * @return  An ASN.1 octet string containing the encoded request value.
    */
-  public static ASN1OctetString encodeRequestValue(
+  public static ByteString encodeRequestValue(
        String symmetricKey,
        String instanceKeyID)
   {
-    ArrayList<ASN1Element> elements = new ArrayList<ASN1Element>(2);
+    ByteStringBuilder builder = new ByteStringBuilder();
+    ASN1Writer writer = ASN1.getWriter(builder);
 
-    ASN1OctetString symmetricKeyElement =
-         new ASN1OctetString(TYPE_SYMMETRIC_KEY_ELEMENT, symmetricKey);
-    elements.add(symmetricKeyElement);
+    try
+    {
+      writer.writeStartSequence();
+      writer.writeOctetString(TYPE_SYMMETRIC_KEY_ELEMENT, symmetricKey);
+      writer.writeOctetString(TYPE_INSTANCE_KEY_ID_ELEMENT, instanceKeyID);
+      writer.writeEndSequence();
+    }
+    catch(Exception e)
+    {
+      // TODO: DO something
+    }
 
-    ASN1OctetString instanceKeyIDElement =
-         new ASN1OctetString(TYPE_INSTANCE_KEY_ID_ELEMENT,
-                             instanceKeyID);
-    elements.add(instanceKeyIDElement);
-
-    ASN1Sequence valueSequence = new ASN1Sequence(elements);
-    return new ASN1OctetString(valueSequence.encode());
+    return builder.toByteString();
   }
 
 
diff --git a/opends/src/server/org/opends/server/extensions/AESPasswordStorageScheme.java b/opends/src/server/org/opends/server/extensions/AESPasswordStorageScheme.java
index 35f04cc..2a7326f 100644
--- a/opends/src/server/org/opends/server/extensions/AESPasswordStorageScheme.java
+++ b/opends/src/server/org/opends/server/extensions/AESPasswordStorageScheme.java
@@ -28,8 +28,6 @@
 
 
 
-import java.util.Arrays;
-
 import org.opends.messages.Message;
 import org.opends.server.admin.std.server.AESPasswordStorageSchemeCfg;
 import org.opends.server.api.PasswordStorageScheme;
@@ -108,15 +106,17 @@
    * {@inheritDoc}
    */
   @Override()
-  public ByteString encodePassword(ByteString plaintext)
+  public ByteString encodePassword(ByteSequence plaintext)
          throws DirectoryException
   {
     try
     {
+      // TODO: Can we avoid this copy?
+      byte[] plaintextBytes = plaintext.toByteArray();
       byte[] encodedBytes = cryptoManager.encrypt(CIPHER_TRANSFORMATION_AES,
                                                   KEY_SIZE_AES,
-                                                  plaintext.value());
-      return ByteStringFactory.create(Base64.encode(encodedBytes));
+                                                  plaintextBytes);
+      return ByteString.valueOf(Base64.encode(encodedBytes));
     }
     catch (Exception e)
     {
@@ -138,7 +138,7 @@
    * {@inheritDoc}
    */
   @Override()
-  public ByteString encodePasswordWithScheme(ByteString plaintext)
+  public ByteString encodePasswordWithScheme(ByteSequence plaintext)
          throws DirectoryException
   {
     StringBuilder buffer = new StringBuilder();
@@ -148,9 +148,11 @@
 
     try
     {
+      // TODO: Can we avoid this copy?
+      byte[] plaintextBytes = plaintext.toByteArray();
       byte[] encodedBytes = cryptoManager.encrypt(CIPHER_TRANSFORMATION_AES,
                                                   KEY_SIZE_AES,
-                                                  plaintext.value());
+                                                  plaintextBytes);
       buffer.append(Base64.encode(encodedBytes));
     }
     catch (Exception e)
@@ -166,7 +168,7 @@
                                    m, e);
     }
 
-    return ByteStringFactory.create(buffer.toString());
+    return ByteString.valueOf(buffer.toString());
   }
 
 
@@ -175,14 +177,15 @@
    * {@inheritDoc}
    */
   @Override()
-  public boolean passwordMatches(ByteString plaintextPassword,
-                                 ByteString storedPassword)
+  public boolean passwordMatches(ByteSequence plaintextPassword,
+                                 ByteSequence storedPassword)
   {
     try
     {
-      byte[] decryptedPassword =
-           cryptoManager.decrypt(Base64.decode(storedPassword.stringValue()));
-      return Arrays.equals(plaintextPassword.value(), decryptedPassword);
+      ByteString decryptedPassword =
+          ByteString.wrap(cryptoManager.decrypt(
+               Base64.decode(storedPassword.toString())));
+      return plaintextPassword.equals(decryptedPassword);
     }
     catch (Exception e)
     {
@@ -212,14 +215,14 @@
    * {@inheritDoc}
    */
   @Override()
-  public ByteString getPlaintextValue(ByteString storedPassword)
+  public ByteString getPlaintextValue(ByteSequence storedPassword)
          throws DirectoryException
   {
     try
     {
       byte[] decryptedPassword =
-           cryptoManager.decrypt(Base64.decode(storedPassword.stringValue()));
-      return ByteStringFactory.create(decryptedPassword);
+           cryptoManager.decrypt(Base64.decode(storedPassword.toString()));
+      return ByteString.wrap(decryptedPassword);
     }
     catch (Exception e)
     {
@@ -253,7 +256,7 @@
    * {@inheritDoc}
    */
   @Override()
-  public ByteString encodeAuthPassword(ByteString plaintext)
+  public ByteString encodeAuthPassword(ByteSequence plaintext)
          throws DirectoryException
   {
     Message message =
@@ -267,7 +270,7 @@
    * {@inheritDoc}
    */
   @Override()
-  public boolean authPasswordMatches(ByteString plaintextPassword,
+  public boolean authPasswordMatches(ByteSequence plaintextPassword,
                                      String authInfo, String authValue)
   {
     // This storage scheme does not support the authentication password syntax.
diff --git a/opends/src/server/org/opends/server/extensions/AnonymousSASLMechanismHandler.java b/opends/src/server/org/opends/server/extensions/AnonymousSASLMechanismHandler.java
index b678835..b83173d 100644
--- a/opends/src/server/org/opends/server/extensions/AnonymousSASLMechanismHandler.java
+++ b/opends/src/server/org/opends/server/extensions/AnonymousSASLMechanismHandler.java
@@ -108,7 +108,7 @@
     ByteString saslCredentials = bindOperation.getSASLCredentials();
     if (saslCredentials != null)
     {
-      String credString = saslCredentials.stringValue();
+      String credString = saslCredentials.toString();
       if (credString.length() > 0)
       {
         MessageBuilder mb = new MessageBuilder();
diff --git a/opends/src/server/org/opends/server/extensions/AttributeValuePasswordValidator.java b/opends/src/server/org/opends/server/extensions/AttributeValuePasswordValidator.java
index 8f722cb..425a289 100644
--- a/opends/src/server/org/opends/server/extensions/AttributeValuePasswordValidator.java
+++ b/opends/src/server/org/opends/server/extensions/AttributeValuePasswordValidator.java
@@ -37,14 +37,7 @@
 import org.opends.server.admin.std.server.AttributeValuePasswordValidatorCfg;
 import org.opends.server.admin.std.server.PasswordValidatorCfg;
 import org.opends.server.api.PasswordValidator;
-import org.opends.server.types.Attribute;
-import org.opends.server.types.AttributeType;
-import org.opends.server.types.AttributeValue;
-import org.opends.server.types.ConfigChangeResult;
-import org.opends.server.types.ByteString;
-import org.opends.server.types.Entry;
-import org.opends.server.types.Operation;
-import org.opends.server.types.ResultCode;
+import org.opends.server.types.*;
 
 import static org.opends.messages.ExtensionMessages.*;
 import org.opends.messages.MessageBuilder;
@@ -117,7 +110,7 @@
 
     // Get the string representation (both forward and reversed) for the
     // password.
-    String password = newPassword.stringValue();
+    String password = newPassword.toString();
     String reversed = new StringBuilder(password).reverse().toString();
 
 
@@ -137,8 +130,8 @@
         continue;
       }
 
-      AttributeValue vf = new AttributeValue(t, password);
-      AttributeValue vr = new AttributeValue(t, reversed);
+      AttributeValue vf = AttributeValues.create(t, password);
+      AttributeValue vr = AttributeValues.create(t, reversed);
 
       for (Attribute a : attrList)
       {
diff --git a/opends/src/server/org/opends/server/extensions/Base64PasswordStorageScheme.java b/opends/src/server/org/opends/server/extensions/Base64PasswordStorageScheme.java
index b14740c..c7825da 100644
--- a/opends/src/server/org/opends/server/extensions/Base64PasswordStorageScheme.java
+++ b/opends/src/server/org/opends/server/extensions/Base64PasswordStorageScheme.java
@@ -33,12 +33,7 @@
 import org.opends.server.api.PasswordStorageScheme;
 import org.opends.server.config.ConfigException;
 import org.opends.server.loggers.debug.DebugTracer;
-import org.opends.server.types.ByteString;
-import org.opends.server.types.ByteStringFactory;
-import org.opends.server.types.DebugLogLevel;
-import org.opends.server.types.DirectoryException;
-import org.opends.server.types.InitializationException;
-import org.opends.server.types.ResultCode;
+import org.opends.server.types.*;
 import org.opends.server.util.Base64;
 
 import static org.opends.messages.ExtensionMessages.*;
@@ -103,10 +98,10 @@
    * {@inheritDoc}
    */
   @Override()
-  public ByteString encodePassword(ByteString plaintext)
+  public ByteString encodePassword(ByteSequence plaintext)
          throws DirectoryException
   {
-    return ByteStringFactory.create(Base64.encode(plaintext.value()));
+    return ByteString.valueOf(Base64.encode(plaintext));
   }
 
 
@@ -115,16 +110,16 @@
    * {@inheritDoc}
    */
   @Override()
-  public ByteString encodePasswordWithScheme(ByteString plaintext)
+  public ByteString encodePasswordWithScheme(ByteSequence plaintext)
          throws DirectoryException
   {
     StringBuilder buffer = new StringBuilder();
     buffer.append('{');
     buffer.append(STORAGE_SCHEME_NAME_BASE64);
     buffer.append('}');
-    buffer.append(Base64.encode(plaintext.value()));
+    buffer.append(Base64.encode(plaintext));
 
-    return ByteStringFactory.create(buffer.toString());
+    return ByteString.valueOf(buffer.toString());
   }
 
 
@@ -133,11 +128,11 @@
    * {@inheritDoc}
    */
   @Override()
-  public boolean passwordMatches(ByteString plaintextPassword,
-                                 ByteString storedPassword)
+  public boolean passwordMatches(ByteSequence plaintextPassword,
+                                 ByteSequence storedPassword)
   {
-    String userString   = Base64.encode(plaintextPassword.value());
-    String storedString = storedPassword.stringValue();
+    String userString   = Base64.encode(plaintextPassword);
+    String storedString = storedPassword.toString();
     return userString.equals(storedString);
   }
 
@@ -158,13 +153,12 @@
    * {@inheritDoc}
    */
   @Override()
-  public ByteString getPlaintextValue(ByteString storedPassword)
+  public ByteString getPlaintextValue(ByteSequence storedPassword)
          throws DirectoryException
   {
     try
     {
-      return ByteStringFactory.create(Base64.decode(
-                                           storedPassword.stringValue()));
+      return ByteString.wrap(Base64.decode(storedPassword.toString()));
     }
     catch (Exception e)
     {
@@ -174,7 +168,7 @@
       }
 
       Message message = ERR_PWSCHEME_CANNOT_BASE64_DECODE_STORED_PASSWORD.get(
-          storedPassword.stringValue(), String.valueOf(e));
+          storedPassword.toString(), String.valueOf(e));
       throw new DirectoryException(ResultCode.INVALID_CREDENTIALS, message,
                                    e);
     }
@@ -198,7 +192,7 @@
    * {@inheritDoc}
    */
   @Override()
-  public ByteString encodeAuthPassword(ByteString plaintext)
+  public ByteString encodeAuthPassword(ByteSequence plaintext)
          throws DirectoryException
   {
     Message message =
@@ -212,7 +206,7 @@
    * {@inheritDoc}
    */
   @Override()
-  public boolean authPasswordMatches(ByteString plaintextPassword,
+  public boolean authPasswordMatches(ByteSequence plaintextPassword,
                                      String authInfo, String authValue)
   {
     // This storage scheme does not support the authentication password syntax.
diff --git a/opends/src/server/org/opends/server/extensions/BlowfishPasswordStorageScheme.java b/opends/src/server/org/opends/server/extensions/BlowfishPasswordStorageScheme.java
index 1bb323f..889088f 100644
--- a/opends/src/server/org/opends/server/extensions/BlowfishPasswordStorageScheme.java
+++ b/opends/src/server/org/opends/server/extensions/BlowfishPasswordStorageScheme.java
@@ -28,8 +28,6 @@
 
 
 
-import java.util.Arrays;
-
 import org.opends.messages.Message;
 import org.opends.server.admin.std.server.BlowfishPasswordStorageSchemeCfg;
 import org.opends.server.api.PasswordStorageScheme;
@@ -108,15 +106,17 @@
    * {@inheritDoc}
    */
   @Override()
-  public ByteString encodePassword(ByteString plaintext)
+  public ByteString encodePassword(ByteSequence plaintext)
          throws DirectoryException
   {
     try
     {
+      // TODO: Can we avoid this copy?
+      byte[] plaintextBytes = plaintext.toByteArray();
       byte[] encodedBytes =
            cryptoManager.encrypt(CIPHER_TRANSFORMATION_BLOWFISH,
-                                 KEY_SIZE_BLOWFISH, plaintext.value());
-      return ByteStringFactory.create(Base64.encode(encodedBytes));
+                                 KEY_SIZE_BLOWFISH, plaintextBytes);
+      return ByteString.valueOf(Base64.encode(encodedBytes));
     }
     catch (Exception e)
     {
@@ -138,7 +138,7 @@
    * {@inheritDoc}
    */
   @Override()
-  public ByteString encodePasswordWithScheme(ByteString plaintext)
+  public ByteString encodePasswordWithScheme(ByteSequence plaintext)
          throws DirectoryException
   {
     StringBuilder buffer = new StringBuilder();
@@ -148,9 +148,11 @@
 
     try
     {
+      // TODO: Can we avoid this copy?
+      byte[] plaintextBytes = plaintext.toByteArray();
       byte[] encodedBytes =
            cryptoManager.encrypt(CIPHER_TRANSFORMATION_BLOWFISH,
-                                 KEY_SIZE_BLOWFISH, plaintext.value());
+                                 KEY_SIZE_BLOWFISH, plaintextBytes);
       buffer.append(Base64.encode(encodedBytes));
     }
     catch (Exception e)
@@ -166,7 +168,7 @@
                                    m, e);
     }
 
-    return ByteStringFactory.create(buffer.toString());
+    return ByteString.valueOf(buffer.toString());
   }
 
 
@@ -175,14 +177,15 @@
    * {@inheritDoc}
    */
   @Override()
-  public boolean passwordMatches(ByteString plaintextPassword,
-                                 ByteString storedPassword)
+  public boolean passwordMatches(ByteSequence plaintextPassword,
+                                 ByteSequence storedPassword)
   {
     try
     {
-      byte[] decryptedPassword =
-           cryptoManager.decrypt(Base64.decode(storedPassword.stringValue()));
-      return Arrays.equals(plaintextPassword.value(), decryptedPassword);
+      ByteString decryptedPassword =
+          ByteString.wrap(cryptoManager.decrypt(
+               Base64.decode(storedPassword.toString())));
+      return plaintextPassword.equals(decryptedPassword);
     }
     catch (Exception e)
     {
@@ -212,14 +215,14 @@
    * {@inheritDoc}
    */
   @Override()
-  public ByteString getPlaintextValue(ByteString storedPassword)
+  public ByteString getPlaintextValue(ByteSequence storedPassword)
          throws DirectoryException
   {
     try
     {
       byte[] decryptedPassword =
-           cryptoManager.decrypt(Base64.decode(storedPassword.stringValue()));
-      return ByteStringFactory.create(decryptedPassword);
+           cryptoManager.decrypt(Base64.decode(storedPassword.toString()));
+      return ByteString.wrap(decryptedPassword);
     }
     catch (Exception e)
     {
@@ -253,7 +256,7 @@
    * {@inheritDoc}
    */
   @Override()
-  public ByteString encodeAuthPassword(ByteString plaintext)
+  public ByteString encodeAuthPassword(ByteSequence plaintext)
          throws DirectoryException
   {
     Message message =
@@ -267,7 +270,7 @@
    * {@inheritDoc}
    */
   @Override()
-  public boolean authPasswordMatches(ByteString plaintextPassword,
+  public boolean authPasswordMatches(ByteSequence plaintextPassword,
                                      String authInfo, String authValue)
   {
     // This storage scheme does not support the authentication password syntax.
diff --git a/opends/src/server/org/opends/server/extensions/CRAMMD5SASLMechanismHandler.java b/opends/src/server/org/opends/server/extensions/CRAMMD5SASLMechanismHandler.java
index afd8b15..5b7165d 100644
--- a/opends/src/server/org/opends/server/extensions/CRAMMD5SASLMechanismHandler.java
+++ b/opends/src/server/org/opends/server/extensions/CRAMMD5SASLMechanismHandler.java
@@ -48,7 +48,6 @@
 import org.opends.server.core.DirectoryServer;
 import org.opends.server.core.PasswordPolicyState;
 import org.opends.server.loggers.debug.DebugTracer;
-import org.opends.server.protocols.asn1.ASN1OctetString;
 import org.opends.server.types.AuthenticationInfo;
 import org.opends.server.types.ByteString;
 import org.opends.server.types.ConfigChangeResult;
@@ -215,8 +214,8 @@
       }
       challengeString.append('>');
 
-      ASN1OctetString challenge =
-           new ASN1OctetString(challengeString.toString());
+      ByteString challenge =
+          ByteString.valueOf(challengeString.toString());
       clientConnection.setSASLAuthStateInfo(challenge);
       bindOperation.setServerSASLCredentials(challenge);
       bindOperation.setResultCode(ResultCode.SASL_BIND_IN_PROGRESS);
@@ -238,7 +237,7 @@
       return;
     }
 
-    if (! (saslStateInfo instanceof ASN1OctetString))
+    if (! (saslStateInfo instanceof  ByteString))
     {
       bindOperation.setResultCode(ResultCode.INVALID_CREDENTIALS);
 
@@ -247,7 +246,7 @@
       return;
     }
 
-    ASN1OctetString  challenge = (ASN1OctetString) saslStateInfo;
+    ByteString  challenge = (ByteString) saslStateInfo;
 
     // Wipe out the stored challenge so it can't be used again.
     clientConnection.setSASLAuthStateInfo(null);
@@ -257,7 +256,7 @@
     // It should be a username followed by a space and a digest string.  Since
     // the username itself may contain spaces but the digest string may not,
     // look for the last space and use it as the delimiter.
-    String credString = clientCredentials.stringValue();
+    String credString = clientCredentials.toString();
     int spacePos = credString.lastIndexOf(' ');
     if (spacePos < 0)
     {
@@ -516,8 +515,8 @@
   private byte[] generateDigest(ByteString password, ByteString challenge)
   {
     // Get the byte arrays backing the password and challenge.
-    byte[] p = password.value();
-    byte[] c = challenge.value();
+    byte[] p = password.toByteArray();
+    byte[] c = challenge.toByteArray();
 
 
     // Grab a lock to protect the MD5 digest generation.
diff --git a/opends/src/server/org/opends/server/extensions/CancelExtendedOperation.java b/opends/src/server/org/opends/server/extensions/CancelExtendedOperation.java
index b84684f..da83334 100644
--- a/opends/src/server/org/opends/server/extensions/CancelExtendedOperation.java
+++ b/opends/src/server/org/opends/server/extensions/CancelExtendedOperation.java
@@ -36,7 +36,8 @@
 import org.opends.server.core.DirectoryServer;
 import org.opends.server.core.ExtendedOperation;
 import org.opends.server.loggers.debug.DebugTracer;
-import org.opends.server.protocols.asn1.ASN1Sequence;
+import org.opends.server.protocols.asn1.ASN1Reader;
+import org.opends.server.protocols.asn1.ASN1;
 import org.opends.server.types.ByteString;
 import org.opends.server.types.CancelRequest;
 import org.opends.server.types.CancelResult;
@@ -144,10 +145,10 @@
     {
       try
       {
-        ASN1Sequence valueSequence =
-             ASN1Sequence.decodeAsSequence(requestValue.value());
-        idToCancel =
-             valueSequence.elements().get(0).decodeAsInteger().intValue();
+        ASN1Reader reader = ASN1.getReader(requestValue);
+        reader.readStartSequence();
+        idToCancel = (int)reader.readInteger();
+        reader.readEndSequence();
       }
       catch (Exception e)
       {
diff --git a/opends/src/server/org/opends/server/extensions/CharacterSetPasswordValidator.java b/opends/src/server/org/opends/server/extensions/CharacterSetPasswordValidator.java
index b362cd4..96fc7de 100644
--- a/opends/src/server/org/opends/server/extensions/CharacterSetPasswordValidator.java
+++ b/opends/src/server/org/opends/server/extensions/CharacterSetPasswordValidator.java
@@ -40,12 +40,7 @@
 import org.opends.server.admin.std.server.PasswordValidatorCfg;
 import org.opends.server.api.PasswordValidator;
 import org.opends.server.config.ConfigException;
-import org.opends.server.types.ConfigChangeResult;
-import org.opends.server.types.ByteString;
-import org.opends.server.types.DirectoryConfig;
-import org.opends.server.types.Entry;
-import org.opends.server.types.Operation;
-import org.opends.server.types.ResultCode;
+import org.opends.server.types.*;
 
 import static org.opends.messages.ExtensionMessages.*;
 import org.opends.messages.MessageBuilder;
@@ -127,7 +122,7 @@
 
 
     // Process the provided password.
-    String password = newPassword.stringValue();
+    String password = newPassword.toString();
     HashMap<String,Integer> counts = new HashMap<String,Integer>();
     for (int i=0; i < password.length(); i++)
     {
diff --git a/opends/src/server/org/opends/server/extensions/ClearPasswordStorageScheme.java b/opends/src/server/org/opends/server/extensions/ClearPasswordStorageScheme.java
index 841fb7b..b53cfeb 100644
--- a/opends/src/server/org/opends/server/extensions/ClearPasswordStorageScheme.java
+++ b/opends/src/server/org/opends/server/extensions/ClearPasswordStorageScheme.java
@@ -28,17 +28,11 @@
 
 
 
-import java.util.Arrays;
-
 import org.opends.messages.Message;
 import org.opends.server.admin.std.server.ClearPasswordStorageSchemeCfg;
 import org.opends.server.api.PasswordStorageScheme;
 import org.opends.server.config.ConfigException;
-import org.opends.server.types.ByteString;
-import org.opends.server.types.ByteStringFactory;
-import org.opends.server.types.DirectoryException;
-import org.opends.server.types.InitializationException;
-import org.opends.server.types.ResultCode;
+import org.opends.server.types.*;
 
 import static org.opends.messages.ExtensionMessages.*;
 import static org.opends.server.extensions.ExtensionsConstants.*;
@@ -94,10 +88,10 @@
    * {@inheritDoc}
    */
   @Override()
-  public ByteString encodePassword(ByteString plaintext)
+  public ByteString encodePassword(ByteSequence plaintext)
          throws DirectoryException
   {
-    return plaintext.duplicate();
+    return plaintext.toByteString();
   }
 
 
@@ -106,16 +100,16 @@
    * {@inheritDoc}
    */
   @Override()
-  public ByteString encodePasswordWithScheme(ByteString plaintext)
+  public ByteString encodePasswordWithScheme(ByteSequence plaintext)
          throws DirectoryException
   {
     StringBuilder buffer = new StringBuilder();
     buffer.append('{');
     buffer.append(STORAGE_SCHEME_NAME_CLEAR);
     buffer.append('}');
-    buffer.append(plaintext.stringValue());
+    buffer.append(plaintext.toString());
 
-    return ByteStringFactory.create(buffer.toString());
+    return ByteString.valueOf(buffer.toString());
   }
 
 
@@ -124,10 +118,10 @@
    * {@inheritDoc}
    */
   @Override()
-  public boolean passwordMatches(ByteString plaintextPassword,
-                                 ByteString storedPassword)
+  public boolean passwordMatches(ByteSequence plaintextPassword,
+                                 ByteSequence storedPassword)
   {
-    return Arrays.equals(plaintextPassword.value(), storedPassword.value());
+    return plaintextPassword.equals(storedPassword);
   }
 
 
@@ -147,10 +141,10 @@
    * {@inheritDoc}
    */
   @Override()
-  public ByteString getPlaintextValue(ByteString storedPassword)
+  public ByteString getPlaintextValue(ByteSequence storedPassword)
          throws DirectoryException
   {
-    return storedPassword.duplicate();
+    return storedPassword.toByteString();
   }
 
 
@@ -171,7 +165,7 @@
    * {@inheritDoc}
    */
   @Override()
-  public ByteString encodeAuthPassword(ByteString plaintext)
+  public ByteString encodeAuthPassword(ByteSequence plaintext)
          throws DirectoryException
   {
     Message message =
@@ -185,7 +179,7 @@
    * {@inheritDoc}
    */
   @Override()
-  public boolean authPasswordMatches(ByteString plaintextPassword,
+  public boolean authPasswordMatches(ByteSequence plaintextPassword,
                                      String authInfo, String authValue)
   {
     // This storage scheme does not support the authentication password syntax.
diff --git a/opends/src/server/org/opends/server/extensions/ConfigFileHandler.java b/opends/src/server/org/opends/server/extensions/ConfigFileHandler.java
index e2abe0c..711145c 100644
--- a/opends/src/server/org/opends/server/extensions/ConfigFileHandler.java
+++ b/opends/src/server/org/opends/server/extensions/ConfigFileHandler.java
@@ -73,7 +73,6 @@
 import org.opends.server.core.ModifyDNOperation;
 import org.opends.server.core.SearchOperation;
 import org.opends.server.loggers.debug.DebugTracer;
-import org.opends.server.protocols.asn1.ASN1OctetString;
 import org.opends.server.schema.GeneralizedTimeSyntax;
 import org.opends.server.tools.LDIFModify;
 import org.opends.server.types.*;
@@ -864,7 +863,7 @@
       {
         try
         {
-          ASN1OctetString ts = new ASN1OctetString(name.substring(7, dotPos));
+          ByteString ts = ByteString.valueOf(name.substring(7, dotPos));
           long timestamp = GeneralizedTimeSyntax.decodeGeneralizedTimeValue(ts);
           if (timestamp > latestTimestamp)
           {
@@ -883,7 +882,7 @@
       {
         try
         {
-          ASN1OctetString ts = new ASN1OctetString(name.substring(7, dashPos));
+          ByteString ts = ByteString.valueOf(name.substring(7, dashPos));
           long timestamp = GeneralizedTimeSyntax.decodeGeneralizedTimeValue(ts);
           int counter = Integer.parseInt(name.substring(dashPos+1, dotPos));
 
diff --git a/opends/src/server/org/opends/server/extensions/ConnectionSecurityProvider.java b/opends/src/server/org/opends/server/extensions/ConnectionSecurityProvider.java
new file mode 100644
index 0000000..e2bfa0e
--- /dev/null
+++ b/opends/src/server/org/opends/server/extensions/ConnectionSecurityProvider.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 2006-2008 Sun Microsystems, Inc.
+ */
+
+package org.opends.server.extensions;
+
+import java.nio.channels.ByteChannel;
+import java.security.cert.Certificate;
+
+/**
+ * This interface can be used to define connection security providers.
+ *
+ */
+public interface ConnectionSecurityProvider {
+
+    /**
+     * Factory method: creates a new security ByteChannel
+     * layer wrapping the provided ByteChannel.
+     *
+     * @param channel The byte channel to be wrapped.
+     * @return A byte channel wrapping the specified byte channel.
+     */
+    ByteChannel wrapChannel(ByteChannel channel);
+
+    /**
+     * Return a buffer size of the byte channel.
+     * @return Integer representing the byte channel application buffer size.
+     */
+    int getAppBufSize();
+
+    /**
+     * Return a certificate chain array.
+     *
+     * @return A certificate chain array.
+     */
+    Certificate[] getClientCertificateChain();
+
+    /**
+     * Return a Security Strength Factor.
+     *
+     * @return Integer representing the current SSF of a provider.
+     */
+    int getSSF();
+
+    /**
+     * Return <CODE>true</CODE> if a provider is secure.
+     *
+     * @return <CODE>true</CODE> if a provider is secure.
+     */
+    boolean isSecure();
+
+    /**
+     * Return the name of a provider.
+     *
+     * @return String representing the name of a provider.
+     */
+    String getName();
+}
diff --git a/opends/src/server/org/opends/server/extensions/CryptPasswordStorageScheme.java b/opends/src/server/org/opends/server/extensions/CryptPasswordStorageScheme.java
index 7af0e87..9692a6f 100644
--- a/opends/src/server/org/opends/server/extensions/CryptPasswordStorageScheme.java
+++ b/opends/src/server/org/opends/server/extensions/CryptPasswordStorageScheme.java
@@ -28,7 +28,6 @@
 
 
 
-import java.util.Arrays;
 import java.util.Random;
 
 import org.opends.messages.Message;
@@ -36,11 +35,7 @@
 import org.opends.server.api.PasswordStorageScheme;
 import org.opends.server.config.ConfigException;
 import org.opends.server.core.DirectoryServer;
-import org.opends.server.types.ByteString;
-import org.opends.server.types.ByteStringFactory;
-import org.opends.server.types.DirectoryException;
-import org.opends.server.types.InitializationException;
-import org.opends.server.types.ResultCode;
+import org.opends.server.types.*;
 import org.opends.server.util.Crypt;
 
 import static org.opends.messages.ExtensionMessages.*;
@@ -115,7 +110,7 @@
    * {@inheritDoc}
    */
   @Override()
-  public ByteString encodePassword(ByteString plaintext)
+  public ByteString encodePassword(ByteSequence plaintext)
          throws DirectoryException
   {
 
@@ -123,7 +118,9 @@
 
     try
     {
-      digestBytes = crypt.crypt(plaintext.value(), randomSalt());
+      // TODO: Can we avoid this copy?
+      byte[] plaintextBytes = plaintext.toByteArray();
+      digestBytes = crypt.crypt(plaintextBytes, randomSalt());
     }
     catch (Exception e)
     {
@@ -133,7 +130,7 @@
                                    message, e);
     }
 
-    return ByteStringFactory.create(digestBytes);
+    return ByteString.wrap(digestBytes);
   }
 
 
@@ -160,7 +157,7 @@
    * {@inheritDoc}
    */
   @Override()
-  public ByteString encodePasswordWithScheme(ByteString plaintext)
+  public ByteString encodePasswordWithScheme(ByteSequence plaintext)
          throws DirectoryException
   {
     StringBuilder buffer =
@@ -171,7 +168,7 @@
 
     buffer.append(encodePassword(plaintext));
 
-    return ByteStringFactory.create(buffer.toString());
+    return ByteString.valueOf(buffer.toString());
   }
 
 
@@ -180,27 +177,28 @@
    * {@inheritDoc}
    */
   @Override()
-  public boolean passwordMatches(ByteString plaintextPassword,
-                                 ByteString storedPassword)
+  public boolean passwordMatches(ByteSequence plaintextPassword,
+                                 ByteSequence storedPassword)
   {
-    byte[] storedPWDigestBytes = storedPassword.value();
+    // TODO: Can we avoid this copy?
+    byte[] plaintextPasswordBytes = plaintextPassword.toByteArray();
 
-    byte[] userPWDigestBytes;
+    ByteString userPWDigestBytes;
     try
     {
       // The salt is stored as the first two bytes of the storedPassword
       // value, and crypt.crypt() only looks at the first two bytes, so
       // we can pass it in directly.
-      byte[] salt = storedPWDigestBytes;
-
-      userPWDigestBytes = crypt.crypt(plaintextPassword.value(), salt);
+      byte[] salt = storedPassword.copyTo(new byte[2]);
+      userPWDigestBytes =
+          ByteString.wrap(crypt.crypt(plaintextPasswordBytes, salt));
     }
     catch (Exception e)
     {
       return false;
     }
 
-    return Arrays.equals(userPWDigestBytes, storedPWDigestBytes);
+    return userPWDigestBytes.equals(storedPassword);
   }
 
 
@@ -221,7 +219,7 @@
    * {@inheritDoc}
    */
   @Override()
-  public ByteString encodeAuthPassword(ByteString plaintext)
+  public ByteString encodeAuthPassword(ByteSequence plaintext)
          throws DirectoryException
   {
     Message message =
@@ -235,7 +233,7 @@
    * {@inheritDoc}
    */
   @Override()
-  public boolean authPasswordMatches(ByteString plaintextPassword,
+  public boolean authPasswordMatches(ByteSequence plaintextPassword,
                                      String authInfo, String authValue)
   {
     // This storage scheme does not support the authentication password syntax.
@@ -259,7 +257,7 @@
    * {@inheritDoc}
    */
   @Override()
-  public ByteString getPlaintextValue(ByteString storedPassword)
+  public ByteString getPlaintextValue(ByteSequence storedPassword)
          throws DirectoryException
   {
     Message message =
diff --git a/opends/src/server/org/opends/server/extensions/DictionaryPasswordValidator.java b/opends/src/server/org/opends/server/extensions/DictionaryPasswordValidator.java
index 8374fa3..172e3b2 100644
--- a/opends/src/server/org/opends/server/extensions/DictionaryPasswordValidator.java
+++ b/opends/src/server/org/opends/server/extensions/DictionaryPasswordValidator.java
@@ -42,14 +42,7 @@
 import org.opends.server.admin.std.server.PasswordValidatorCfg;
 import org.opends.server.api.PasswordValidator;
 import org.opends.server.config.ConfigException;
-import org.opends.server.types.ConfigChangeResult;
-import org.opends.server.types.ByteString;
-import org.opends.server.types.DebugLogLevel;
-import org.opends.server.types.DirectoryConfig;
-import org.opends.server.types.Entry;
-import org.opends.server.types.InitializationException;
-import org.opends.server.types.Operation;
-import org.opends.server.types.ResultCode;
+import org.opends.server.types.*;
 
 import static org.opends.server.loggers.debug.DebugLogger.*;
 import org.opends.server.loggers.debug.DebugTracer;
@@ -136,7 +129,7 @@
 
     // Check to see if the provided password is in the dictionary in the order
     // that it was provided.
-    String password = newPassword.stringValue();
+    String password = newPassword.toString();
     if (! config.isCaseSensitiveValidation())
     {
       password = toLowerCase(password);
diff --git a/opends/src/server/org/opends/server/extensions/DynamicGroup.java b/opends/src/server/org/opends/server/extensions/DynamicGroup.java
index 8a627ad..dc81701 100644
--- a/opends/src/server/org/opends/server/extensions/DynamicGroup.java
+++ b/opends/src/server/org/opends/server/extensions/DynamicGroup.java
@@ -158,7 +158,7 @@
         {
           try
           {
-            memberURLs.add(LDAPURL.decode(v.getStringValue(), true));
+            memberURLs.add(LDAPURL.decode(v.getValue().toString(), true));
           }
           catch (DirectoryException de)
           {
@@ -168,7 +168,7 @@
             }
 
             Message message = ERR_DYNAMICGROUP_CANNOT_DECODE_MEMBERURL.
-                get(v.getStringValue(), String.valueOf(groupEntry.getDN()),
+                get(v.getValue().toString(), String.valueOf(groupEntry.getDN()),
                     de.getMessageObject());
             ErrorLogger.logError(message);
           }
diff --git a/opends/src/server/org/opends/server/extensions/EntryDNVirtualAttributeProvider.java b/opends/src/server/org/opends/server/extensions/EntryDNVirtualAttributeProvider.java
index 31ada60..a791ebe 100644
--- a/opends/src/server/org/opends/server/extensions/EntryDNVirtualAttributeProvider.java
+++ b/opends/src/server/org/opends/server/extensions/EntryDNVirtualAttributeProvider.java
@@ -40,18 +40,7 @@
 import org.opends.server.core.DirectoryServer;
 import org.opends.server.core.SearchOperation;
 import org.opends.server.loggers.debug.DebugTracer;
-import org.opends.server.types.AttributeType;
-import org.opends.server.types.AttributeValue;
-import org.opends.server.types.ByteString;
-import org.opends.server.types.ByteStringFactory;
-import org.opends.server.types.ConditionResult;
-import org.opends.server.types.DebugLogLevel;
-import org.opends.server.types.DN;
-import org.opends.server.types.Entry;
-import org.opends.server.types.InitializationException;
-import org.opends.server.types.SearchFilter;
-import org.opends.server.types.SearchScope;
-import org.opends.server.types.VirtualAttributeRule;
+import org.opends.server.types.*;
 
 import static org.opends.server.loggers.debug.DebugLogger.*;
 import static org.opends.server.util.ServerConstants.*;
@@ -115,9 +104,9 @@
                                        VirtualAttributeRule rule)
   {
     String normDNString = entry.getDN().toNormalizedString();
-    AttributeValue value = new AttributeValue(
-                                  ByteStringFactory.create(normDNString),
-                                  ByteStringFactory.create(normDNString));
+    AttributeValue value = AttributeValues.create(
+                                  ByteString.valueOf(normDNString),
+                                  ByteString.valueOf(normDNString));
     return Collections.singleton(value);
   }
 
@@ -145,7 +134,7 @@
     try
     {
       String normalizedDN    = entry.getDN().toNormalizedString();
-      String normalizedValue = value.getNormalizedStringValue();
+      String normalizedValue = value.getNormalizedValue().toString();
       return normalizedDN.equals(normalizedValue);
     }
     catch (Exception e)
@@ -170,8 +159,8 @@
   {
     String ndnString = entry.getDN().toNormalizedString();
 
-    AttributeValue v = new AttributeValue(ByteStringFactory.create(ndnString),
-                                          ByteStringFactory.create(ndnString));
+    AttributeValue v = AttributeValues.create(ByteString.valueOf(ndnString),
+        ByteString.valueOf(ndnString));
     return values.contains(v);
   }
 
diff --git a/opends/src/server/org/opends/server/extensions/EntryUUIDVirtualAttributeProvider.java b/opends/src/server/org/opends/server/extensions/EntryUUIDVirtualAttributeProvider.java
index 036a995..3f64cea 100644
--- a/opends/src/server/org/opends/server/extensions/EntryUUIDVirtualAttributeProvider.java
+++ b/opends/src/server/org/opends/server/extensions/EntryUUIDVirtualAttributeProvider.java
@@ -39,15 +39,7 @@
 import org.opends.server.config.ConfigException;
 import org.opends.server.core.SearchOperation;
 import org.opends.server.loggers.debug.DebugTracer;
-import org.opends.server.types.AttributeValue;
-import org.opends.server.types.ByteString;
-import org.opends.server.types.ByteStringFactory;
-import org.opends.server.types.ConditionResult;
-import org.opends.server.types.DebugLogLevel;
-import org.opends.server.types.Entry;
-import org.opends.server.types.InitializationException;
-import org.opends.server.types.ResultCode;
-import org.opends.server.types.VirtualAttributeRule;
+import org.opends.server.types.*;
 
 import static org.opends.messages.ExtensionMessages.*;
 import static org.opends.server.loggers.debug.DebugLogger.*;
@@ -118,9 +110,9 @@
     String normDNString = entry.getDN().toNormalizedString();
     String uuidString =
          UUID.nameUUIDFromBytes(getBytes(normDNString)).toString();
-    AttributeValue value = new AttributeValue(
-        ByteStringFactory.create(uuidString),
-        ByteStringFactory.create(uuidString));
+    AttributeValue value = AttributeValues.create(
+         ByteString.valueOf(uuidString),
+         ByteString.valueOf(uuidString));
     return Collections.singleton(value);
   }
 
@@ -151,7 +143,7 @@
       String uuidString =
            UUID.nameUUIDFromBytes(getBytes(normalizedDN)).toString();
 
-      String normalizedValue = value.getNormalizedStringValue();
+      String normalizedValue = value.getNormalizedValue().toString();
       return uuidString.equals(normalizedValue);
     }
     catch (Exception e)
diff --git a/opends/src/server/org/opends/server/extensions/ExactMatchIdentityMapper.java b/opends/src/server/org/opends/server/extensions/ExactMatchIdentityMapper.java
index dd97e49..8e58dad 100644
--- a/opends/src/server/org/opends/server/extensions/ExactMatchIdentityMapper.java
+++ b/opends/src/server/org/opends/server/extensions/ExactMatchIdentityMapper.java
@@ -46,25 +46,10 @@
 import org.opends.server.core.DirectoryServer;
 import org.opends.server.protocols.internal.InternalClientConnection;
 import org.opends.server.protocols.internal.InternalSearchOperation;
-import org.opends.server.types.AttributeType;
-import org.opends.server.types.AttributeValue;
-import org.opends.server.types.ConfigChangeResult;
-import org.opends.server.types.DereferencePolicy;
-import org.opends.server.types.DirectoryException;
-import org.opends.server.types.DN;
-import org.opends.server.types.Entry;
-import org.opends.server.types.IndexType;
-import org.opends.server.types.InitializationException;
-import org.opends.server.types.ResultCode;
-import org.opends.server.types.SearchFilter;
-import org.opends.server.types.SearchResultEntry;
-import org.opends.server.types.SearchScope;
+import org.opends.server.types.*;
 
 import static org.opends.messages.ExtensionMessages.*;
 
-import static org.opends.server.util.StaticUtils.*;
-
-
 
 /**
  * This class provides an implementation of a Directory Server identity mapper
@@ -193,7 +178,7 @@
     SearchFilter filter;
     if (attributeTypes.length == 1)
     {
-      AttributeValue value = new AttributeValue(attributeTypes[0], id);
+      AttributeValue value = AttributeValues.create(attributeTypes[0], id);
       filter = SearchFilter.createEqualityFilter(attributeTypes[0], value);
     }
     else
@@ -202,7 +187,7 @@
            new ArrayList<SearchFilter>(attributeTypes.length);
       for (AttributeType t : attributeTypes)
       {
-        AttributeValue value = new AttributeValue(t, id);
+        AttributeValue value = AttributeValues.create(t, id);
         filterComps.add(SearchFilter.createEqualityFilter(t, value));
       }
 
diff --git a/opends/src/server/org/opends/server/extensions/ExternalSASLMechanismHandler.java b/opends/src/server/org/opends/server/extensions/ExternalSASLMechanismHandler.java
index be9ee9c..b0c60f4 100644
--- a/opends/src/server/org/opends/server/extensions/ExternalSASLMechanismHandler.java
+++ b/opends/src/server/org/opends/server/extensions/ExternalSASLMechanismHandler.java
@@ -29,6 +29,7 @@
 
 
 
+import java.security.cert.Certificate;
 import java.util.ArrayList;
 import java.util.List;
 
@@ -37,27 +38,16 @@
 import org.opends.server.admin.std.server.SASLMechanismHandlerCfg;
 import org.opends.server.api.CertificateMapper;
 import org.opends.server.api.ClientConnection;
-import org.opends.server.api.ConnectionSecurityProvider;
 import org.opends.server.api.SASLMechanismHandler;
 import org.opends.server.config.ConfigException;
 import org.opends.server.core.BindOperation;
 import org.opends.server.core.DirectoryServer;
-import org.opends.server.protocols.asn1.ASN1OctetString;
-import org.opends.server.types.Attribute;
-import org.opends.server.types.AttributeType;
-import org.opends.server.types.AttributeValue;
-import org.opends.server.types.AuthenticationInfo;
-import org.opends.server.types.ConfigChangeResult;
-import org.opends.server.types.DirectoryException;
-import org.opends.server.types.DN;
-import org.opends.server.types.Entry;
-import org.opends.server.types.InitializationException;
-import org.opends.server.types.ResultCode;
 
 import static org.opends.server.config.ConfigConstants.*;
 import static org.opends.server.loggers.debug.DebugLogger.*;
 import org.opends.server.loggers.debug.DebugTracer;
-import org.opends.server.types.DebugLogLevel;
+import org.opends.server.protocols.ldap.LDAPClientConnection;
+import org.opends.server.types.*;
 import static org.opends.messages.ExtensionMessages.*;
 
 import static org.opends.server.util.ServerConstants.*;
@@ -178,51 +168,24 @@
     // Get the client connection used for the bind request, and get the
     // security manager for that connection.  If either are null, then fail.
     ClientConnection clientConnection = bindOperation.getClientConnection();
-    if (clientConnection == null)
-    {
+    if (clientConnection == null) {
       bindOperation.setResultCode(ResultCode.INVALID_CREDENTIALS);
-
       Message message = ERR_SASLEXTERNAL_NO_CLIENT_CONNECTION.get();
       bindOperation.setAuthFailureReason(message);
       return;
     }
 
-    ConnectionSecurityProvider securityProvider =
-         clientConnection.getConnectionSecurityProvider();
-    if (securityProvider == null)
-    {
-      bindOperation.setResultCode(ResultCode.INVALID_CREDENTIALS);
-
-      Message message = ERR_SASLEXTERNAL_NO_SECURITY_PROVIDER.get();
-      bindOperation.setAuthFailureReason(message);
-      return;
+    if(!(clientConnection instanceof LDAPClientConnection)) {
+        //TODO SASLPhase2 need better message
+        bindOperation.setResultCode(ResultCode.INVALID_CREDENTIALS);
+        Message message = ERR_SASLEXTERNAL_NO_SECURITY_PROVIDER.get();
+        bindOperation.setAuthFailureReason(message);
+        return;
     }
-
-
-    // Make sure that the client connection is using the TLS security provider.
-    // If not, then fail.
-    if (! (securityProvider instanceof TLSConnectionSecurityProvider))
-    {
+    LDAPClientConnection lc = (LDAPClientConnection) clientConnection;
+    Certificate[] clientCertChain = lc.getClientCertificateChain();
+    if ((clientCertChain == null) || (clientCertChain.length == 0)) {
       bindOperation.setResultCode(ResultCode.INVALID_CREDENTIALS);
-
-      Message message = ERR_SASLEXTERNAL_CLIENT_NOT_USING_TLS_PROVIDER.get(
-              securityProvider.getSecurityMechanismName());
-      bindOperation.setAuthFailureReason(message);
-      return;
-    }
-
-    TLSConnectionSecurityProvider tlsSecurityProvider =
-         (TLSConnectionSecurityProvider) securityProvider;
-
-
-    // Get the certificate chain that the client presented to the server, if
-    // possible.  If there isn't one, then fail.
-    java.security.cert.Certificate[] clientCertChain =
-         tlsSecurityProvider.getClientCertificateChain();
-    if ((clientCertChain == null) || (clientCertChain.length == 0))
-    {
-      bindOperation.setResultCode(ResultCode.INVALID_CREDENTIALS);
-
       Message message = ERR_SASLEXTERNAL_NO_CLIENT_CERT.get();
       bindOperation.setAuthFailureReason(message);
       return;
@@ -295,8 +258,8 @@
           {
             byte[] certBytes = clientCertChain[0].getEncoded();
             AttributeValue v =
-                 new AttributeValue(certificateAttributeType,
-                                    new ASN1OctetString(certBytes));
+                AttributeValues.create(
+                    certificateAttributeType, ByteString.wrap(certBytes));
 
             boolean found = false;
             for (Attribute a : certAttrList)
@@ -343,8 +306,8 @@
           {
             byte[] certBytes = clientCertChain[0].getEncoded();
             AttributeValue v =
-                 new AttributeValue(certificateAttributeType,
-                                    new ASN1OctetString(certBytes));
+                AttributeValues.create(
+                    certificateAttributeType, ByteString.wrap(certBytes));
 
             boolean found = false;
             for (Attribute a : certAttrList)
diff --git a/opends/src/server/org/opends/server/extensions/FileSystemEntryCache.java b/opends/src/server/org/opends/server/extensions/FileSystemEntryCache.java
index 0a212b1..8ecd2a6 100644
--- a/opends/src/server/org/opends/server/extensions/FileSystemEntryCache.java
+++ b/opends/src/server/org/opends/server/extensions/FileSystemEntryCache.java
@@ -68,18 +68,8 @@
 import org.opends.server.backends.jeb.ConfigurableEnvironment;
 import org.opends.server.config.ConfigException;
 import org.opends.server.core.DirectoryServer;
-import org.opends.server.types.ConfigChangeResult;
-import org.opends.server.types.DN;
-import org.opends.server.types.Entry;
-import org.opends.server.types.EntryEncodeConfig;
-import org.opends.server.types.InitializationException;
-import org.opends.server.types.ResultCode;
-import org.opends.server.types.SearchFilter;
-import org.opends.server.types.FilePermission;
-import org.opends.server.types.DebugLogLevel;
-import org.opends.server.types.OpenDsException;
 import org.opends.server.loggers.debug.DebugTracer;
-import org.opends.server.types.Attribute;
+import org.opends.server.types.*;
 import org.opends.server.util.ServerConstants;
 
 import static org.opends.server.loggers.debug.DebugLogger.*;
@@ -215,6 +205,7 @@
   /**
    * {@inheritDoc}
    */
+  @Override
   @SuppressWarnings("unchecked")
   public void initializeEntryCache(FileSystemEntryCacheCfg configuration)
           throws ConfigException, InitializationException {
@@ -441,6 +432,7 @@
   /**
    * {@inheritDoc}
    */
+  @Override
   @SuppressWarnings("unchecked")
   public void finalizeEntryCache() {
 
@@ -530,6 +522,7 @@
   /**
    * {@inheritDoc}
    */
+  @Override
   public boolean containsEntry(DN entryDN)
   {
     if (entryDN == null) {
@@ -551,6 +544,7 @@
   /**
    * {@inheritDoc}
    */
+  @Override
   public Entry getEntry(DN entryDN) {
     // Get the entry from the DN map if it is present.  If not, then return
     // null.
@@ -575,6 +569,7 @@
   /**
    * {@inheritDoc}
    */
+  @Override
   public long getEntryID(DN entryDN) {
     long entryID = -1;
     cacheReadLock.lock();
@@ -592,6 +587,7 @@
   /**
    * {@inheritDoc}
    */
+  @Override
   public DN getEntryDN(Backend backend, long entryID) {
 
     DN entryDN = null;
@@ -616,12 +612,15 @@
   /**
    * {@inheritDoc}
    */
+  @Override
   public void putEntry(Entry entry, Backend backend, long entryID)
   {
     try {
-      byte[] entryBytes = entry.encode(encodeConfig);
+      // TODO: Cache the buffer?
+      ByteStringBuilder buffer = new ByteStringBuilder();
+      entry.encode(buffer, encodeConfig);
       putEntryToDB(entry.getDN().toNormalizedString(),
-        backend, entryID, entryBytes);
+        backend, entryID, buffer);
     } catch (Exception e) {
       if (debugEnabled()) {
         TRACER.debugCaught(DebugLogLevel.ERROR, e);
@@ -632,6 +631,7 @@
   /**
    * {@inheritDoc}
    */
+  @Override
   public boolean putEntryIfAbsent(Entry entry, Backend backend, long entryID)
   {
     cacheReadLock.lock();
@@ -646,9 +646,11 @@
       cacheReadLock.unlock();
     }
     try {
-      byte[] entryBytes = entry.encode(encodeConfig);
+      // TODO: Cache the buffer?
+      ByteStringBuilder buffer = new ByteStringBuilder();
+      entry.encode(buffer, encodeConfig);
       return putEntryToDB(entry.getDN().toNormalizedString(),
-        backend, entryID, entryBytes);
+        backend, entryID, buffer);
     } catch (Exception e) {
       if (debugEnabled()) {
         TRACER.debugCaught(DebugLogLevel.ERROR, e);
@@ -661,6 +663,7 @@
   /**
    * {@inheritDoc}
    */
+  @Override
   public void removeEntry(DN entryDN) {
 
     cacheWriteLock.lock();
@@ -701,6 +704,7 @@
   /**
    * {@inheritDoc}
    */
+  @Override
   @SuppressWarnings("unchecked")
   public void clear() {
 
@@ -743,6 +747,7 @@
   /**
    * {@inheritDoc}
    */
+  @Override
   public void clearBackend(Backend backend) {
 
     cacheWriteLock.lock();
@@ -795,6 +800,7 @@
   /**
    * {@inheritDoc}
    */
+  @Override
   public void clearSubtree(DN baseDN) {
     // Determine which backend should be used for the provided base DN.  If
     // there is none, then we don't need to do anything.
@@ -914,6 +920,7 @@
   /**
    * {@inheritDoc}
    */
+  @Override
   public void handleLowMemory() {
     // This is about all we can do.
     if (entryCacheEnv != null) {
@@ -1265,6 +1272,7 @@
   /**
    * {@inheritDoc}
    */
+  @Override
   public ArrayList<Attribute> getMonitorData()
   {
     ArrayList<Attribute> attrs = new ArrayList<Attribute>();
@@ -1295,6 +1303,7 @@
   /**
    * {@inheritDoc}
    */
+  @Override
   public Long getCacheCount()
   {
     return new Long(entryCacheIndex.dnMap.size());
@@ -1320,7 +1329,8 @@
               primaryData,
               LockMode.DEFAULT) == OperationStatus.SUCCESS) {
 
-        Entry entry = Entry.decode(primaryData.getData());
+        Entry entry = Entry.decode(
+            ByteString.wrap(primaryData.getData()).asReader());
         entry.setDN(entryDN);
         return entry;
       } else {
@@ -1340,7 +1350,6 @@
   /**
    * Encodes and stores the entry in the JE backend db.
    *
-   * @param  entry    The entry to store in the cache.
    * @param  backend  The backend with which the entry is associated.
    * @param  entryID  The entry ID within the provided backend that uniquely
    *                  identifies the specified entry.
@@ -1353,7 +1362,7 @@
   private boolean putEntryToDB(String dnString,
                                Backend backend,
                                long entryID,
-                               byte[] entryBytes) {
+                               ByteStringBuilder entryBytes) {
     try {
       // Obtain a lock on the cache.  If this fails, then don't do anything.
       if (!cacheWriteLock.tryLock(getLockTimeout(), TimeUnit.MILLISECONDS)) {
@@ -1398,7 +1407,8 @@
 
       // Create data and put this cache entry into the database.
       if (entryCacheDB.put(null, cacheEntryKey,
-          new DatabaseEntry(entryBytes)) == OperationStatus.SUCCESS) {
+          new DatabaseEntry(entryBytes.getBackingArray(), 0,
+              entryBytes.length())) == OperationStatus.SUCCESS) {
         // Add the entry to the cache index maps.
         Map<Long,String> map =
           entryCacheIndex.backendMap.get(backend.getBackendID());
diff --git a/opends/src/server/org/opends/server/extensions/FingerprintCertificateMapper.java b/opends/src/server/org/opends/server/extensions/FingerprintCertificateMapper.java
index 4df618f..0cc4e2e 100644
--- a/opends/src/server/org/opends/server/extensions/FingerprintCertificateMapper.java
+++ b/opends/src/server/org/opends/server/extensions/FingerprintCertificateMapper.java
@@ -49,19 +49,7 @@
 import org.opends.server.loggers.debug.DebugTracer;
 import org.opends.server.protocols.internal.InternalClientConnection;
 import org.opends.server.protocols.internal.InternalSearchOperation;
-import org.opends.server.types.DirectoryException;
-import org.opends.server.types.AttributeType;
-import org.opends.server.types.AttributeValue;
-import org.opends.server.types.ConfigChangeResult;
-import org.opends.server.types.DebugLogLevel;
-import org.opends.server.types.DN;
-import org.opends.server.types.Entry;
-import org.opends.server.types.IndexType;
-import org.opends.server.types.InitializationException;
-import org.opends.server.types.ResultCode;
-import org.opends.server.types.SearchFilter;
-import org.opends.server.types.SearchResultEntry;
-import org.opends.server.types.SearchScope;
+import org.opends.server.types.*;
 
 import static org.opends.messages.ExtensionMessages.*;
 import static org.opends.server.loggers.debug.DebugLogger.*;
@@ -233,7 +221,7 @@
 
     // Create the search filter from the fingerprint.
     AttributeValue value =
-         new AttributeValue(fingerprintAttributeType, fingerprintString);
+        AttributeValues.create(fingerprintAttributeType, fingerprintString);
     SearchFilter filter =
          SearchFilter.createEqualityFilter(fingerprintAttributeType, value);
 
diff --git a/opends/src/server/org/opends/server/extensions/GSSAPISASLMechanismHandler.java b/opends/src/server/org/opends/server/extensions/GSSAPISASLMechanismHandler.java
index 6e3ff5f..2ec2a10 100644
--- a/opends/src/server/org/opends/server/extensions/GSSAPISASLMechanismHandler.java
+++ b/opends/src/server/org/opends/server/extensions/GSSAPISASLMechanismHandler.java
@@ -25,10 +25,15 @@
  *      Copyright 2006-2008 Sun Microsystems, Inc.
  */
 package org.opends.server.extensions;
-import org.opends.messages.Message;
 
 
 
+import static org.opends.messages.ExtensionMessages.*;
+import static org.opends.server.loggers.ErrorLogger.*;
+import static org.opends.server.loggers.debug.DebugLogger.*;
+import static org.opends.server.util.ServerConstants.*;
+import static org.opends.server.util.StaticUtils.*;
+
 import java.io.BufferedWriter;
 import java.io.File;
 import java.io.FileWriter;
@@ -38,6 +43,7 @@
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
+
 import javax.security.auth.callback.Callback;
 import javax.security.auth.callback.CallbackHandler;
 import javax.security.auth.callback.UnsupportedCallbackException;
@@ -45,8 +51,11 @@
 import javax.security.auth.login.LoginException;
 import javax.security.sasl.Sasl;
 import javax.security.sasl.SaslException;
+
+import org.opends.messages.Message;
 import org.opends.server.admin.server.ConfigurationChangeListener;
-import org.opends.server.admin.std.meta.GSSAPISASLMechanismHandlerCfgDefn.*;
+import org.opends.server.admin.std.meta.
+  GSSAPISASLMechanismHandlerCfgDefn.QualityOfProtection;
 import org.opends.server.admin.std.server.GSSAPISASLMechanismHandlerCfg;
 import org.opends.server.admin.std.server.SASLMechanismHandlerCfg;
 import org.opends.server.api.ClientConnection;
@@ -55,35 +64,31 @@
 import org.opends.server.config.ConfigException;
 import org.opends.server.core.BindOperation;
 import org.opends.server.core.DirectoryServer;
+import org.opends.server.loggers.debug.DebugTracer;
 import org.opends.server.types.ConfigChangeResult;
-import org.opends.server.types.DirectoryException;
 import org.opends.server.types.DN;
+import org.opends.server.types.DebugLogLevel;
+import org.opends.server.types.DirectoryException;
 import org.opends.server.types.Entry;
 import org.opends.server.types.InitializationException;
 import org.opends.server.types.ResultCode;
-import static org.opends.server.loggers.debug.DebugLogger.*;
-import org.opends.server.loggers.debug.DebugTracer;
-import org.opends.server.types.DebugLogLevel;
-import static org.opends.server.loggers.ErrorLogger.logError;
-import static org.opends.messages.ExtensionMessages.*;
-import static org.opends.server.util.ServerConstants.*;
-import static org.opends.server.util.StaticUtils.*;
 
 
 
 /**
- * This class provides an implementation of a SASL mechanism that authenticates
- * clients through Kerberos over GSSAPI.
+ * This class provides an implementation of a SASL mechanism that
+ * authenticates clients through Kerberos over GSSAPI.
  */
-public class GSSAPISASLMechanismHandler
-       extends SASLMechanismHandler<GSSAPISASLMechanismHandlerCfg>
-       implements ConfigurationChangeListener< GSSAPISASLMechanismHandlerCfg>,
-       CallbackHandler {
+public class GSSAPISASLMechanismHandler extends
+    SASLMechanismHandler<GSSAPISASLMechanismHandlerCfg> implements
+    ConfigurationChangeListener<GSSAPISASLMechanismHandlerCfg>, CallbackHandler
+{
 
-  //The tracer object for the debug logger.
+  // The tracer object for the debug logger.
   private static final DebugTracer TRACER = getTracer();
 
-  // The DN of the configuration entry for this SASL mechanism handler.
+  // The DN of the configuration entry for this SASL mechanism
+  // handler.
   private DN configEntryDN;
 
   // The current configuration for this SASL mechanism handler.
@@ -92,20 +97,24 @@
   // The identity mapper that will be used to map identities.
   private IdentityMapper<?> identityMapper;
 
-  //The properties to use when creating a SASL server to process the GSSAPI
-  //authentication.
-  private HashMap<String,String> saslProps;
+  // The properties to use when creating a SASL server to process the
+  // GSSAPI authentication.
+  private HashMap<String, String> saslProps;
 
-  //The fully qualified domain name used when creating the SASL server.
+  // The fully qualified domain name used when creating the SASL
+  // server.
   private String serverFQDN;
 
-  //The login context used to perform server-side authentication.
+  // The login context used to perform server-side authentication.
   private LoginContext loginContext;
 
+
+
   /**
-   * Creates a new instance of this SASL mechanism handler.  No initialization
-   * should be done in this method, as it should all be performed in the
-   * <CODE>initializeSASLMechanismHandler</CODE> method.
+   * Creates a new instance of this SASL mechanism handler. No
+   * initialization should be done in this method, as it should all be
+   * performed in the <CODE>initializeSASLMechanismHandler</CODE>
+   * method.
    */
   public GSSAPISASLMechanismHandler()
   {
@@ -113,255 +122,308 @@
   }
 
 
+
   /**
    * {@inheritDoc}
    */
   @Override()
-  public void
-  initializeSASLMechanismHandler(GSSAPISASLMechanismHandlerCfg configuration)
-  throws ConfigException, InitializationException {
-      configuration.addGSSAPIChangeListener(this);
-      this.configuration = configuration;
-      configEntryDN = configuration.dn();
-      try {
-          DN identityMapperDN = configuration.getIdentityMapperDN();
-          identityMapper = DirectoryServer.getIdentityMapper(identityMapperDN);
-          serverFQDN = getFQDN(configuration);
-          Message msg= INFO_GSSAPI_SERVER_FQDN.get(serverFQDN);
-          logError(msg);
-          saslProps = new HashMap<String,String>();
-          saslProps.put(Sasl.QOP, getQOP(configuration));
-          saslProps.put(Sasl.REUSE, "false");
-          String configFileName=configureLoginConfFile(configuration);
-          System.setProperty(JAAS_PROPERTY_CONFIG_FILE, configFileName);
-          System.setProperty(JAAS_PROPERTY_SUBJECT_CREDS_ONLY, "false");
-          getKdcRealm(configuration);
-          DirectoryServer.registerSASLMechanismHandler(SASL_MECHANISM_GSSAPI,
-                  this);
-          login();
-      } catch (UnknownHostException unhe) {
-          if (debugEnabled()) {
-            TRACER.debugCaught(DebugLogLevel.ERROR, unhe);
-          }
-          Message message = ERR_SASL_CANNOT_GET_SERVER_FQDN.get(
-                  String.valueOf(configEntryDN), getExceptionMessage(unhe));
-          throw new InitializationException(message, unhe);
-      } catch(IOException ioe) {
-          if (debugEnabled()) {
-              TRACER.debugCaught(DebugLogLevel.ERROR, ioe);
-            }
-          Message message = ERR_SASLGSSAPI_CANNOT_CREATE_JAAS_CONFIG.get(
-                                                     getExceptionMessage(ioe));
-          throw new InitializationException(message, ioe);
-      } catch (LoginException le) {
-          if (debugEnabled()) {
-              TRACER.debugCaught(DebugLogLevel.ERROR, le);
-           }
-          Message message = ERR_SASLGSSAPI_CANNOT_CREATE_LOGIN_CONTEXT.get(
-                  getExceptionMessage(le));
-          throw new InitializationException(message, le);
+  public void initializeSASLMechanismHandler(
+      GSSAPISASLMechanismHandlerCfg configuration) throws ConfigException,
+      InitializationException
+  {
+    configuration.addGSSAPIChangeListener(this);
+    this.configuration = configuration;
+    configEntryDN = configuration.dn();
+    try
+    {
+      DN identityMapperDN = configuration.getIdentityMapperDN();
+      identityMapper = DirectoryServer.getIdentityMapper(identityMapperDN);
+      serverFQDN = getFQDN(configuration);
+      Message msg = INFO_GSSAPI_SERVER_FQDN.get(serverFQDN);
+      logError(msg);
+      saslProps = new HashMap<String, String>();
+      saslProps.put(Sasl.QOP, getQOP(configuration));
+      saslProps.put(Sasl.REUSE, "false");
+      String configFileName = configureLoginConfFile(configuration);
+      System.setProperty(JAAS_PROPERTY_CONFIG_FILE, configFileName);
+      System.setProperty(JAAS_PROPERTY_SUBJECT_CREDS_ONLY, "false");
+      getKdcRealm(configuration);
+      DirectoryServer.registerSASLMechanismHandler(SASL_MECHANISM_GSSAPI, this);
+      login();
+    }
+    catch (UnknownHostException unhe)
+    {
+      if (debugEnabled())
+      {
+        TRACER.debugCaught(DebugLogLevel.ERROR, unhe);
       }
+      Message message = ERR_SASL_CANNOT_GET_SERVER_FQDN.get(String
+          .valueOf(configEntryDN), getExceptionMessage(unhe));
+      throw new InitializationException(message, unhe);
+    }
+    catch (IOException ioe)
+    {
+      if (debugEnabled())
+      {
+        TRACER.debugCaught(DebugLogLevel.ERROR, ioe);
+      }
+      Message message = ERR_SASLGSSAPI_CANNOT_CREATE_JAAS_CONFIG
+          .get(getExceptionMessage(ioe));
+      throw new InitializationException(message, ioe);
+    }
+    catch (LoginException le)
+    {
+      if (debugEnabled())
+      {
+        TRACER.debugCaught(DebugLogLevel.ERROR, le);
+      }
+      Message message = ERR_SASLGSSAPI_CANNOT_CREATE_LOGIN_CONTEXT
+          .get(getExceptionMessage(le));
+      throw new InitializationException(message, le);
+    }
   }
 
 
+
   /**
-   * Checks to make sure that the ds-cfg-kdc-address and dc-cfg-realm are
-   * both defined in the configuration. If only one is set, then that is an
-   * error. If both are defined, or, both are null that is fine.
+   * Checks to make sure that the ds-cfg-kdc-address and dc-cfg-realm
+   * are both defined in the configuration. If only one is set, then
+   * that is an error. If both are defined, or, both are null that is
+   * fine.
    *
-   * @param configuration The configuration to use.
-   * @throws InitializationException If the properties violate the requirements.
+   * @param configuration
+   *          The configuration to use.
+   * @throws InitializationException
+   *           If the properties violate the requirements.
    */
   private void getKdcRealm(GSSAPISASLMechanismHandlerCfg configuration)
-  throws InitializationException {
-      String kdcAddress = configuration.getKdcAddress();
-      String realm = configuration.getRealm();
-      if((kdcAddress != null && realm == null) ||
-         (kdcAddress == null && realm != null)) {
-          Message message = ERR_SASLGSSAPI_KDC_REALM_NOT_DEFINED.get();
-          throw new InitializationException(message);
-      } else if(kdcAddress != null && realm != null) {
-          System.setProperty(KRBV_PROPERTY_KDC, kdcAddress);
-          System.setProperty(KRBV_PROPERTY_REALM, realm);
+      throws InitializationException
+  {
+    String kdcAddress = configuration.getKdcAddress();
+    String realm = configuration.getRealm();
+    if ((kdcAddress != null && realm == null)
+        || (kdcAddress == null && realm != null))
+    {
+      Message message = ERR_SASLGSSAPI_KDC_REALM_NOT_DEFINED.get();
+      throw new InitializationException(message);
+    }
+    else if (kdcAddress != null && realm != null)
+    {
+      System.setProperty(KRBV_PROPERTY_KDC, kdcAddress);
+      System.setProperty(KRBV_PROPERTY_REALM, realm);
 
-      }
+    }
   }
 
 
+
   /**
-   * During login, callbacks are usually used to prompt for passwords. All of
-   * the GSSAPI login information is provided in the properties and login.conf
-   * file, so callbacks are ignored.
+   * During login, callbacks are usually used to prompt for passwords.
+   * All of the GSSAPI login information is provided in the properties
+   * and login.conf file, so callbacks are ignored.
    *
-   * @param callbacks An array of callbacks to process.
-   * @throws UnsupportedCallbackException if an error occurs.
+   * @param callbacks
+   *          An array of callbacks to process.
+   * @throws UnsupportedCallbackException
+   *           if an error occurs.
    */
-  public void handle(Callback[] callbacks)
-  throws UnsupportedCallbackException {
+  public void handle(Callback[] callbacks) throws UnsupportedCallbackException
+  {
   }
 
 
+
   /**
-   * Returns the fully qualified name either defined in the configuration, or,
-   * determined by examining the system configuration.
+   * Returns the fully qualified name either defined in the
+   * configuration, or, determined by examining the system
+   * configuration.
    *
-   * @param configuration The configuration to check.
+   * @param configuration
+   *          The configuration to check.
    * @return The fully qualified hostname of the server.
-   *
-   * @throws UnknownHostException If the name cannot be determined from the
-   *                              system configuration.
+   * @throws UnknownHostException
+   *           If the name cannot be determined from the system
+   *           configuration.
    */
   private String getFQDN(GSSAPISASLMechanismHandlerCfg configuration)
-  throws UnknownHostException {
-      String serverName = configuration.getServerFqdn();
-      if (serverName == null) {
-              serverName = InetAddress.getLocalHost().getCanonicalHostName();
-      }
-      return serverName;
+      throws UnknownHostException
+  {
+    String serverName = configuration.getServerFqdn();
+    if (serverName == null)
+    {
+      serverName = InetAddress.getLocalHost().getCanonicalHostName();
+    }
+    return serverName;
   }
 
 
+
   /**
-   * Create a login context or login using the principal and keytab information
-   * specified in the configuration.
+   * Create a login context or login using the principal and keytab
+   * information specified in the configuration.
    *
-   * @throws LoginException If a login context cannot be created.
+   * @throws LoginException
+   *           If a login context cannot be created.
    */
-  private void login() throws LoginException {
-      loginContext =
-          new LoginContext(GSSAPISASLMechanismHandler.class.getName(), this);
-      loginContext.login();
+  private void login() throws LoginException
+  {
+    loginContext = new LoginContext(GSSAPISASLMechanismHandler.class.getName(),
+        this);
+    loginContext.login();
   }
 
 
+
   /**
    * Logout of the current login context.
-   *
    */
-  private void logout() {
-      try {
-          loginContext.logout();
-      } catch (LoginException e) {
-          if (debugEnabled()) {
-              TRACER.debugCaught(DebugLogLevel.ERROR, e);
-          }
+  private void logout()
+  {
+    try
+    {
+      loginContext.logout();
+    }
+    catch (LoginException e)
+    {
+      if (debugEnabled())
+      {
+        TRACER.debugCaught(DebugLogLevel.ERROR, e);
       }
+    }
   }
 
 
+
   /**
-   * Creates an login.conf file from information in the specified configuration.
-   * This file is used during the login phase.
+   * Creates an login.conf file from information in the specified
+   * configuration. This file is used during the login phase.
    *
-   * @param configuration The new configuration to use.
+   * @param configuration
+   *          The new configuration to use.
    * @return The filename of the new configuration file.
-   *
-   * @throws IOException If the configuration file cannot be created.
+   * @throws IOException
+   *           If the configuration file cannot be created.
    */
-  private String
-  configureLoginConfFile(GSSAPISASLMechanismHandlerCfg configuration)
-  throws IOException {
-      String configFileName;
-      File tempFile = File.createTempFile("login", "conf");
-      configFileName = tempFile.getAbsolutePath();
-      tempFile.deleteOnExit();
-      BufferedWriter w = new BufferedWriter(new FileWriter(tempFile, false));
-      w.write(getClass().getName() + " {");
-      w.newLine();
-      w.write("  com.sun.security.auth.module.Krb5LoginModule required " +
-      "storeKey=true useKeyTab=true ");
-      String keyTabFile = configuration.getKeytab();
-      if (keyTabFile != null) {
-          w.write("keyTab=\"" + keyTabFile + "\" ");
-      }
-      StringBuilder principal= new StringBuilder();
-      String principalName = configuration.getPrincipalName();
-      String realm = configuration.getRealm();
-      if(principalName != null) {
-          principal.append("principal=\"" + principalName);
-      } else {
-          principal.append("principal=\"ldap/" + serverFQDN);
-      }
-      if (realm != null) {
-          principal.append("@" + realm);
-      }
-      w.write(principal.toString());
-      Message msg =  INFO_GSSAPI_PRINCIPAL_NAME.get(principal.toString());
-      logError(msg);
-      w.write("\";");
-      w.newLine();
-      w.write("};");
-      w.newLine();
-      w.flush();
-      w.close();
-      return configFileName;
+  private String configureLoginConfFile(
+      GSSAPISASLMechanismHandlerCfg configuration) throws IOException
+  {
+    String configFileName;
+    File tempFile = File.createTempFile("login", "conf");
+    configFileName = tempFile.getAbsolutePath();
+    tempFile.deleteOnExit();
+    BufferedWriter w = new BufferedWriter(new FileWriter(tempFile, false));
+    w.write(getClass().getName() + " {");
+    w.newLine();
+    w.write("  com.sun.security.auth.module.Krb5LoginModule required "
+        + "storeKey=true useKeyTab=true ");
+    String keyTabFile = configuration.getKeytab();
+    if (keyTabFile != null)
+    {
+      w.write("keyTab=\"" + keyTabFile + "\" ");
+    }
+    StringBuilder principal = new StringBuilder();
+    String principalName = configuration.getPrincipalName();
+    String realm = configuration.getRealm();
+    if (principalName != null)
+    {
+      principal.append("principal=\"" + principalName);
+    }
+    else
+    {
+      principal.append("principal=\"ldap/" + serverFQDN);
+    }
+    if (realm != null)
+    {
+      principal.append("@" + realm);
+    }
+    w.write(principal.toString());
+    Message msg = INFO_GSSAPI_PRINCIPAL_NAME.get(principal.toString());
+    logError(msg);
+    w.write("\";");
+    w.newLine();
+    w.write("};");
+    w.newLine();
+    w.flush();
+    w.close();
+    return configFileName;
   }
 
 
+
   /**
    * {@inheritDoc}
    */
   @Override()
-  public void finalizeSASLMechanismHandler() {
-      logout();
-      configuration.removeGSSAPIChangeListener(this);
-      DirectoryServer.deregisterSASLMechanismHandler(SASL_MECHANISM_GSSAPI);
+  public void finalizeSASLMechanismHandler()
+  {
+    logout();
+    configuration.removeGSSAPIChangeListener(this);
+    DirectoryServer.deregisterSASLMechanismHandler(SASL_MECHANISM_GSSAPI);
   }
 
 
+
   /**
    * {@inheritDoc}
    */
   @Override()
-  public void processSASLBind(BindOperation bindOp) {
-      ClientConnection clientConnection = bindOp.getClientConnection();
-      if (clientConnection == null) {
-          Message message = ERR_SASLGSSAPI_NO_CLIENT_CONNECTION.get();
-          bindOp.setAuthFailureReason(message);
-          bindOp.setResultCode(ResultCode.INVALID_CREDENTIALS);
-          return;
+  public void processSASLBind(BindOperation bindOp)
+  {
+    ClientConnection clientConnection = bindOp.getClientConnection();
+    if (clientConnection == null)
+    {
+      Message message = ERR_SASLGSSAPI_NO_CLIENT_CONNECTION.get();
+      bindOp.setAuthFailureReason(message);
+      bindOp.setResultCode(ResultCode.INVALID_CREDENTIALS);
+      return;
+    }
+    ClientConnection clientConn = bindOp.getClientConnection();
+    SASLContext saslContext = (SASLContext) clientConn.getSASLAuthStateInfo();
+    if (saslContext == null)
+    {
+      try
+      {
+        saslContext = SASLContext.createSASLContext(saslProps, serverFQDN,
+            SASL_MECHANISM_GSSAPI, identityMapper);
       }
-      ClientConnection clientConn  = bindOp.getClientConnection();
-      SASLContext saslContext = (SASLContext) clientConn.getSASLAuthStateInfo();
-      if(saslContext == null) {
-          try {
-              saslContext = SASLContext.createSASLContext(saslProps, serverFQDN,
-                                        SASL_MECHANISM_GSSAPI, identityMapper);
-          } catch (SaslException ex) {
-              if (debugEnabled()) {
-                  TRACER.debugCaught(DebugLogLevel.ERROR, ex);
-               }
-              Message msg =
-                  ERR_SASL_CONTEXT_CREATE_ERROR.get(SASL_MECHANISM_GSSAPI,
-                                                    getExceptionMessage(ex));
-              clientConn.setSASLAuthStateInfo(null);
-              bindOp.setAuthFailureReason(msg);
-              bindOp.setResultCode(ResultCode.INVALID_CREDENTIALS);
-              return;
-          }
+      catch (SaslException ex)
+      {
+        if (debugEnabled())
+        {
+          TRACER.debugCaught(DebugLogLevel.ERROR, ex);
+        }
+        Message msg = ERR_SASL_CONTEXT_CREATE_ERROR.get(SASL_MECHANISM_GSSAPI,
+            getExceptionMessage(ex));
+        clientConn.setSASLAuthStateInfo(null);
+        bindOp.setAuthFailureReason(msg);
+        bindOp.setResultCode(ResultCode.INVALID_CREDENTIALS);
+        return;
       }
-      saslContext.performAuthentication(loginContext, bindOp);
+    }
+    saslContext.performAuthentication(loginContext, bindOp);
   }
 
 
+
   /**
-   * Retrieves the user account for the user associated with the provided
-   * authorization ID.
+   * Retrieves the user account for the user associated with the
+   * provided authorization ID.
    *
-   * @param  bindOperation  The bind operation from which the provided
-   *                        authorization ID was derived.
-   * @param  authzID        The authorization ID for which to retrieve the
-   *                        associated user.
-   *
-   * @return  The user entry for the user with the specified authorization ID,
-   *          or {@code null} if none is identified.
-   *
-   * @throws  DirectoryException  If a problem occurs while searching the
-   *                              directory for the associated user, or if
-   *                              multiple matching entries are found.
+   * @param bindOperation
+   *          The bind operation from which the provided authorization
+   *          ID was derived.
+   * @param authzID
+   *          The authorization ID for which to retrieve the
+   *          associated user.
+   * @return The user entry for the user with the specified
+   *         authorization ID, or {@code null} if none is identified.
+   * @throws DirectoryException
+   *           If a problem occurs while searching the directory for
+   *           the associated user, or if multiple matching entries
+   *           are found.
    */
   public Entry getUserForAuthzID(BindOperation bindOperation, String authzID)
-         throws DirectoryException
+      throws DirectoryException
   {
     return identityMapper.getEntryForID(authzID);
   }
@@ -397,11 +459,10 @@
    */
   @Override()
   public boolean isConfigurationAcceptable(
-                      SASLMechanismHandlerCfg configuration,
-                      List<Message> unacceptableReasons)
+      SASLMechanismHandlerCfg configuration, List<Message> unacceptableReasons)
   {
     GSSAPISASLMechanismHandlerCfg config =
-         (GSSAPISASLMechanismHandlerCfg) configuration;
+      (GSSAPISASLMechanismHandlerCfg) configuration;
     return isConfigurationChangeAcceptable(config, unacceptableReasons);
   }
 
@@ -411,48 +472,52 @@
    * {@inheritDoc}
    */
   public boolean isConfigurationChangeAcceptable(
-                      GSSAPISASLMechanismHandlerCfg configuration,
-                      List<Message> unacceptableReasons)
+      GSSAPISASLMechanismHandlerCfg configuration,
+      List<Message> unacceptableReasons)
   {
     return true;
   }
 
 
+
   /**
    * {@inheritDoc}
    */
   public ConfigChangeResult applyConfigurationChange(
-          GSSAPISASLMechanismHandlerCfg configuration) {
-      ResultCode        resultCode          = ResultCode.SUCCESS;
-      boolean           adminActionRequired = false;
-      ArrayList<Message> messages            = new ArrayList<Message>();
-      DN identityMapperDN = configuration.getIdentityMapperDN();
-      IdentityMapper<?> newIdentityMapper =
-          DirectoryServer.getIdentityMapper(identityMapperDN);
-      identityMapper = newIdentityMapper;
-      saslProps = new HashMap<String,String>();
-      saslProps.put(Sasl.QOP, getQOP(configuration));
-      saslProps.put(Sasl.REUSE, "false");
-      this.configuration  = configuration;
-      return new ConfigChangeResult(resultCode, adminActionRequired, messages);
+      GSSAPISASLMechanismHandlerCfg configuration)
+  {
+    ResultCode resultCode = ResultCode.SUCCESS;
+    boolean adminActionRequired = false;
+    ArrayList<Message> messages = new ArrayList<Message>();
+    DN identityMapperDN = configuration.getIdentityMapperDN();
+    IdentityMapper<?> newIdentityMapper = DirectoryServer
+        .getIdentityMapper(identityMapperDN);
+    identityMapper = newIdentityMapper;
+    saslProps = new HashMap<String, String>();
+    saslProps.put(Sasl.QOP, getQOP(configuration));
+    saslProps.put(Sasl.REUSE, "false");
+    this.configuration = configuration;
+    return new ConfigChangeResult(resultCode, adminActionRequired, messages);
   }
 
 
+
   /**
    * Retrieves the QOP (quality-of-protection) from the specified
    * configuration.
    *
-   * @param configuration The new configuration to use.
+   * @param configuration
+   *          The new configuration to use.
    * @return A string representing the quality-of-protection.
    */
-  private String
-  getQOP(GSSAPISASLMechanismHandlerCfg configuration) {
-      QualityOfProtection QOP = configuration.getQualityOfProtection();
-      if(QOP.equals(QualityOfProtection.CONFIDENTIALITY))
-          return "auth-conf";
-      else if(QOP.equals(QualityOfProtection.INTEGRITY))
-          return "auth-int";
-      else
-          return "auth";
+  private String getQOP(GSSAPISASLMechanismHandlerCfg configuration)
+  {
+    QualityOfProtection QOP = configuration.getQualityOfProtection();
+    if (QOP.equals(QualityOfProtection.CONFIDENTIALITY))
+      return "auth-conf";
+    else if (QOP.equals(QualityOfProtection.INTEGRITY))
+      return "auth-int";
+    else
+      return "auth";
   }
 }
diff --git a/opends/src/server/org/opends/server/extensions/GetConnectionIDExtendedOperation.java b/opends/src/server/org/opends/server/extensions/GetConnectionIDExtendedOperation.java
index 5631910..f17cc74 100644
--- a/opends/src/server/org/opends/server/extensions/GetConnectionIDExtendedOperation.java
+++ b/opends/src/server/org/opends/server/extensions/GetConnectionIDExtendedOperation.java
@@ -34,14 +34,16 @@
 import org.opends.server.config.ConfigException;
 import org.opends.server.core.DirectoryServer;
 import org.opends.server.core.ExtendedOperation;
-import org.opends.server.protocols.asn1.ASN1Exception;
-import org.opends.server.protocols.asn1.ASN1Long;
-import org.opends.server.protocols.asn1.ASN1OctetString;
 import org.opends.server.types.InitializationException;
 import org.opends.server.types.ResultCode;
+import org.opends.server.types.ByteString;
+import org.opends.server.types.ByteStringBuilder;
 
-import static org.opends.messages.ExtensionMessages.*;
 import static org.opends.server.util.ServerConstants.*;
+import org.opends.server.protocols.asn1.ASN1Writer;
+import org.opends.server.protocols.asn1.ASN1;
+import org.opends.server.protocols.asn1.ASN1Exception;
+import org.opends.server.protocols.asn1.ASN1Reader;
 
 
 /**
@@ -114,9 +116,21 @@
    *
    * @return  The ASN.1 octet string containing the encoded connection ID.
    */
-  public static ASN1OctetString encodeResponseValue(long connectionID)
+  public static ByteString encodeResponseValue(long connectionID)
   {
-    return new ASN1OctetString(new ASN1Long(connectionID).encode());
+    ByteStringBuilder builder = new ByteStringBuilder(8);
+    ASN1Writer writer = ASN1.getWriter(builder);
+
+    try
+    {
+      writer.writeInteger(connectionID);
+    }
+    catch(Exception e)
+    {
+      // TODO: DO something.
+    }
+
+    return builder.toByteString();
   }
 
 
@@ -128,13 +142,22 @@
    *
    * @return  The connection ID decoded from the provided response value.
    *
-   * @throws  ASN1Exception  If an error occurs while trying to decode the
+   * @throws ASN1Exception  If an error occurs while trying to decode the
    *                         response value.
    */
-  public static long decodeResponseValue(ASN1OctetString responseValue)
+  public static long decodeResponseValue(ByteString responseValue)
          throws ASN1Exception
   {
-    return ASN1Long.decodeAsLong(responseValue.value()).longValue();
+    ASN1Reader reader = ASN1.getReader(responseValue);
+    try
+    {
+      return reader.readInteger();
+    }
+    catch(Exception e)
+    {
+      // TODO: DO something
+      return 0;
+    }
   }
 }
 
diff --git a/opends/src/server/org/opends/server/extensions/HasSubordinatesVirtualAttributeProvider.java b/opends/src/server/org/opends/server/extensions/HasSubordinatesVirtualAttributeProvider.java
index 130b741..0ceec6e 100644
--- a/opends/src/server/org/opends/server/extensions/HasSubordinatesVirtualAttributeProvider.java
+++ b/opends/src/server/org/opends/server/extensions/HasSubordinatesVirtualAttributeProvider.java
@@ -40,16 +40,7 @@
 import org.opends.server.core.SearchOperation;
 import org.opends.server.config.ConfigException;
 import org.opends.server.loggers.debug.DebugTracer;
-import org.opends.server.types.AttributeValue;
-import org.opends.server.types.ByteString;
-import org.opends.server.types.ByteStringFactory;
-import org.opends.server.types.ConditionResult;
-import org.opends.server.types.DebugLogLevel;
-import org.opends.server.types.DirectoryException;
-import org.opends.server.types.Entry;
-import org.opends.server.types.InitializationException;
-import org.opends.server.types.ResultCode;
-import org.opends.server.types.VirtualAttributeRule;
+import org.opends.server.types.*;
 
 import static org.opends.messages.ExtensionMessages.*;
 import static org.opends.server.loggers.debug.DebugLogger.getTracer;
@@ -121,8 +112,8 @@
       if(ret != null && ret != ConditionResult.UNDEFINED)
       {
         AttributeValue value =
-            new AttributeValue(ByteStringFactory.create(ret.toString()),
-                               ByteStringFactory.create(ret.toString()));
+            AttributeValues.create(ByteString.valueOf(ret.toString()),
+                ByteString.valueOf(ret.toString()));
         return Collections.singleton(value);
       }
     }
@@ -179,8 +170,8 @@
       ConditionResult ret = backend.hasSubordinates(entry.getDN());
       if(ret != null && ret != ConditionResult.UNDEFINED)
       {
-        return ConditionResult.valueOf(value.getNormalizedStringValue()).
-            equals(ret);
+        return ConditionResult.valueOf(
+            value.getNormalizedValue().toString()).equals(ret);
       }
       return false;
     }
diff --git a/opends/src/server/org/opends/server/extensions/InternalConnectionSecurityProvider.java b/opends/src/server/org/opends/server/extensions/InternalConnectionSecurityProvider.java
deleted file mode 100644
index eea0ec2..0000000
--- a/opends/src/server/org/opends/server/extensions/InternalConnectionSecurityProvider.java
+++ /dev/null
@@ -1,127 +0,0 @@
-/*
- * CDDL HEADER START
- *
- * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
- *
- * You can obtain a copy of the license at
- * trunk/opends/resource/legal-notices/OpenDS.LICENSE
- * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
- * See the License for the specific language governing permissions
- * and limitations under the License.
- *
- * When distributing Covered Code, include this CDDL HEADER in each
- * file and include the License file at
- * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
- * add the following below this CDDL 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.server.extensions;
-
-
-
-import java.nio.channels.SocketChannel;
-
-import org.opends.server.api.ClientConnection;
-import org.opends.server.api.ConnectionSecurityProvider;
-import org.opends.server.types.DirectoryException;
-
-
-
-
-/**
- * This provides an implementation of a connection security provider that is
- * intended to be used for internal client connections.  It is exactly the same
- * as the null connection security provider in that it doesn't actually protect
- * anything, but the <CODE>isSecure</CODE> method always returns
- * <CODE>true</CODE> because it is inherently secure by being an internal
- * connection.
- */
-public class InternalConnectionSecurityProvider
-       extends NullConnectionSecurityProvider
-{
-
-
-
-  /**
-   * Creates a new instance of this internal connection security provider.
-   */
-  public InternalConnectionSecurityProvider()
-  {
-    super();
-  }
-
-
-
-  /**
-   * Creates a new instance of this internal connection security provider with
-   * the provided information.
-   *
-   * @param  clientConnection  The client connection for this security provider
-   *                           instance.
-   * @param  socketChannel     The socket channel for this security provider
-   *                           instance.
-   */
-  protected InternalConnectionSecurityProvider(
-                 ClientConnection clientConnection, SocketChannel socketChannel)
-  {
-    super(clientConnection, socketChannel);
-  }
-
-
-
-  /**
-   * {@inheritDoc}
-   */
-  public String getSecurityMechanismName()
-  {
-    return "INTERNAL";
-  }
-
-
-
-  /**
-   * {@inheritDoc}
-   */
-  public boolean isSecure()
-  {
-    // Internal connections are inherently secure.
-    return true;
-  }
-
-
-
-  /**
-   * Creates a new instance of this connection security provider that will be
-   * used to encode and decode all communication on the provided client
-   * connection.
-   *
-   * @param  clientConnection  The client connection with which this security
-   *                           provider will be associated.
-   * @param  socketChannel     The socket channel that may be used to
-   *                           communicate with the client.
-   *
-   * @return  The created connection security provider instance.
-   *
-   * @throws  DirectoryException  If a problem occurs while creating a new
-   *                              instance of this security provider for the
-   *                              given client connection.
-   */
-  public ConnectionSecurityProvider newInstance(ClientConnection
-                                                      clientConnection,
-                                                SocketChannel socketChannel)
-         throws DirectoryException
-  {
-    return new InternalConnectionSecurityProvider(clientConnection,
-                                                  socketChannel);
-  }
-}
-
diff --git a/opends/src/server/org/opends/server/extensions/IsMemberOfVirtualAttributeProvider.java b/opends/src/server/org/opends/server/extensions/IsMemberOfVirtualAttributeProvider.java
index 8cf32ea..b2c7985 100644
--- a/opends/src/server/org/opends/server/extensions/IsMemberOfVirtualAttributeProvider.java
+++ b/opends/src/server/org/opends/server/extensions/IsMemberOfVirtualAttributeProvider.java
@@ -41,19 +41,7 @@
 import org.opends.server.core.DirectoryServer;
 import org.opends.server.core.SearchOperation;
 import org.opends.server.loggers.debug.DebugTracer;
-import org.opends.server.types.AttributeType;
-import org.opends.server.types.AttributeValue;
-import org.opends.server.types.ByteString;
-import org.opends.server.types.ConditionResult;
-import org.opends.server.types.DebugLogLevel;
-import org.opends.server.types.DirectoryException;
-import org.opends.server.types.DN;
-import org.opends.server.types.Entry;
-import org.opends.server.types.InitializationException;
-import org.opends.server.types.MemberList;
-import org.opends.server.types.SearchFilter;
-import org.opends.server.types.SearchScope;
-import org.opends.server.types.VirtualAttributeRule;
+import org.opends.server.types.*;
 
 import static org.opends.server.loggers.debug.DebugLogger.*;
 import static org.opends.server.util.ServerConstants.*;
@@ -125,7 +113,7 @@
       {
         if (g.isMember(entry))
         {
-          values.add(new AttributeValue(rule.getAttributeType(),
+          values.add(AttributeValues.create(rule.getAttributeType(),
                                         g.getGroupDN().toString()));
         }
       }
diff --git a/opends/src/server/org/opends/server/extensions/LengthBasedPasswordValidator.java b/opends/src/server/org/opends/server/extensions/LengthBasedPasswordValidator.java
index 1a1e150..bc1f47f 100644
--- a/opends/src/server/org/opends/server/extensions/LengthBasedPasswordValidator.java
+++ b/opends/src/server/org/opends/server/extensions/LengthBasedPasswordValidator.java
@@ -37,12 +37,7 @@
 import org.opends.server.admin.std.server.PasswordValidatorCfg;
 import org.opends.server.api.PasswordValidator;
 import org.opends.server.config.ConfigException;
-import org.opends.server.types.ByteString;
-import org.opends.server.types.ConfigChangeResult;
-import org.opends.server.types.Entry;
-import org.opends.server.types.InitializationException;
-import org.opends.server.types.Operation;
-import org.opends.server.types.ResultCode;
+import org.opends.server.types.*;
 
 import static org.opends.messages.ExtensionMessages.*;
 import org.opends.messages.MessageBuilder;
@@ -122,7 +117,7 @@
   {
     LengthBasedPasswordValidatorCfg config = currentConfig;
 
-    int numChars = newPassword.stringValue().length();
+    int numChars = newPassword.toString().length();
 
     int minLength = config.getMinPasswordLength();
     if ((minLength > 0) && (numChars < minLength))
diff --git a/opends/src/server/org/opends/server/extensions/MD5PasswordStorageScheme.java b/opends/src/server/org/opends/server/extensions/MD5PasswordStorageScheme.java
index 63ebe3d..aae5497 100644
--- a/opends/src/server/org/opends/server/extensions/MD5PasswordStorageScheme.java
+++ b/opends/src/server/org/opends/server/extensions/MD5PasswordStorageScheme.java
@@ -29,7 +29,6 @@
 
 
 import java.security.MessageDigest;
-import java.util.Arrays;
 
 import org.opends.messages.Message;
 import org.opends.server.admin.std.server.MD5PasswordStorageSchemeCfg;
@@ -37,12 +36,7 @@
 import org.opends.server.config.ConfigException;
 import org.opends.server.core.DirectoryServer;
 import org.opends.server.loggers.debug.DebugTracer;
-import org.opends.server.types.ByteString;
-import org.opends.server.types.ByteStringFactory;
-import org.opends.server.types.DebugLogLevel;
-import org.opends.server.types.DirectoryException;
-import org.opends.server.types.InitializationException;
-import org.opends.server.types.ResultCode;
+import org.opends.server.types.*;
 import org.opends.server.util.Base64;
 
 import static org.opends.messages.ExtensionMessages.*;
@@ -143,7 +137,7 @@
    * {@inheritDoc}
    */
   @Override()
-  public ByteString encodePassword(ByteString plaintext)
+  public ByteString encodePassword(ByteSequence plaintext)
          throws DirectoryException
   {
     byte[] digestBytes;
@@ -152,7 +146,9 @@
     {
       try
       {
-        digestBytes = messageDigest.digest(plaintext.value());
+        // TODO: Can we avoid this copy?
+        byte[] plaintextBytes = plaintext.toByteArray();
+        digestBytes = messageDigest.digest(plaintextBytes);
       }
       catch (Exception e)
       {
@@ -168,7 +164,7 @@
       }
     }
 
-    return ByteStringFactory.create(Base64.encode(digestBytes));
+    return ByteString.valueOf(Base64.encode(digestBytes));
   }
 
 
@@ -177,7 +173,7 @@
    * {@inheritDoc}
    */
   @Override()
-  public ByteString encodePasswordWithScheme(ByteString plaintext)
+  public ByteString encodePasswordWithScheme(ByteSequence plaintext)
          throws DirectoryException
   {
     StringBuilder buffer = new StringBuilder();
@@ -185,13 +181,15 @@
     buffer.append(STORAGE_SCHEME_NAME_MD5);
     buffer.append('}');
 
+    // TODO: Can we avoid this copy?
+    byte[] plaintextBytes = plaintext.toByteArray();
     byte[] digestBytes;
 
     synchronized (digestLock)
     {
       try
       {
-        digestBytes = messageDigest.digest(plaintext.value());
+        digestBytes = messageDigest.digest(plaintextBytes);
       }
       catch (Exception e)
       {
@@ -210,7 +208,7 @@
     buffer.append(Base64.encode(digestBytes));
 
 
-    return ByteStringFactory.create(buffer.toString());
+    return ByteString.valueOf(buffer.toString());
   }
 
 
@@ -219,16 +217,19 @@
    * {@inheritDoc}
    */
   @Override()
-  public boolean passwordMatches(ByteString plaintextPassword,
-                                 ByteString storedPassword)
+  public boolean passwordMatches(ByteSequence plaintextPassword,
+                                 ByteSequence storedPassword)
   {
-    byte[] userPWDigestBytes;
+    // TODO: Can we avoid this copy?
+    byte[] plaintextPasswordBytes = plaintextPassword.toByteArray();
+    ByteString userPWDigestBytes;
 
     synchronized (digestLock)
     {
       try
       {
-        userPWDigestBytes = messageDigest.digest(plaintextPassword.value());
+        userPWDigestBytes =
+            ByteString.wrap(messageDigest.digest(plaintextPasswordBytes));
       }
       catch (Exception e)
       {
@@ -241,10 +242,11 @@
       }
     }
 
-    byte[] storedPWDigestBytes;
+    ByteString storedPWDigestBytes;
     try
     {
-      storedPWDigestBytes = Base64.decode(storedPassword.stringValue());
+      storedPWDigestBytes =
+          ByteString.wrap(Base64.decode(storedPassword.toString()));
     }
     catch (Exception e)
     {
@@ -254,12 +256,12 @@
       }
 
       logError(ERR_PWSCHEME_CANNOT_BASE64_DECODE_STORED_PASSWORD.get(
-          storedPassword.stringValue(), String.valueOf(e)));
+          storedPassword.toString(), String.valueOf(e)));
 
       return false;
     }
 
-    return Arrays.equals(userPWDigestBytes, storedPWDigestBytes);
+    return userPWDigestBytes.equals(storedPWDigestBytes);
   }
 
 
@@ -280,7 +282,7 @@
    * {@inheritDoc}
    */
   @Override()
-  public ByteString encodeAuthPassword(ByteString plaintext)
+  public ByteString encodeAuthPassword(ByteSequence plaintext)
          throws DirectoryException
   {
     Message message =
@@ -294,7 +296,7 @@
    * {@inheritDoc}
    */
   @Override()
-  public boolean authPasswordMatches(ByteString plaintextPassword,
+  public boolean authPasswordMatches(ByteSequence plaintextPassword,
                                      String authInfo, String authValue)
   {
     // This storage scheme does not support the authentication password syntax.
@@ -318,7 +320,7 @@
    * {@inheritDoc}
    */
   @Override()
-  public ByteString getPlaintextValue(ByteString storedPassword)
+  public ByteString getPlaintextValue(ByteSequence storedPassword)
          throws DirectoryException
   {
     Message message = ERR_PWSCHEME_NOT_REVERSIBLE.get(STORAGE_SCHEME_NAME_MD5);
diff --git a/opends/src/server/org/opends/server/extensions/MemberVirtualAttributeProvider.java b/opends/src/server/org/opends/server/extensions/MemberVirtualAttributeProvider.java
index d9f57ac..b83cd1f 100644
--- a/opends/src/server/org/opends/server/extensions/MemberVirtualAttributeProvider.java
+++ b/opends/src/server/org/opends/server/extensions/MemberVirtualAttributeProvider.java
@@ -43,6 +43,7 @@
 import org.opends.server.core.DirectoryServer;
 import org.opends.server.core.SearchOperation;
 import org.opends.server.types.AttributeValue;
+import org.opends.server.types.AttributeValues;
 import org.opends.server.types.ByteString;
 import org.opends.server.types.ConditionResult;
 import org.opends.server.types.ConfigChangeResult;
@@ -146,7 +147,7 @@
           DN memberDN = memberList.nextMemberDN();
           if (memberDN != null)
           {
-            values.add(new AttributeValue(rule.getAttributeType(),
+            values.add(AttributeValues.create(rule.getAttributeType(),
                                           memberDN.toString()));
           }
         }
diff --git a/opends/src/server/org/opends/server/extensions/NullConnectionSecurityProvider.java b/opends/src/server/org/opends/server/extensions/NullConnectionSecurityProvider.java
deleted file mode 100644
index 3563114..0000000
--- a/opends/src/server/org/opends/server/extensions/NullConnectionSecurityProvider.java
+++ /dev/null
@@ -1,510 +0,0 @@
-/*
- * CDDL HEADER START
- *
- * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
- *
- * You can obtain a copy of the license at
- * trunk/opends/resource/legal-notices/OpenDS.LICENSE
- * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
- * See the License for the specific language governing permissions
- * and limitations under the License.
- *
- * When distributing Covered Code, include this CDDL HEADER in each
- * file and include the License file at
- * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
- * add the following below this CDDL 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.server.extensions;
-
-
-
-import java.io.IOException;
-import java.nio.ByteBuffer;
-import java.nio.channels.SelectionKey;
-import java.nio.channels.Selector;
-import java.nio.channels.SocketChannel;
-import java.util.Iterator;
-
-import org.opends.server.api.ClientConnection;
-import org.opends.server.api.ConnectionSecurityProvider;
-import org.opends.server.config.ConfigEntry;
-import org.opends.server.config.ConfigException;
-import org.opends.server.loggers.debug.DebugTracer;
-import org.opends.server.types.DirectoryException;
-import org.opends.server.types.DisconnectReason;
-import org.opends.server.types.InitializationException;
-import org.opends.server.types.DebugLogLevel;
-
-import static org.opends.messages.ExtensionMessages.*;
-import static org.opends.server.loggers.debug.DebugLogger.*;
-import static org.opends.server.util.StaticUtils.*;
-
-
-
-/**
- * This class provides an implementation of a connection security provider that
- * does not actually provide any security for the communication process.  Any
- * data read or written will be assumed to be clear text.
- */
-public class NullConnectionSecurityProvider
-       extends ConnectionSecurityProvider
-{
-  /**
-   * The tracer object for the debug logger.
-   */
-  private static final DebugTracer TRACER = getTracer();
-
-
-
-  /**
-   * The buffer size in bytes that will be used for data on this connection.
-   */
-  private static final int BUFFER_SIZE = 4096;
-
-
-
-  // The buffer that will be used when reading clear-text data.
-  private ByteBuffer clearBuffer;
-
-  // The client connection with which this security provider is associated.
-  private ClientConnection clientConnection;
-
-  // The socket channel that may be used to communicate with the client.
-  private SocketChannel socketChannel;
-
-
-
-  /**
-   * Creates a new instance of this connection security provider.  Note that
-   * no initialization should be done here, since it should all be done in the
-   * <CODE>initializeConnectionSecurityProvider</CODE> method.  Also note that
-   * this instance should only be used to create new instances that are
-   * associated with specific client connections.  This instance itself should
-   * not be used to attempt secure communication with the client.
-   */
-  public NullConnectionSecurityProvider()
-  {
-    super();
-  }
-
-
-
-  /**
-   * Creates a new instance of this connection security provider that will be
-   * associated with the provided client connection.
-   *
-   * @param  clientConnection  The client connection with which this connection
-   *                           security provider should be associated.
-   * @param  socketChannel     The socket channel that may be used to
-   *                           communicate with the client.
-   */
-  protected NullConnectionSecurityProvider(ClientConnection clientConnection,
-                                           SocketChannel socketChannel)
-  {
-    super();
-
-
-    this.clientConnection = clientConnection;
-    this.socketChannel    = socketChannel;
-
-    clearBuffer = ByteBuffer.allocate(BUFFER_SIZE);
-  }
-
-
-
-  /**
-   * {@inheritDoc}
-   */
-  @Override()
-  public void initializeConnectionSecurityProvider(ConfigEntry configEntry)
-         throws ConfigException, InitializationException
-  {
-    clearBuffer      = null;
-    clientConnection = null;
-    socketChannel    = null;
-  }
-
-
-
-  /**
-   * {@inheritDoc}
-   */
-  @Override()
-  public void finalizeConnectionSecurityProvider()
-  {
-    // No implementation is required.
-  }
-
-
-
-  /**
-   * {@inheritDoc}
-   */
-  @Override()
-  public String getSecurityMechanismName()
-  {
-    return "NULL";
-  }
-
-
-
-  /**
-   * {@inheritDoc}
-   */
-  @Override()
-  public boolean isSecure()
-  {
-    // This is not a secure provider.
-    return false;
-  }
-
-
-
-  /**
-   * {@inheritDoc}
-   */
-  @Override
-  public boolean isActive() {
-      //This provider is always active.
-      return true;
-  }
-
-  /**
-   * {@inheritDoc}
-   */
-  @Override()
-  public ConnectionSecurityProvider newInstance(ClientConnection
-                                                      clientConnection,
-                                                SocketChannel socketChannel)
-         throws DirectoryException
-  {
-    return new NullConnectionSecurityProvider(clientConnection,
-                                              socketChannel);
-  }
-
-
-
-  /**
-   * {@inheritDoc}
-   */
-  @Override()
-  public void disconnect(boolean connectionValid)
-  {
-    // No implementation is required.
-  }
-
-
-
-  /**
-   * {@inheritDoc}
-   */
-  @Override()
-  public int getClearBufferSize()
-  {
-    return BUFFER_SIZE;
-  }
-
-
-
-  /**
-   * {@inheritDoc}
-   */
-  @Override()
-  public int getEncodedBufferSize()
-  {
-    return BUFFER_SIZE;
-  }
-
-
-
-  /**
-   * {@inheritDoc}
-   */
-  @Override()
-  public boolean readData()
-  {
-    clearBuffer.clear();
-    while (true)
-    {
-      try
-      {
-        int bytesRead = socketChannel.read(clearBuffer);
-        clearBuffer.flip();
-
-        if (bytesRead < 0)
-        {
-          // The connection has been closed by the client.  Disconnect and
-          // return.
-          clientConnection.disconnect(DisconnectReason.CLIENT_DISCONNECT, false,
-                                      null);
-          return false;
-        }
-        else if (bytesRead == 0)
-        {
-          // We have read all the data that there is to read right now (or there
-          // wasn't any in the first place).  Just return and wait for future
-          // notification.
-          return true;
-        }
-        else
-        {
-          // We have read data from the client.  Since there is no actual
-          // security on this connection, then just deal with it as-is.
-          if (! clientConnection.processDataRead(clearBuffer))
-          {
-            return false;
-          }
-        }
-      }
-      catch (IOException ioe)
-      {
-        if (debugEnabled())
-        {
-          TRACER.debugCaught(DebugLogLevel.ERROR, ioe);
-        }
-
-        // An error occurred while trying to read data from the client.
-        // Disconnect and return.
-        clientConnection.disconnect(DisconnectReason.IO_ERROR, false, null);
-        return false;
-      }
-      catch (Exception e)
-      {
-        if (debugEnabled())
-        {
-          TRACER.debugCaught(DebugLogLevel.ERROR, e);
-        }
-
-        // An unexpected error occurred.  Disconnect and return.
-        clientConnection.disconnect(DisconnectReason.SERVER_ERROR, true,
-                                    ERR_NULL_SECURITY_PROVIDER_READ_ERROR.get(
-                                      getExceptionMessage(e)));
-        return false;
-      }
-    }
-  }
-
-
-
-  /**
-   * {@inheritDoc}
-   */
-  @Override()
-  public boolean writeData(ByteBuffer clearData)
-  {
-    int position = clearData.position();
-    int limit    = clearData.limit();
-
-    try
-    {
-      while (clearData.hasRemaining())
-      {
-        int bytesWritten = socketChannel.write(clearData);
-        if (bytesWritten < 0)
-        {
-          // The client connection has been closed.  Disconnect and return.
-          clientConnection.disconnect(DisconnectReason.CLIENT_DISCONNECT, false,
-                                      null);
-          return false;
-        }
-        else if (bytesWritten == 0)
-        {
-          // This can happen if the server can't send data to the client (e.g.,
-          // because the client is blocked or there is a network problem.  In
-          // that case, then use a selector to perform the write, timing out and
-          // terminating the client connection if necessary.
-          return writeWithTimeout(clientConnection, socketChannel, clearData);
-        }
-      }
-
-      return true;
-    }
-    catch (IOException ioe)
-    {
-      if (debugEnabled())
-      {
-        TRACER.debugCaught(DebugLogLevel.ERROR, ioe);
-      }
-
-      // An error occurred while trying to write data to the client.  Disconnect
-      // and return.
-      clientConnection.disconnect(DisconnectReason.IO_ERROR, false, null);
-      return false;
-    }
-    catch (Exception e)
-    {
-      if (debugEnabled())
-      {
-        TRACER.debugCaught(DebugLogLevel.ERROR, e);
-      }
-
-      // An unexpected error occurred.  Disconnect and return.
-      clientConnection.disconnect(DisconnectReason.SERVER_ERROR, true,
-                                  ERR_NULL_SECURITY_PROVIDER_WRITE_ERROR.get(
-                                  getExceptionMessage(e)));
-      return false;
-    }
-    finally
-    {
-      clearData.position(position);
-      clearData.limit(limit);
-    }
-  }
-
-
-
-  /**
-   * Writes the contents of the provided buffer to the client, terminating the
-   * connection if the write is unsuccessful for too long (e.g., if the client
-   * is unresponsive or there is a network problem).  If possible, it will
-   * attempt to use the selector returned by the
-   * {@code ClientConnection.getWriteSelector} method, but it is capable of
-   * working even if that method returns {@code null}.
-   * <BR><BR>
-   * Note that this method has been written in a generic manner so that other
-   * connection security providers can use it to send data to the client,
-   * provided that the given buffer contains the appropriate pre-encoded
-   * information.
-   * <BR><BR>
-   * Also note that the original position and limit values will not be
-   * preserved, so if that is important to the caller, then it should record
-   * them before calling this method and restore them after it returns.
-   *
-   * @param  clientConnection  The client connection to which the data is to be
-   *                           written.
-   * @param  socketChannel     The socket channel over which to write the data.
-   * @param  buffer            The data to be written to the client.
-   *
-   * @return  <CODE>true</CODE> if all the data in the provided buffer was
-   *          written to the client and the connection may remain established,
-   *          or <CODE>false</CODE> if a problem occurred and the client
-   *          connection is no longer valid.  Note that if this method does
-   *          return <CODE>false</CODE>, then it must have already disconnected
-   *          the client.
-   *
-   * @throws  IOException  If a problem occurs while attempting to write data
-   *                       to the client.  The caller will be responsible for
-   *                       catching this and terminating the client connection.
-   */
-  public static boolean writeWithTimeout(ClientConnection clientConnection,
-                                         SocketChannel socketChannel,
-                                         ByteBuffer buffer)
-         throws IOException
-  {
-    long startTime = System.currentTimeMillis();
-    long waitTime  = clientConnection.getMaxBlockedWriteTimeLimit();
-    if (waitTime <= 0)
-    {
-      // We won't support an infinite time limit, so fall back to using
-      // five minutes, which is a very long timeout given that we're
-      // blocking a worker thread.
-      waitTime = 300000L;
-    }
-
-    long stopTime = startTime + waitTime;
-
-
-    Selector selector = clientConnection.getWriteSelector();
-    if (selector == null)
-    {
-      // The client connection does not provide a selector, so we'll fall back
-      // to a more inefficient way that will work without a selector.
-      while (buffer.hasRemaining() && (System.currentTimeMillis() < stopTime))
-      {
-        if (socketChannel.write(buffer) < 0)
-        {
-          // The client connection has been closed.  Disconnect and return.
-          clientConnection.disconnect(DisconnectReason.CLIENT_DISCONNECT, false,
-                                      null);
-          return false;
-        }
-      }
-
-      if (buffer.hasRemaining())
-      {
-        // If we've gotten here, then the write timed out.  Terminate the client
-        // connection.
-        clientConnection.disconnect(DisconnectReason.IO_TIMEOUT, false, null);
-        return false;
-      }
-
-      return true;
-    }
-
-
-    // Register with the selector for handling write operations.
-    SelectionKey key = socketChannel.register(selector, SelectionKey.OP_WRITE);
-
-    try
-    {
-      selector.select(waitTime);
-      while (buffer.hasRemaining())
-      {
-        long currentTime = System.currentTimeMillis();
-        if (currentTime >= stopTime)
-        {
-          // We've been blocked for too long.  Terminate the client connection.
-          clientConnection.disconnect(DisconnectReason.IO_TIMEOUT, false, null);
-          return false;
-        }
-        else
-        {
-          waitTime = stopTime - currentTime;
-        }
-
-        Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
-        while (iterator.hasNext())
-        {
-          SelectionKey k = iterator.next();
-          if (k.isWritable())
-          {
-            int bytesWritten = socketChannel.write(buffer);
-            if (bytesWritten < 0)
-            {
-              // The client connection has been closed.  Disconnect and return.
-              clientConnection.disconnect(DisconnectReason.CLIENT_DISCONNECT,
-                                          false, null);
-              return false;
-            }
-
-            iterator.remove();
-          }
-        }
-
-        if (buffer.hasRemaining())
-        {
-          selector.select(waitTime);
-        }
-      }
-
-      return true;
-    }
-    finally
-    {
-      if (key.isValid())
-      {
-        key.cancel();
-        selector.selectNow();
-      }
-    }
-  }
-
-  /**
-   * Always returns 0, there is no cipher used.
-   * @return Returns 0 always.
-   */
-  public int getSSF() {
-      return 0;
-  }
-}
-
diff --git a/opends/src/server/org/opends/server/extensions/NumSubordinatesVirtualAttributeProvider.java b/opends/src/server/org/opends/server/extensions/NumSubordinatesVirtualAttributeProvider.java
index 727d220..070873d 100644
--- a/opends/src/server/org/opends/server/extensions/NumSubordinatesVirtualAttributeProvider.java
+++ b/opends/src/server/org/opends/server/extensions/NumSubordinatesVirtualAttributeProvider.java
@@ -40,16 +40,7 @@
 import org.opends.server.core.DirectoryServer;
 import org.opends.server.core.SearchOperation;
 import org.opends.server.loggers.debug.DebugTracer;
-import org.opends.server.types.AttributeValue;
-import org.opends.server.types.ByteString;
-import org.opends.server.types.ByteStringFactory;
-import org.opends.server.types.ConditionResult;
-import org.opends.server.types.DebugLogLevel;
-import org.opends.server.types.DirectoryException;
-import org.opends.server.types.Entry;
-import org.opends.server.types.InitializationException;
-import org.opends.server.types.ResultCode;
-import org.opends.server.types.VirtualAttributeRule;
+import org.opends.server.types.*;
 
 import static org.opends.messages.ExtensionMessages.*;
 import static org.opends.server.loggers.debug.DebugLogger.getTracer;
@@ -122,8 +113,8 @@
       if(count >= 0)
       {
         AttributeValue value =
-            new AttributeValue(ByteStringFactory.create(String.valueOf(count)),
-                               ByteStringFactory.create(String.valueOf(count)));
+            AttributeValues.create(ByteString.valueOf(String.valueOf(count)),
+                ByteString.valueOf(String.valueOf(count)));
         return Collections.singleton(value);
       }
     }
@@ -179,7 +170,8 @@
       long count = backend.numSubordinates(entry.getDN(), false);
       if(count >= 0)
       {
-        return Long.parseLong(value.getNormalizedStringValue()) == count;
+        return Long.parseLong(value.getNormalizedValue().toString())
+            == count;
       }
       return false;
     }
diff --git a/opends/src/server/org/opends/server/extensions/PasswordModifyExtendedOperation.java b/opends/src/server/org/opends/server/extensions/PasswordModifyExtendedOperation.java
index 2ca82a4..d5c216f 100644
--- a/opends/src/server/org/opends/server/extensions/PasswordModifyExtendedOperation.java
+++ b/opends/src/server/org/opends/server/extensions/PasswordModifyExtendedOperation.java
@@ -30,7 +30,6 @@
 
 
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.HashSet;
@@ -54,31 +53,11 @@
 import org.opends.server.core.ModifyOperation;
 import org.opends.server.core.PasswordPolicyState;
 import org.opends.server.loggers.debug.DebugTracer;
-import org.opends.server.protocols.asn1.ASN1Element;
-import org.opends.server.protocols.asn1.ASN1Exception;
-import org.opends.server.protocols.asn1.ASN1OctetString;
-import org.opends.server.protocols.asn1.ASN1Sequence;
+import org.opends.server.protocols.asn1.*;
 import org.opends.server.protocols.internal.InternalClientConnection;
 import org.opends.server.schema.AuthPasswordSyntax;
 import org.opends.server.schema.UserPasswordSyntax;
-import org.opends.server.types.Attribute;
-import org.opends.server.types.AttributeBuilder;
-import org.opends.server.types.AttributeType;
-import org.opends.server.types.AttributeValue;
-import org.opends.server.types.AuthenticationInfo;
-import org.opends.server.types.ByteString;
-import org.opends.server.types.ConfigChangeResult;
-import org.opends.server.types.Control;
-import org.opends.server.types.DebugLogLevel;
-import org.opends.server.types.DirectoryException;
-import org.opends.server.types.DN;
-import org.opends.server.types.Entry;
-import org.opends.server.types.InitializationException;
-import org.opends.server.types.LockManager;
-import org.opends.server.types.Modification;
-import org.opends.server.types.ModificationType;
-import org.opends.server.types.Privilege;
-import org.opends.server.types.ResultCode;
+import org.opends.server.types.*;
 
 import static org.opends.server.extensions.ExtensionsConstants.*;
 import static org.opends.server.loggers.debug.DebugLogger.*;
@@ -268,21 +247,20 @@
     {
       try
       {
-        ASN1Sequence requestSequence =
-             ASN1Sequence.decodeAsSequence(requestValue.value());
-
-        for (ASN1Element e : requestSequence.elements())
+        ASN1Reader reader = ASN1.getReader(requestValue);
+        reader.readStartSequence();
+        while(reader.hasNextElement())
         {
-          switch (e.getType())
+          switch (reader.peekType())
           {
             case TYPE_PASSWORD_MODIFY_USER_ID:
-              userIdentity = e.decodeAsOctetString();
+              userIdentity = reader.readOctetString();
               break;
             case TYPE_PASSWORD_MODIFY_OLD_PASSWORD:
-              oldPassword = e.decodeAsOctetString();
+              oldPassword = reader.readOctetString();
               break;
             case TYPE_PASSWORD_MODIFY_NEW_PASSWORD:
-              newPassword = e.decodeAsOctetString();
+              newPassword = reader.readOctetString();
               break;
             default:
               operation.setResultCode(ResultCode.PROTOCOL_ERROR);
@@ -290,12 +268,13 @@
 
               operation.appendErrorMessage(
                       ERR_EXTOP_PASSMOD_ILLEGAL_REQUEST_ELEMENT_TYPE.get(
-                              byteToHex(e.getType())));
+                              byteToHex(reader.peekType())));
               return;
           }
         }
+        reader.readEndSequence();
       }
-      catch (ASN1Exception ae)
+      catch (Exception ae)
       {
         if (debugEnabled())
         {
@@ -374,7 +353,7 @@
       else
       {
         // There was a userIdentity field in the request.
-        String authzIDStr      = userIdentity.stringValue();
+        String authzIDStr      = userIdentity.toString();
         String lowerAuthzIDStr = toLowerCase(authzIDStr);
         if (lowerAuthzIDStr.startsWith("dn:"))
         {
@@ -924,7 +903,7 @@
               clearPasswords.add(oldPassword);
               for (ByteString pw : pwPolicyState.getClearPasswords())
               {
-                if (! Arrays.equals(pw.value(), oldPassword.value()))
+                if (! pw.equals(oldPassword))
                 {
                   clearPasswords.add(pw);
                 }
@@ -1058,7 +1037,7 @@
             try
             {
               StringBuilder[] components =
-                   AuthPasswordSyntax.decodeAuthPassword(v.getStringValue());
+                 AuthPasswordSyntax.decodeAuthPassword(v.getValue().toString());
               PasswordStorageScheme<?> scheme =
                    DirectoryServer.getAuthPasswordStorageScheme(
                         components[0].toString());
@@ -1098,7 +1077,7 @@
             try
             {
               String[] components =
-                   UserPasswordSyntax.decodeUserPassword(v.getStringValue());
+                 UserPasswordSyntax.decodeUserPassword(v.getValue().toString());
               PasswordStorageScheme<?> scheme =
                    DirectoryServer.getPasswordStorageScheme(
                         toLowerCase(components[0]));
@@ -1111,7 +1090,7 @@
               else
               {
                 if (scheme.passwordMatches(oldPassword,
-                                           new ASN1OctetString(components[1])))
+                    ByteString.valueOf(components[1])))
                 {
                   deleteValues.add(v);
                 }
@@ -1142,7 +1121,7 @@
              new LinkedHashSet<AttributeValue>(encodedPasswords.size());
         for (ByteString s : encodedPasswords)
         {
-          addValues.add(new AttributeValue(attrType, s));
+          addValues.add(AttributeValues.create(attrType, s));
         }
 
         builder = new AttributeBuilder(attrType);
@@ -1156,7 +1135,8 @@
              new LinkedHashSet<AttributeValue>(encodedPasswords.size());
         for (ByteString s : encodedPasswords)
         {
-          replaceValues.add(new AttributeValue(attrType, s));
+          replaceValues.add(
+              AttributeValues.create(attrType, s));
         }
 
         AttributeBuilder builder = new AttributeBuilder(attrType);
@@ -1257,16 +1237,22 @@
 
         if (generatedPassword)
         {
-          ArrayList<ASN1Element> valueElements = new ArrayList<ASN1Element>(1);
+          ByteStringBuilder builder = new ByteStringBuilder();
+          ASN1Writer writer = ASN1.getWriter(builder);
 
-          ASN1OctetString newPWString =
-               new ASN1OctetString(TYPE_PASSWORD_MODIFY_GENERATED_PASSWORD,
-                                   newPassword.value());
-          valueElements.add(newPWString);
+          try
+          {
+          writer.writeStartSequence();
+          writer.writeOctetString(TYPE_PASSWORD_MODIFY_GENERATED_PASSWORD,
+                                   newPassword);
+          writer.writeEndSequence();
+          }
+          catch(Exception e)
+          {
+            TRACER.debugCaught(DebugLogLevel.ERROR, e);
+          }
 
-          ASN1Sequence valueSequence = new ASN1Sequence(valueElements);
-          operation.setResponseValue(new ASN1OctetString(
-                                              valueSequence.encode()));
+          operation.setResponseValue(builder.toByteString());
         }
 
 
diff --git a/opends/src/server/org/opends/server/extensions/PasswordPolicyStateExtendedOperation.java b/opends/src/server/org/opends/server/extensions/PasswordPolicyStateExtendedOperation.java
index 50ee497..84a1c48 100644
--- a/opends/src/server/org/opends/server/extensions/PasswordPolicyStateExtendedOperation.java
+++ b/opends/src/server/org/opends/server/extensions/PasswordPolicyStateExtendedOperation.java
@@ -22,7 +22,7 @@
  * CDDL HEADER END
  *
  *
- *      Copyright 2006-2008 Sun Microsystems, Inc.
+ *      Copyright 2006-2009 Sun Microsystems, Inc.
  */
 package org.opends.server.extensions;
 
@@ -31,6 +31,7 @@
 import java.util.ArrayList;
 import java.util.LinkedHashSet;
 import java.util.List;
+import java.io.IOException;
 
 import org.opends.messages.Message;
 import org.opends.server.admin.std.server.
@@ -44,25 +45,13 @@
 import org.opends.server.core.PasswordPolicy;
 import org.opends.server.core.PasswordPolicyState;
 import org.opends.server.loggers.debug.DebugTracer;
-import org.opends.server.protocols.asn1.ASN1Element;
-import org.opends.server.protocols.asn1.ASN1Enumerated;
-import org.opends.server.protocols.asn1.ASN1OctetString;
-import org.opends.server.protocols.asn1.ASN1Sequence;
 import org.opends.server.protocols.internal.InternalClientConnection;
 import org.opends.server.protocols.internal.InternalSearchOperation;
+import org.opends.server.protocols.asn1.ASN1Reader;
+import org.opends.server.protocols.asn1.ASN1;
+import org.opends.server.protocols.asn1.ASN1Writer;
 import org.opends.server.schema.GeneralizedTimeSyntax;
-import org.opends.server.types.DebugLogLevel;
-import org.opends.server.types.DereferencePolicy;
-import org.opends.server.types.DirectoryException;
-import org.opends.server.types.DN;
-import org.opends.server.types.Entry;
-import org.opends.server.types.InitializationException;
-import org.opends.server.types.Modification;
-import org.opends.server.types.Privilege;
-import org.opends.server.types.ResultCode;
-import org.opends.server.types.SearchFilter;
-import org.opends.server.types.SearchResultEntry;
-import org.opends.server.types.SearchScope;
+import org.opends.server.types.*;
 
 import static org.opends.messages.ExtensionMessages.*;
 import static org.opends.server.loggers.debug.DebugLogger.*;
@@ -539,7 +528,7 @@
 
     // There must be a request value, and it must be a sequence.  Decode it
     // into its components.
-    ASN1OctetString requestValue = operation.getRequestValue();
+    ByteString requestValue = operation.getRequestValue();
     if (requestValue == null)
     {
       Message message = ERR_PWPSTATE_EXTOP_NO_REQUEST_VALUE.get();
@@ -548,23 +537,12 @@
       return;
     }
 
-    ASN1OctetString dnString;
-    ASN1Sequence    opSequence;
+    ByteString dnString;
+    ASN1Reader reader = ASN1.getReader(requestValue);
     try
     {
-      ASN1Sequence valueSequence =
-           ASN1Sequence.decodeAsSequence(requestValue.value());
-      List<ASN1Element> elements = valueSequence.elements();
-      dnString   = elements.get(0).decodeAsOctetString();
-
-      if (elements.size() == 2)
-      {
-        opSequence = elements.get(1).decodeAsSequence();
-      }
-      else
-      {
-        opSequence = null;
-      }
+      reader.readStartSequence();
+      dnString   = reader.readOctetString();
     }
     catch (Exception e)
     {
@@ -664,610 +642,65 @@
     // types that should be included in the response.
     boolean returnAll;
     LinkedHashSet<Integer> returnTypes = new LinkedHashSet<Integer>();
-    if ((opSequence == null) || opSequence.elements().isEmpty())
+    try
     {
-      returnAll = true;
-    }
-    else
-    {
-      returnAll = false;
-      for (ASN1Element element : opSequence.elements())
+      if (!reader.hasNextElement())
       {
-        int opType;
-        ArrayList<String> opValues;
-        try
+        // There is no operations sequence.
+        returnAll = true;
+      }
+      else if(reader.peekLength() <= 0)
+      {
+        // There is an operations sequence but its empty.
+        returnAll = true;
+        reader.readStartSequence();
+        reader.readEndSequence();
+      }
+      else
+      {
+        returnAll = false;
+        reader.readStartSequence();
+        while(reader.hasNextElement())
         {
-          List<ASN1Element> opElements = element.decodeAsSequence().elements();
-          opType = opElements.get(0).decodeAsEnumerated().intValue();
+          int opType;
+          ArrayList<String> opValues;
 
-          if (opElements.size() == 1)
+          reader.readStartSequence();
+          opType = (int)reader.readInteger();
+
+          if (!reader.hasNextElement())
           {
+            // There is no values sequence
             opValues = null;
           }
+          else if(reader.peekLength() <= 0)
+          {
+            // There is a values sequence but its empty
+            opValues = null;
+            reader.readStartSequence();
+            reader.readEndSequence();
+          }
           else
           {
-            List<ASN1Element> valueElements =
-                 opElements.get(1).decodeAsSequence().elements();
-            if (valueElements.isEmpty())
+            reader.readStartSequence();
+            opValues = new ArrayList<String>();
+            while (reader.hasNextElement())
             {
-              opValues = null;
+              opValues.add(reader.readOctetStringAsString());
             }
-            else
-            {
-              opValues = new ArrayList<String>(valueElements.size());
-              for (ASN1Element e : valueElements)
-              {
-                opValues.add(e.decodeAsOctetString().stringValue());
-              }
-            }
+            reader.readEndSequence();
           }
-        }
-        catch (Exception e)
-        {
-          if (debugEnabled())
+          reader.readEndSequence();
+
+          if(!processOp(opType, opValues, operation,
+              returnTypes, pwpState, policy))
           {
-            TRACER.debugCaught(DebugLogLevel.ERROR, e);
-          }
-
-          Message message = ERR_PWPSTATE_EXTOP_INVALID_OP_ENCODING.get(
-            e.getLocalizedMessage());
-          operation.appendErrorMessage(message);
-          operation.setResultCode(ResultCode.PROTOCOL_ERROR);
-          return;
-        }
-
-        switch (opType)
-        {
-          case OP_GET_PASSWORD_POLICY_DN:
-            returnTypes.add(OP_GET_PASSWORD_POLICY_DN);
-            break;
-
-          case OP_GET_ACCOUNT_DISABLED_STATE:
-            returnTypes.add(OP_GET_ACCOUNT_DISABLED_STATE);
-            break;
-
-          case OP_SET_ACCOUNT_DISABLED_STATE:
-            if (opValues == null)
-            {
-              operation.appendErrorMessage(
-                      ERR_PWPSTATE_EXTOP_NO_DISABLED_VALUE.get());
-              operation.setResultCode(ResultCode.CONSTRAINT_VIOLATION);
-              return;
-            }
-            else if (opValues.size() != 1)
-            {
-              operation.appendErrorMessage(
-                      ERR_PWPSTATE_EXTOP_BAD_DISABLED_VALUE_COUNT.get());
-              operation.setResultCode(ResultCode.CONSTRAINT_VIOLATION);
-              return;
-            }
-            else
-            {
-              String value = opValues.get(0);
-              if (value.equalsIgnoreCase("true"))
-              {
-                pwpState.setDisabled(true);
-              }
-              else if (value.equalsIgnoreCase("false"))
-              {
-                pwpState.setDisabled(false);
-              }
-              else
-              {
-                operation.appendErrorMessage(
-                        ERR_PWPSTATE_EXTOP_BAD_DISABLED_VALUE.get());
-                operation.setResultCode(ResultCode.CONSTRAINT_VIOLATION);
-                return;
-              }
-            }
-
-            returnTypes.add(OP_GET_ACCOUNT_DISABLED_STATE);
-            break;
-
-          case OP_CLEAR_ACCOUNT_DISABLED_STATE:
-            pwpState.setDisabled(false);
-            returnTypes.add(OP_GET_ACCOUNT_DISABLED_STATE);
-            break;
-
-          case OP_GET_ACCOUNT_EXPIRATION_TIME:
-            returnTypes.add(OP_GET_ACCOUNT_EXPIRATION_TIME);
-            break;
-
-          case OP_SET_ACCOUNT_EXPIRATION_TIME:
-            if (opValues == null)
-            {
-              pwpState.setAccountExpirationTime(pwpState.getCurrentTime());
-            }
-            else if (opValues.size() != 1)
-            {
-              operation.appendErrorMessage(
-                      ERR_PWPSTATE_EXTOP_BAD_ACCT_EXP_VALUE_COUNT.get());
-              operation.setResultCode(ResultCode.CONSTRAINT_VIOLATION);
-              return;
-            }
-            else
-            {
-              try
-              {
-                ASN1OctetString valueString =
-                     new ASN1OctetString(opValues.get(0));
-                long time = GeneralizedTimeSyntax.decodeGeneralizedTimeValue(
-                                 valueString);
-                pwpState.setAccountExpirationTime(time);
-              }
-              catch (DirectoryException de)
-              {
-                operation.appendErrorMessage(
-                        ERR_PWPSTATE_EXTOP_BAD_ACCT_EXP_VALUE.get(
-                                opValues.get(0),
-                                de.getMessageObject()));
-                operation.setResultCode(ResultCode.CONSTRAINT_VIOLATION);
-                return;
-              }
-            }
-
-            returnTypes.add(OP_GET_ACCOUNT_EXPIRATION_TIME);
-            break;
-
-          case OP_CLEAR_ACCOUNT_EXPIRATION_TIME:
-            pwpState.clearAccountExpirationTime();
-            returnTypes.add(OP_GET_ACCOUNT_EXPIRATION_TIME);
-            break;
-
-          case OP_GET_SECONDS_UNTIL_ACCOUNT_EXPIRATION:
-            returnTypes.add(OP_GET_SECONDS_UNTIL_ACCOUNT_EXPIRATION);
-            break;
-
-          case OP_GET_PASSWORD_CHANGED_TIME:
-            returnTypes.add(OP_GET_PASSWORD_CHANGED_TIME);
-            break;
-
-          case OP_SET_PASSWORD_CHANGED_TIME:
-            if (opValues == null)
-            {
-              pwpState.setPasswordChangedTime();
-            }
-            else if (opValues.size() != 1)
-            {
-              operation.appendErrorMessage(
-                      ERR_PWPSTATE_EXTOP_BAD_PWCHANGETIME_VALUE_COUNT.get());
-              operation.setResultCode(ResultCode.CONSTRAINT_VIOLATION);
-              return;
-            }
-            else
-            {
-              try
-              {
-                ASN1OctetString valueString =
-                     new ASN1OctetString(opValues.get(0));
-                long time = GeneralizedTimeSyntax.decodeGeneralizedTimeValue(
-                                 valueString);
-                pwpState.setPasswordChangedTime(time);
-              }
-              catch (DirectoryException de)
-              {
-                operation.appendErrorMessage(
-                        ERR_PWPSTATE_EXTOP_BAD_PWCHANGETIME_VALUE.get(
-                                opValues.get(0),
-                                de.getMessageObject()));
-                operation.setResultCode(ResultCode.CONSTRAINT_VIOLATION);
-                return;
-              }
-            }
-
-            returnTypes.add(OP_GET_PASSWORD_CHANGED_TIME);
-            break;
-
-          case OP_CLEAR_PASSWORD_CHANGED_TIME:
-            pwpState.clearPasswordChangedTime();
-            returnTypes.add(OP_GET_PASSWORD_CHANGED_TIME);
-            break;
-
-          case OP_GET_PASSWORD_EXPIRATION_WARNED_TIME:
-            returnTypes.add(OP_GET_PASSWORD_EXPIRATION_WARNED_TIME);
-            break;
-
-          case OP_SET_PASSWORD_EXPIRATION_WARNED_TIME:
-            if (opValues == null)
-            {
-              pwpState.setWarnedTime();
-            }
-            else if (opValues.size() != 1)
-            {
-              operation.appendErrorMessage(
-                      ERR_PWPSTATE_EXTOP_BAD_PWWARNEDTIME_VALUE_COUNT.get());
-              operation.setResultCode(ResultCode.CONSTRAINT_VIOLATION);
-              return;
-            }
-            else
-            {
-              try
-              {
-                ASN1OctetString valueString =
-                     new ASN1OctetString(opValues.get(0));
-                long time = GeneralizedTimeSyntax.decodeGeneralizedTimeValue(
-                                 valueString);
-                pwpState.setWarnedTime(time);
-              }
-              catch (DirectoryException de)
-              {
-                operation.appendErrorMessage(
-                        ERR_PWPSTATE_EXTOP_BAD_PWWARNEDTIME_VALUE.get(
-                                opValues.get(0),
-                                de.getMessageObject()));
-                operation.setResultCode(ResultCode.CONSTRAINT_VIOLATION);
-                return;
-              }
-            }
-
-            returnTypes.add(OP_GET_PASSWORD_EXPIRATION_WARNED_TIME);
-            break;
-
-          case OP_CLEAR_PASSWORD_EXPIRATION_WARNED_TIME:
-            pwpState.clearWarnedTime();
-            returnTypes.add(OP_GET_PASSWORD_EXPIRATION_WARNED_TIME);
-            break;
-
-          case OP_GET_SECONDS_UNTIL_PASSWORD_EXPIRATION:
-            returnTypes.add(OP_GET_SECONDS_UNTIL_PASSWORD_EXPIRATION);
-            break;
-
-          case OP_GET_SECONDS_UNTIL_PASSWORD_EXPIRATION_WARNING:
-            returnTypes.add(OP_GET_SECONDS_UNTIL_PASSWORD_EXPIRATION_WARNING);
-            break;
-
-          case OP_GET_AUTHENTICATION_FAILURE_TIMES:
-            returnTypes.add(OP_GET_AUTHENTICATION_FAILURE_TIMES);
-            break;
-
-          case OP_ADD_AUTHENTICATION_FAILURE_TIME:
-            if (opValues == null)
-            {
-              if (policy.getLockoutFailureCount() == 0)
-              {
-                returnTypes.add(OP_GET_AUTHENTICATION_FAILURE_TIMES);
-                break;
-              }
-
-              pwpState.updateAuthFailureTimes();
-            }
-            else if (opValues.size() != 1)
-            {
-              operation.appendErrorMessage(
-                      ERR_PWPSTATE_EXTOP_BAD_ADD_FAILURE_TIME_COUNT.get());
-              operation.setResultCode(ResultCode.CONSTRAINT_VIOLATION);
-              return;
-            }
-            else
-            {
-              try
-              {
-                ASN1OctetString valueString =
-                     new ASN1OctetString(opValues.get(0));
-                long time = GeneralizedTimeSyntax.decodeGeneralizedTimeValue(
-                                 valueString);
-                List<Long> authFailureTimes = pwpState.getAuthFailureTimes();
-                ArrayList<Long> newFailureTimes =
-                     new ArrayList<Long>(authFailureTimes.size()+1);
-                newFailureTimes.addAll(authFailureTimes);
-                newFailureTimes.add(time);
-                pwpState.setAuthFailureTimes(newFailureTimes);
-              }
-              catch (DirectoryException de)
-              {
-                Message message = ERR_PWPSTATE_EXTOP_BAD_AUTH_FAILURE_TIME.get(
-                        opValues.get(0),
-                        de.getMessageObject());
-                operation.setResultCode(de.getResultCode());
-                operation.appendErrorMessage(message);
-                return;
-              }
-            }
-
-            returnTypes.add(OP_GET_AUTHENTICATION_FAILURE_TIMES);
-            break;
-
-          case OP_SET_AUTHENTICATION_FAILURE_TIMES:
-            if (opValues == null)
-            {
-              ArrayList<Long> valueList = new ArrayList<Long>(1);
-              valueList.add(pwpState.getCurrentTime());
-              pwpState.setAuthFailureTimes(valueList);
-            }
-            else
-            {
-              ArrayList<Long> valueList = new ArrayList<Long>(opValues.size());
-              for (String s : opValues)
-              {
-                try
-                {
-                  valueList.add(
-                       GeneralizedTimeSyntax.decodeGeneralizedTimeValue(
-                            new ASN1OctetString(s)));
-                }
-                catch (DirectoryException de)
-                {
-                  Message message =
-                          ERR_PWPSTATE_EXTOP_BAD_AUTH_FAILURE_TIME.get(
-                                  s,
-                                  de.getMessageObject());
-                  operation.setResultCode(de.getResultCode());
-                  operation.appendErrorMessage(message);
-                  return;
-                }
-              }
-              pwpState.setAuthFailureTimes(valueList);
-            }
-
-            returnTypes.add(OP_GET_AUTHENTICATION_FAILURE_TIMES);
-            break;
-
-          case OP_CLEAR_AUTHENTICATION_FAILURE_TIMES:
-            pwpState.clearFailureLockout();
-            returnTypes.add(OP_GET_AUTHENTICATION_FAILURE_TIMES);
-            break;
-
-          case OP_GET_SECONDS_UNTIL_AUTHENTICATION_FAILURE_UNLOCK:
-            returnTypes.add(OP_GET_SECONDS_UNTIL_AUTHENTICATION_FAILURE_UNLOCK);
-            break;
-
-          case OP_GET_REMAINING_AUTHENTICATION_FAILURE_COUNT:
-            returnTypes.add(OP_GET_REMAINING_AUTHENTICATION_FAILURE_COUNT);
-            break;
-
-          case OP_GET_LAST_LOGIN_TIME:
-            returnTypes.add(OP_GET_LAST_LOGIN_TIME);
-            break;
-
-          case OP_SET_LAST_LOGIN_TIME:
-            if (opValues == null)
-            {
-              pwpState.setLastLoginTime();
-            }
-            else if (opValues.size() != 1)
-            {
-              operation.appendErrorMessage(
-                      ERR_PWPSTATE_EXTOP_BAD_LAST_LOGIN_TIME_COUNT.get());
-              operation.setResultCode(ResultCode.CONSTRAINT_VIOLATION);
-              return;
-            }
-            else
-            {
-              try
-              {
-                ASN1OctetString valueString =
-                     new ASN1OctetString(opValues.get(0));
-                long time = GeneralizedTimeSyntax.decodeGeneralizedTimeValue(
-                                 valueString);
-                pwpState.setLastLoginTime(time);
-              }
-              catch (DirectoryException de)
-              {
-                operation.appendErrorMessage(
-                        ERR_PWPSTATE_EXTOP_BAD_LAST_LOGIN_TIME.get(
-                                opValues.get(0),
-                                de.getMessageObject()));
-                operation.setResultCode(ResultCode.CONSTRAINT_VIOLATION);
-                return;
-              }
-            }
-
-            returnTypes.add(OP_GET_LAST_LOGIN_TIME);
-            break;
-
-          case OP_CLEAR_LAST_LOGIN_TIME:
-            pwpState.clearLastLoginTime();
-            returnTypes.add(OP_GET_LAST_LOGIN_TIME);
-            break;
-
-          case OP_GET_SECONDS_UNTIL_IDLE_LOCKOUT:
-            returnTypes.add(OP_GET_SECONDS_UNTIL_IDLE_LOCKOUT);
-            break;
-
-          case OP_GET_PASSWORD_RESET_STATE:
-            returnTypes.add(OP_GET_PASSWORD_RESET_STATE);
-            break;
-
-          case OP_SET_PASSWORD_RESET_STATE:
-            if (opValues == null)
-            {
-              operation.appendErrorMessage(
-                      ERR_PWPSTATE_EXTOP_NO_RESET_STATE_VALUE.get());
-              operation.setResultCode(ResultCode.CONSTRAINT_VIOLATION);
-              return;
-            }
-            else if (opValues.size() != 1)
-            {
-              operation.appendErrorMessage(
-                      ERR_PWPSTATE_EXTOP_BAD_RESET_STATE_VALUE_COUNT.get());
-              operation.setResultCode(ResultCode.CONSTRAINT_VIOLATION);
-              return;
-            }
-            else
-            {
-              String value = opValues.get(0);
-              if (value.equalsIgnoreCase("true"))
-              {
-                pwpState.setMustChangePassword(true);
-              }
-              else if (value.equalsIgnoreCase("false"))
-              {
-                pwpState.setMustChangePassword(false);
-              }
-              else
-              {
-                operation.appendErrorMessage(
-                        ERR_PWPSTATE_EXTOP_BAD_RESET_STATE_VALUE.get());
-                operation.setResultCode(ResultCode.CONSTRAINT_VIOLATION);
-                return;
-              }
-            }
-
-            returnTypes.add(OP_GET_PASSWORD_RESET_STATE);
-            break;
-
-          case OP_CLEAR_PASSWORD_RESET_STATE:
-            pwpState.setMustChangePassword(false);
-            returnTypes.add(OP_GET_PASSWORD_RESET_STATE);
-            break;
-
-          case OP_GET_SECONDS_UNTIL_PASSWORD_RESET_LOCKOUT:
-            returnTypes.add(OP_GET_SECONDS_UNTIL_PASSWORD_RESET_LOCKOUT);
-            break;
-
-          case OP_GET_GRACE_LOGIN_USE_TIMES:
-            returnTypes.add(OP_GET_GRACE_LOGIN_USE_TIMES);
-            break;
-
-          case OP_ADD_GRACE_LOGIN_USE_TIME:
-            if (opValues == null)
-            {
-              pwpState.updateGraceLoginTimes();
-            }
-            else if (opValues.size() != 1)
-            {
-              operation.appendErrorMessage(
-                      ERR_PWPSTATE_EXTOP_BAD_ADD_GRACE_LOGIN_TIME_COUNT.get());
-              operation.setResultCode(ResultCode.CONSTRAINT_VIOLATION);
-              return;
-            }
-            else
-            {
-              try
-              {
-                ASN1OctetString valueString =
-                     new ASN1OctetString(opValues.get(0));
-                long time = GeneralizedTimeSyntax.decodeGeneralizedTimeValue(
-                                 valueString);
-                List<Long> authFailureTimes = pwpState.getGraceLoginTimes();
-                ArrayList<Long> newGraceTimes =
-                     new ArrayList<Long>(authFailureTimes.size()+1);
-                newGraceTimes.addAll(authFailureTimes);
-                newGraceTimes.add(time);
-                pwpState.setGraceLoginTimes(newGraceTimes);
-              }
-              catch (DirectoryException de)
-              {
-                Message message = ERR_PWPSTATE_EXTOP_BAD_GRACE_LOGIN_TIME.get(
-                        opValues.get(0),
-                        de.getMessageObject());
-                operation.setResultCode(de.getResultCode());
-                operation.appendErrorMessage(message);
-                return;
-              }
-            }
-
-            returnTypes.add(OP_GET_GRACE_LOGIN_USE_TIMES);
-            break;
-
-          case OP_SET_GRACE_LOGIN_USE_TIMES:
-            if (opValues == null)
-            {
-              ArrayList<Long> valueList = new ArrayList<Long>(1);
-              valueList.add(pwpState.getCurrentTime());
-              pwpState.setGraceLoginTimes(valueList);
-            }
-            else
-            {
-              ArrayList<Long> valueList = new ArrayList<Long>(opValues.size());
-              for (String s : opValues)
-              {
-                try
-                {
-                  valueList.add(
-                       GeneralizedTimeSyntax.decodeGeneralizedTimeValue(
-                            new ASN1OctetString(s)));
-                }
-                catch (DirectoryException de)
-                {
-                  Message message = ERR_PWPSTATE_EXTOP_BAD_GRACE_LOGIN_TIME.get(
-                          s, de.getMessageObject());
-                  operation.setResultCode(de.getResultCode());
-                  operation.appendErrorMessage(message);
-                  return;
-                }
-              }
-              pwpState.setGraceLoginTimes(valueList);
-            }
-
-            returnTypes.add(OP_GET_GRACE_LOGIN_USE_TIMES);
-            break;
-
-          case OP_CLEAR_GRACE_LOGIN_USE_TIMES:
-            pwpState.clearGraceLoginTimes();
-            returnTypes.add(OP_GET_GRACE_LOGIN_USE_TIMES);
-            break;
-
-          case OP_GET_REMAINING_GRACE_LOGIN_COUNT:
-            returnTypes.add(OP_GET_REMAINING_GRACE_LOGIN_COUNT);
-            break;
-
-          case OP_GET_PASSWORD_CHANGED_BY_REQUIRED_TIME:
-            returnTypes.add(OP_GET_PASSWORD_CHANGED_BY_REQUIRED_TIME);
-            break;
-
-          case OP_SET_PASSWORD_CHANGED_BY_REQUIRED_TIME:
-            if (opValues == null)
-            {
-              pwpState.setRequiredChangeTime();
-            }
-            else if (opValues.size() != 1)
-            {
-              operation.appendErrorMessage(
-                      ERR_PWPSTATE_EXTOP_BAD_REQUIRED_CHANGE_TIME_COUNT.get());
-              operation.setResultCode(ResultCode.CONSTRAINT_VIOLATION);
-              return;
-            }
-            else
-            {
-              try
-              {
-                ASN1OctetString valueString =
-                     new ASN1OctetString(opValues.get(0));
-                long time = GeneralizedTimeSyntax.decodeGeneralizedTimeValue(
-                                 valueString);
-                pwpState.setRequiredChangeTime(time);
-              }
-              catch (DirectoryException de)
-              {
-                operation.appendErrorMessage(
-                        ERR_PWPSTATE_EXTOP_BAD_REQUIRED_CHANGE_TIME.get(
-                                opValues.get(0),
-                                de.getMessageObject()));
-                operation.setResultCode(ResultCode.CONSTRAINT_VIOLATION);
-                return;
-              }
-            }
-
-            returnTypes.add(OP_GET_PASSWORD_CHANGED_BY_REQUIRED_TIME);
-            break;
-
-          case OP_CLEAR_PASSWORD_CHANGED_BY_REQUIRED_TIME:
-            pwpState.clearRequiredChangeTime();
-            returnTypes.add(OP_GET_PASSWORD_CHANGED_BY_REQUIRED_TIME);
-            break;
-
-          case OP_GET_SECONDS_UNTIL_REQUIRED_CHANGE_TIME:
-            returnTypes.add(OP_GET_SECONDS_UNTIL_REQUIRED_CHANGE_TIME);
-            break;
-
-          case OP_GET_PASSWORD_HISTORY:
-            returnTypes.add(OP_GET_PASSWORD_HISTORY);
-            break;
-
-          case OP_CLEAR_PASSWORD_HISTORY:
-            pwpState.clearPasswordHistory();
-            returnTypes.add(OP_GET_PASSWORD_HISTORY);
-            break;
-
-          default:
-
-            operation.appendErrorMessage(ERR_PWPSTATE_EXTOP_UNKNOWN_OP_TYPE.get(
-                    String.valueOf(opType)));
-            operation.setResultCode(ResultCode.CONSTRAINT_VIOLATION);
             return;
+          }
         }
+        reader.readEndSequence();
       }
+      reader.readEndSequence();
 
 
       // If there are any modifications that need to be made to the password
@@ -1276,7 +709,7 @@
       if ((stateMods != null) && (! stateMods.isEmpty()))
       {
         ModifyOperation modifyOperation =
-             conn.processModify(targetDN, stateMods);
+            conn.processModify(targetDN, stateMods);
         if (modifyOperation.getResultCode() != ResultCode.SUCCESS)
         {
           operation.setResultCode(modifyOperation.getResultCode());
@@ -1287,20 +720,150 @@
         }
       }
     }
+    catch (Exception e)
+    {
+      if (debugEnabled())
+      {
+        TRACER.debugCaught(DebugLogLevel.ERROR, e);
+      }
+
+      Message message = ERR_PWPSTATE_EXTOP_INVALID_OP_ENCODING.get(
+          e.getLocalizedMessage());
+      operation.appendErrorMessage(message);
+      operation.setResultCode(ResultCode.PROTOCOL_ERROR);
+      return;
+    }
 
 
-    // Construct the sequence of values to return.
-    ArrayList<ASN1Element> opElements = new ArrayList<ASN1Element>();
+    try
+    {
+      // Construct the sequence of values to return.
+      ByteString responseValue =
+          encodeResponse(dnString, returnAll, returnTypes, pwpState, policy);
+      operation.setResponseOID(OID_PASSWORD_POLICY_STATE_EXTOP);
+      operation.setResponseValue(responseValue);
+      operation.setResultCode(ResultCode.SUCCESS);
+    }
+    catch(Exception e)
+    {
+      // TODO: Need a better message
+      Message message = ERR_PWPSTATE_EXTOP_INVALID_OP_ENCODING.get(
+          e.getLocalizedMessage());
+      operation.appendErrorMessage(message);
+      operation.setResultCode(ResultCode.PROTOCOL_ERROR);
+    }
+  }
+
+
+
+  /**
+   * Encodes the provided information in a form suitable for including in the
+   * response value.
+   *
+   * @param  writer  The ASN1Writer to use to encode.
+   * @param  opType  The operation type to use for the value.
+   * @param  value   The single value to include in the response.
+   *
+   * @throws IOException if an error occurs while encoding.
+   */
+  public static void encode(ASN1Writer writer, int opType, String value)
+      throws IOException
+  {
+    writer.writeStartSequence();
+    writer.writeInteger(opType);
+
+    if ((value != null))
+    {
+      writer.writeStartSequence();
+      writer.writeOctetString(value);
+      writer.writeEndSequence();
+    }
+
+    writer.writeEndSequence();
+  }
+
+
+
+  /**
+   * Encodes the provided information in a form suitable for including in the
+   * response value.
+   *
+   * @param  writer  The ASN1Writer to use to encode.
+   * @param  opType  The operation type to use for the value.
+   * @param  values  The set of string values to include in the response.
+   *
+   * @throws IOException if an error occurs while encoding.
+   */
+  public static void encode(ASN1Writer writer, int opType, String[] values)
+      throws IOException
+  {
+    writer.writeStartSequence();
+    writer.writeInteger(opType);
+
+    if ((values != null) && (values.length > 0))
+    {
+      writer.writeStartSequence();
+      for (int i=0; i < values.length; i++)
+      {
+        writer.writeOctetString(values[i]);
+      }
+      writer.writeEndSequence();
+    }
+
+    writer.writeEndSequence();
+  }
+
+  /**
+   * Encodes the provided information in a form suitable for including in the
+   * response value.
+   *
+   * @param  writer  The ASN1Writer to use to encode.
+   * @param  opType  The operation type to use for the value.
+   * @param  values  The set of timestamp values to include in the response.
+   *
+   * @throws IOException if an error occurs while encoding.
+   */
+  public static void encode(ASN1Writer writer, int opType, List<Long> values)
+      throws IOException
+  {
+    writer.writeStartSequence();
+    writer.writeInteger(opType);
+
+    if ((values != null) && (values.size() > 0))
+    {
+      writer.writeStartSequence();
+      for (long l : values)
+      {
+        writer.writeOctetString(GeneralizedTimeSyntax.format(l));
+      }
+      writer.writeEndSequence();
+    }
+
+    writer.writeEndSequence();
+  }
+
+  private ByteString encodeResponse(ByteString dnString, boolean returnAll,
+                                    LinkedHashSet<Integer> returnTypes,
+                                    PasswordPolicyState pwpState,
+                                    PasswordPolicy policy)
+      throws IOException
+  {
+    ByteStringBuilder builder = new ByteStringBuilder();
+    ASN1Writer writer = ASN1.getWriter(builder);
+    writer.writeStartSequence();
+    writer.writeOctetString(dnString);
+
+    writer.writeStartSequence();
     if (returnAll || returnTypes.contains(OP_GET_PASSWORD_POLICY_DN))
     {
-      opElements.add(encode(OP_GET_PASSWORD_POLICY_DN,
-                            policy.getConfigEntryDN().toString()));
+      encode(writer, OP_GET_PASSWORD_POLICY_DN,
+                            policy.getConfigEntryDN().toString());
     }
 
     if (returnAll || returnTypes.contains(OP_GET_ACCOUNT_DISABLED_STATE))
     {
-      opElements.add(encode(OP_GET_ACCOUNT_DISABLED_STATE,
-                            String.valueOf(pwpState.isDisabled())));
+      encode(writer, OP_GET_ACCOUNT_DISABLED_STATE,
+                            String.valueOf(pwpState.isDisabled()));
     }
 
     if (returnAll || returnTypes.contains(OP_GET_ACCOUNT_EXPIRATION_TIME))
@@ -1316,7 +879,7 @@
         expTimeStr = GeneralizedTimeSyntax.format(expTime);
       }
 
-      opElements.add(encode(OP_GET_ACCOUNT_EXPIRATION_TIME, expTimeStr));
+      encode(writer, OP_GET_ACCOUNT_EXPIRATION_TIME, expTimeStr);
     }
 
     if (returnAll ||
@@ -1334,8 +897,8 @@
              String.valueOf((expTime - pwpState.getCurrentTime()) / 1000);
       }
 
-      opElements.add(encode(OP_GET_SECONDS_UNTIL_ACCOUNT_EXPIRATION,
-                            secondsStr));
+      encode(writer, OP_GET_SECONDS_UNTIL_ACCOUNT_EXPIRATION,
+                            secondsStr);
     }
 
     if (returnAll || returnTypes.contains(OP_GET_PASSWORD_CHANGED_TIME))
@@ -1351,7 +914,7 @@
         timeStr = GeneralizedTimeSyntax.format(changedTime);
       }
 
-      opElements.add(encode(OP_GET_PASSWORD_CHANGED_TIME, timeStr));
+      encode(writer, OP_GET_PASSWORD_CHANGED_TIME, timeStr);
     }
 
     if (returnAll ||
@@ -1368,7 +931,7 @@
         timeStr = GeneralizedTimeSyntax.format(warnedTime);
       }
 
-      opElements.add(encode(OP_GET_PASSWORD_EXPIRATION_WARNED_TIME, timeStr));
+      encode(writer, OP_GET_PASSWORD_EXPIRATION_WARNED_TIME, timeStr);
     }
 
     if (returnAll ||
@@ -1385,8 +948,8 @@
         secondsStr = String.valueOf(secondsUntilExp);
       }
 
-      opElements.add(encode(OP_GET_SECONDS_UNTIL_PASSWORD_EXPIRATION,
-                            secondsStr));
+      encode(writer, OP_GET_SECONDS_UNTIL_PASSWORD_EXPIRATION,
+                            secondsStr);
     }
 
     if (returnAll ||
@@ -1411,14 +974,14 @@
         }
       }
 
-      opElements.add(encode(OP_GET_SECONDS_UNTIL_PASSWORD_EXPIRATION_WARNING,
-                            secondsStr));
+      encode(writer, OP_GET_SECONDS_UNTIL_PASSWORD_EXPIRATION_WARNING,
+                            secondsStr);
     }
 
     if (returnAll || returnTypes.contains(OP_GET_AUTHENTICATION_FAILURE_TIMES))
     {
-      opElements.add(encode(OP_GET_AUTHENTICATION_FAILURE_TIMES,
-                            pwpState.getAuthFailureTimes()));
+      encode(writer, OP_GET_AUTHENTICATION_FAILURE_TIMES,
+                            pwpState.getAuthFailureTimes());
     }
 
     if (returnAll || returnTypes.contains(
@@ -1444,8 +1007,8 @@
         secondsStr = null;
       }
 
-      opElements.add(encode(OP_GET_SECONDS_UNTIL_AUTHENTICATION_FAILURE_UNLOCK,
-                            secondsStr));
+      encode(writer, OP_GET_SECONDS_UNTIL_AUTHENTICATION_FAILURE_UNLOCK,
+                            secondsStr);
     }
 
     if (returnAll ||
@@ -1469,8 +1032,8 @@
         remainingFailuresStr = null;
       }
 
-      opElements.add(encode(OP_GET_REMAINING_AUTHENTICATION_FAILURE_COUNT,
-                            remainingFailuresStr));
+      encode(writer, OP_GET_REMAINING_AUTHENTICATION_FAILURE_COUNT,
+                            remainingFailuresStr);
     }
 
     if (returnAll || returnTypes.contains(OP_GET_LAST_LOGIN_TIME))
@@ -1486,7 +1049,7 @@
         timeStr = GeneralizedTimeSyntax.format(lastLoginTime);
       }
 
-      opElements.add(encode(OP_GET_LAST_LOGIN_TIME, timeStr));
+      encode(writer, OP_GET_LAST_LOGIN_TIME, timeStr);
     }
 
     if (returnAll || returnTypes.contains(OP_GET_SECONDS_UNTIL_IDLE_LOCKOUT))
@@ -1520,13 +1083,13 @@
         secondsStr = null;
       }
 
-      opElements.add(encode(OP_GET_SECONDS_UNTIL_IDLE_LOCKOUT, secondsStr));
+      encode(writer, OP_GET_SECONDS_UNTIL_IDLE_LOCKOUT, secondsStr);
     }
 
     if (returnAll || returnTypes.contains(OP_GET_PASSWORD_RESET_STATE))
     {
-      opElements.add(encode(OP_GET_PASSWORD_RESET_STATE,
-                            String.valueOf(pwpState.mustChangePassword())));
+      encode(writer, OP_GET_PASSWORD_RESET_STATE,
+                            String.valueOf(pwpState.mustChangePassword()));
     }
 
     if (returnAll ||
@@ -1561,14 +1124,14 @@
         secondsStr = null;
       }
 
-      opElements.add(encode(OP_GET_SECONDS_UNTIL_PASSWORD_RESET_LOCKOUT,
-                            secondsStr));
+      encode(writer, OP_GET_SECONDS_UNTIL_PASSWORD_RESET_LOCKOUT,
+                            secondsStr);
     }
 
     if (returnAll || returnTypes.contains(OP_GET_GRACE_LOGIN_USE_TIMES))
     {
-      opElements.add(encode(OP_GET_GRACE_LOGIN_USE_TIMES,
-                            pwpState.getGraceLoginTimes()));
+      encode(writer, OP_GET_GRACE_LOGIN_USE_TIMES,
+                            pwpState.getGraceLoginTimes());
     }
 
     if (returnAll || returnTypes.contains(OP_GET_REMAINING_GRACE_LOGIN_COUNT))
@@ -1584,7 +1147,7 @@
         remainingStr = String.valueOf(remainingGraceLogins);
       }
 
-      opElements.add(encode(OP_GET_REMAINING_GRACE_LOGIN_COUNT, remainingStr));
+      encode(writer, OP_GET_REMAINING_GRACE_LOGIN_COUNT, remainingStr);
     }
 
     if (returnAll ||
@@ -1601,7 +1164,7 @@
         timeStr = GeneralizedTimeSyntax.format(requiredChangeTime);
       }
 
-      opElements.add(encode(OP_GET_PASSWORD_CHANGED_BY_REQUIRED_TIME, timeStr));
+      encode(writer, OP_GET_PASSWORD_CHANGED_BY_REQUIRED_TIME, timeStr);
     }
 
     if (returnAll ||
@@ -1636,110 +1199,581 @@
         secondsStr = null;
       }
 
-      opElements.add(encode(OP_GET_SECONDS_UNTIL_REQUIRED_CHANGE_TIME,
-                            secondsStr));
+      encode(writer, OP_GET_SECONDS_UNTIL_REQUIRED_CHANGE_TIME,
+                            secondsStr);
     }
 
     if (returnAll || returnTypes.contains(OP_GET_PASSWORD_HISTORY))
     {
-      opElements.add(encode(OP_GET_PASSWORD_HISTORY,
-                            pwpState.getPasswordHistoryValues()));
+      encode(writer, OP_GET_PASSWORD_HISTORY,
+                            pwpState.getPasswordHistoryValues());
     }
+    writer.writeEndSequence();
 
-    ArrayList<ASN1Element> responseValueElements =
-         new ArrayList<ASN1Element>(2);
-    responseValueElements.add(dnString);
-    responseValueElements.add(new ASN1Sequence(opElements));
+    writer.writeEndSequence();
 
-    ASN1OctetString responseValue =
-         new ASN1OctetString(new ASN1Sequence(responseValueElements).encode());
-
-    operation.setResponseOID(OID_PASSWORD_POLICY_STATE_EXTOP);
-    operation.setResponseValue(responseValue);
-    operation.setResultCode(ResultCode.SUCCESS);
+    return builder.toByteString();
   }
 
-
-
-  /**
-   * Encodes the provided information in a form suitable for including in the
-   * response value.
-   *
-   * @param  opType  The operation type to use for the value.
-   * @param  value   The single value to include in the response.
-   *
-   * @return  The encoded ASN.1 element.
-   */
-  public static ASN1Element encode(int opType, String value)
+  private boolean processOp(int opType, ArrayList<String> opValues,
+                         ExtendedOperation operation,
+                         LinkedHashSet<Integer> returnTypes,
+                         PasswordPolicyState pwpState,
+                         PasswordPolicy policy)
   {
-    ArrayList<ASN1Element> elements = new ArrayList<ASN1Element>(2);
-    elements.add(new ASN1Enumerated(opType));
-
-    if (value != null)
+    switch (opType)
     {
-      ArrayList<ASN1Element> valueElements = new ArrayList<ASN1Element>(1);
-      valueElements.add(new ASN1OctetString(value));
-      elements.add(new ASN1Sequence(valueElements));
+      case OP_GET_PASSWORD_POLICY_DN:
+        returnTypes.add(OP_GET_PASSWORD_POLICY_DN);
+        break;
+
+      case OP_GET_ACCOUNT_DISABLED_STATE:
+        returnTypes.add(OP_GET_ACCOUNT_DISABLED_STATE);
+        break;
+
+      case OP_SET_ACCOUNT_DISABLED_STATE:
+        if (opValues == null)
+        {
+          operation.appendErrorMessage(
+              ERR_PWPSTATE_EXTOP_NO_DISABLED_VALUE.get());
+          operation.setResultCode(ResultCode.CONSTRAINT_VIOLATION);
+          return false;
+        }
+        else if (opValues.size() != 1)
+        {
+          operation.appendErrorMessage(
+              ERR_PWPSTATE_EXTOP_BAD_DISABLED_VALUE_COUNT.get());
+          operation.setResultCode(ResultCode.CONSTRAINT_VIOLATION);
+          return false;
+        }
+        else
+        {
+          String value = opValues.get(0);
+          if (value.equalsIgnoreCase("true"))
+          {
+            pwpState.setDisabled(true);
+          }
+          else if (value.equalsIgnoreCase("false"))
+          {
+            pwpState.setDisabled(false);
+          }
+          else
+          {
+            operation.appendErrorMessage(
+                ERR_PWPSTATE_EXTOP_BAD_DISABLED_VALUE.get());
+            operation.setResultCode(ResultCode.CONSTRAINT_VIOLATION);
+            return false;
+          }
+        }
+
+        returnTypes.add(OP_GET_ACCOUNT_DISABLED_STATE);
+        break;
+
+      case OP_CLEAR_ACCOUNT_DISABLED_STATE:
+        pwpState.setDisabled(false);
+        returnTypes.add(OP_GET_ACCOUNT_DISABLED_STATE);
+        break;
+
+      case OP_GET_ACCOUNT_EXPIRATION_TIME:
+        returnTypes.add(OP_GET_ACCOUNT_EXPIRATION_TIME);
+        break;
+
+      case OP_SET_ACCOUNT_EXPIRATION_TIME:
+        if (opValues == null)
+        {
+          pwpState.setAccountExpirationTime(pwpState.getCurrentTime());
+        }
+        else if (opValues.size() != 1)
+        {
+          operation.appendErrorMessage(
+              ERR_PWPSTATE_EXTOP_BAD_ACCT_EXP_VALUE_COUNT.get());
+          operation.setResultCode(ResultCode.CONSTRAINT_VIOLATION);
+          return false;
+        }
+        else
+        {
+          try
+          {
+            ByteString valueString =
+                ByteString.valueOf(opValues.get(0));
+            long time = GeneralizedTimeSyntax.decodeGeneralizedTimeValue(
+                valueString);
+            pwpState.setAccountExpirationTime(time);
+          }
+          catch (DirectoryException de)
+          {
+            operation.appendErrorMessage(
+                ERR_PWPSTATE_EXTOP_BAD_ACCT_EXP_VALUE.get(
+                    opValues.get(0),
+                    de.getMessageObject()));
+            operation.setResultCode(ResultCode.CONSTRAINT_VIOLATION);
+            return false;
+          }
+        }
+
+        returnTypes.add(OP_GET_ACCOUNT_EXPIRATION_TIME);
+        break;
+
+      case OP_CLEAR_ACCOUNT_EXPIRATION_TIME:
+        pwpState.clearAccountExpirationTime();
+        returnTypes.add(OP_GET_ACCOUNT_EXPIRATION_TIME);
+        break;
+
+      case OP_GET_SECONDS_UNTIL_ACCOUNT_EXPIRATION:
+        returnTypes.add(OP_GET_SECONDS_UNTIL_ACCOUNT_EXPIRATION);
+        break;
+
+      case OP_GET_PASSWORD_CHANGED_TIME:
+        returnTypes.add(OP_GET_PASSWORD_CHANGED_TIME);
+        break;
+
+      case OP_SET_PASSWORD_CHANGED_TIME:
+        if (opValues == null)
+        {
+          pwpState.setPasswordChangedTime();
+        }
+        else if (opValues.size() != 1)
+        {
+          operation.appendErrorMessage(
+              ERR_PWPSTATE_EXTOP_BAD_PWCHANGETIME_VALUE_COUNT.get());
+          operation.setResultCode(ResultCode.CONSTRAINT_VIOLATION);
+          return false;
+        }
+        else
+        {
+          try
+          {
+            ByteString valueString =
+                ByteString.valueOf(opValues.get(0));
+            long time = GeneralizedTimeSyntax.decodeGeneralizedTimeValue(
+                valueString);
+            pwpState.setPasswordChangedTime(time);
+          }
+          catch (DirectoryException de)
+          {
+            operation.appendErrorMessage(
+                ERR_PWPSTATE_EXTOP_BAD_PWCHANGETIME_VALUE.get(
+                    opValues.get(0),
+                    de.getMessageObject()));
+            operation.setResultCode(ResultCode.CONSTRAINT_VIOLATION);
+            return false;
+          }
+        }
+
+        returnTypes.add(OP_GET_PASSWORD_CHANGED_TIME);
+        break;
+
+      case OP_CLEAR_PASSWORD_CHANGED_TIME:
+        pwpState.clearPasswordChangedTime();
+        returnTypes.add(OP_GET_PASSWORD_CHANGED_TIME);
+        break;
+
+      case OP_GET_PASSWORD_EXPIRATION_WARNED_TIME:
+        returnTypes.add(OP_GET_PASSWORD_EXPIRATION_WARNED_TIME);
+        break;
+
+      case OP_SET_PASSWORD_EXPIRATION_WARNED_TIME:
+        if (opValues == null)
+        {
+          pwpState.setWarnedTime();
+        }
+        else if (opValues.size() != 1)
+        {
+          operation.appendErrorMessage(
+              ERR_PWPSTATE_EXTOP_BAD_PWWARNEDTIME_VALUE_COUNT.get());
+          operation.setResultCode(ResultCode.CONSTRAINT_VIOLATION);
+          return false;
+        }
+        else
+        {
+          try
+          {
+            ByteString valueString =
+                ByteString.valueOf(opValues.get(0));
+            long time = GeneralizedTimeSyntax.decodeGeneralizedTimeValue(
+                valueString);
+            pwpState.setWarnedTime(time);
+          }
+          catch (DirectoryException de)
+          {
+            operation.appendErrorMessage(
+                ERR_PWPSTATE_EXTOP_BAD_PWWARNEDTIME_VALUE.get(
+                    opValues.get(0),
+                    de.getMessageObject()));
+            operation.setResultCode(ResultCode.CONSTRAINT_VIOLATION);
+            return false;
+          }
+        }
+
+        returnTypes.add(OP_GET_PASSWORD_EXPIRATION_WARNED_TIME);
+        break;
+
+      case OP_CLEAR_PASSWORD_EXPIRATION_WARNED_TIME:
+        pwpState.clearWarnedTime();
+        returnTypes.add(OP_GET_PASSWORD_EXPIRATION_WARNED_TIME);
+        break;
+
+      case OP_GET_SECONDS_UNTIL_PASSWORD_EXPIRATION:
+        returnTypes.add(OP_GET_SECONDS_UNTIL_PASSWORD_EXPIRATION);
+        break;
+
+      case OP_GET_SECONDS_UNTIL_PASSWORD_EXPIRATION_WARNING:
+        returnTypes.add(OP_GET_SECONDS_UNTIL_PASSWORD_EXPIRATION_WARNING);
+        break;
+
+      case OP_GET_AUTHENTICATION_FAILURE_TIMES:
+        returnTypes.add(OP_GET_AUTHENTICATION_FAILURE_TIMES);
+        break;
+
+      case OP_ADD_AUTHENTICATION_FAILURE_TIME:
+        if (opValues == null)
+        {
+          if (policy.getLockoutFailureCount() == 0)
+          {
+            returnTypes.add(OP_GET_AUTHENTICATION_FAILURE_TIMES);
+            break;
+          }
+
+          pwpState.updateAuthFailureTimes();
+        }
+        else if (opValues.size() != 1)
+        {
+          operation.appendErrorMessage(
+              ERR_PWPSTATE_EXTOP_BAD_ADD_FAILURE_TIME_COUNT.get());
+          operation.setResultCode(ResultCode.CONSTRAINT_VIOLATION);
+          return false;
+        }
+        else
+        {
+          try
+          {
+            ByteString valueString =
+                ByteString.valueOf(opValues.get(0));
+            long time = GeneralizedTimeSyntax.decodeGeneralizedTimeValue(
+                valueString);
+            List<Long> authFailureTimes = pwpState.getAuthFailureTimes();
+            ArrayList<Long> newFailureTimes =
+                new ArrayList<Long>(authFailureTimes.size()+1);
+            newFailureTimes.addAll(authFailureTimes);
+            newFailureTimes.add(time);
+            pwpState.setAuthFailureTimes(newFailureTimes);
+          }
+          catch (DirectoryException de)
+          {
+            Message message = ERR_PWPSTATE_EXTOP_BAD_AUTH_FAILURE_TIME.get(
+                opValues.get(0),
+                de.getMessageObject());
+            operation.setResultCode(de.getResultCode());
+            operation.appendErrorMessage(message);
+            return false;
+          }
+        }
+
+        returnTypes.add(OP_GET_AUTHENTICATION_FAILURE_TIMES);
+        break;
+
+      case OP_SET_AUTHENTICATION_FAILURE_TIMES:
+        if (opValues == null)
+        {
+          ArrayList<Long> valueList = new ArrayList<Long>(1);
+          valueList.add(pwpState.getCurrentTime());
+          pwpState.setAuthFailureTimes(valueList);
+        }
+        else
+        {
+          ArrayList<Long> valueList = new ArrayList<Long>(opValues.size());
+          for (String s : opValues)
+          {
+            try
+            {
+              valueList.add(
+                  GeneralizedTimeSyntax.decodeGeneralizedTimeValue(
+                      ByteString.valueOf(s)));
+            }
+            catch (DirectoryException de)
+            {
+              Message message =
+                  ERR_PWPSTATE_EXTOP_BAD_AUTH_FAILURE_TIME.get(
+                      s,
+                      de.getMessageObject());
+              operation.setResultCode(de.getResultCode());
+              operation.appendErrorMessage(message);
+              return false;
+            }
+          }
+          pwpState.setAuthFailureTimes(valueList);
+        }
+
+        returnTypes.add(OP_GET_AUTHENTICATION_FAILURE_TIMES);
+        break;
+
+      case OP_CLEAR_AUTHENTICATION_FAILURE_TIMES:
+        pwpState.clearFailureLockout();
+        returnTypes.add(OP_GET_AUTHENTICATION_FAILURE_TIMES);
+        break;
+
+      case OP_GET_SECONDS_UNTIL_AUTHENTICATION_FAILURE_UNLOCK:
+        returnTypes.add(OP_GET_SECONDS_UNTIL_AUTHENTICATION_FAILURE_UNLOCK);
+        break;
+
+      case OP_GET_REMAINING_AUTHENTICATION_FAILURE_COUNT:
+        returnTypes.add(OP_GET_REMAINING_AUTHENTICATION_FAILURE_COUNT);
+        break;
+
+      case OP_GET_LAST_LOGIN_TIME:
+        returnTypes.add(OP_GET_LAST_LOGIN_TIME);
+        break;
+
+      case OP_SET_LAST_LOGIN_TIME:
+        if (opValues == null)
+        {
+          pwpState.setLastLoginTime();
+        }
+        else if (opValues.size() != 1)
+        {
+          operation.appendErrorMessage(
+              ERR_PWPSTATE_EXTOP_BAD_LAST_LOGIN_TIME_COUNT.get());
+          operation.setResultCode(ResultCode.CONSTRAINT_VIOLATION);
+          return false;
+        }
+        else
+        {
+          try
+          {
+            ByteString valueString =
+                ByteString.valueOf(opValues.get(0));
+            long time = GeneralizedTimeSyntax.decodeGeneralizedTimeValue(
+                valueString);
+            pwpState.setLastLoginTime(time);
+          }
+          catch (DirectoryException de)
+          {
+            operation.appendErrorMessage(
+                ERR_PWPSTATE_EXTOP_BAD_LAST_LOGIN_TIME.get(
+                    opValues.get(0),
+                    de.getMessageObject()));
+            operation.setResultCode(ResultCode.CONSTRAINT_VIOLATION);
+            return false;
+          }
+        }
+
+        returnTypes.add(OP_GET_LAST_LOGIN_TIME);
+        break;
+
+      case OP_CLEAR_LAST_LOGIN_TIME:
+        pwpState.clearLastLoginTime();
+        returnTypes.add(OP_GET_LAST_LOGIN_TIME);
+        break;
+
+      case OP_GET_SECONDS_UNTIL_IDLE_LOCKOUT:
+        returnTypes.add(OP_GET_SECONDS_UNTIL_IDLE_LOCKOUT);
+        break;
+
+      case OP_GET_PASSWORD_RESET_STATE:
+        returnTypes.add(OP_GET_PASSWORD_RESET_STATE);
+        break;
+
+      case OP_SET_PASSWORD_RESET_STATE:
+        if (opValues == null)
+        {
+          operation.appendErrorMessage(
+              ERR_PWPSTATE_EXTOP_NO_RESET_STATE_VALUE.get());
+          operation.setResultCode(ResultCode.CONSTRAINT_VIOLATION);
+          return false;
+        }
+        else if (opValues.size() != 1)
+        {
+          operation.appendErrorMessage(
+              ERR_PWPSTATE_EXTOP_BAD_RESET_STATE_VALUE_COUNT.get());
+          operation.setResultCode(ResultCode.CONSTRAINT_VIOLATION);
+          return false;
+        }
+        else
+        {
+          String value = opValues.get(0);
+          if (value.equalsIgnoreCase("true"))
+          {
+            pwpState.setMustChangePassword(true);
+          }
+          else if (value.equalsIgnoreCase("false"))
+          {
+            pwpState.setMustChangePassword(false);
+          }
+          else
+          {
+            operation.appendErrorMessage(
+                ERR_PWPSTATE_EXTOP_BAD_RESET_STATE_VALUE.get());
+            operation.setResultCode(ResultCode.CONSTRAINT_VIOLATION);
+            return false;
+          }
+        }
+
+        returnTypes.add(OP_GET_PASSWORD_RESET_STATE);
+        break;
+
+      case OP_CLEAR_PASSWORD_RESET_STATE:
+        pwpState.setMustChangePassword(false);
+        returnTypes.add(OP_GET_PASSWORD_RESET_STATE);
+        break;
+
+      case OP_GET_SECONDS_UNTIL_PASSWORD_RESET_LOCKOUT:
+        returnTypes.add(OP_GET_SECONDS_UNTIL_PASSWORD_RESET_LOCKOUT);
+        break;
+
+      case OP_GET_GRACE_LOGIN_USE_TIMES:
+        returnTypes.add(OP_GET_GRACE_LOGIN_USE_TIMES);
+        break;
+
+      case OP_ADD_GRACE_LOGIN_USE_TIME:
+        if (opValues == null)
+        {
+          pwpState.updateGraceLoginTimes();
+        }
+        else if (opValues.size() != 1)
+        {
+          operation.appendErrorMessage(
+              ERR_PWPSTATE_EXTOP_BAD_ADD_GRACE_LOGIN_TIME_COUNT.get());
+          operation.setResultCode(ResultCode.CONSTRAINT_VIOLATION);
+          return false;
+        }
+        else
+        {
+          try
+          {
+            ByteString valueString =
+                ByteString.valueOf(opValues.get(0));
+            long time = GeneralizedTimeSyntax.decodeGeneralizedTimeValue(
+                valueString);
+            List<Long> authFailureTimes = pwpState.getGraceLoginTimes();
+            ArrayList<Long> newGraceTimes =
+                new ArrayList<Long>(authFailureTimes.size()+1);
+            newGraceTimes.addAll(authFailureTimes);
+            newGraceTimes.add(time);
+            pwpState.setGraceLoginTimes(newGraceTimes);
+          }
+          catch (DirectoryException de)
+          {
+            Message message = ERR_PWPSTATE_EXTOP_BAD_GRACE_LOGIN_TIME.get(
+                opValues.get(0),
+                de.getMessageObject());
+            operation.setResultCode(de.getResultCode());
+            operation.appendErrorMessage(message);
+            return false;
+          }
+        }
+
+        returnTypes.add(OP_GET_GRACE_LOGIN_USE_TIMES);
+        break;
+
+      case OP_SET_GRACE_LOGIN_USE_TIMES:
+        if (opValues == null)
+        {
+          ArrayList<Long> valueList = new ArrayList<Long>(1);
+          valueList.add(pwpState.getCurrentTime());
+          pwpState.setGraceLoginTimes(valueList);
+        }
+        else
+        {
+          ArrayList<Long> valueList = new ArrayList<Long>(opValues.size());
+          for (String s : opValues)
+          {
+            try
+            {
+              valueList.add(
+                  GeneralizedTimeSyntax.decodeGeneralizedTimeValue(
+                      ByteString.valueOf(s)));
+            }
+            catch (DirectoryException de)
+            {
+              Message message = ERR_PWPSTATE_EXTOP_BAD_GRACE_LOGIN_TIME.get(
+                  s, de.getMessageObject());
+              operation.setResultCode(de.getResultCode());
+              operation.appendErrorMessage(message);
+              return false;
+            }
+          }
+          pwpState.setGraceLoginTimes(valueList);
+        }
+
+        returnTypes.add(OP_GET_GRACE_LOGIN_USE_TIMES);
+        break;
+
+      case OP_CLEAR_GRACE_LOGIN_USE_TIMES:
+        pwpState.clearGraceLoginTimes();
+        returnTypes.add(OP_GET_GRACE_LOGIN_USE_TIMES);
+        break;
+
+      case OP_GET_REMAINING_GRACE_LOGIN_COUNT:
+        returnTypes.add(OP_GET_REMAINING_GRACE_LOGIN_COUNT);
+        break;
+
+      case OP_GET_PASSWORD_CHANGED_BY_REQUIRED_TIME:
+        returnTypes.add(OP_GET_PASSWORD_CHANGED_BY_REQUIRED_TIME);
+        break;
+
+      case OP_SET_PASSWORD_CHANGED_BY_REQUIRED_TIME:
+        if (opValues == null)
+        {
+          pwpState.setRequiredChangeTime();
+        }
+        else if (opValues.size() != 1)
+        {
+          operation.appendErrorMessage(
+              ERR_PWPSTATE_EXTOP_BAD_REQUIRED_CHANGE_TIME_COUNT.get());
+          operation.setResultCode(ResultCode.CONSTRAINT_VIOLATION);
+          return false;
+        }
+        else
+        {
+          try
+          {
+            ByteString valueString =
+                ByteString.valueOf(opValues.get(0));
+            long time = GeneralizedTimeSyntax.decodeGeneralizedTimeValue(
+                valueString);
+            pwpState.setRequiredChangeTime(time);
+          }
+          catch (DirectoryException de)
+          {
+            operation.appendErrorMessage(
+                ERR_PWPSTATE_EXTOP_BAD_REQUIRED_CHANGE_TIME.get(
+                    opValues.get(0),
+                    de.getMessageObject()));
+            operation.setResultCode(ResultCode.CONSTRAINT_VIOLATION);
+            return false;
+          }
+        }
+
+        returnTypes.add(OP_GET_PASSWORD_CHANGED_BY_REQUIRED_TIME);
+        break;
+
+      case OP_CLEAR_PASSWORD_CHANGED_BY_REQUIRED_TIME:
+        pwpState.clearRequiredChangeTime();
+        returnTypes.add(OP_GET_PASSWORD_CHANGED_BY_REQUIRED_TIME);
+        break;
+
+      case OP_GET_SECONDS_UNTIL_REQUIRED_CHANGE_TIME:
+        returnTypes.add(OP_GET_SECONDS_UNTIL_REQUIRED_CHANGE_TIME);
+        break;
+
+      case OP_GET_PASSWORD_HISTORY:
+        returnTypes.add(OP_GET_PASSWORD_HISTORY);
+        break;
+
+      case OP_CLEAR_PASSWORD_HISTORY:
+        pwpState.clearPasswordHistory();
+        returnTypes.add(OP_GET_PASSWORD_HISTORY);
+        break;
+
+      default:
+
+        operation.appendErrorMessage(ERR_PWPSTATE_EXTOP_UNKNOWN_OP_TYPE.get(
+            String.valueOf(opType)));
+        operation.setResultCode(ResultCode.CONSTRAINT_VIOLATION);
+        return false;
     }
 
-    return new ASN1Sequence(elements);
-  }
-
-
-
-  /**
-   * Encodes the provided information in a form suitable for including in the
-   * response value.
-   *
-   * @param  opType  The operation type to use for the value.
-   * @param  values  The set of string values to include in the response.
-   *
-   * @return  The encoded ASN.1 element.
-   */
-  public static ASN1Element encode(int opType, String[] values)
-  {
-    ArrayList<ASN1Element> elements = new ArrayList<ASN1Element>(2);
-    elements.add(new ASN1Enumerated(opType));
-
-    if ((values != null) && (values.length > 0))
-    {
-      ArrayList<ASN1Element> valueElements =
-           new ArrayList<ASN1Element>(values.length);
-      for (int i=0; i < values.length; i++)
-      {
-        valueElements.add(new ASN1OctetString(values[i]));
-      }
-      elements.add(new ASN1Sequence(valueElements));
-    }
-
-    return new ASN1Sequence(elements);
-  }
-
-
-
-  /**
-   * Encodes the provided information in a form suitable for including in the
-   * response value.
-   *
-   * @param  opType  The operation type to use for the value.
-   * @param  values  The set of timestamp values to include in the response.
-   *
-   * @return  The encoded ASN.1 element.
-   */
-  public static ASN1Element encode(int opType, List<Long> values)
-  {
-    ArrayList<ASN1Element> elements = new ArrayList<ASN1Element>(2);
-    elements.add(new ASN1Enumerated(opType));
-
-    ArrayList<ASN1Element> valueElements =
-         new ArrayList<ASN1Element>(values.size());
-    for (long l : values)
-    {
-      valueElements.add(new ASN1OctetString(GeneralizedTimeSyntax.format(l)));
-    }
-    elements.add(new ASN1Sequence(valueElements));
-
-    return new ASN1Sequence(elements);
+    return true;
   }
 }
 
diff --git a/opends/src/server/org/opends/server/extensions/PlainSASLMechanismHandler.java b/opends/src/server/org/opends/server/extensions/PlainSASLMechanismHandler.java
index ee3a4b2..446c28c 100644
--- a/opends/src/server/org/opends/server/extensions/PlainSASLMechanismHandler.java
+++ b/opends/src/server/org/opends/server/extensions/PlainSASLMechanismHandler.java
@@ -42,7 +42,6 @@
 import org.opends.server.core.BindOperation;
 import org.opends.server.core.DirectoryServer;
 import org.opends.server.core.PasswordPolicyState;
-import org.opends.server.protocols.asn1.ASN1OctetString;
 import org.opends.server.protocols.internal.InternalClientConnection;
 import org.opends.server.types.AuthenticationInfo;
 import org.opends.server.types.ByteString;
@@ -164,7 +163,7 @@
       return;
     }
 
-    String credString = saslCredentials.stringValue();
+    String credString = saslCredentials.toString();
     int    length     = credString.length();
     int    nullPos1   = credString.indexOf('\u0000');
     if (nullPos1 < 0)
@@ -511,7 +510,7 @@
     {
       PasswordPolicyState pwPolicyState =
            new PasswordPolicyState(userEntry, false);
-      if (! pwPolicyState.passwordMatches(new ASN1OctetString(password)))
+      if (! pwPolicyState.passwordMatches(ByteString.valueOf(password)))
       {
         bindOperation.setResultCode(ResultCode.INVALID_CREDENTIALS);
 
diff --git a/opends/src/server/org/opends/server/extensions/RC4PasswordStorageScheme.java b/opends/src/server/org/opends/server/extensions/RC4PasswordStorageScheme.java
index f60450b..06f963c 100644
--- a/opends/src/server/org/opends/server/extensions/RC4PasswordStorageScheme.java
+++ b/opends/src/server/org/opends/server/extensions/RC4PasswordStorageScheme.java
@@ -28,8 +28,6 @@
 
 
 
-import java.util.Arrays;
-
 import org.opends.messages.Message;
 import org.opends.server.admin.std.server.RC4PasswordStorageSchemeCfg;
 import org.opends.server.api.PasswordStorageScheme;
@@ -107,15 +105,17 @@
    * {@inheritDoc}
    */
   @Override()
-  public ByteString encodePassword(ByteString plaintext)
+  public ByteString encodePassword(ByteSequence plaintext)
          throws DirectoryException
   {
     try
     {
+      // TODO: Can we avoid this copy?
+      byte[] plaintextBytes = plaintext.toByteArray();
       byte[] encodedBytes = cryptoManager.encrypt(CIPHER_TRANSFORMATION_RC4,
                                                   KEY_SIZE_RC4,
-                                                  plaintext.value());
-      return ByteStringFactory.create(Base64.encode(encodedBytes));
+                                                  plaintextBytes);
+      return ByteString.valueOf(Base64.encode(encodedBytes));
     }
     catch (Exception e)
     {
@@ -137,7 +137,7 @@
    * {@inheritDoc}
    */
   @Override()
-  public ByteString encodePasswordWithScheme(ByteString plaintext)
+  public ByteString encodePasswordWithScheme(ByteSequence plaintext)
          throws DirectoryException
   {
     StringBuilder buffer = new StringBuilder();
@@ -147,9 +147,11 @@
 
     try
     {
+      // TODO: Can we avoid this copy?
+      byte[] plaintextBytes = plaintext.toByteArray();
       byte[] encodedBytes = cryptoManager.encrypt(CIPHER_TRANSFORMATION_RC4,
                                                   KEY_SIZE_RC4,
-                                                  plaintext.value());
+                                                  plaintextBytes);
       buffer.append(Base64.encode(encodedBytes));
     }
     catch (Exception e)
@@ -165,7 +167,7 @@
                                    m, e);
     }
 
-    return ByteStringFactory.create(buffer.toString());
+    return ByteString.valueOf(buffer.toString());
   }
 
 
@@ -174,14 +176,15 @@
    * {@inheritDoc}
    */
   @Override()
-  public boolean passwordMatches(ByteString plaintextPassword,
-                                 ByteString storedPassword)
+  public boolean passwordMatches(ByteSequence plaintextPassword,
+                                 ByteSequence storedPassword)
   {
     try
     {
-      byte[] decryptedPassword =
-           cryptoManager.decrypt(Base64.decode(storedPassword.stringValue()));
-      return Arrays.equals(plaintextPassword.value(), decryptedPassword);
+      ByteString decryptedPassword =
+          ByteString.wrap(cryptoManager.decrypt(
+               Base64.decode(storedPassword.toString())));
+      return plaintextPassword.equals(decryptedPassword);
     }
     catch (Exception e)
     {
@@ -211,14 +214,14 @@
    * {@inheritDoc}
    */
   @Override()
-  public ByteString getPlaintextValue(ByteString storedPassword)
+  public ByteString getPlaintextValue(ByteSequence storedPassword)
          throws DirectoryException
   {
     try
     {
       byte[] decryptedPassword =
-           cryptoManager.decrypt(Base64.decode(storedPassword.stringValue()));
-      return ByteStringFactory.create(decryptedPassword);
+           cryptoManager.decrypt(Base64.decode(storedPassword.toString()));
+      return ByteString.wrap(decryptedPassword);
     }
     catch (Exception e)
     {
@@ -252,7 +255,7 @@
    * {@inheritDoc}
    */
   @Override()
-  public ByteString encodeAuthPassword(ByteString plaintext)
+  public ByteString encodeAuthPassword(ByteSequence plaintext)
          throws DirectoryException
   {
     Message message =
@@ -266,7 +269,7 @@
    * {@inheritDoc}
    */
   @Override()
-  public boolean authPasswordMatches(ByteString plaintextPassword,
+  public boolean authPasswordMatches(ByteSequence plaintextPassword,
                                      String authInfo, String authValue)
   {
     // This storage scheme does not support the authentication password syntax.
diff --git a/opends/src/server/org/opends/server/extensions/RandomPasswordGenerator.java b/opends/src/server/org/opends/server/extensions/RandomPasswordGenerator.java
index 21ee028..89d4153 100644
--- a/opends/src/server/org/opends/server/extensions/RandomPasswordGenerator.java
+++ b/opends/src/server/org/opends/server/extensions/RandomPasswordGenerator.java
@@ -42,16 +42,7 @@
 import org.opends.server.config.ConfigException;
 import org.opends.server.core.DirectoryServer;
 import org.opends.server.loggers.debug.DebugTracer;
-import org.opends.server.types.ByteString;
-import org.opends.server.types.ByteStringFactory;
-import org.opends.server.types.ConfigChangeResult;
-import org.opends.server.types.DebugLogLevel;
-import org.opends.server.types.DirectoryException;
-import org.opends.server.types.DN;
-import org.opends.server.types.Entry;
-import org.opends.server.types.InitializationException;
-import org.opends.server.types.NamedCharacterSet;
-import org.opends.server.types.ResultCode;
+import org.opends.server.types.*;
 
 import static org.opends.messages.ExtensionMessages.*;
 import static org.opends.server.loggers.debug.DebugLogger.*;
@@ -280,7 +271,7 @@
       }
     }
 
-    return ByteStringFactory.create(buffer.toString());
+    return ByteString.valueOf(buffer.toString());
   }
 
 
diff --git a/opends/src/server/org/opends/server/extensions/RedirectingByteChannel.java b/opends/src/server/org/opends/server/extensions/RedirectingByteChannel.java
new file mode 100644
index 0000000..f3272de
--- /dev/null
+++ b/opends/src/server/org/opends/server/extensions/RedirectingByteChannel.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 2006-2008 Sun Microsystems, Inc.
+ */
+
+package org.opends.server.extensions;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.channels.ByteChannel;
+
+/**
+ * This class redirects read and write requests either to a child byte channel,
+ * or a byte channel to be redirected to.
+ *
+ */
+public class RedirectingByteChannel implements ByteChannel {
+    private final ByteChannel child;
+    private ByteChannel redirect = null;
+
+    private RedirectingByteChannel(ByteChannel child) {
+        this.child = child;
+    }
+
+    /**
+     * Create an instance of a redirecting byte channel using the specified
+     * byte channel as the child.
+     *
+     * @param bc A byte channel to use as the child.
+     * @return A redirecting byte channel.
+     */
+    public static
+    RedirectingByteChannel getRedirectingByteChannel(ByteChannel bc) {
+        return new RedirectingByteChannel(bc);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public int read(ByteBuffer buffer) throws IOException {
+        if (redirect != null)
+            return redirect.read(buffer);
+        else
+            return child.read(buffer);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void close() throws IOException {
+        if(redirect != null)
+            redirect.close();
+        else
+            child.close();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isOpen() {
+        if(redirect != null)
+            return redirect.isOpen();
+        return child.isOpen();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public int write(ByteBuffer buffer) throws IOException {
+        if (redirect != null)
+            return redirect.write(buffer);
+        else
+            return child.write(buffer);
+    }
+
+    /**
+     * Redirects a byte channel to a byte channel associated with the specified
+     * provider.
+     *
+     * @param provider The provider to redirect to.
+     */
+    public final void redirect(ConnectionSecurityProvider provider) {
+      redirect = provider.wrapChannel(child);
+    }
+
+    /**
+     * Disable redirection.
+     */
+    public final void disable() {
+        redirect = null;
+    }
+}
diff --git a/opends/src/server/org/opends/server/extensions/RegularExpressionIdentityMapper.java b/opends/src/server/org/opends/server/extensions/RegularExpressionIdentityMapper.java
index 6b30894..c357df9 100644
--- a/opends/src/server/org/opends/server/extensions/RegularExpressionIdentityMapper.java
+++ b/opends/src/server/org/opends/server/extensions/RegularExpressionIdentityMapper.java
@@ -48,24 +48,10 @@
 import org.opends.server.core.DirectoryServer;
 import org.opends.server.protocols.internal.InternalClientConnection;
 import org.opends.server.protocols.internal.InternalSearchOperation;
-import org.opends.server.types.AttributeType;
-import org.opends.server.types.AttributeValue;
-import org.opends.server.types.ConfigChangeResult;
-import org.opends.server.types.DereferencePolicy;
-import org.opends.server.types.DirectoryException;
-import org.opends.server.types.DN;
-import org.opends.server.types.Entry;
-import org.opends.server.types.IndexType;
-import org.opends.server.types.InitializationException;
-import org.opends.server.types.ResultCode;
-import org.opends.server.types.SearchFilter;
-import org.opends.server.types.SearchResultEntry;
-import org.opends.server.types.SearchScope;
+import org.opends.server.types.*;
 
 import static org.opends.messages.ExtensionMessages.*;
 import org.opends.messages.Message;
-import static org.opends.server.util.StaticUtils.*;
-
 
 
 /**
@@ -215,7 +201,8 @@
     SearchFilter filter;
     if (attributeTypes.length == 1)
     {
-      AttributeValue value = new AttributeValue(attributeTypes[0], processedID);
+      AttributeValue value =
+          AttributeValues.create(attributeTypes[0], processedID);
       filter = SearchFilter.createEqualityFilter(attributeTypes[0], value);
     }
     else
@@ -224,7 +211,7 @@
            new ArrayList<SearchFilter>(attributeTypes.length);
       for (AttributeType t : attributeTypes)
       {
-        AttributeValue value = new AttributeValue(t, processedID);
+        AttributeValue value = AttributeValues.create(t, processedID);
         filterComps.add(SearchFilter.createEqualityFilter(t, value));
       }
 
diff --git a/opends/src/server/org/opends/server/extensions/RepeatedCharactersPasswordValidator.java b/opends/src/server/org/opends/server/extensions/RepeatedCharactersPasswordValidator.java
index e9ee550..3d907da 100644
--- a/opends/src/server/org/opends/server/extensions/RepeatedCharactersPasswordValidator.java
+++ b/opends/src/server/org/opends/server/extensions/RepeatedCharactersPasswordValidator.java
@@ -37,11 +37,7 @@
 import org.opends.server.admin.std.server.
             RepeatedCharactersPasswordValidatorCfg;
 import org.opends.server.api.PasswordValidator;
-import org.opends.server.types.ConfigChangeResult;
-import org.opends.server.types.ByteString;
-import org.opends.server.types.Entry;
-import org.opends.server.types.Operation;
-import org.opends.server.types.ResultCode;
+import org.opends.server.types.*;
 
 import static org.opends.messages.ExtensionMessages.*;
 import org.opends.messages.MessageBuilder;
@@ -121,7 +117,7 @@
 
     // Get the password as a string.  If we should use case-insensitive
     // validation, then convert it to use all lowercase characters.
-    String passwordString = newPassword.stringValue();
+    String passwordString = newPassword.toString();
     if (! config.isCaseSensitiveValidation())
     {
       passwordString = passwordString.toLowerCase();
diff --git a/opends/src/server/org/opends/server/extensions/SASLByteChannel.java b/opends/src/server/org/opends/server/extensions/SASLByteChannel.java
new file mode 100644
index 0000000..fc5a959
--- /dev/null
+++ b/opends/src/server/org/opends/server/extensions/SASLByteChannel.java
@@ -0,0 +1,329 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License").  You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE
+ * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
+ * add the following below this CDDL 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.server.extensions;
+
+import java.nio.channels.ByteChannel;
+import java.security.cert.Certificate;
+import static org.opends.server.loggers.debug.DebugLogger.*;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.channels.ClosedChannelException;
+import java.nio.channels.SocketChannel;
+import javax.security.sasl.Sasl;
+import org.opends.server.api.ClientConnection;
+import org.opends.server.loggers.debug.DebugTracer;
+import org.opends.server.protocols.ldap.LDAPClientConnection;
+import org.opends.server.util.StaticUtils;
+
+/**
+ * This class implements a SASL byte channel that can be used during
+ * confidentiality and integrity.
+ *
+ */
+public class
+SASLByteChannel implements ByteChannel, ConnectionSecurityProvider {
+
+    // The tracer object for the debug logger.
+    private static final DebugTracer TRACER = getTracer();
+
+    // The client connection associated with this provider.
+    private ClientConnection connection;
+
+    // The socket channel associated with this provider.
+    private SocketChannel sockChannel;
+
+    // The SASL context associated with the provider
+    private SASLContext saslContext;
+
+    // The number of bytes in the length buffer.
+    private final int lengthSize = 4;
+
+    // A byte buffer used to hold the length of the clear buffer.
+    private ByteBuffer lengthBuf = ByteBuffer.allocate(lengthSize);
+
+    // The SASL mechanism name.
+    private String name;
+
+
+    /**
+     * Create a SASL byte channel with the specified parameters
+     * that is capable of processing a confidentiality/integrity SASL
+     * connection.
+     *
+     * @param connection
+     *          The client connection to read/write the bytes.
+     * @param name
+     *          The SASL mechanism name.
+     * @param saslContext
+     *          The SASL context to process the data through.
+     */
+    private SASLByteChannel(ClientConnection connection, String name,
+        SASLContext saslContext) {
+      this.connection = connection;
+      this.name = name;
+      this.saslContext = saslContext;
+      this.sockChannel = ((LDAPClientConnection) connection).getSocketChannel();
+    }
+
+    /**
+     * Return a SASL byte channel instance created using the specified
+     * parameters.
+     *
+     * @param c A client connection associated with the instance.
+     * @param name The name of the instance (SASL mechanism name).
+     * @param context A SASL context associaetd with the instance.
+     * @return A SASL byte channel.
+     */
+    public static SASLByteChannel
+    getSASLByteChannel(ClientConnection c, String name,
+                          SASLContext context) {
+          return new SASLByteChannel(c, name, context);
+    }
+
+    /**
+     * Read from the socket channel into the specified byte buffer the
+     * number of bytes specified in the total parameter.
+     *
+     * @param byteBuf
+     *          The byte buffer to put the bytes in.
+     * @param total
+     *          The total number of bytes to read from the socket
+     *          channel.
+     * @return The number of bytes read, 0 or -1.
+     * @throws IOException
+     *           If an error occurred reading the socket channel.
+     */
+    private int readAll(ByteBuffer byteBuf, int total) throws IOException
+    {
+      int count = 0;
+      while (sockChannel.isOpen() && total > 0) {
+        count = sockChannel.read(byteBuf);
+        if (count == -1) return -1;
+        if (count == 0) return 0;
+        total -= count;
+      }
+      if (total > 0)
+        return -1;
+      else
+        return byteBuf.position();
+    }
+
+    /**
+     * Return the clear buffer length as determined by processing the
+     * first 4 bytes of the specified buffer.
+     *
+     * @param byteBuf
+     *          The buffer to examine the first 4 bytes of.
+     * @return The size of the clear buffer.
+     */
+    private int getBufLength(ByteBuffer byteBuf)
+    {
+      int answer = 0;
+      byte[] buf = byteBuf.array();
+
+      for (int i = 0; i < lengthSize; i++)
+      {
+        answer <<= 8;
+        answer |= ((int) buf[i] & 0xff);
+      }
+      return answer;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public int read(ByteBuffer clearDst) throws IOException {
+        int recvBufSize = getAppBufSize();
+        if(recvBufSize > clearDst.capacity())
+            return -1;
+        lengthBuf.clear();
+        int readResult = readAll(lengthBuf, lengthSize);
+        if (readResult == -1)
+            return -1;
+        else if (readResult == 0) return 0;
+        int bufLength = getBufLength(lengthBuf);
+        if (bufLength > recvBufSize) //TODO SASLPhase2 add message
+            return -1;
+        ByteBuffer readBuf = ByteBuffer.allocate(bufLength);
+        readResult = readAll(readBuf, bufLength);
+        if (readResult == -1)
+            return -1;
+        else if (readResult == 0) return 0;
+        byte[] inBytes = readBuf.array();
+        byte[] clearBytes = saslContext.unwrap(inBytes, 0, inBytes.length);
+        for(int i = 0; i < clearBytes.length; i++) {
+            clearDst.put(clearBytes[i]);
+        }
+        return clearDst.remaining();
+    }
+
+    /**
+     * Writes the specified len parameter into the buffer in a form that
+     * can be sent over a network to the client.
+     *
+     * @param buf
+     *          The buffer to hold the length bytes.
+     * @param len
+     *          The length to encode.
+     */
+    private void writeBufLen(byte[] buf, int len)
+    {
+      for (int i = 3; i >= 0; i--)
+      {
+        buf[i] = (byte) (len & 0xff);
+        len >>>= 8;
+      }
+    }
+
+    /**
+     * Creates a buffer suitable to send to the client using the
+     * specified clear byte array  and length of the bytes to
+     * wrap.
+     *
+     * @param clearBytes
+     *          The clear byte array to send to the client.
+     * @param len
+     *          The length of the bytes to wrap in the byte array.
+     * @throws SaslException
+     *           If the wrap of the bytes fails.
+     */
+    private ByteBuffer wrap(byte[] clearBytes, int len) throws IOException {
+      byte[] wrapBytes = saslContext.wrap(clearBytes, 0, len);
+      byte[] outBytes = new byte[wrapBytes.length + lengthSize];
+      writeBufLen(outBytes, wrapBytes.length);
+      System.arraycopy(wrapBytes, 0, outBytes, lengthSize, wrapBytes.length);
+      return ByteBuffer.wrap(outBytes);
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public int write(ByteBuffer clearSrc) throws IOException {
+        int sendBufSize = getAppBufSize();
+        int srcLen = clearSrc.remaining();
+        ByteBuffer sendBuffer = ByteBuffer.allocate(sendBufSize);
+        if (srcLen > sendBufSize) {
+            int oldPos = clearSrc.position();
+            int curPos = oldPos;
+            int curLimit = oldPos + sendBufSize;
+            while (curPos < srcLen) {
+                clearSrc.position(curPos);
+                clearSrc.limit(curLimit);
+                sendBuffer.put(clearSrc);
+                writeChannel(wrap(sendBuffer.array(), clearSrc.remaining()));
+                curPos = curLimit;
+                curLimit = Math.min(srcLen, curPos + sendBufSize);
+            }
+            return srcLen;
+        } else {
+            sendBuffer.put(clearSrc);
+            return writeChannel(wrap(sendBuffer.array() ,srcLen));
+        }
+    }
+
+
+    /**
+     * Write the specified byte buffer to the socket channel.
+     *
+     * @param buffer
+     *          The byte buffer to write to the socket channel.
+     * @return {@code true} if the byte buffer was successfully written
+     *         to the socket channel, or, {@code false} if not.
+     */
+    private int writeChannel(ByteBuffer buffer) throws IOException {
+        int bytesWritten = sockChannel.write(buffer);
+        if (bytesWritten < 0)
+            throw new ClosedChannelException();
+        else if (bytesWritten == 0) {
+            if(!StaticUtils.writeWithTimeout(
+                    connection, sockChannel, buffer))
+                throw new ClosedChannelException();
+        }
+        return bytesWritten;
+      }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void close() throws IOException {
+        saslContext.dispose();
+        saslContext=null;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isOpen() {
+        return saslContext != null;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public int getAppBufSize() {
+        return saslContext.getBufSize(Sasl.RAW_SEND_SIZE) + lengthSize;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public Certificate[] getClientCertificateChain() {
+        return new Certificate[0];
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public int getSSF() {
+        return saslContext.getSSF();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public ByteChannel wrapChannel(ByteChannel channel) {
+        return this;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public String getName() {
+        return name;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isSecure() {
+        return true;
+    }
+
+}
diff --git a/opends/src/server/org/opends/server/extensions/SASLContext.java b/opends/src/server/org/opends/server/extensions/SASLContext.java
index c4ba120..2c22972 100644
--- a/opends/src/server/org/opends/server/extensions/SASLContext.java
+++ b/opends/src/server/org/opends/server/extensions/SASLContext.java
@@ -52,7 +52,6 @@
 import org.opends.server.core.BindOperation;
 import org.opends.server.core.DirectoryServer;
 import org.opends.server.core.PasswordPolicyState;
-import org.opends.server.protocols.asn1.ASN1OctetString;
 import org.opends.server.protocols.internal.InternalClientConnection;
 import org.opends.server.protocols.ldap.LDAPClientConnection;
 import org.opends.server.types.*;
@@ -292,9 +291,16 @@
      *
      * @throws SaslException If the SASL server cannot evaluate the byte array.
      */
-    private byte[] evaluateResponse(byte[] bytes) throws SaslException {
-          return saslServer.evaluateResponse(bytes);
+    private ByteString evaluateResponse(ByteString response)
+      throws SaslException
+    {
+      if (response == null)
+      {
+        response = ByteString.empty();
       }
+      return ByteString.wrap(saslServer.evaluateResponse(
+          response.toByteArray()));
+    }
 
 
     /**
@@ -752,17 +758,11 @@
                return false;
            }
        }
-       byte[] clientCredBytes = new byte[0];
-       ASN1OctetString clientCredentials = bindOp.getSASLCredentials();
-       if(clientCredentials != null) {
-           clientCredBytes = clientCredentials.value();
-       }
+
+       ByteString clientCredentials = bindOp.getSASLCredentials();
        clientConn.setSASLAuthStateInfo(null);
        try {
-           byte[] responseBytes =
-               evaluateResponse(clientCredBytes);
-           ASN1OctetString responseAuthStr =
-               new ASN1OctetString(responseBytes);
+           ByteString responseAuthStr = evaluateResponse(clientCredentials);
            //If the bind has not been completed,then
            //more handshake is needed and SASL_BIND_IN_PROGRESS is returned back
            //to the client.
@@ -779,11 +779,12 @@
                //connection. If confidentiality/integrity has not been
                //negotiated, dispose of the SASL server.
                if(isConfidentialIntegrity()) {
-                   SASLSecurityProvider secProvider =
-                       new SASLSecurityProvider(clientConn, mechanism, this);
+                   SASLByteChannel saslByteChannel =
+                        SASLByteChannel.getSASLByteChannel(clientConn,
+                                                           mechanism, this);
                    LDAPClientConnection ldapConn =
                        (LDAPClientConnection) clientConn;
-                       ldapConn.setSASLConnectionSecurityProvider(secProvider);
+                       ldapConn.setSASLPendingProvider(saslByteChannel);
                } else {
                    dispose();
                    clientConn.setSASLAuthStateInfo(null);
@@ -842,8 +843,7 @@
        this.bindOp = bindOp;
        ClientConnection clientConn = bindOp.getClientConnection();
        try {
-           byte[] challengeBuffer = evaluateResponse(new byte[0]);
-           ASN1OctetString challenge = new ASN1OctetString(challengeBuffer);
+           ByteString challenge = evaluateResponse(ByteString.empty());
            bindOp.setResultCode(ResultCode.SASL_BIND_IN_PROGRESS);
            bindOp.setServerSASLCredentials(challenge);
            clientConn.setSASLAuthStateInfo(this);
@@ -866,9 +866,9 @@
    void
    evaluateFinalStage(BindOperation bindOp) {
       this.bindOp = bindOp;
-       ASN1OctetString clientCredentials = bindOp.getSASLCredentials();
+       ByteString clientCredentials = bindOp.getSASLCredentials();
        if ((clientCredentials == null) ||
-               (clientCredentials.value().length == 0)) {
+               (clientCredentials.length() == 0)) {
            Message msg =
                ERR_SASL_NO_CREDENTIALS.get(mechanism, mechanism);
            handleError(msg);
@@ -877,10 +877,7 @@
        ClientConnection clientConn = bindOp.getClientConnection();
        clientConn.setSASLAuthStateInfo(null);
        try {
-           byte[] responseBytes =
-                        evaluateResponse(clientCredentials.value());
-           ASN1OctetString responseAuthStr =
-               new ASN1OctetString(responseBytes);
+           ByteString responseAuthStr = evaluateResponse(clientCredentials);
            bindOp.setResultCode(ResultCode.SUCCESS);
            bindOp.setServerSASLCredentials(responseAuthStr);
            bindOp.setSASLAuthUserEntry(authEntry);
@@ -893,11 +890,11 @@
            //SASL security provider and save it in the client connection for
            //use in later processing.
            if(isConfidentialIntegrity()) {
-               SASLSecurityProvider secProvider =
-                   new SASLSecurityProvider(clientConn, mechanism, this);
+               SASLByteChannel saslByteChannel =
+                SASLByteChannel.getSASLByteChannel(clientConn, mechanism, this);
                LDAPClientConnection ldapConn =
                    (LDAPClientConnection) clientConn;
-               ldapConn.setSASLConnectionSecurityProvider(secProvider);
+               ldapConn.setSASLPendingProvider(saslByteChannel);
            } else {
                dispose();
                clientConn.setSASLAuthStateInfo(null);
@@ -911,4 +908,4 @@
            handleError(msg);
        }
    }
-}
\ No newline at end of file
+}
diff --git a/opends/src/server/org/opends/server/extensions/SASLSecurityProvider.java b/opends/src/server/org/opends/server/extensions/SASLSecurityProvider.java
deleted file mode 100644
index 64a64b7..0000000
--- a/opends/src/server/org/opends/server/extensions/SASLSecurityProvider.java
+++ /dev/null
@@ -1,467 +0,0 @@
-/*
- * CDDL HEADER START
- *
- * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
- *
- * You can obtain a copy of the license at
- * trunk/opends/resource/legal-notices/OpenDS.LICENSE
- * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
- * See the License for the specific language governing permissions
- * and limitations under the License.
- *
- * When distributing Covered Code, include this CDDL HEADER in each
- * file and include the License file at
- * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
- * add the following below this CDDL 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.server.extensions;
-
-import java.io.IOException;
-import java.nio.ByteBuffer;
-import java.nio.channels.SelectionKey;
-import java.nio.channels.Selector;
-import java.nio.channels.SocketChannel;
-import java.util.Iterator;
-import javax.security.sasl.Sasl;
-import javax.security.sasl.SaslException;
-import org.opends.server.api.ClientConnection;
-import org.opends.server.api.ConnectionSecurityProvider;
-import org.opends.server.config.ConfigEntry;
-import org.opends.server.config.ConfigException;
-import org.opends.server.loggers.debug.DebugTracer;
-import org.opends.server.protocols.ldap.LDAPClientConnection;
-import org.opends.server.types.DebugLogLevel;
-import org.opends.server.types.DirectoryException;
-import org.opends.server.types.DisconnectReason;
-import org.opends.server.types.InitializationException;
-import static org.opends.server.loggers.debug.DebugLogger.*;
-
-/**
- * This class provides an implementation of a connection security provider that
- * provides SASL confidentiality/integrity between the server and client.
- *
- */
-public class SASLSecurityProvider extends ConnectionSecurityProvider {
-
-    // The tracer object for the debug logger.
-    private static final DebugTracer TRACER = getTracer();
-
-    //The client connection associated with this provider.
-    private ClientConnection connection;
-
-    //The socket channel associated with this provider.
-    private SocketChannel sockChannel;
-
-    //The SASL context associated with the provider
-    private SASLContext saslContext;
-
-    //The number of bytes in the length buffer.
-    private final int lengthSize = 4;
-
-    //A byte buffer used to hold the length of the clear buffer.
-    private ByteBuffer lengthBuf =  ByteBuffer.allocate(lengthSize);
-
-    //The SASL mechanism name.
-    private String name;
-
-    /**
-     * Create a SASL security provider with the specified parameters that is
-     * capable of processing a confidentiality/integrity SASL connection.
-     *
-     * @param connection The client connection to read/write the bytes.
-     * @param name The SASL mechanism name.
-     * @param saslContext The SASL context to process the data through.
-     */
-    public SASLSecurityProvider(ClientConnection connection, String name,
-                               SASLContext saslContext) {
-      super();
-      this.connection = connection;
-      this.name = name;
-      this.saslContext = saslContext;
-      this.sockChannel = ((LDAPClientConnection) connection).getSocketChannel();
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public void disconnect(boolean connectionValid) {
-        this.saslContext.dispose();
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public void finalizeConnectionSecurityProvider() {
-
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public int getClearBufferSize() {
-        return 0;
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public int getEncodedBufferSize() {
-        return 0;
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public String getSecurityMechanismName() {
-        return name;
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public void initializeConnectionSecurityProvider(ConfigEntry configEntry)
-            throws ConfigException, InitializationException {
-        this.connection = null;
-        this.sockChannel = null;
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public boolean isSecure() {
-        return true;
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public ConnectionSecurityProvider newInstance(ClientConnection clientConn,
-                                                  SocketChannel socketChannel) {
-            return new SASLSecurityProvider(clientConn, null,null);
-    }
-
-    /**
-     * Return the clear buffer length as determined by processing the first
-     * 4 bytes of the specified buffer.
-     *
-     * @param byteBuf The buffer to examine the first 4 bytes of.
-     * @return The size of the clear buffer.
-     */
-    private int getBufLength(ByteBuffer byteBuf) {
-        int answer = 0;
-        byte[] buf = byteBuf.array();
-
-        for (int i = 0; i < lengthSize; i++) {
-            answer <<= 8;
-            answer |= ((int)buf[i] & 0xff);
-        }
-        return answer;
-    }
-
-    /**
-     * Read from the socket channel into the specified byte buffer the
-     * number of bytes specified in the total parameter.
-     *
-     * @param byteBuf The byte buffer to put the bytes in.
-     * @param total The total number of bytes to read from the socket channel.
-     * @return The number of bytes read, 0 or -1.
-     * @throws IOException If an error occurred reading the socket channel.
-     */
-    private int readAll(ByteBuffer byteBuf, int total) throws IOException {
-        int count = 0;
-        while(sockChannel.isOpen() && total > 0) {
-            count = sockChannel.read(byteBuf);
-            if(count == -1)
-                return -1;
-           if(count == 0)
-                return 0;
-            total -= count;
-        }
-        if(total > 0)
-            return -1;
-        else
-            return byteBuf.position();
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public boolean readData() throws DirectoryException {
-        int recvBufSize = saslContext.getBufSize(Sasl.MAX_BUFFER);
-        try {
-            while(true) {
-                lengthBuf.clear();
-                int readResult = readAll(lengthBuf, lengthSize);
-                if (readResult == -1) {
-                    //Client connection has been closed. Disconnect and return.
-                    connection.disconnect(DisconnectReason.CLIENT_DISCONNECT,
-                            false, null);
-                    return false;
-                } else if(readResult == 0)
-                    return true;
-                int bufLength = getBufLength(lengthBuf);
-                if(bufLength > recvBufSize) {
-                    connection.disconnect(DisconnectReason.CLIENT_DISCONNECT,
-                            false, null);
-                    return false;
-                }
-                ByteBuffer readBuf = ByteBuffer.allocate(bufLength);
-                readResult = readAll(readBuf, bufLength);
-                if (readResult == -1) {
-                    //Client connection has been closed. Disconnect and return.
-                    connection.disconnect(DisconnectReason.CLIENT_DISCONNECT,
-                            false, null);
-                    return false;
-                } else if (readResult == 0)
-                    return true;
-                byte[] inBytes = readBuf.array();
-                byte[] clearBytes =
-                                saslContext.unwrap(inBytes, 0, inBytes.length);
-                ByteBuffer clearBuffer = ByteBuffer.wrap(clearBytes);
-                if (!connection.processDataRead(clearBuffer))
-                    return false;
-            }
-        } catch (SaslException saslEx) {
-            if (debugEnabled()) {
-                TRACER.debugCaught(DebugLogLevel.ERROR, saslEx);
-              }
-            //Error trying to unwrap the data.
-            connection.disconnect(DisconnectReason.IO_ERROR, false, null);
-            return false;
-        } catch (IOException ioe) {
-            // An error occurred while trying to communicate with the client.
-            // Disconnect and return.
-            if (debugEnabled()) {
-                TRACER.debugCaught(DebugLogLevel.ERROR, ioe);
-            }
-            connection.disconnect(DisconnectReason.IO_ERROR, false, null);
-            return false;
-        }
-    }
-
-    /**
-     * Creates a buffer suitable to send to the client using the specified
-     * clear byte array, offset and length of the bytes to wrap.
-     *
-     * @param clearBytes The clear byte array to send to the client.
-     * @param offSet An offset into the byte array to start the wrap at.
-     * @param len The length of the bytes to wrap in the byte array.
-     * @throws SaslException If the wrap of the bytes fails.
-     */
-    private ByteBuffer
-    createSendBuffer(byte[] clearBytes, int offSet, int len)
-    throws SaslException {
-        byte[] wrapBytes = saslContext.wrap(clearBytes, offSet, len);
-        byte[] outBuf = new  byte[wrapBytes.length + lengthSize];
-        writeBufLen(outBuf, wrapBytes.length);
-        System.arraycopy(wrapBytes, 0, outBuf, lengthSize, wrapBytes.length);
-        return ByteBuffer.wrap(outBuf);
-    }
-
-    /**
-     *  Writes the specified len parameter into the buffer in a form that can
-     *  be sent over a network to the client.
-     *
-     * @param buf The buffer to hold the length bytes.
-     * @param len The length to encode.
-     */
-    private void writeBufLen(byte[] buf, int len) {
-        for (int i = 3; i >= 0; i--) {
-            buf[i] = (byte)(len & 0xff);
-            len >>>= 8;
-        }
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override()
-    public boolean writeData(ByteBuffer clearData) {
-        int maxSendBufSize = saslContext.getBufSize(Sasl.RAW_SEND_SIZE);
-        int clearLength = clearData.limit();
-        try {
-            if(clearLength < maxSendBufSize) {
-                ByteBuffer sendBuffer =
-                    createSendBuffer(clearData.array(),0,clearLength);
-                return writeChannel(sendBuffer);
-            } else {
-                byte[] clearBytes = clearData.array();
-                for(int i=0; i < clearLength; i += maxSendBufSize) {
-                    int totLength = (clearLength - i) < maxSendBufSize ?
-                                    (clearLength - i) : maxSendBufSize;
-                    ByteBuffer sendBuffer =
-                                     createSendBuffer(clearBytes, i, totLength);
-                    if(!writeChannel(sendBuffer))
-                        return false;
-                }
-            }
-        } catch (SaslException e) {
-            if (debugEnabled()) {
-                TRACER.debugCaught(DebugLogLevel.ERROR, e);
-            }
-            connection.disconnect(DisconnectReason.IO_ERROR, false, null);
-            return false;
-        }
-        return true;
-    }
-
-   /**
-    * Write the specified byte buffer to the socket channel.
-    *
-    * @param buffer The byte buffer to write to the socket channel.
-    * @return {@code true} if the byte buffer was successfully written to the
-    *         socket channel, or, {@code false} if not.
-    */
-    private boolean writeChannel(ByteBuffer buffer) {
-        try {
-            while (buffer.hasRemaining())  {
-                int bytesWritten = sockChannel.write(buffer);
-                if (bytesWritten < 0)  {
-                    connection.disconnect(DisconnectReason.CLIENT_DISCONNECT,
-                                          false, null);
-                    return false;
-                } else if (bytesWritten == 0)  {
-                    return writeWithTimeout(buffer);
-                }
-            }
-        }  catch (IOException ioe)  {
-            if (debugEnabled()) {
-                TRACER.debugCaught(DebugLogLevel.ERROR, ioe);
-            }
-            connection.disconnect(DisconnectReason.IO_ERROR, false, null);
-            return false;
-        }
-        return true;
-    }
-
-    /**
-     * Writes the specified byte buffer parameter to the socket channel waiting
-     * for a period of time if the buffer cannot be written immediately.
-     *
-     * @param buffer The byte buffer to write to the channel.
-     * @return {@code true} if the bytes were sent, or, {@code false} otherwise.
-     * @throws IOException If an IO error occurs while writing the bytes.
-     */
-    private boolean writeWithTimeout(ByteBuffer buffer) throws IOException {
-        long startTime = System.currentTimeMillis();
-        long waitTime  = connection.getMaxBlockedWriteTimeLimit();
-        if (waitTime <= 0) {
-            // We won't support an infinite time limit, so fall back to using
-            // five minutes, which is a very long timeout given that we're
-            // blocking a worker thread.
-            waitTime = 300000L;
-        }
-        long stopTime = startTime + waitTime;
-        Selector selector = connection.getWriteSelector();
-        if (selector == null) {
-            // The client connection does not provide a selector, so we'll
-            // fall back to a more inefficient way that will work without a
-            // selector.
-            while (buffer.hasRemaining() &&
-                   (System.currentTimeMillis() < stopTime)) {
-                if (sockChannel.write(buffer) < 0) {
-                    // The client connection has been closed
-                    connection.disconnect(DisconnectReason.CLIENT_DISCONNECT,
-                                          false,  null);
-                    return false;
-                }
-            }
-            if (buffer.hasRemaining()) {
-                // If we've gotten here, then the write timed out.
-                // Terminate the client connection.
-                connection.disconnect(DisconnectReason.IO_TIMEOUT, false, null);
-                return false;
-            }
-            return true;
-        }
-        // Register with the selector for handling write operations.
-        SelectionKey key =
-                         sockChannel.register(selector, SelectionKey.OP_WRITE);
-        try
-        {
-            selector.select(waitTime);
-            while (buffer.hasRemaining())
-            {
-                long currentTime = System.currentTimeMillis();
-                if (currentTime >= stopTime) {
-                    // We've been blocked for too long
-                    connection.disconnect(DisconnectReason.IO_TIMEOUT,
-                                          false, null);
-                    return false;
-                }
-                else {
-                    waitTime = stopTime - currentTime;
-                }
-                Iterator<SelectionKey> iterator =
-                                             selector.selectedKeys().iterator();
-                while (iterator.hasNext()) {
-                    SelectionKey k = iterator.next();
-                    if (k.isWritable()) {
-                        int bytesWritten = sockChannel.write(buffer);
-                        if (bytesWritten < 0) {
-                            // The client connection has been closed.
-                            connection.disconnect(
-                                      DisconnectReason.CLIENT_DISCONNECT,
-                                      false, null);
-                            return false;
-                        }
-                        iterator.remove();
-                    }
-                }
-                if (buffer.hasRemaining()) {
-                    selector.select(waitTime);
-                }
-            }
-            return true;
-        } finally {
-            if (key.isValid()) {
-                key.cancel();
-                selector.selectNow();
-            }
-        }
-    }
-
-    /**
-     * Return if the underlying SASL context is active or not. The SASL context
-     * may still be negotiating a multi-stage SASL bind and is not ready to
-     * process confidentiality or integrity data yet.
-     *
-     * @return {@code true} if the underlying SASL context is active or ready
-     *         to process confidentiality/integrity messages, or, {@code false}
-     *         if not.
-    */
-
-    public boolean isActive() {
-        return saslContext.isBindComplete();
-    }
-
-    /**
-     * Return the cipher Security Strength Function of the cipher used in the
-     * SSAL context.
-     *
-     * @return The cipher SSF of the cipher used in the SASL context.
-     */
-    public int getSSF() {
-        return saslContext.getSSF();
-    }
-}
diff --git a/opends/src/server/org/opends/server/extensions/SHA1PasswordStorageScheme.java b/opends/src/server/org/opends/server/extensions/SHA1PasswordStorageScheme.java
index 30f3539..569c24d 100644
--- a/opends/src/server/org/opends/server/extensions/SHA1PasswordStorageScheme.java
+++ b/opends/src/server/org/opends/server/extensions/SHA1PasswordStorageScheme.java
@@ -29,7 +29,6 @@
 
 
 import java.security.MessageDigest;
-import java.util.Arrays;
 
 import org.opends.messages.Message;
 import org.opends.server.admin.std.server.SHA1PasswordStorageSchemeCfg;
@@ -37,12 +36,7 @@
 import org.opends.server.config.ConfigException;
 import org.opends.server.core.DirectoryServer;
 import org.opends.server.loggers.debug.DebugTracer;
-import org.opends.server.types.ByteString;
-import org.opends.server.types.ByteStringFactory;
-import org.opends.server.types.DebugLogLevel;
-import org.opends.server.types.DirectoryException;
-import org.opends.server.types.InitializationException;
-import org.opends.server.types.ResultCode;
+import org.opends.server.types.*;
 import org.opends.server.util.Base64;
 
 import static org.opends.messages.ExtensionMessages.*;
@@ -142,7 +136,7 @@
    * {@inheritDoc}
    */
   @Override()
-  public ByteString encodePassword(ByteString plaintext)
+  public ByteString encodePassword(ByteSequence plaintext)
          throws DirectoryException
   {
     byte[] digestBytes;
@@ -151,7 +145,9 @@
     {
       try
       {
-        digestBytes = messageDigest.digest(plaintext.value());
+        // TODO: Can we avoid this copy?
+        byte[] plaintextBytes = plaintext.toByteArray();
+        digestBytes = messageDigest.digest(plaintextBytes);
       }
       catch (Exception e)
       {
@@ -167,7 +163,7 @@
       }
     }
 
-    return ByteStringFactory.create(Base64.encode(digestBytes));
+    return ByteString.valueOf(Base64.encode(digestBytes));
   }
 
 
@@ -176,7 +172,7 @@
    * {@inheritDoc}
    */
   @Override()
-  public ByteString encodePasswordWithScheme(ByteString plaintext)
+  public ByteString encodePasswordWithScheme(ByteSequence plaintext)
          throws DirectoryException
   {
     StringBuilder buffer = new StringBuilder();
@@ -184,13 +180,15 @@
     buffer.append(STORAGE_SCHEME_NAME_SHA_1);
     buffer.append('}');
 
+    // TODO: Can we avoid this copy?
+    byte[] plaintextBytes = plaintext.toByteArray();
     byte[] digestBytes;
 
     synchronized (digestLock)
     {
       try
       {
-        digestBytes = messageDigest.digest(plaintext.value());
+        digestBytes = messageDigest.digest(plaintextBytes);
       }
       catch (Exception e)
       {
@@ -208,7 +206,7 @@
 
     buffer.append(Base64.encode(digestBytes));
 
-    return ByteStringFactory.create(buffer.toString());
+    return ByteString.valueOf(buffer.toString());
   }
 
 
@@ -217,16 +215,19 @@
    * {@inheritDoc}
    */
   @Override()
-  public boolean passwordMatches(ByteString plaintextPassword,
-                                 ByteString storedPassword)
+  public boolean passwordMatches(ByteSequence plaintextPassword,
+                                 ByteSequence storedPassword)
   {
-    byte[] userPWDigestBytes;
+    // TODO: Can we avoid this copy?
+    byte[] plaintextPasswordBytes = plaintextPassword.toByteArray();
+    ByteString userPWDigestBytes;
 
     synchronized (digestLock)
     {
       try
       {
-        userPWDigestBytes = messageDigest.digest(plaintextPassword.value());
+        userPWDigestBytes =
+            ByteString.wrap(messageDigest.digest(plaintextPasswordBytes));
       }
       catch (Exception e)
       {
@@ -239,10 +240,11 @@
       }
     }
 
-    byte[] storedPWDigestBytes;
+    ByteString storedPWDigestBytes;
     try
     {
-      storedPWDigestBytes = Base64.decode(storedPassword.stringValue());
+      storedPWDigestBytes =
+          ByteString.wrap(Base64.decode(storedPassword.toString()));
     }
     catch (Exception e)
     {
@@ -252,12 +254,12 @@
       }
 
       logError(ERR_PWSCHEME_CANNOT_BASE64_DECODE_STORED_PASSWORD.get(
-          storedPassword.stringValue(), String.valueOf(e)));
+          storedPassword.toString(), String.valueOf(e)));
 
       return false;
     }
 
-    return Arrays.equals(userPWDigestBytes, storedPWDigestBytes);
+    return userPWDigestBytes.equals(storedPWDigestBytes);
   }
 
 
@@ -278,7 +280,7 @@
    * {@inheritDoc}
    */
   @Override()
-  public ByteString encodeAuthPassword(ByteString plaintext)
+  public ByteString encodeAuthPassword(ByteSequence plaintext)
          throws DirectoryException
   {
     Message message =
@@ -292,7 +294,7 @@
    * {@inheritDoc}
    */
   @Override()
-  public boolean authPasswordMatches(ByteString plaintextPassword,
+  public boolean authPasswordMatches(ByteSequence plaintextPassword,
                                      String authInfo, String authValue)
   {
     // This storage scheme does not support the authentication password syntax.
@@ -316,7 +318,7 @@
    * {@inheritDoc}
    */
   @Override()
-  public ByteString getPlaintextValue(ByteString storedPassword)
+  public ByteString getPlaintextValue(ByteSequence storedPassword)
          throws DirectoryException
   {
     Message message =
diff --git a/opends/src/server/org/opends/server/extensions/SMTPAccountStatusNotificationHandler.java b/opends/src/server/org/opends/server/extensions/SMTPAccountStatusNotificationHandler.java
index f031fd1..0f70535 100644
--- a/opends/src/server/org/opends/server/extensions/SMTPAccountStatusNotificationHandler.java
+++ b/opends/src/server/org/opends/server/extensions/SMTPAccountStatusNotificationHandler.java
@@ -572,11 +572,11 @@
               if (debugEnabled())
               {
                 TRACER.debugInfo("Adding end user recipient " +
-                                 v.getStringValue() + " from attr " +
+                                 v.getValue().toString() + " from attr " +
                                  a.getNameWithOptions());
               }
 
-              recipients.add(v.getStringValue());
+              recipients.add(v.getValue().toString());
             }
           }
         }
diff --git a/opends/src/server/org/opends/server/extensions/SaltedMD5PasswordStorageScheme.java b/opends/src/server/org/opends/server/extensions/SaltedMD5PasswordStorageScheme.java
index 0c2d371..38194f4 100644
--- a/opends/src/server/org/opends/server/extensions/SaltedMD5PasswordStorageScheme.java
+++ b/opends/src/server/org/opends/server/extensions/SaltedMD5PasswordStorageScheme.java
@@ -39,12 +39,7 @@
 import org.opends.server.core.DirectoryServer;
 import org.opends.server.loggers.ErrorLogger;
 import org.opends.server.loggers.debug.DebugTracer;
-import org.opends.server.types.ByteString;
-import org.opends.server.types.ByteStringFactory;
-import org.opends.server.types.DebugLogLevel;
-import org.opends.server.types.DirectoryException;
-import org.opends.server.types.InitializationException;
-import org.opends.server.types.ResultCode;
+import org.opends.server.types.*;
 import org.opends.server.util.Base64;
 
 import static org.opends.messages.ExtensionMessages.*;
@@ -159,14 +154,14 @@
    * {@inheritDoc}
    */
   @Override()
-  public ByteString encodePassword(ByteString plaintext)
+  public ByteString encodePassword(ByteSequence plaintext)
          throws DirectoryException
   {
-    byte[] plainBytes    = plaintext.value();
+    int plainBytesLength = plaintext.length();
     byte[] saltBytes     = new byte[NUM_SALT_BYTES];
-    byte[] plainPlusSalt = new byte[plainBytes.length + NUM_SALT_BYTES];
+    byte[] plainPlusSalt = new byte[plainBytesLength + NUM_SALT_BYTES];
 
-    System.arraycopy(plainBytes, 0, plainPlusSalt, 0, plainBytes.length);
+    plaintext.copyTo(plainPlusSalt);
 
     byte[] digestBytes;
 
@@ -176,7 +171,7 @@
       {
         // Generate the salt and put in the plain+salt array.
         random.nextBytes(saltBytes);
-        System.arraycopy(saltBytes,0, plainPlusSalt, plainBytes.length,
+        System.arraycopy(saltBytes,0, plainPlusSalt, plainBytesLength,
                          NUM_SALT_BYTES);
 
         // Create the hash from the concatenated value.
@@ -203,7 +198,7 @@
     System.arraycopy(saltBytes, 0, hashPlusSalt, digestBytes.length,
                      NUM_SALT_BYTES);
 
-    return ByteStringFactory.create(Base64.encode(hashPlusSalt));
+    return ByteString.valueOf(Base64.encode(hashPlusSalt));
   }
 
 
@@ -212,7 +207,7 @@
    * {@inheritDoc}
    */
   @Override()
-  public ByteString encodePasswordWithScheme(ByteString plaintext)
+  public ByteString encodePasswordWithScheme(ByteSequence plaintext)
          throws DirectoryException
   {
     StringBuilder buffer = new StringBuilder();
@@ -220,11 +215,11 @@
     buffer.append(STORAGE_SCHEME_NAME_SALTED_MD5);
     buffer.append('}');
 
-    byte[] plainBytes    = plaintext.value();
+    int plainBytesLength = plaintext.length();
     byte[] saltBytes     = new byte[NUM_SALT_BYTES];
-    byte[] plainPlusSalt = new byte[plainBytes.length + NUM_SALT_BYTES];
+    byte[] plainPlusSalt = new byte[plainBytesLength + NUM_SALT_BYTES];
 
-    System.arraycopy(plainBytes, 0, plainPlusSalt, 0, plainBytes.length);
+    plaintext.copyTo(plainPlusSalt);
 
     byte[] digestBytes;
 
@@ -234,7 +229,7 @@
       {
         // Generate the salt and put in the plain+salt array.
         random.nextBytes(saltBytes);
-        System.arraycopy(saltBytes,0, plainPlusSalt, plainBytes.length,
+        System.arraycopy(saltBytes,0, plainPlusSalt, plainBytesLength,
                          NUM_SALT_BYTES);
 
         // Create the hash from the concatenated value.
@@ -262,7 +257,7 @@
                      NUM_SALT_BYTES);
     buffer.append(Base64.encode(hashPlusSalt));
 
-    return ByteStringFactory.create(buffer.toString());
+    return ByteString.valueOf(buffer.toString());
   }
 
 
@@ -271,15 +266,15 @@
    * {@inheritDoc}
    */
   @Override()
-  public boolean passwordMatches(ByteString plaintextPassword,
-                                 ByteString storedPassword)
+  public boolean passwordMatches(ByteSequence plaintextPassword,
+                                 ByteSequence storedPassword)
   {
     // Base64-decode the stored value and take the last 8 bytes as the salt.
     byte[] saltBytes = new byte[NUM_SALT_BYTES];
     byte[] digestBytes;
     try
     {
-      byte[] decodedBytes = Base64.decode(storedPassword.stringValue());
+      byte[] decodedBytes = Base64.decode(storedPassword.toString());
 
       int digestLength = decodedBytes.length - NUM_SALT_BYTES;
       digestBytes = new byte[digestLength];
@@ -295,17 +290,17 @@
       }
 
       Message message = ERR_PWSCHEME_CANNOT_BASE64_DECODE_STORED_PASSWORD.get(
-          storedPassword.stringValue(), String.valueOf(e));
+          storedPassword.toString(), String.valueOf(e));
       ErrorLogger.logError(message);
       return false;
     }
 
 
     // Use the salt to generate a digest based on the provided plain-text value.
-    byte[] plainBytes    = plaintextPassword.value();
-    byte[] plainPlusSalt = new byte[plainBytes.length + NUM_SALT_BYTES];
-    System.arraycopy(plainBytes, 0, plainPlusSalt, 0, plainBytes.length);
-    System.arraycopy(saltBytes, 0,plainPlusSalt, plainBytes.length,
+    int plainBytesLength = plaintextPassword.length();
+    byte[] plainPlusSalt = new byte[plainBytesLength + NUM_SALT_BYTES];
+    plaintextPassword.copyTo(plainPlusSalt);
+    System.arraycopy(saltBytes, 0,plainPlusSalt, plainBytesLength,
                      NUM_SALT_BYTES);
 
     byte[] userDigestBytes;
@@ -359,14 +354,14 @@
    * {@inheritDoc}
    */
   @Override()
-  public ByteString encodeAuthPassword(ByteString plaintext)
+  public ByteString encodeAuthPassword(ByteSequence plaintext)
          throws DirectoryException
   {
-    byte[] plainBytes    = plaintext.value();
+    int plaintextLength = plaintext.length();
     byte[] saltBytes     = new byte[NUM_SALT_BYTES];
-    byte[] plainPlusSalt = new byte[plainBytes.length + NUM_SALT_BYTES];
+    byte[] plainPlusSalt = new byte[plaintextLength + NUM_SALT_BYTES];
 
-    System.arraycopy(plainBytes, 0, plainPlusSalt, 0, plainBytes.length);
+    plaintext.copyTo(plainPlusSalt);
 
     byte[] digestBytes;
 
@@ -376,7 +371,7 @@
       {
         // Generate the salt and put in the plain+salt array.
         random.nextBytes(saltBytes);
-        System.arraycopy(saltBytes,0, plainPlusSalt, plainBytes.length,
+        System.arraycopy(saltBytes,0, plainPlusSalt, plaintextLength,
                          NUM_SALT_BYTES);
 
         // Create the hash from the concatenated value.
@@ -405,7 +400,7 @@
     authPWValue.append('$');
     authPWValue.append(Base64.encode(digestBytes));
 
-    return ByteStringFactory.create(authPWValue.toString());
+    return ByteString.valueOf(authPWValue.toString());
   }
 
 
@@ -414,7 +409,7 @@
    * {@inheritDoc}
    */
   @Override()
-  public boolean authPasswordMatches(ByteString plaintextPassword,
+  public boolean authPasswordMatches(ByteSequence plaintextPassword,
                                      String authInfo, String authValue)
   {
     byte[] saltBytes;
@@ -435,10 +430,10 @@
     }
 
 
-    byte[] plainBytes = plaintextPassword.value();
-    byte[] plainPlusSaltBytes = new byte[plainBytes.length + saltBytes.length];
-    System.arraycopy(plainBytes, 0, plainPlusSaltBytes, 0, plainBytes.length);
-    System.arraycopy(saltBytes, 0, plainPlusSaltBytes, plainBytes.length,
+    int plainBytesLength = plaintextPassword.length();
+    byte[] plainPlusSaltBytes = new byte[plainBytesLength + saltBytes.length];
+    plaintextPassword.copyTo(plainPlusSaltBytes);
+    System.arraycopy(saltBytes, 0, plainPlusSaltBytes, plainBytesLength,
                      saltBytes.length);
 
     synchronized (digestLock)
@@ -465,7 +460,7 @@
    * {@inheritDoc}
    */
   @Override()
-  public ByteString getPlaintextValue(ByteString storedPassword)
+  public ByteString getPlaintextValue(ByteSequence storedPassword)
          throws DirectoryException
   {
     Message message =
diff --git a/opends/src/server/org/opends/server/extensions/SaltedSHA1PasswordStorageScheme.java b/opends/src/server/org/opends/server/extensions/SaltedSHA1PasswordStorageScheme.java
index ed111d6..18d63f2 100644
--- a/opends/src/server/org/opends/server/extensions/SaltedSHA1PasswordStorageScheme.java
+++ b/opends/src/server/org/opends/server/extensions/SaltedSHA1PasswordStorageScheme.java
@@ -39,12 +39,7 @@
 import org.opends.server.core.DirectoryServer;
 import org.opends.server.loggers.ErrorLogger;
 import org.opends.server.loggers.debug.DebugTracer;
-import org.opends.server.types.ByteString;
-import org.opends.server.types.ByteStringFactory;
-import org.opends.server.types.DebugLogLevel;
-import org.opends.server.types.DirectoryException;
-import org.opends.server.types.InitializationException;
-import org.opends.server.types.ResultCode;
+import org.opends.server.types.*;
 import org.opends.server.util.Base64;
 
 import static org.opends.messages.ExtensionMessages.*;
@@ -157,14 +152,14 @@
    * {@inheritDoc}
    */
   @Override()
-  public ByteString encodePassword(ByteString plaintext)
+  public ByteString encodePassword(ByteSequence plaintext)
          throws DirectoryException
   {
-    byte[] plainBytes    = plaintext.value();
+    int plainBytesLength = plaintext.length();
     byte[] saltBytes     = new byte[NUM_SALT_BYTES];
-    byte[] plainPlusSalt = new byte[plainBytes.length + NUM_SALT_BYTES];
+    byte[] plainPlusSalt = new byte[plainBytesLength + NUM_SALT_BYTES];
 
-    System.arraycopy(plainBytes, 0, plainPlusSalt,0,plainBytes.length);
+    plaintext.copyTo(plainPlusSalt);
 
     byte[] digestBytes;
 
@@ -174,7 +169,7 @@
       {
         // Generate the salt and put in the plain+salt array.
         random.nextBytes(saltBytes);
-        System.arraycopy(saltBytes,0, plainPlusSalt, plainBytes.length,
+        System.arraycopy(saltBytes,0, plainPlusSalt, plainBytesLength,
                          NUM_SALT_BYTES);
 
         // Create the hash from the concatenated value.
@@ -201,7 +196,7 @@
     System.arraycopy(saltBytes, 0, hashPlusSalt, digestBytes.length,
                      NUM_SALT_BYTES);
 
-    return ByteStringFactory.create(Base64.encode(hashPlusSalt));
+    return ByteString.valueOf(Base64.encode(hashPlusSalt));
   }
 
 
@@ -210,7 +205,7 @@
    * {@inheritDoc}
    */
   @Override()
-  public ByteString encodePasswordWithScheme(ByteString plaintext)
+  public ByteString encodePasswordWithScheme(ByteSequence plaintext)
          throws DirectoryException
   {
     StringBuilder buffer = new StringBuilder();
@@ -218,11 +213,11 @@
     buffer.append(STORAGE_SCHEME_NAME_SALTED_SHA_1);
     buffer.append('}');
 
-    byte[] plainBytes    = plaintext.value();
+    int plainBytesLength = plaintext.length();
     byte[] saltBytes     = new byte[NUM_SALT_BYTES];
-    byte[] plainPlusSalt = new byte[plainBytes.length + NUM_SALT_BYTES];
+    byte[] plainPlusSalt = new byte[plainBytesLength + NUM_SALT_BYTES];
 
-    System.arraycopy(plainBytes, 0, plainPlusSalt,0,plainBytes.length);
+    plaintext.copyTo(plainPlusSalt);
 
     byte[] digestBytes;
 
@@ -232,7 +227,7 @@
       {
         // Generate the salt and put in the plain+salt array.
         random.nextBytes(saltBytes);
-        System.arraycopy(saltBytes,0, plainPlusSalt, plainBytes.length,
+        System.arraycopy(saltBytes,0, plainPlusSalt, plainBytesLength,
                          NUM_SALT_BYTES);
 
         // Create the hash from the concatenated value.
@@ -260,7 +255,7 @@
                      NUM_SALT_BYTES);
     buffer.append(Base64.encode(hashPlusSalt));
 
-    return ByteStringFactory.create(buffer.toString());
+    return ByteString.valueOf(buffer.toString());
   }
 
 
@@ -269,15 +264,15 @@
    * {@inheritDoc}
    */
   @Override()
-  public boolean passwordMatches(ByteString plaintextPassword,
-                                 ByteString storedPassword)
+  public boolean passwordMatches(ByteSequence plaintextPassword,
+                                 ByteSequence storedPassword)
   {
     // Base64-decode the stored value and take the last 8 bytes as the salt.
     byte[] saltBytes = new byte[NUM_SALT_BYTES];
     byte[] digestBytes;
     try
     {
-      byte[] decodedBytes = Base64.decode(storedPassword.stringValue());
+      byte[] decodedBytes = Base64.decode(storedPassword.toString());
 
       int digestLength = decodedBytes.length - NUM_SALT_BYTES;
       digestBytes = new byte[digestLength];
@@ -293,17 +288,17 @@
       }
 
       Message message = ERR_PWSCHEME_CANNOT_BASE64_DECODE_STORED_PASSWORD.get(
-          storedPassword.stringValue(), String.valueOf(e));
+          storedPassword.toString(), String.valueOf(e));
       ErrorLogger.logError(message);
       return false;
     }
 
 
     // Use the salt to generate a digest based on the provided plain-text value.
-    byte[] plainBytes    = plaintextPassword.value();
-    byte[] plainPlusSalt = new byte[plainBytes.length + NUM_SALT_BYTES];
-    System.arraycopy(plainBytes, 0, plainPlusSalt, 0, plainBytes.length);
-    System.arraycopy(saltBytes, 0,plainPlusSalt, plainBytes.length,
+    int plainBytesLength = plaintextPassword.length();
+    byte[] plainPlusSalt = new byte[plainBytesLength + NUM_SALT_BYTES];
+    plaintextPassword.copyTo(plainPlusSalt);
+    System.arraycopy(saltBytes, 0,plainPlusSalt, plainBytesLength,
                      NUM_SALT_BYTES);
 
     byte[] userDigestBytes;
@@ -357,14 +352,14 @@
    * {@inheritDoc}
    */
   @Override()
-  public ByteString encodeAuthPassword(ByteString plaintext)
+  public ByteString encodeAuthPassword(ByteSequence plaintext)
          throws DirectoryException
   {
-    byte[] plainBytes    = plaintext.value();
+    int plaintextLength = plaintext.length();
     byte[] saltBytes     = new byte[NUM_SALT_BYTES];
-    byte[] plainPlusSalt = new byte[plainBytes.length + NUM_SALT_BYTES];
+    byte[] plainPlusSalt = new byte[plaintextLength + NUM_SALT_BYTES];
 
-    System.arraycopy(plainBytes, 0, plainPlusSalt, 0, plainBytes.length);
+    plaintext.copyTo(plainPlusSalt);
 
     byte[] digestBytes;
 
@@ -374,7 +369,7 @@
       {
         // Generate the salt and put in the plain+salt array.
         random.nextBytes(saltBytes);
-        System.arraycopy(saltBytes,0, plainPlusSalt, plainBytes.length,
+        System.arraycopy(saltBytes,0, plainPlusSalt, plaintextLength,
                          NUM_SALT_BYTES);
 
         // Create the hash from the concatenated value.
@@ -403,7 +398,7 @@
     authPWValue.append('$');
     authPWValue.append(Base64.encode(digestBytes));
 
-    return ByteStringFactory.create(authPWValue.toString());
+    return ByteString.valueOf(authPWValue.toString());
   }
 
 
@@ -412,7 +407,7 @@
    * {@inheritDoc}
    */
   @Override()
-  public boolean authPasswordMatches(ByteString plaintextPassword,
+  public boolean authPasswordMatches(ByteSequence plaintextPassword,
                                      String authInfo, String authValue)
   {
     byte[] saltBytes;
@@ -433,10 +428,10 @@
     }
 
 
-    byte[] plainBytes = plaintextPassword.value();
-    byte[] plainPlusSaltBytes = new byte[plainBytes.length + saltBytes.length];
-    System.arraycopy(plainBytes, 0, plainPlusSaltBytes, 0, plainBytes.length);
-    System.arraycopy(saltBytes, 0, plainPlusSaltBytes, plainBytes.length,
+    int plainBytesLength = plaintextPassword.length();
+    byte[] plainPlusSaltBytes = new byte[plainBytesLength + saltBytes.length];
+    plaintextPassword.copyTo(plainPlusSaltBytes);
+    System.arraycopy(saltBytes, 0, plainPlusSaltBytes, plainBytesLength,
                      saltBytes.length);
 
     synchronized (digestLock)
@@ -463,7 +458,7 @@
    * {@inheritDoc}
    */
   @Override()
-  public ByteString getPlaintextValue(ByteString storedPassword)
+  public ByteString getPlaintextValue(ByteSequence storedPassword)
          throws DirectoryException
   {
     Message message =
diff --git a/opends/src/server/org/opends/server/extensions/SaltedSHA256PasswordStorageScheme.java b/opends/src/server/org/opends/server/extensions/SaltedSHA256PasswordStorageScheme.java
index 0e40234..258e3af 100644
--- a/opends/src/server/org/opends/server/extensions/SaltedSHA256PasswordStorageScheme.java
+++ b/opends/src/server/org/opends/server/extensions/SaltedSHA256PasswordStorageScheme.java
@@ -39,12 +39,7 @@
 import org.opends.server.core.DirectoryServer;
 import org.opends.server.loggers.ErrorLogger;
 import org.opends.server.loggers.debug.DebugTracer;
-import org.opends.server.types.ByteString;
-import org.opends.server.types.ByteStringFactory;
-import org.opends.server.types.DebugLogLevel;
-import org.opends.server.types.DirectoryException;
-import org.opends.server.types.InitializationException;
-import org.opends.server.types.ResultCode;
+import org.opends.server.types.*;
 import org.opends.server.util.Base64;
 
 import static org.opends.messages.ExtensionMessages.*;
@@ -160,14 +155,14 @@
    * {@inheritDoc}
    */
   @Override()
-  public ByteString encodePassword(ByteString plaintext)
+  public ByteString encodePassword(ByteSequence plaintext)
          throws DirectoryException
   {
-    byte[] plainBytes    = plaintext.value();
+    int plainBytesLength = plaintext.length();
     byte[] saltBytes     = new byte[NUM_SALT_BYTES];
-    byte[] plainPlusSalt = new byte[plainBytes.length + NUM_SALT_BYTES];
+    byte[] plainPlusSalt = new byte[plainBytesLength + NUM_SALT_BYTES];
 
-    System.arraycopy(plainBytes, 0, plainPlusSalt,0,plainBytes.length);
+    plaintext.copyTo(plainPlusSalt);
 
     byte[] digestBytes;
 
@@ -177,7 +172,7 @@
       {
         // Generate the salt and put in the plain+salt array.
         random.nextBytes(saltBytes);
-        System.arraycopy(saltBytes,0, plainPlusSalt, plainBytes.length,
+        System.arraycopy(saltBytes,0, plainPlusSalt, plainBytesLength,
                          NUM_SALT_BYTES);
 
         // Create the hash from the concatenated value.
@@ -204,7 +199,7 @@
     System.arraycopy(saltBytes, 0, hashPlusSalt, digestBytes.length,
                      NUM_SALT_BYTES);
 
-    return ByteStringFactory.create(Base64.encode(hashPlusSalt));
+    return ByteString.valueOf(Base64.encode(hashPlusSalt));
   }
 
 
@@ -213,7 +208,7 @@
    * {@inheritDoc}
    */
   @Override()
-  public ByteString encodePasswordWithScheme(ByteString plaintext)
+  public ByteString encodePasswordWithScheme(ByteSequence plaintext)
          throws DirectoryException
   {
     StringBuilder buffer = new StringBuilder();
@@ -221,11 +216,11 @@
     buffer.append(STORAGE_SCHEME_NAME_SALTED_SHA_256);
     buffer.append('}');
 
-    byte[] plainBytes    = plaintext.value();
+    int plainBytesLength = plaintext.length();
     byte[] saltBytes     = new byte[NUM_SALT_BYTES];
-    byte[] plainPlusSalt = new byte[plainBytes.length + NUM_SALT_BYTES];
+    byte[] plainPlusSalt = new byte[plainBytesLength + NUM_SALT_BYTES];
 
-    System.arraycopy(plainBytes, 0, plainPlusSalt,0,plainBytes.length);
+    plaintext.copyTo(plainPlusSalt);
 
     byte[] digestBytes;
 
@@ -235,7 +230,7 @@
       {
         // Generate the salt and put in the plain+salt array.
         random.nextBytes(saltBytes);
-        System.arraycopy(saltBytes,0, plainPlusSalt, plainBytes.length,
+        System.arraycopy(saltBytes,0, plainPlusSalt, plainBytesLength,
                          NUM_SALT_BYTES);
 
         // Create the hash from the concatenated value.
@@ -263,7 +258,7 @@
                      NUM_SALT_BYTES);
     buffer.append(Base64.encode(hashPlusSalt));
 
-    return ByteStringFactory.create(buffer.toString());
+    return ByteString.valueOf(buffer.toString());
   }
 
 
@@ -272,15 +267,15 @@
    * {@inheritDoc}
    */
   @Override()
-  public boolean passwordMatches(ByteString plaintextPassword,
-                                 ByteString storedPassword)
+  public boolean passwordMatches(ByteSequence plaintextPassword,
+                                 ByteSequence storedPassword)
   {
     // Base64-decode the stored value and take the last 8 bytes as the salt.
     byte[] saltBytes = new byte[NUM_SALT_BYTES];
     byte[] digestBytes;
     try
     {
-      byte[] decodedBytes = Base64.decode(storedPassword.stringValue());
+      byte[] decodedBytes = Base64.decode(storedPassword.toString());
 
       int digestLength = decodedBytes.length - NUM_SALT_BYTES;
       digestBytes = new byte[digestLength];
@@ -296,17 +291,17 @@
       }
 
       Message message = ERR_PWSCHEME_CANNOT_BASE64_DECODE_STORED_PASSWORD.get(
-          storedPassword.stringValue(), String.valueOf(e));
+          storedPassword.toString(), String.valueOf(e));
       ErrorLogger.logError(message);
       return false;
     }
 
 
     // Use the salt to generate a digest based on the provided plain-text value.
-    byte[] plainBytes    = plaintextPassword.value();
-    byte[] plainPlusSalt = new byte[plainBytes.length + NUM_SALT_BYTES];
-    System.arraycopy(plainBytes, 0, plainPlusSalt, 0, plainBytes.length);
-    System.arraycopy(saltBytes, 0,plainPlusSalt, plainBytes.length,
+    int plainBytesLength = plaintextPassword.length();
+    byte[] plainPlusSalt = new byte[plainBytesLength + NUM_SALT_BYTES];
+    plaintextPassword.copyTo(plainPlusSalt);
+    System.arraycopy(saltBytes, 0,plainPlusSalt, plainBytesLength,
                      NUM_SALT_BYTES);
 
     byte[] userDigestBytes;
@@ -360,14 +355,14 @@
    * {@inheritDoc}
    */
   @Override()
-  public ByteString encodeAuthPassword(ByteString plaintext)
+  public ByteString encodeAuthPassword(ByteSequence plaintext)
          throws DirectoryException
   {
-    byte[] plainBytes    = plaintext.value();
+    int plaintextLength = plaintext.length();
     byte[] saltBytes     = new byte[NUM_SALT_BYTES];
-    byte[] plainPlusSalt = new byte[plainBytes.length + NUM_SALT_BYTES];
+    byte[] plainPlusSalt = new byte[plaintextLength + NUM_SALT_BYTES];
 
-    System.arraycopy(plainBytes, 0, plainPlusSalt, 0, plainBytes.length);
+    plaintext.copyTo(plainPlusSalt);
 
     byte[] digestBytes;
 
@@ -377,7 +372,7 @@
       {
         // Generate the salt and put in the plain+salt array.
         random.nextBytes(saltBytes);
-        System.arraycopy(saltBytes,0, plainPlusSalt, plainBytes.length,
+        System.arraycopy(saltBytes,0, plainPlusSalt, plaintextLength,
                          NUM_SALT_BYTES);
 
         // Create the hash from the concatenated value.
@@ -406,7 +401,7 @@
     authPWValue.append('$');
     authPWValue.append(Base64.encode(digestBytes));
 
-    return ByteStringFactory.create(authPWValue.toString());
+    return ByteString.valueOf(authPWValue.toString());
   }
 
 
@@ -415,7 +410,7 @@
    * {@inheritDoc}
    */
   @Override()
-  public boolean authPasswordMatches(ByteString plaintextPassword,
+  public boolean authPasswordMatches(ByteSequence plaintextPassword,
                                      String authInfo, String authValue)
   {
     byte[] saltBytes;
@@ -436,10 +431,10 @@
     }
 
 
-    byte[] plainBytes = plaintextPassword.value();
-    byte[] plainPlusSaltBytes = new byte[plainBytes.length + saltBytes.length];
-    System.arraycopy(plainBytes, 0, plainPlusSaltBytes, 0, plainBytes.length);
-    System.arraycopy(saltBytes, 0, plainPlusSaltBytes, plainBytes.length,
+    int plainBytesLength = plaintextPassword.length();
+    byte[] plainPlusSaltBytes = new byte[plainBytesLength + saltBytes.length];
+    plaintextPassword.copyTo(plainPlusSaltBytes);
+    System.arraycopy(saltBytes, 0, plainPlusSaltBytes, plainBytesLength,
                      saltBytes.length);
 
     synchronized (digestLock)
@@ -466,7 +461,7 @@
    * {@inheritDoc}
    */
   @Override()
-  public ByteString getPlaintextValue(ByteString storedPassword)
+  public ByteString getPlaintextValue(ByteSequence storedPassword)
          throws DirectoryException
   {
     Message message =
diff --git a/opends/src/server/org/opends/server/extensions/SaltedSHA384PasswordStorageScheme.java b/opends/src/server/org/opends/server/extensions/SaltedSHA384PasswordStorageScheme.java
index e94c0a9..5ae2c10 100644
--- a/opends/src/server/org/opends/server/extensions/SaltedSHA384PasswordStorageScheme.java
+++ b/opends/src/server/org/opends/server/extensions/SaltedSHA384PasswordStorageScheme.java
@@ -39,12 +39,7 @@
 import org.opends.server.core.DirectoryServer;
 import org.opends.server.loggers.ErrorLogger;
 import org.opends.server.loggers.debug.DebugTracer;
-import org.opends.server.types.ByteString;
-import org.opends.server.types.ByteStringFactory;
-import org.opends.server.types.DebugLogLevel;
-import org.opends.server.types.DirectoryException;
-import org.opends.server.types.InitializationException;
-import org.opends.server.types.ResultCode;
+import org.opends.server.types.*;
 import org.opends.server.util.Base64;
 
 import static org.opends.messages.ExtensionMessages.*;
@@ -160,14 +155,14 @@
    * {@inheritDoc}
    */
   @Override()
-  public ByteString encodePassword(ByteString plaintext)
+  public ByteString encodePassword(ByteSequence plaintext)
          throws DirectoryException
   {
-    byte[] plainBytes    = plaintext.value();
+    int plainBytesLength = plaintext.length();
     byte[] saltBytes     = new byte[NUM_SALT_BYTES];
-    byte[] plainPlusSalt = new byte[plainBytes.length + NUM_SALT_BYTES];
+    byte[] plainPlusSalt = new byte[plainBytesLength + NUM_SALT_BYTES];
 
-    System.arraycopy(plainBytes, 0, plainPlusSalt,0,plainBytes.length);
+    plaintext.copyTo(plainPlusSalt);
 
     byte[] digestBytes;
 
@@ -177,7 +172,7 @@
       {
         // Generate the salt and put in the plain+salt array.
         random.nextBytes(saltBytes);
-        System.arraycopy(saltBytes,0, plainPlusSalt, plainBytes.length,
+        System.arraycopy(saltBytes,0, plainPlusSalt, plainBytesLength,
                          NUM_SALT_BYTES);
 
         // Create the hash from the concatenated value.
@@ -204,7 +199,7 @@
     System.arraycopy(saltBytes, 0, hashPlusSalt, digestBytes.length,
                      NUM_SALT_BYTES);
 
-    return ByteStringFactory.create(Base64.encode(hashPlusSalt));
+    return ByteString.valueOf(Base64.encode(hashPlusSalt));
   }
 
 
@@ -213,7 +208,7 @@
    * {@inheritDoc}
    */
   @Override()
-  public ByteString encodePasswordWithScheme(ByteString plaintext)
+  public ByteString encodePasswordWithScheme(ByteSequence plaintext)
          throws DirectoryException
   {
     StringBuilder buffer = new StringBuilder();
@@ -221,11 +216,11 @@
     buffer.append(STORAGE_SCHEME_NAME_SALTED_SHA_384);
     buffer.append('}');
 
-    byte[] plainBytes    = plaintext.value();
+    int plainBytesLength = plaintext.length();
     byte[] saltBytes     = new byte[NUM_SALT_BYTES];
-    byte[] plainPlusSalt = new byte[plainBytes.length + NUM_SALT_BYTES];
+    byte[] plainPlusSalt = new byte[plainBytesLength + NUM_SALT_BYTES];
 
-    System.arraycopy(plainBytes, 0, plainPlusSalt,0,plainBytes.length);
+    plaintext.copyTo(plainPlusSalt);
 
     byte[] digestBytes;
 
@@ -235,7 +230,7 @@
       {
         // Generate the salt and put in the plain+salt array.
         random.nextBytes(saltBytes);
-        System.arraycopy(saltBytes,0, plainPlusSalt, plainBytes.length,
+        System.arraycopy(saltBytes,0, plainPlusSalt, plainBytesLength,
                          NUM_SALT_BYTES);
 
         // Create the hash from the concatenated value.
@@ -263,7 +258,7 @@
                      NUM_SALT_BYTES);
     buffer.append(Base64.encode(hashPlusSalt));
 
-    return ByteStringFactory.create(buffer.toString());
+    return ByteString.valueOf(buffer.toString());
   }
 
 
@@ -272,15 +267,15 @@
    * {@inheritDoc}
    */
   @Override()
-  public boolean passwordMatches(ByteString plaintextPassword,
-                                 ByteString storedPassword)
+  public boolean passwordMatches(ByteSequence plaintextPassword,
+                                 ByteSequence storedPassword)
   {
     // Base64-decode the stored value and take the last 8 bytes as the salt.
     byte[] saltBytes = new byte[NUM_SALT_BYTES];
     byte[] digestBytes;
     try
     {
-      byte[] decodedBytes = Base64.decode(storedPassword.stringValue());
+      byte[] decodedBytes = Base64.decode(storedPassword.toString());
 
       int digestLength = decodedBytes.length - NUM_SALT_BYTES;
       digestBytes = new byte[digestLength];
@@ -296,17 +291,17 @@
       }
 
       Message message = ERR_PWSCHEME_CANNOT_BASE64_DECODE_STORED_PASSWORD.get(
-          storedPassword.stringValue(), String.valueOf(e));
+          storedPassword.toString(), String.valueOf(e));
       ErrorLogger.logError(message);
       return false;
     }
 
 
     // Use the salt to generate a digest based on the provided plain-text value.
-    byte[] plainBytes    = plaintextPassword.value();
-    byte[] plainPlusSalt = new byte[plainBytes.length + NUM_SALT_BYTES];
-    System.arraycopy(plainBytes, 0, plainPlusSalt, 0, plainBytes.length);
-    System.arraycopy(saltBytes, 0,plainPlusSalt, plainBytes.length,
+    int plainBytesLength = plaintextPassword.length();
+    byte[] plainPlusSalt = new byte[plainBytesLength + NUM_SALT_BYTES];
+    plaintextPassword.copyTo(plainPlusSalt);
+    System.arraycopy(saltBytes, 0,plainPlusSalt, plainBytesLength,
                      NUM_SALT_BYTES);
 
     byte[] userDigestBytes;
@@ -360,14 +355,14 @@
    * {@inheritDoc}
    */
   @Override()
-  public ByteString encodeAuthPassword(ByteString plaintext)
+  public ByteString encodeAuthPassword(ByteSequence plaintext)
          throws DirectoryException
   {
-    byte[] plainBytes    = plaintext.value();
+    int plaintextLength = plaintext.length();
     byte[] saltBytes     = new byte[NUM_SALT_BYTES];
-    byte[] plainPlusSalt = new byte[plainBytes.length + NUM_SALT_BYTES];
+    byte[] plainPlusSalt = new byte[plaintextLength + NUM_SALT_BYTES];
 
-    System.arraycopy(plainBytes, 0, plainPlusSalt, 0, plainBytes.length);
+    plaintext.copyTo(plainPlusSalt);
 
     byte[] digestBytes;
 
@@ -377,7 +372,7 @@
       {
         // Generate the salt and put in the plain+salt array.
         random.nextBytes(saltBytes);
-        System.arraycopy(saltBytes,0, plainPlusSalt, plainBytes.length,
+        System.arraycopy(saltBytes,0, plainPlusSalt, plaintextLength,
                          NUM_SALT_BYTES);
 
         // Create the hash from the concatenated value.
@@ -406,7 +401,7 @@
     authPWValue.append('$');
     authPWValue.append(Base64.encode(digestBytes));
 
-    return ByteStringFactory.create(authPWValue.toString());
+    return ByteString.valueOf(authPWValue.toString());
   }
 
 
@@ -415,7 +410,7 @@
    * {@inheritDoc}
    */
   @Override()
-  public boolean authPasswordMatches(ByteString plaintextPassword,
+  public boolean authPasswordMatches(ByteSequence plaintextPassword,
                                      String authInfo, String authValue)
   {
     byte[] saltBytes;
@@ -436,10 +431,10 @@
     }
 
 
-    byte[] plainBytes = plaintextPassword.value();
-    byte[] plainPlusSaltBytes = new byte[plainBytes.length + saltBytes.length];
-    System.arraycopy(plainBytes, 0, plainPlusSaltBytes, 0, plainBytes.length);
-    System.arraycopy(saltBytes, 0, plainPlusSaltBytes, plainBytes.length,
+    int plainBytesLength = plaintextPassword.length();
+    byte[] plainPlusSaltBytes = new byte[plainBytesLength + saltBytes.length];
+    plaintextPassword.copyTo(plainPlusSaltBytes);
+    System.arraycopy(saltBytes, 0, plainPlusSaltBytes, plainBytesLength,
                      saltBytes.length);
 
     synchronized (digestLock)
@@ -466,7 +461,7 @@
    * {@inheritDoc}
    */
   @Override()
-  public ByteString getPlaintextValue(ByteString storedPassword)
+  public ByteString getPlaintextValue(ByteSequence storedPassword)
          throws DirectoryException
   {
     Message message =
diff --git a/opends/src/server/org/opends/server/extensions/SaltedSHA512PasswordStorageScheme.java b/opends/src/server/org/opends/server/extensions/SaltedSHA512PasswordStorageScheme.java
index b8c9480..b0a6bcf 100644
--- a/opends/src/server/org/opends/server/extensions/SaltedSHA512PasswordStorageScheme.java
+++ b/opends/src/server/org/opends/server/extensions/SaltedSHA512PasswordStorageScheme.java
@@ -39,12 +39,7 @@
 import org.opends.server.core.DirectoryServer;
 import org.opends.server.loggers.ErrorLogger;
 import org.opends.server.loggers.debug.DebugTracer;
-import org.opends.server.types.ByteString;
-import org.opends.server.types.ByteStringFactory;
-import org.opends.server.types.DebugLogLevel;
-import org.opends.server.types.DirectoryException;
-import org.opends.server.types.InitializationException;
-import org.opends.server.types.ResultCode;
+import org.opends.server.types.*;
 import org.opends.server.util.Base64;
 
 import static org.opends.messages.ExtensionMessages.*;
@@ -159,14 +154,14 @@
    * {@inheritDoc}
    */
   @Override()
-  public ByteString encodePassword(ByteString plaintext)
+  public ByteString encodePassword(ByteSequence plaintext)
          throws DirectoryException
   {
-    byte[] plainBytes    = plaintext.value();
+    int plainBytesLength = plaintext.length();
     byte[] saltBytes     = new byte[NUM_SALT_BYTES];
-    byte[] plainPlusSalt = new byte[plainBytes.length + NUM_SALT_BYTES];
+    byte[] plainPlusSalt = new byte[plainBytesLength + NUM_SALT_BYTES];
 
-    System.arraycopy(plainBytes, 0, plainPlusSalt,0,plainBytes.length);
+    plaintext.copyTo(plainPlusSalt);
 
     byte[] digestBytes;
 
@@ -176,7 +171,7 @@
       {
         // Generate the salt and put in the plain+salt array.
         random.nextBytes(saltBytes);
-        System.arraycopy(saltBytes,0, plainPlusSalt, plainBytes.length,
+        System.arraycopy(saltBytes,0, plainPlusSalt, plainBytesLength,
                          NUM_SALT_BYTES);
 
         // Create the hash from the concatenated value.
@@ -203,7 +198,7 @@
     System.arraycopy(saltBytes, 0, hashPlusSalt, digestBytes.length,
                      NUM_SALT_BYTES);
 
-    return ByteStringFactory.create(Base64.encode(hashPlusSalt));
+    return ByteString.valueOf(Base64.encode(hashPlusSalt));
   }
 
 
@@ -212,7 +207,7 @@
    * {@inheritDoc}
    */
   @Override()
-  public ByteString encodePasswordWithScheme(ByteString plaintext)
+  public ByteString encodePasswordWithScheme(ByteSequence plaintext)
          throws DirectoryException
   {
     StringBuilder buffer = new StringBuilder();
@@ -220,11 +215,11 @@
     buffer.append(STORAGE_SCHEME_NAME_SALTED_SHA_512);
     buffer.append('}');
 
-    byte[] plainBytes    = plaintext.value();
+    int plainBytesLength = plaintext.length();
     byte[] saltBytes     = new byte[NUM_SALT_BYTES];
-    byte[] plainPlusSalt = new byte[plainBytes.length + NUM_SALT_BYTES];
+    byte[] plainPlusSalt = new byte[plainBytesLength + NUM_SALT_BYTES];
 
-    System.arraycopy(plainBytes, 0, plainPlusSalt,0,plainBytes.length);
+    plaintext.copyTo(plainPlusSalt);
 
     byte[] digestBytes;
 
@@ -234,7 +229,7 @@
       {
         // Generate the salt and put in the plain+salt array.
         random.nextBytes(saltBytes);
-        System.arraycopy(saltBytes,0, plainPlusSalt, plainBytes.length,
+        System.arraycopy(saltBytes,0, plainPlusSalt, plainBytesLength,
                          NUM_SALT_BYTES);
 
         // Create the hash from the concatenated value.
@@ -262,7 +257,7 @@
                      NUM_SALT_BYTES);
     buffer.append(Base64.encode(hashPlusSalt));
 
-    return ByteStringFactory.create(buffer.toString());
+    return ByteString.valueOf(buffer.toString());
   }
 
 
@@ -271,15 +266,15 @@
    * {@inheritDoc}
    */
   @Override()
-  public boolean passwordMatches(ByteString plaintextPassword,
-                                 ByteString storedPassword)
+  public boolean passwordMatches(ByteSequence plaintextPassword,
+                                 ByteSequence storedPassword)
   {
     // Base64-decode the stored value and take the last 8 bytes as the salt.
     byte[] saltBytes = new byte[NUM_SALT_BYTES];
     byte[] digestBytes;
     try
     {
-      byte[] decodedBytes = Base64.decode(storedPassword.stringValue());
+      byte[] decodedBytes = Base64.decode(storedPassword.toString());
 
       int digestLength = decodedBytes.length - NUM_SALT_BYTES;
       digestBytes = new byte[digestLength];
@@ -295,17 +290,17 @@
       }
 
       Message message = ERR_PWSCHEME_CANNOT_BASE64_DECODE_STORED_PASSWORD.get(
-          storedPassword.stringValue(), String.valueOf(e));
+          storedPassword.toString(), String.valueOf(e));
       ErrorLogger.logError(message);
       return false;
     }
 
 
     // Use the salt to generate a digest based on the provided plain-text value.
-    byte[] plainBytes    = plaintextPassword.value();
-    byte[] plainPlusSalt = new byte[plainBytes.length + NUM_SALT_BYTES];
-    System.arraycopy(plainBytes, 0, plainPlusSalt, 0, plainBytes.length);
-    System.arraycopy(saltBytes, 0,plainPlusSalt, plainBytes.length,
+    int plainBytesLength = plaintextPassword.length();
+    byte[] plainPlusSalt = new byte[plainBytesLength + NUM_SALT_BYTES];
+    plaintextPassword.copyTo(plainPlusSalt);
+    System.arraycopy(saltBytes, 0,plainPlusSalt, plainBytesLength,
                      NUM_SALT_BYTES);
 
     byte[] userDigestBytes;
@@ -359,14 +354,14 @@
    * {@inheritDoc}
    */
   @Override()
-  public ByteString encodeAuthPassword(ByteString plaintext)
+  public ByteString encodeAuthPassword(ByteSequence plaintext)
          throws DirectoryException
   {
-    byte[] plainBytes    = plaintext.value();
+    int plaintextLength = plaintext.length();
     byte[] saltBytes     = new byte[NUM_SALT_BYTES];
-    byte[] plainPlusSalt = new byte[plainBytes.length + NUM_SALT_BYTES];
+    byte[] plainPlusSalt = new byte[plaintextLength + NUM_SALT_BYTES];
 
-    System.arraycopy(plainBytes, 0, plainPlusSalt, 0, plainBytes.length);
+    plaintext.copyTo(plainPlusSalt);
 
     byte[] digestBytes;
 
@@ -376,7 +371,7 @@
       {
         // Generate the salt and put in the plain+salt array.
         random.nextBytes(saltBytes);
-        System.arraycopy(saltBytes,0, plainPlusSalt, plainBytes.length,
+        System.arraycopy(saltBytes,0, plainPlusSalt, plaintextLength,
                          NUM_SALT_BYTES);
 
         // Create the hash from the concatenated value.
@@ -405,7 +400,7 @@
     authPWValue.append('$');
     authPWValue.append(Base64.encode(digestBytes));
 
-    return ByteStringFactory.create(authPWValue.toString());
+    return ByteString.valueOf(authPWValue.toString());
   }
 
 
@@ -414,7 +409,7 @@
    * {@inheritDoc}
    */
   @Override()
-  public boolean authPasswordMatches(ByteString plaintextPassword,
+  public boolean authPasswordMatches(ByteSequence plaintextPassword,
                                      String authInfo, String authValue)
   {
     byte[] saltBytes;
@@ -435,10 +430,10 @@
     }
 
 
-    byte[] plainBytes = plaintextPassword.value();
-    byte[] plainPlusSaltBytes = new byte[plainBytes.length + saltBytes.length];
-    System.arraycopy(plainBytes, 0, plainPlusSaltBytes, 0, plainBytes.length);
-    System.arraycopy(saltBytes, 0, plainPlusSaltBytes, plainBytes.length,
+    int plainBytesLength = plaintextPassword.length();
+    byte[] plainPlusSaltBytes = new byte[plainBytesLength + saltBytes.length];
+    plaintextPassword.copyTo(plainPlusSaltBytes);
+    System.arraycopy(saltBytes, 0, plainPlusSaltBytes, plainBytesLength,
                      saltBytes.length);
 
     synchronized (digestLock)
@@ -465,7 +460,7 @@
    * {@inheritDoc}
    */
   @Override()
-  public ByteString getPlaintextValue(ByteString storedPassword)
+  public ByteString getPlaintextValue(ByteSequence storedPassword)
          throws DirectoryException
   {
     Message message =
diff --git a/opends/src/server/org/opends/server/extensions/SimilarityBasedPasswordValidator.java b/opends/src/server/org/opends/server/extensions/SimilarityBasedPasswordValidator.java
index a435e39..c9e92f4 100644
--- a/opends/src/server/org/opends/server/extensions/SimilarityBasedPasswordValidator.java
+++ b/opends/src/server/org/opends/server/extensions/SimilarityBasedPasswordValidator.java
@@ -32,13 +32,7 @@
 
 import org.opends.server.api.PasswordValidator;
 import org.opends.server.config.ConfigException;
-import org.opends.server.types.ByteString;
-import org.opends.server.types.ByteStringFactory;
-import org.opends.server.types.ConfigChangeResult;
-import org.opends.server.types.Entry;
-import org.opends.server.types.InitializationException;
-import org.opends.server.types.Operation;
-import org.opends.server.types.ResultCode;
+import org.opends.server.types.*;
 import org.opends.server.util.LevenshteinDistance;
 import org.opends.server.admin.std.server.SimilarityBasedPasswordValidatorCfg;
 import org.opends.server.admin.server.ConfigurationChangeListener;
@@ -107,7 +101,7 @@
 
     int minDifference = currentConfig.getMinPasswordDifference();
     ByteString passwd = newPassword == null
-                        ? ByteStringFactory.create("")
+                        ? ByteString.empty()
                         : newPassword;
 
     if (currentPasswords == null || currentPasswords.size() == 0) {
@@ -124,8 +118,8 @@
         if (bs == null) {
             continue;
         }
-        int ldistance = LevenshteinDistance.calculate(passwd.stringValue(),
-                                                      bs.stringValue());
+        int ldistance = LevenshteinDistance.calculate(passwd.toString(),
+                                                      bs.toString());
         if (ldistance < minDifference) {
           invalidReason.append(ERR_PWDIFFERENCEVALIDATOR_TOO_SMALL.get(
                   minDifference));
diff --git a/opends/src/server/org/opends/server/extensions/StartTLSExtendedOperation.java b/opends/src/server/org/opends/server/extensions/StartTLSExtendedOperation.java
index 0c4b3c8..115a22f 100644
--- a/opends/src/server/org/opends/server/extensions/StartTLSExtendedOperation.java
+++ b/opends/src/server/org/opends/server/extensions/StartTLSExtendedOperation.java
@@ -37,7 +37,6 @@
 import org.opends.server.core.ExtendedOperation;
 import org.opends.server.loggers.debug.DebugTracer;
 import org.opends.server.types.DebugLogLevel;
-import org.opends.server.types.DirectoryException;
 import org.opends.server.types.DisconnectReason;
 import org.opends.server.types.InitializationException;
 import org.opends.server.types.ResultCode;
@@ -160,32 +159,13 @@
     }
 
     MessageBuilder unavailableReason = new MessageBuilder();
-    if (! tlsCapableConnection.tlsProtectionAvailable(unavailableReason))
+    if (! tlsCapableConnection.isTLSAvailable(unavailableReason))
     {
       operation.setResultCode(ResultCode.UNAVAILABLE);
       operation.setErrorMessage(unavailableReason);
       return;
     }
 
-
-    // Actually enable TLS protection on the client connection.  This may fail,
-    // but if it does then the connection will be closed so we'll just need to
-    // log it.
-    try
-    {
-      tlsCapableConnection.enableTLSConnectionSecurityProvider();
-    }
-    catch (DirectoryException de)
-    {
-      if (debugEnabled())
-      {
-        TRACER.debugCaught(DebugLogLevel.ERROR, de);
-      }
-
-      logError(ERR_STARTTLS_ERROR_ON_ENABLE.get(getExceptionMessage(de)));
-    }
-
-
     // TLS was successfully enabled on the client connection, but we need to
     // send the response in the clear.
     operation.setResultCode(ResultCode.SUCCESS);
@@ -194,6 +174,7 @@
     {
       tlsCapableConnection.sendClearResponse(operation);
       operation.setResponseSent();
+      tlsCapableConnection.enableTLS();
     }
     catch (Exception e)
     {
diff --git a/opends/src/server/org/opends/server/extensions/StaticGroup.java b/opends/src/server/org/opends/server/extensions/StaticGroup.java
index f502262..6804905 100644
--- a/opends/src/server/org/opends/server/extensions/StaticGroup.java
+++ b/opends/src/server/org/opends/server/extensions/StaticGroup.java
@@ -44,6 +44,7 @@
 import org.opends.server.loggers.ErrorLogger;
 import org.opends.server.loggers.debug.DebugTracer;
 import org.opends.server.protocols.internal.InternalClientConnection;
+import org.opends.server.protocols.ldap.LDAPControl;
 import org.opends.server.types.Attribute;
 import org.opends.server.types.AttributeType;
 import org.opends.server.types.AttributeValue;
@@ -245,7 +246,7 @@
             }
 
             Message message = ERR_STATICGROUP_CANNOT_DECODE_MEMBER_VALUE_AS_DN.
-                get(v.getStringValue(), memberAttributeType.getNameOrOID(),
+                get(v.getValue().toString(), memberAttributeType.getNameOrOID(),
                     String.valueOf(groupEntry.getDN()), de.getMessageObject());
             ErrorLogger.logError(message);
           }
@@ -395,7 +396,7 @@
       mods.add(new Modification(ModificationType.ADD, attr));
 
       LinkedList<Control> requestControls = new LinkedList<Control>();
-      requestControls.add(new Control(OID_INTERNAL_GROUP_MEMBERSHIP_UPDATE,
+      requestControls.add(new LDAPControl(OID_INTERNAL_GROUP_MEMBERSHIP_UPDATE,
                                       false));
 
       InternalClientConnection conn =
@@ -455,7 +456,7 @@
       mods.add(new Modification(ModificationType.DELETE, attr));
 
       LinkedList<Control> requestControls = new LinkedList<Control>();
-      requestControls.add(new Control(OID_INTERNAL_GROUP_MEMBERSHIP_UPDATE,
+      requestControls.add(new LDAPControl(OID_INTERNAL_GROUP_MEMBERSHIP_UPDATE,
                                       false));
 
       InternalClientConnection conn =
@@ -656,7 +657,7 @@
       mods.add(new Modification(ModificationType.ADD, attr));
 
       LinkedList<Control> requestControls = new LinkedList<Control>();
-      requestControls.add(new Control(OID_INTERNAL_GROUP_MEMBERSHIP_UPDATE,
+      requestControls.add(new LDAPControl(OID_INTERNAL_GROUP_MEMBERSHIP_UPDATE,
                                       false));
 
       InternalClientConnection conn =
@@ -710,7 +711,7 @@
       mods.add(new Modification(ModificationType.DELETE, attr));
 
       LinkedList<Control> requestControls = new LinkedList<Control>();
-      requestControls.add(new Control(OID_INTERNAL_GROUP_MEMBERSHIP_UPDATE,
+      requestControls.add(new LDAPControl(OID_INTERNAL_GROUP_MEMBERSHIP_UPDATE,
                                       false));
 
       InternalClientConnection conn =
diff --git a/opends/src/server/org/opends/server/extensions/SubjectDNToUserAttributeCertificateMapper.java b/opends/src/server/org/opends/server/extensions/SubjectDNToUserAttributeCertificateMapper.java
index 124ca3e..5883717 100644
--- a/opends/src/server/org/opends/server/extensions/SubjectDNToUserAttributeCertificateMapper.java
+++ b/opends/src/server/org/opends/server/extensions/SubjectDNToUserAttributeCertificateMapper.java
@@ -48,19 +48,7 @@
 import org.opends.server.loggers.debug.DebugTracer;
 import org.opends.server.protocols.internal.InternalClientConnection;
 import org.opends.server.protocols.internal.InternalSearchOperation;
-import org.opends.server.types.DirectoryException;
-import org.opends.server.types.AttributeType;
-import org.opends.server.types.AttributeValue;
-import org.opends.server.types.ConfigChangeResult;
-import org.opends.server.types.DebugLogLevel;
-import org.opends.server.types.DN;
-import org.opends.server.types.Entry;
-import org.opends.server.types.IndexType;
-import org.opends.server.types.InitializationException;
-import org.opends.server.types.ResultCode;
-import org.opends.server.types.SearchFilter;
-import org.opends.server.types.SearchResultEntry;
-import org.opends.server.types.SearchScope;
+import org.opends.server.types.*;
 
 import static org.opends.messages.ExtensionMessages.*;
 import static org.opends.server.loggers.debug.DebugLogger.*;
@@ -194,7 +182,8 @@
     // filter.
     X500Principal peerPrincipal = peerCertificate.getSubjectX500Principal();
     String peerName = peerPrincipal.getName(X500Principal.RFC2253);
-    AttributeValue value = new AttributeValue(subjectAttributeType, peerName);
+    AttributeValue value =
+        AttributeValues.create(subjectAttributeType, peerName);
     SearchFilter filter =
          SearchFilter.createEqualityFilter(subjectAttributeType, value);
 
diff --git a/opends/src/server/org/opends/server/extensions/SubschemaSubentryVirtualAttributeProvider.java b/opends/src/server/org/opends/server/extensions/SubschemaSubentryVirtualAttributeProvider.java
index f8e58ca..adf9955 100644
--- a/opends/src/server/org/opends/server/extensions/SubschemaSubentryVirtualAttributeProvider.java
+++ b/opends/src/server/org/opends/server/extensions/SubschemaSubentryVirtualAttributeProvider.java
@@ -38,13 +38,7 @@
 import org.opends.server.config.ConfigException;
 import org.opends.server.core.DirectoryServer;
 import org.opends.server.core.SearchOperation;
-import org.opends.server.types.AttributeValue;
-import org.opends.server.types.ByteString;
-import org.opends.server.types.ConditionResult;
-import org.opends.server.types.Entry;
-import org.opends.server.types.InitializationException;
-import org.opends.server.types.ResultCode;
-import org.opends.server.types.VirtualAttributeRule;
+import org.opends.server.types.*;
 
 import static org.opends.messages.ExtensionMessages.*;
 
@@ -103,8 +97,8 @@
                                        VirtualAttributeRule rule)
   {
     AttributeValue value =
-        new AttributeValue(rule.getAttributeType(),
-                           DirectoryServer.getSchemaDN().toString());
+        AttributeValues.create(rule.getAttributeType(), DirectoryServer
+            .getSchemaDN().toString());
     return Collections.singleton(value);
   }
 
diff --git a/opends/src/server/org/opends/server/extensions/TLSByteChannel.java b/opends/src/server/org/opends/server/extensions/TLSByteChannel.java
new file mode 100644
index 0000000..559f01f
--- /dev/null
+++ b/opends/src/server/org/opends/server/extensions/TLSByteChannel.java
@@ -0,0 +1,400 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License").  You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE
+ * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
+ * add the following below this CDDL 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.server.extensions;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.channels.ByteChannel;
+import java.nio.channels.ClosedChannelException;
+import java.nio.channels.SocketChannel;
+import java.security.cert.Certificate;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.Set;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLEngine;
+import javax.net.ssl.SSLEngineResult;
+import javax.net.ssl.SSLPeerUnverifiedException;
+import javax.net.ssl.SSLSession;
+import org.opends.server.admin.std.server.LDAPConnectionHandlerCfg;
+import org.opends.server.api.ClientConnection;
+import org.opends.server.loggers.debug.DebugTracer;
+import org.opends.server.types.DebugLogLevel;
+import org.opends.server.util.StaticUtils;
+
+import static org.opends.server.loggers.debug.DebugLogger.*;
+
+/**
+ * A class that provides a TLS byte channel implementation.
+ *
+ */
+public class TLSByteChannel implements
+                                ByteChannel, ConnectionSecurityProvider {
+
+    private static final DebugTracer TRACER = getTracer();
+
+    private ClientConnection connection;
+    private SocketChannel socketChannel;
+
+    private SSLEngine sslEngine;
+
+    //read copy to buffer
+    private ByteBuffer appData;
+    //read encrypted
+    private ByteBuffer appNetData;
+
+    //Write encrypted
+    private ByteBuffer netData, tempData;
+    private int sslBufferSize, appBufSize;
+
+
+    //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> cipherMap;
+
+    static {
+        cipherMap = new LinkedHashMap<String, Integer>();
+        cipherMap.put("_WITH_AES_256_CBC_", new Integer(256));
+        cipherMap.put("_WITH_CAMELLIA_256_CBC_", new Integer(256));
+        cipherMap.put("_WITH_AES_256_GCM_", new Integer(256));
+        cipherMap.put("_WITH_3DES_EDE_CBC_", new Integer(112));
+        cipherMap.put("_WITH_AES_128_GCM_", new Integer(128));
+        cipherMap.put("_WITH_SEED_CBC_", new Integer(128));
+        cipherMap.put("_WITH_CAMELLIA_128_CBC_", new Integer(128));
+        cipherMap.put("_WITH_AES_128_CBC_", new Integer(128));
+        cipherMap.put("_WITH_IDEA_CBC_", new Integer(128));
+        cipherMap.put("_WITH_DES_CBC_", new Integer(56));
+        cipherMap.put("_WITH_RC2_CBC_40_", new Integer(40));
+        cipherMap.put("_WITH_RC4_40_", new Integer(40));
+        cipherMap.put("_WITH_DES40_CBC_", new Integer(40));
+        cipherMap.put("_WITH_NULL_", new Integer(0));
+    };
+
+    private TLSByteChannel(LDAPConnectionHandlerCfg config, ClientConnection c,
+                         SocketChannel socketChannel, SSLContext sslContext)  {
+
+        this.socketChannel = socketChannel;
+        this.connection = c;
+        String hostName = socketChannel.socket().getInetAddress().getHostName();
+        int port = socketChannel.socket().getPort();
+        sslEngine = sslContext.createSSLEngine(hostName, port);
+        sslEngine.setUseClientMode(false);
+        Set<String> protocols = config.getSSLProtocol();
+        if (!protocols.isEmpty())
+            sslEngine.setEnabledProtocols(protocols.toArray(new String[0]));
+        Set<String> ciphers = config.getSSLCipherSuite();
+        if (!ciphers.isEmpty())
+            sslEngine.setEnabledCipherSuites(ciphers.toArray(new String[0]));
+        switch (config.getSSLClientAuthPolicy()) {
+        case DISABLED:
+            sslEngine.setNeedClientAuth(false);
+            sslEngine.setWantClientAuth(false);
+            break;
+        case REQUIRED:
+            sslEngine.setWantClientAuth(true);
+            sslEngine.setNeedClientAuth(true);
+            break;
+        case OPTIONAL:
+        default:
+            sslEngine.setNeedClientAuth(false);
+            sslEngine.setWantClientAuth(true);
+            break;
+        }
+        SSLSession sslSession = sslEngine.getSession();
+        sslBufferSize = sslSession.getPacketBufferSize();
+        appBufSize = sslSession.getApplicationBufferSize();
+
+        appNetData = ByteBuffer.allocate(sslBufferSize);
+        netData = ByteBuffer.allocate(sslBufferSize);
+
+        appData = ByteBuffer.allocate(sslSession.getApplicationBufferSize());
+        tempData = ByteBuffer.allocate(sslSession.getApplicationBufferSize());
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public int getAppBufSize() {
+        return appBufSize;
+    }
+
+    /**
+     * Create an TLS byte channel instance using the specified LDAP connection
+     * configuration, client connection, SSL context and socket channel
+     * parameters.
+     *
+     * @param config The LDAP connection configuration.
+     * @param c The client connection.
+     * @param sslContext The SSL context.
+     * @param socketChannel The socket channel.
+     * @return A TLS capable byte channel.
+     */
+    public static TLSByteChannel
+    getTLSByteChannel(LDAPConnectionHandlerCfg config, ClientConnection c,
+                        SSLContext sslContext, SocketChannel socketChannel) {
+        return new TLSByteChannel(config, c, socketChannel, sslContext);
+    }
+
+    private SSLEngineResult.HandshakeStatus doTasks() {
+        Runnable task;
+        while ((task = sslEngine.getDelegatedTask()) != null)
+            task.run();
+        return sslEngine.getHandshakeStatus();
+    }
+
+    private void doHandshakeRead(SSLEngineResult.HandshakeStatus hsStatus)
+    throws IOException {
+        do {
+            doHandshakeOp(hsStatus);
+            hsStatus = sslEngine.getHandshakeStatus();
+        } while (hsStatus == SSLEngineResult.HandshakeStatus.NEED_WRAP ||
+                hsStatus == SSLEngineResult.HandshakeStatus.NEED_TASK);
+    }
+
+    private void  doHandshakeOp(SSLEngineResult.HandshakeStatus hsStatus)
+    throws IOException {
+        SSLEngineResult res;
+        switch (hsStatus) {
+        case NEED_TASK:
+            hsStatus = doTasks();
+            break;
+        case NEED_WRAP:
+            tempData.clear();
+            netData.clear();
+            res = sslEngine.wrap(tempData, netData);
+            hsStatus = res.getHandshakeStatus();
+            netData.flip();
+            while(netData.hasRemaining()) {
+                socketChannel.write(netData);
+            }
+            hsStatus = sslEngine.getHandshakeStatus();
+            return;
+        default:
+            return;
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public int read(ByteBuffer clearBuffer) throws IOException {
+        SSLEngineResult.HandshakeStatus hsStatus;
+        appData.clear();
+        appNetData.clear();
+        if(!socketChannel.isOpen())
+            return -1;
+        if(sslEngine.isInboundDone())
+            return -1;
+        do {
+            int wrappedBytes = socketChannel.read(appNetData);
+            appNetData.flip();
+            if(wrappedBytes == -1) {
+                return -1;
+            }
+            hsStatus = sslEngine.getHandshakeStatus();
+            if (hsStatus == SSLEngineResult.HandshakeStatus.NEED_TASK ||
+                    hsStatus == SSLEngineResult.HandshakeStatus.NEED_WRAP)
+                doHandshakeRead(hsStatus);
+            if(wrappedBytes == 0)
+                return 0;
+            while (appNetData.hasRemaining()) {
+                appData.clear();
+                SSLEngineResult res = sslEngine.unwrap(appNetData, appData);
+                appData.flip();
+                if(res.getStatus() != SSLEngineResult.Status.OK)
+                    return -1;
+                hsStatus = sslEngine.getHandshakeStatus();
+                if (hsStatus == SSLEngineResult.HandshakeStatus.NEED_TASK ||
+                        hsStatus == SSLEngineResult.HandshakeStatus.NEED_WRAP)
+                    doHandshakeOp(hsStatus);
+                int limit = appData.remaining();
+                for(int i = 0; i < limit; i++) {
+                    clearBuffer.put(appData.get());
+                }
+            }
+            hsStatus = sslEngine.getHandshakeStatus();
+        } while (hsStatus == SSLEngineResult.HandshakeStatus.NEED_TASK ||
+                 hsStatus == SSLEngineResult.HandshakeStatus.NEED_WRAP);
+        return clearBuffer.remaining();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void close() throws IOException {
+        sslEngine.closeInbound();
+        sslEngine.closeOutbound();
+        SSLEngineResult.HandshakeStatus hsStatus =
+                                      sslEngine.getHandshakeStatus();
+        if(hsStatus != SSLEngineResult.HandshakeStatus.FINISHED &&
+           hsStatus !=  SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING)
+            doHandshakeWrite(hsStatus);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isOpen() {
+        return sslEngine.isInboundDone() && sslEngine.isOutboundDone();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public int getSSF() {
+        int cipherKeySSF = 0;
+        String cipherString = sslEngine.getSession().getCipherSuite();
+        for(Map.Entry<String, Integer> mapEntry : cipherMap.entrySet()) {
+            if(cipherString.indexOf(mapEntry.getKey()) >= 0) {
+                cipherKeySSF = mapEntry.getValue().intValue();
+                break;
+            }
+        }
+        return cipherKeySSF;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public  Certificate[] getClientCertificateChain() {
+        try {
+          return sslEngine.getSession().getPeerCertificates();
+        }
+        catch (SSLPeerUnverifiedException e) {
+          if (debugEnabled()) {
+            TRACER.debugCaught(DebugLogLevel.ERROR, e);
+          }
+          return new Certificate[0];
+        }
+    }
+
+    private void doHandshakeUnwrap() throws IOException {
+        netData.clear();
+        tempData.clear();
+        int bytesRead = socketChannel.read(netData);
+        if (bytesRead <= 0)
+            throw new ClosedChannelException();
+         else
+          sslEngine.unwrap(netData, tempData);
+    }
+
+    private void
+    doHandshakeWrite(SSLEngineResult.HandshakeStatus hsStatus)
+    throws IOException {
+        do {
+            if(hsStatus == SSLEngineResult.HandshakeStatus.NEED_UNWRAP) {
+                doHandshakeUnwrap();
+            } else
+               doHandshakeOp(hsStatus);
+            hsStatus = sslEngine.getHandshakeStatus();
+        } while (hsStatus == SSLEngineResult.HandshakeStatus.NEED_WRAP ||
+                hsStatus == SSLEngineResult.HandshakeStatus.NEED_TASK ||
+                hsStatus == SSLEngineResult.HandshakeStatus.NEED_UNWRAP);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public int write(ByteBuffer clearData) throws IOException {
+        if(!socketChannel.isOpen() || sslEngine.isOutboundDone()) {
+            throw new ClosedChannelException();
+        }
+        int originalPosition = clearData.position();
+        int originalLimit = clearData.limit();
+        int length = originalLimit - originalPosition;
+        if (length > sslBufferSize) {
+            int pos = originalPosition;
+            int lim = originalPosition + sslBufferSize;
+            while (pos < originalLimit) {
+                clearData.position(pos);
+                clearData.limit(lim);
+                writeInternal(clearData);
+                pos = lim;
+                lim = Math.min(originalLimit, pos + sslBufferSize);
+            }
+            return length;
+        }  else {
+            return writeInternal(clearData);
+        }
+    }
+
+    private int writeInternal(ByteBuffer clearData) throws IOException {
+        int totBytesSent = 0;
+        SSLEngineResult.HandshakeStatus hsStatus;
+        hsStatus = sslEngine.getHandshakeStatus();
+        if (hsStatus == SSLEngineResult.HandshakeStatus.NEED_TASK ||
+                hsStatus == SSLEngineResult.HandshakeStatus.NEED_WRAP ||
+                hsStatus == SSLEngineResult.HandshakeStatus.NEED_UNWRAP)
+            doHandshakeWrite(hsStatus);
+        while(clearData.hasRemaining()) {
+            netData.clear();
+            SSLEngineResult res = sslEngine.wrap(clearData, netData);
+            netData.flip();
+            if(res.getStatus() != SSLEngineResult.Status.OK)
+                throw new ClosedChannelException();
+            if (hsStatus == SSLEngineResult.HandshakeStatus.NEED_TASK ||
+                    hsStatus == SSLEngineResult.HandshakeStatus.NEED_WRAP ||
+                    hsStatus == SSLEngineResult.HandshakeStatus.NEED_UNWRAP)
+                doHandshakeWrite(hsStatus);
+            while (netData.hasRemaining()) {
+                int bytesWritten = socketChannel.write(netData);
+                if (bytesWritten < 0)
+                    throw new ClosedChannelException();
+                else if (bytesWritten == 0) {
+                    int bytesSent = netData.remaining();
+                    if(!StaticUtils.writeWithTimeout(
+                            connection, socketChannel, netData))
+                        throw new ClosedChannelException();
+                    totBytesSent += bytesSent;
+                } else
+                    totBytesSent += bytesWritten;
+            }
+        }
+        return totBytesSent;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public ByteChannel wrapChannel(ByteChannel channel) {
+        return this;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public String getName() {
+        return "TLS";
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isSecure() {
+        return true;
+    }
+}
diff --git a/opends/src/server/org/opends/server/extensions/TLSCapableConnection.java b/opends/src/server/org/opends/server/extensions/TLSCapableConnection.java
index 9d72e00..c53ade0 100644
--- a/opends/src/server/org/opends/server/extensions/TLSCapableConnection.java
+++ b/opends/src/server/org/opends/server/extensions/TLSCapableConnection.java
@@ -55,7 +55,7 @@
    * @return  <CODE>true</CODE> if TLS is available on the underlying client
    *          connection, or <CODE>false</CODE> if it is not.
    */
-  public boolean tlsProtectionAvailable(MessageBuilder unavailableReason);
+  public boolean isTLSAvailable(MessageBuilder unavailableReason);
 
 
 
@@ -69,27 +69,10 @@
    *                              not be enabled and the underlying connection
    *                              has been closed.
    */
-  public void enableTLSConnectionSecurityProvider()
+  public void enableTLS()
          throws DirectoryException;
 
 
-
-  /**
-   * Disables the TLS connection security provider on this client connection.
-   * This must also eliminate any authentication that had been performed on the
-   * client connection so that it is in an anonymous state.  If a problem occurs
-   * while attempting to revert the connection to a non-TLS-protected state,
-   * then an exception must be thrown and the client connection must be
-   * terminated.
-   *
-   * @throws  DirectoryException  If TLS protection cannot be reverted and the
-   *                              underlying client connection has been closed.
-   */
-  public void disableTLSConnectionSecurityProvider()
-         throws DirectoryException;
-
-
-
   /**
    * Sends a response to the client in the clear rather than through the
    * encrypted channel.  This should only be used when processing the StartTLS
diff --git a/opends/src/server/org/opends/server/extensions/TLSConnectionSecurityProvider.java b/opends/src/server/org/opends/server/extensions/TLSConnectionSecurityProvider.java
deleted file mode 100644
index 6629b74..0000000
--- a/opends/src/server/org/opends/server/extensions/TLSConnectionSecurityProvider.java
+++ /dev/null
@@ -1,1082 +0,0 @@
-/*
- * CDDL HEADER START
- *
- * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
- *
- * You can obtain a copy of the license at
- * trunk/opends/resource/legal-notices/OpenDS.LICENSE
- * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
- * See the License for the specific language governing permissions
- * and limitations under the License.
- *
- * When distributing Covered Code, include this CDDL HEADER in each
- * file and include the License file at
- * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
- * add the following below this CDDL 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.server.extensions;
-
-
-
-import java.io.IOException;
-import java.net.InetAddress;
-import java.net.Socket;
-import java.nio.ByteBuffer;
-import java.nio.channels.SocketChannel;
-import java.security.cert.Certificate;
-import java.util.LinkedHashMap;
-import java.util.Map;
-import javax.net.ssl.SSLContext;
-import javax.net.ssl.SSLEngine;
-import javax.net.ssl.SSLEngineResult;
-import javax.net.ssl.SSLSession;
-
-import org.opends.messages.Message;
-import org.opends.server.api.ClientConnection;
-import org.opends.server.api.ConnectionSecurityProvider;
-import org.opends.server.api.KeyManagerProvider;
-import org.opends.server.api.TrustManagerProvider;
-import org.opends.server.config.ConfigEntry;
-import org.opends.server.config.ConfigException;
-import org.opends.server.core.DirectoryServer;
-import org.opends.server.loggers.debug.DebugTracer;
-import org.opends.server.types.DebugLogLevel;
-import org.opends.server.types.DirectoryException;
-import org.opends.server.types.DisconnectReason;
-import org.opends.server.types.InitializationException;
-import org.opends.server.types.SSLClientAuthPolicy;
-import org.opends.server.util.SelectableCertificateKeyManager;
-
-import static org.opends.messages.ExtensionMessages.*;
-import static org.opends.server.loggers.debug.DebugLogger.*;
-import static org.opends.server.util.StaticUtils.*;
-
-
-
-/**
- * This class provides an implementation of a connection security provider that
- * uses SSL/TLS to encrypt the communication to and from the client.  It uses
- * the {@code javax.net.ssl.SSLEngine} class to provide the actual SSL
- * communication layer, and the Directory Server key and trust store providers
- * to determine which key and trust stores to use.
- */
-public class TLSConnectionSecurityProvider
-       extends ConnectionSecurityProvider
-{
-  /**
-   * The tracer object for the debug logger.
-   */
-  private static final DebugTracer TRACER = getTracer();
-
-  /**
-   * The SSL context name that should be used for this TLS connection security
-   * provider.
-   */
-  private static final String SSL_CONTEXT_INSTANCE_NAME = "TLS";
-
-  // The buffer that will be used when reading clear-text data.
-  private ByteBuffer clearInBuffer;
-
-  // The buffer that will be used when writing clear-text data.
-  private ByteBuffer clearOutBuffer;
-
-  // The buffer that will be used when reading encrypted data.
-  private ByteBuffer sslInBuffer;
-
-  // The buffer that willa be used when writing encrypted data.
-  private ByteBuffer sslOutBuffer;
-
-  // The client connection with which this security provider is associated.
-  private ClientConnection clientConnection;
-
-  // The size in bytes that should be used for the buffer holding clear-text
-  // data.
-  private int clearBufferSize;
-
-  // The size in bytes that should be used for the buffer holding the encrypted
-  // data.
-  private int sslBufferSize;
-
-  // The socket channel that may be used to communicate with the client.
-  private SocketChannel socketChannel;
-
-  // The SSL client certificate policy.
-  private SSLClientAuthPolicy sslClientAuthPolicy;
-
-  // The SSL context that will be used for all SSL/TLS communication.
-  private SSLContext sslContext;
-
-  // The SSL engine that will be used for this connection.
-  private SSLEngine sslEngine;
-
-  // The set of cipher suites to allow.
-  private String[] enabledCipherSuites;
-
-  // The set of protocols to allow.
-  private String[] enabledProtocols;
-
-  //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> cipherMap;
-
-  static {
-      cipherMap = new LinkedHashMap<String, Integer>();
-      cipherMap.put("_WITH_AES_256_CBC_", new Integer(256));
-      cipherMap.put("_WITH_CAMELLIA_256_CBC_", new Integer(256));
-      cipherMap.put("_WITH_AES_256_GCM_", new Integer(256));
-      cipherMap.put("_WITH_3DES_EDE_CBC_", new Integer(112));
-      cipherMap.put("_WITH_AES_128_GCM_", new Integer(128));
-      cipherMap.put("_WITH_SEED_CBC_", new Integer(128));
-      cipherMap.put("_WITH_CAMELLIA_128_CBC_", new Integer(128));
-      cipherMap.put("_WITH_AES_128_CBC_", new Integer(128));
-      cipherMap.put("_WITH_IDEA_CBC_", new Integer(128));
-      cipherMap.put("_WITH_DES_CBC_", new Integer(56));
-      cipherMap.put("_WITH_RC2_CBC_40_", new Integer(40));
-      cipherMap.put("_WITH_RC4_40_", new Integer(40));
-      cipherMap.put("_WITH_DES40_CBC_", new Integer(40));
-      cipherMap.put("_WITH_NULL_", new Integer(0));
-  };
-
-
-  /**
-   * Creates a new instance of this connection security provider.  Note that
-   * no initialization should be done here, since it should all be done in the
-   * {@code initializeConnectionSecurityProvider} method.  Also note that this
-   * instance should only be used to create new instances that are associated
-   * with specific client connections.  This instance itself should not be used
-   * to attempt secure communication with the client.
-   */
-  public TLSConnectionSecurityProvider()
-  {
-    super();
-
-  }
-
-
-
-  /**
-   * Creates a new instance of this connection security provider that will be
-   * associated with the provided client connection.
-   *
-   * @param  clientConnection  The client connection with which this connection
-   *                           security provider should be associated.
-   * @param  socketChannel     The socket channel that may be used to
-   *                           communicate with the client.
-   * @param  parentProvider    A reference to the parent TLS connection security
-   *                           provider that is being used to create this
-   *                           instance.
-   */
-  private TLSConnectionSecurityProvider(ClientConnection clientConnection,
-                                        SocketChannel socketChannel,
-                                        TLSConnectionSecurityProvider
-                                             parentProvider)
-          throws DirectoryException
-  {
-    super();
-
-
-    this.clientConnection = clientConnection;
-    this.socketChannel    = socketChannel;
-
-    Socket socket = socketChannel.socket();
-    InetAddress inetAddress = socketChannel.socket().getInetAddress();
-
-
-    // Create an SSL session based on the configured key and trust stores in the
-    // Directory Server.
-    KeyManagerProvider<?> keyManagerProvider =
-         DirectoryServer.getKeyManagerProvider(
-              clientConnection.getKeyManagerProviderDN());
-    if (keyManagerProvider == null)
-    {
-      keyManagerProvider = new NullKeyManagerProvider();
-    }
-
-    TrustManagerProvider<?> trustManagerProvider =
-         DirectoryServer.getTrustManagerProvider(
-              clientConnection.getTrustManagerProviderDN());
-    if (trustManagerProvider == null)
-    {
-      trustManagerProvider = new NullTrustManagerProvider();
-    }
-
-    try
-    {
-      // FIXME -- Is it bad to create a new SSLContext for each connection?
-      sslContext = SSLContext.getInstance(SSL_CONTEXT_INSTANCE_NAME);
-
-      String alias = clientConnection.getCertificateAlias();
-      if (alias == null)
-      {
-        sslContext.init(keyManagerProvider.getKeyManagers(),
-                        trustManagerProvider.getTrustManagers(), null);
-      }
-      else
-      {
-        sslContext.init(SelectableCertificateKeyManager.wrap(
-                             keyManagerProvider.getKeyManagers(), alias),
-                        trustManagerProvider.getTrustManagers(), null);
-      }
-    }
-    catch (Exception e)
-    {
-      if (debugEnabled())
-      {
-        TRACER.debugCaught(DebugLogLevel.ERROR, e);
-      }
-
-      Message message = ERR_TLS_SECURITY_PROVIDER_CANNOT_INITIALIZE.get(
-          getExceptionMessage(e));
-      throw new DirectoryException(DirectoryServer.getServerErrorResultCode(),
-                                   message, e);
-    }
-
-    sslEngine = sslContext.createSSLEngine(inetAddress.getHostName(),
-                                           socket.getPort());
-    sslEngine.setUseClientMode(false);
-
-    enabledProtocols = parentProvider.enabledProtocols;
-    if (enabledProtocols != null)
-    {
-      sslEngine.setEnabledProtocols(enabledProtocols);
-    }
-
-    enabledCipherSuites = parentProvider.enabledCipherSuites;
-    if (enabledCipherSuites != null)
-    {
-      sslEngine.setEnabledCipherSuites(enabledCipherSuites);
-    }
-
-    sslClientAuthPolicy = parentProvider.sslClientAuthPolicy;
-    if (sslClientAuthPolicy == null)
-    {
-      sslClientAuthPolicy = SSLClientAuthPolicy.OPTIONAL;
-    }
-    switch (sslClientAuthPolicy)
-    {
-      case REQUIRED:
-        sslEngine.setWantClientAuth(true);
-        sslEngine.setNeedClientAuth(true);
-        break;
-
-      case DISABLED:
-        sslEngine.setNeedClientAuth(false);
-        sslEngine.setWantClientAuth(false);
-        break;
-
-      case OPTIONAL:
-      default:
-        sslEngine.setNeedClientAuth(false);
-        sslEngine.setWantClientAuth(true);
-        break;
-    }
-
-    SSLSession sslSession = sslEngine.getSession();
-
-    clearBufferSize = sslSession.getApplicationBufferSize();
-    clearInBuffer   = ByteBuffer.allocate(clearBufferSize);
-    clearOutBuffer  = ByteBuffer.allocate(clearBufferSize);
-
-    sslBufferSize   = sslSession.getPacketBufferSize();
-    sslInBuffer     = ByteBuffer.allocate(sslBufferSize);
-    sslOutBuffer    = ByteBuffer.allocate(sslBufferSize);
-  }
-
-
-
-  /**
-   * {@inheritDoc}
-   */
-  @Override()
-  public void initializeConnectionSecurityProvider(ConfigEntry configEntry)
-         throws ConfigException, InitializationException
-  {
-    // Initialize default values for the connection-specific variables.
-    clientConnection = null;
-    socketChannel    = null;
-
-    clearInBuffer    = null;
-    clearOutBuffer   = null;
-    sslInBuffer      = null;
-    sslOutBuffer     = null;
-    clearBufferSize  = -1;
-    sslBufferSize    = -1;
-
-    sslEngine        = null;
-
-    enabledProtocols    = null;
-    enabledCipherSuites = null;
-    sslClientAuthPolicy = SSLClientAuthPolicy.OPTIONAL;
-  }
-
-
-
-  /**
-   * {@inheritDoc}
-   */
-  @Override()
-  public void finalizeConnectionSecurityProvider()
-  {
-    // No implementation is required.
-  }
-
-
-
-  /**
-   * {@inheritDoc}
-   */
-  @Override()
-  public String getSecurityMechanismName()
-  {
-    return SSL_CONTEXT_INSTANCE_NAME;
-  }
-
-
-
-  /**
-   * {@inheritDoc}
-   */
-  @Override()
-  public boolean isSecure()
-  {
-    // This should be considered secure.
-    return true;
-  }
-
-
-
-  /**
-   * {@inheritDoc}
-   */
-  @Override
-  public boolean isActive() {
-      //This provider is always active.
-      return true;
-  }
-
-  /**
-   * {@inheritDoc}
-   */
-  @Override()
-  public ConnectionSecurityProvider newInstance(ClientConnection
-                                                      clientConnection,
-                                                SocketChannel socketChannel)
-         throws DirectoryException
-  {
-    return new TLSConnectionSecurityProvider(clientConnection, socketChannel,
-                                             this);
-  }
-
-
-
-  /**
-   * {@inheritDoc}
-   */
-  @Override()
-  public void disconnect(boolean connectionValid)
-  {
-    if (connectionValid)
-    {
-      try
-      {
-        sslEngine.closeInbound();
-        sslEngine.closeOutbound();
-
-        while (true)
-        {
-          switch (sslEngine.getHandshakeStatus())
-          {
-            case FINISHED:
-            case NOT_HANDSHAKING:
-              // We don't need to do anything else.
-              return;
-
-            case NEED_TASK:
-              // We need to process some task before continuing.
-              Runnable task = sslEngine.getDelegatedTask();
-              task.run();
-              break;
-
-            case NEED_WRAP:
-              // We need to send data to the client.
-              clearOutBuffer.clear();
-              sslOutBuffer.clear();
-              sslEngine.wrap(clearOutBuffer, sslOutBuffer);
-              sslOutBuffer.flip();
-              while (sslOutBuffer.hasRemaining())
-              {
-                socketChannel.write(sslOutBuffer);
-              }
-              break;
-
-            case NEED_UNWRAP:
-              // We need to read data from the client.  We can do this if it's
-              // immediately available, but otherwise, ignore it because
-              // otherwise it could chew up a lot of time.
-              if (sslInBuffer.hasRemaining())
-              {
-                clearInBuffer.clear();
-                sslEngine.unwrap(sslInBuffer, clearInBuffer);
-                clearInBuffer.flip();
-              }
-              else
-              {
-                sslInBuffer.clear();
-                clearInBuffer.clear();
-                int bytesRead = socketChannel.read(sslInBuffer);
-                if (bytesRead <= 0)
-                {
-                  return;
-                }
-                sslEngine.unwrap(sslInBuffer, clearInBuffer);
-                clearInBuffer.flip();
-              }
-          }
-        }
-      }
-      catch (Exception e)
-      {
-        if (debugEnabled())
-        {
-          TRACER.debugCaught(DebugLogLevel.ERROR, e);
-        }
-      }
-    }
-  }
-
-
-
-  /**
-   * {@inheritDoc}
-   */
-  @Override()
-  public int getClearBufferSize()
-  {
-    return clearBufferSize;
-  }
-
-
-
-  /**
-   * {@inheritDoc}
-   */
-  @Override()
-  public int getEncodedBufferSize()
-  {
-    return sslBufferSize;
-  }
-
-
-
-  /**
-   * {@inheritDoc}
-   */
-  @Override()
-  public boolean readData()
-  {
-    while (true)
-    {
-      try
-      {
-        sslInBuffer.clear();
-        int bytesRead = socketChannel.read(sslInBuffer);
-        sslInBuffer.flip();
-
-        if (bytesRead < 0)
-        {
-          // The client connection has been closed.  Disconnect and return.
-          clientConnection.disconnect(DisconnectReason.CLIENT_DISCONNECT, false,
-                                      null);
-          return false;
-        }
-
-
-        // See if there is any preliminary handshake work to do.
-handshakeLoop:
-        while (true)
-        {
-          switch (sslEngine.getHandshakeStatus())
-          {
-            case NEED_TASK:
-              Runnable task = sslEngine.getDelegatedTask();
-              task.run();
-              break;
-
-            case NEED_WRAP:
-              clearOutBuffer.clear();
-              sslOutBuffer.clear();
-              sslEngine.wrap(clearOutBuffer, sslOutBuffer);
-              sslOutBuffer.flip();
-
-              while (sslOutBuffer.hasRemaining())
-              {
-                int bytesWritten = socketChannel.write(sslOutBuffer);
-                if (bytesWritten < 0)
-                {
-                  // The client connection has been closed.  Disconnect and
-                  // return.
-                  clientConnection.disconnect(
-                       DisconnectReason.CLIENT_DISCONNECT, false, null);
-                  return false;
-                }
-              }
-              break;
-
-            default:
-              break handshakeLoop;
-          }
-        }
-
-        if (bytesRead == 0)
-        {
-          // We don't have any data to process, and we've already done any
-          // necessary handshaking, so we can break out and wait for more data
-          // to arrive.
-          return true;
-        }
-
-
-        // Read any SSL-encrypted data provided by the client.
-        while (sslInBuffer.hasRemaining())
-        {
-          clearInBuffer.clear();
-          SSLEngineResult unwrapResult = sslEngine.unwrap(sslInBuffer,
-                                                          clearInBuffer);
-          clearInBuffer.flip();
-
-          switch (unwrapResult.getStatus())
-          {
-            case OK:
-              // This is fine.
-              break;
-
-            case CLOSED:
-              // The client connection (or at least the SSL side of it) has been
-              // closed.
-              // FIXME -- Allow for closing the SSL channel without closing the
-              //          underlying connection.
-              clientConnection.disconnect(DisconnectReason.CLIENT_DISCONNECT,
-                                          false, null);
-              return false;
-
-            default:
-              // This should not have happened.
-              clientConnection.disconnect(DisconnectReason.SECURITY_PROBLEM,
-                      false,
-                      ERR_TLS_SECURITY_PROVIDER_UNEXPECTED_UNWRAP_STATUS.get(
-                              String.valueOf(unwrapResult.getStatus())));
-              return false;
-          }
-
-          switch (unwrapResult.getHandshakeStatus())
-          {
-            case NEED_TASK:
-              Runnable task = sslEngine.getDelegatedTask();
-              task.run();
-              break;
-
-            case NEED_WRAP:
-              clearOutBuffer.clear();
-              sslOutBuffer.clear();
-              sslEngine.wrap(clearOutBuffer, sslOutBuffer);
-              sslOutBuffer.flip();
-
-              while (sslOutBuffer.hasRemaining())
-              {
-                int bytesWritten = socketChannel.write(sslOutBuffer);
-                if (bytesWritten < 0)
-                {
-                  // The client connection has been closed.  Disconnect and
-                  // return.
-                  clientConnection.disconnect(
-                       DisconnectReason.CLIENT_DISCONNECT, false, null);
-                  return false;
-                }
-              }
-              break;
-          }
-
-          // If there is any clear-text data, then process it.
-          if (! clientConnection.processDataRead(clearInBuffer))
-          {
-            // If this happens, then the client connection disconnect method
-            // should have already been called, so we don't need to do it again.
-            return false;
-          }
-        }
-      }
-      catch (IOException ioe)
-      {
-        if (debugEnabled())
-        {
-          TRACER.debugCaught(DebugLogLevel.ERROR, ioe);
-        }
-
-        // An error occurred while trying to communicate with the client.
-        // Disconnect and return.
-        clientConnection.disconnect(DisconnectReason.IO_ERROR, false, null);
-        return false;
-      }
-      catch (Exception e)
-      {
-        if (debugEnabled())
-        {
-          TRACER.debugCaught(DebugLogLevel.ERROR, e);
-        }
-
-        // An unexpected error occurred while trying to process the data read.
-        // Disconnect and return.
-        clientConnection.disconnect(DisconnectReason.SERVER_ERROR, true,
-                                    ERR_TLS_SECURITY_PROVIDER_READ_ERROR.get(
-                                    getExceptionMessage(e)));
-        return false;
-      }
-    }
-  }
-
-
-
-  /**
-   * {@inheritDoc}
-   */
-  @Override()
-  public boolean writeData(ByteBuffer clearData)
-  {
-    int originalPosition = clearData.position();
-    int originalLimit    = clearData.limit();
-    int length           = originalLimit - originalPosition;
-
-    try
-    {
-      if (length > clearBufferSize)
-      {
-        // There is more data to write than we can deal with in one chunk, so
-        // break it up.
-        int pos = originalPosition;
-        int lim = originalPosition + clearBufferSize;
-
-        while (pos < originalLimit)
-        {
-          clearData.position(pos);
-          clearData.limit(lim);
-
-          if (! writeInternal(clearData))
-          {
-            return false;
-          }
-
-          pos = lim;
-          lim = Math.min(originalLimit, pos+clearBufferSize);
-        }
-
-        return true;
-      }
-      else
-      {
-        return writeInternal(clearData);
-      }
-    }
-    finally
-    {
-      clearData.position(originalPosition);
-      clearData.limit(originalLimit);
-    }
-  }
-
-
-
-  /**
-   * Writes the data contained in the provided clear-text buffer to the client,
-   * performing any necessary encoding in the process.  The amount of data in
-   * the provided buffer must be less than or equal to the value returned by the
-   * {@code getClearBufferSize} method.
-   *
-   * @param  clearData  The buffer containing the clear-text data to write to
-   *                    the client.
-   *
-   * @return  {@code true} if all the data in the provided buffer was written to
-   *          the client and the connection may remain established, or
-   *          {@code false} if a problem occurred and the client connection is
-   *          no longer valid.  Note that if this method does return
-   *          {@code false}, then it must have already disconnected the client.
-   */
-  private boolean writeInternal(ByteBuffer clearData)
-  {
-    try
-    {
-      // See if there is any preliminary handshake work to be done.
-handshakeStatusLoop:
-      while (true)
-      {
-        switch (sslEngine.getHandshakeStatus())
-        {
-          case NEED_TASK:
-            Runnable task = sslEngine.getDelegatedTask();
-            task.run();
-            break;
-
-          case NEED_WRAP:
-            clearOutBuffer.clear();
-            sslOutBuffer.clear();
-            sslEngine.wrap(clearOutBuffer, sslOutBuffer);
-            sslOutBuffer.flip();
-
-            while (sslOutBuffer.hasRemaining())
-            {
-              int bytesWritten = socketChannel.write(sslOutBuffer);
-              if (bytesWritten < 0)
-              {
-                // The client connection has been closed.  Disconnect and
-                // return.
-                clientConnection.disconnect(
-                     DisconnectReason.CLIENT_DISCONNECT, false, null);
-                return false;
-              }
-              else if (bytesWritten == 0)
-              {
-                return NullConnectionSecurityProvider.writeWithTimeout(
-                            clientConnection, socketChannel, sslOutBuffer);
-              }
-            }
-            break;
-
-          case NEED_UNWRAP:
-            // We need to read data from the client before the negotiation can
-            // continue.  This is bad, because we don't know if there is data
-            // available but we do know that we can't write until we have read.
-            // See if there is something available for reading, and if not, then
-            // we can't afford to wait for it because otherwise we would be
-            // potentially blocking reads from other clients.  Our only recourse
-            // is to close the connection.
-            sslInBuffer.clear();
-            clearInBuffer.clear();
-            int bytesRead = socketChannel.read(sslInBuffer);
-            if (bytesRead < 0)
-            {
-              // The client connection is already closed, so we don't need to
-              // worry about it.
-              clientConnection.disconnect(DisconnectReason.CLIENT_DISCONNECT,
-                                          false, null);
-              return false;
-            }
-            else if (bytesRead == 0)
-            {
-              // We didn't get the data that we need.  We'll have to disconnect
-              // to avoid blocking other clients.
-              clientConnection.disconnect(DisconnectReason.SECURITY_PROBLEM,
-                   false, ERR_TLS_SECURITY_PROVIDER_WRITE_NEEDS_UNWRAP.get());
-              return false;
-            }
-            else
-            {
-              // We were lucky and got the data we were looking for, so read and
-              // process it.
-              sslEngine.unwrap(sslInBuffer, clearInBuffer);
-              clearInBuffer.flip();
-            }
-            break;
-
-          default:
-            break handshakeStatusLoop;
-        }
-      }
-
-
-      while (clearData.hasRemaining())
-      {
-        sslOutBuffer.clear();
-        SSLEngineResult wrapResult = sslEngine.wrap(clearData, sslOutBuffer);
-        sslOutBuffer.flip();
-
-        switch (wrapResult.getStatus())
-        {
-          case OK:
-            // This is fine.
-            break;
-
-          case CLOSED:
-            // The client connection (or at least the SSL side of it) has been
-            // closed.
-            // FIXME -- Allow for closing the SSL channel without closing the
-            //          underlying connection.
-            clientConnection.disconnect(DisconnectReason.CLIENT_DISCONNECT,
-                                        false, null);
-            return false;
-
-          default:
-            // This should not have happened.
-            clientConnection.disconnect(DisconnectReason.SECURITY_PROBLEM,
-                 false, ERR_TLS_SECURITY_PROVIDER_UNEXPECTED_WRAP_STATUS.get(
-                  String.valueOf(wrapResult.getStatus())));
-            return false;
-        }
-
-        switch (wrapResult.getHandshakeStatus())
-        {
-          case NEED_TASK:
-            Runnable task = sslEngine.getDelegatedTask();
-            task.run();
-            break;
-
-          case NEED_WRAP:
-            // FIXME -- Could this overwrite the SSL out that we just wrapped?
-            // FIXME -- Is this even a feasible result?
-            clearOutBuffer.clear();
-            sslOutBuffer.clear();
-            sslEngine.wrap(clearOutBuffer, sslOutBuffer);
-            sslOutBuffer.flip();
-
-            while (sslOutBuffer.hasRemaining())
-            {
-              int bytesWritten = socketChannel.write(sslOutBuffer);
-              if (bytesWritten < 0)
-              {
-                // The client connection has been closed.  Disconnect and
-                // return.
-                clientConnection.disconnect(
-                     DisconnectReason.CLIENT_DISCONNECT, false, null);
-                return false;
-              }
-              else if (bytesWritten == 0)
-              {
-                return NullConnectionSecurityProvider.writeWithTimeout(
-                            clientConnection, socketChannel, sslOutBuffer);
-              }
-            }
-            break;
-
-          case NEED_UNWRAP:
-            // We need to read data from the client before the negotiation can
-            // continue.  This is bad, because we don't know if there is data
-            // available but we do know that we can't write until we have read.
-            // See if there is something available for reading, and if not, then
-            // we can't afford to wait for it because otherwise we would be
-            // potentially blocking reads from other clients.  Our only recourse
-            // is to close the connection.
-            sslInBuffer.clear();
-            clearInBuffer.clear();
-            int bytesRead = socketChannel.read(sslInBuffer);
-            if (bytesRead < 0)
-            {
-              // The client connection is already closed, so we don't need to
-              // worry about it.
-              clientConnection.disconnect(DisconnectReason.CLIENT_DISCONNECT,
-                                          false, null);
-              return false;
-            }
-            else if (bytesRead == 0)
-            {
-              // We didn't get the data that we need.  We'll have to disconnect
-              // to avoid blocking other clients.
-              clientConnection.disconnect(DisconnectReason.SECURITY_PROBLEM,
-                   false, ERR_TLS_SECURITY_PROVIDER_WRITE_NEEDS_UNWRAP.get());
-              return false;
-            }
-            else
-            {
-              // We were lucky and got the data we were looking for, so read and
-              // process it.
-              sslEngine.unwrap(sslInBuffer, clearInBuffer);
-              clearInBuffer.flip();
-            }
-            break;
-        }
-
-        while (sslOutBuffer.hasRemaining())
-        {
-          int bytesWritten = socketChannel.write(sslOutBuffer);
-          if (bytesWritten < 0)
-          {
-            // The client connection has been closed.
-            clientConnection.disconnect(DisconnectReason.CLIENT_DISCONNECT,
-                                        false, null);
-            return false;
-          }
-          else if (bytesWritten == 0)
-          {
-            return NullConnectionSecurityProvider.writeWithTimeout(
-                        clientConnection, socketChannel, sslOutBuffer);
-          }
-        }
-      }
-
-
-      // If we've gotten here, then everything must have been written
-      // successfully.
-      return true;
-    }
-    catch (IOException ioe)
-    {
-      if (debugEnabled())
-      {
-        TRACER.debugCaught(DebugLogLevel.ERROR, ioe);
-      }
-
-      // An error occurred while trying to communicate with the client.
-      // Disconnect and return.
-      clientConnection.disconnect(DisconnectReason.IO_ERROR, false, null);
-      return false;
-    }
-    catch (Exception e)
-    {
-      if (debugEnabled())
-      {
-        TRACER.debugCaught(DebugLogLevel.ERROR, e);
-      }
-
-      // An unexpected error occurred while trying to process the data read.
-      // Disconnect and return.
-      clientConnection.disconnect(DisconnectReason.SERVER_ERROR, true,
-              ERR_TLS_SECURITY_PROVIDER_WRITE_ERROR.get(
-                      getExceptionMessage(e)));
-      return false;
-    }
-  }
-
-
-
-  /**
-   * Retrieves the set of SSL protocols that will be allowed.
-   *
-   * @return  The set of SSL protocols that will be allowed, or {@code null} if
-   *          the default set will be used.
-   */
-  public String[] getEnabledProtocols()
-  {
-    return enabledProtocols;
-  }
-
-
-
-  /**
-   * Specifies the set of SSL protocols that will be allowed.
-   *
-   * @param  enabledProtocols  The set of SSL protocols that will be allowed, or
-   *                           {@code null} if the default set will be used.
-   */
-  public void setEnabledProtocols(String[] enabledProtocols)
-  {
-    this.enabledProtocols = enabledProtocols;
-  }
-
-
-
-  /**
-   * Retrieves the set of SSL cipher suites that will be allowed.
-   *
-   * @return  The set of SSL cipher suites that will be allowed.
-   */
-  public String[] getEnabledCipherSuites()
-  {
-    return enabledCipherSuites;
-  }
-
-
-
-  /**
-   * Specifies the set of SSL cipher suites that will be allowed.
-   *
-   * @param  enabledCipherSuites  The set of SSL cipher suites that will be
-   *                              allowed.
-   */
-  public void setEnabledCipherSuites(String[] enabledCipherSuites)
-  {
-    this.enabledCipherSuites = enabledCipherSuites;
-  }
-
-
-
-  /**
-   * Retrieves the policy that should be used for SSL client authentication.
-   *
-   * @return  The policy that should be used for SSL client authentication.
-   */
-  public SSLClientAuthPolicy getSSLClientAuthPolicy()
-  {
-    return sslClientAuthPolicy;
-  }
-
-
-
-  /**
-   * Specifies the policy that should be used for SSL client authentication.
-   *
-   * @param  sslClientAuthPolicy  The policy that should be used for SSL client
-   *                              authentication.
-   */
-  public void setSSLClientAuthPolicy(SSLClientAuthPolicy sslClientAuthPolicy)
-  {
-    this.sslClientAuthPolicy = sslClientAuthPolicy;
-  }
-
-
-
-  /**
-   * Retrieves the SSL session associated with this client connection.
-   *
-   * @return  The SSL session associated with this client connection.
-   */
-  public SSLSession getSSLSession()
-  {
-    return sslEngine.getSession();
-  }
-
-
-
-  /**
-   * Retrieves the certificate chain that the client presented to the server
-   * during the handshake process.  The client's certificate will be the first
-   * listed, followed by the certificates of any issuers in the chain.
-   *
-   * @return  The certificate chain that the client presented to the server
-   *          during the handshake process, or {@code null} if the client did
-   *          not present a certificate.
-   */
-  public Certificate[] getClientCertificateChain()
-  {
-    try
-    {
-      return sslEngine.getSession().getPeerCertificates();
-    }
-    catch (Exception e)
-    {
-      if (debugEnabled())
-      {
-        TRACER.debugCaught(DebugLogLevel.ERROR, e);
-      }
-
-      return null;
-    }
-  }
-
-
-  /**
-   * Return the Security Strength FActor of the cipher used in the current
-   * TLS session.
-   *
-   * @return The cipher SSF used in the current TLS session.
-   */
-
-  public int getSSF() {
-      int cipherKeySSF = 0;
-      String cipherString = sslEngine.getSession().getCipherSuite();
-      for(Map.Entry<String, Integer> mapEntry : cipherMap.entrySet()) {
-          if(cipherString.indexOf(mapEntry.getKey()) >= 0) {
-              cipherKeySSF = mapEntry.getValue().intValue();
-              break;
-          }
-      }
-      return cipherKeySSF;
-  }
-}
-
diff --git a/opends/src/server/org/opends/server/extensions/TripleDESPasswordStorageScheme.java b/opends/src/server/org/opends/server/extensions/TripleDESPasswordStorageScheme.java
index 31cd39a..61a94e4 100644
--- a/opends/src/server/org/opends/server/extensions/TripleDESPasswordStorageScheme.java
+++ b/opends/src/server/org/opends/server/extensions/TripleDESPasswordStorageScheme.java
@@ -28,8 +28,6 @@
 
 
 
-import java.util.Arrays;
-
 import org.opends.messages.Message;
 import org.opends.server.admin.std.server.TripleDESPasswordStorageSchemeCfg;
 import org.opends.server.api.PasswordStorageScheme;
@@ -108,15 +106,17 @@
    * {@inheritDoc}
    */
   @Override()
-  public ByteString encodePassword(ByteString plaintext)
+  public ByteString encodePassword(ByteSequence plaintext)
          throws DirectoryException
   {
     try
     {
+      // TODO: Can we avoid this copy?
+      byte[] plaintextBytes = plaintext.toByteArray();
       byte[] encodedBytes = cryptoManager.encrypt(CIPHER_TRANSFORMATION_3DES,
                                                   KEY_SIZE_3DES,
-                                                  plaintext.value());
-      return ByteStringFactory.create(Base64.encode(encodedBytes));
+                                                  plaintextBytes);
+      return ByteString.valueOf(Base64.encode(encodedBytes));
     }
     catch (Exception e)
     {
@@ -138,7 +138,7 @@
    * {@inheritDoc}
    */
   @Override()
-  public ByteString encodePasswordWithScheme(ByteString plaintext)
+  public ByteString encodePasswordWithScheme(ByteSequence plaintext)
          throws DirectoryException
   {
     StringBuilder buffer = new StringBuilder();
@@ -148,9 +148,11 @@
 
     try
     {
+      // TODO: Can we avoid this copy?
+      byte[] plaintextBytes = plaintext.toByteArray();
       byte[] encodedBytes = cryptoManager.encrypt(CIPHER_TRANSFORMATION_3DES,
                                                   KEY_SIZE_3DES,
-                                                  plaintext.value());
+                                                  plaintextBytes);
       buffer.append(Base64.encode(encodedBytes));
     }
     catch (Exception e)
@@ -166,7 +168,7 @@
                                    m, e);
     }
 
-    return ByteStringFactory.create(buffer.toString());
+    return ByteString.valueOf(buffer.toString());
   }
 
 
@@ -175,14 +177,15 @@
    * {@inheritDoc}
    */
   @Override()
-  public boolean passwordMatches(ByteString plaintextPassword,
-                                 ByteString storedPassword)
+  public boolean passwordMatches(ByteSequence plaintextPassword,
+                                 ByteSequence storedPassword)
   {
     try
     {
-      byte[] decryptedPassword =
-           cryptoManager.decrypt(Base64.decode(storedPassword.stringValue()));
-      return Arrays.equals(plaintextPassword.value(), decryptedPassword);
+      ByteString decryptedPassword =
+          ByteString.wrap(cryptoManager.decrypt(
+               Base64.decode(storedPassword.toString())));
+      return plaintextPassword.equals(decryptedPassword);
     }
     catch (Exception e)
     {
@@ -212,14 +215,14 @@
    * {@inheritDoc}
    */
   @Override()
-  public ByteString getPlaintextValue(ByteString storedPassword)
+  public ByteString getPlaintextValue(ByteSequence storedPassword)
          throws DirectoryException
   {
     try
     {
       byte[] decryptedPassword =
-           cryptoManager.decrypt(Base64.decode(storedPassword.stringValue()));
-      return ByteStringFactory.create(decryptedPassword);
+           cryptoManager.decrypt(Base64.decode(storedPassword.toString()));
+      return ByteString.wrap(decryptedPassword);
     }
     catch (Exception e)
     {
@@ -253,7 +256,7 @@
    * {@inheritDoc}
    */
   @Override()
-  public ByteString encodeAuthPassword(ByteString plaintext)
+  public ByteString encodeAuthPassword(ByteSequence plaintext)
          throws DirectoryException
   {
     Message message =
@@ -267,7 +270,7 @@
    * {@inheritDoc}
    */
   @Override()
-  public boolean authPasswordMatches(ByteString plaintextPassword,
+  public boolean authPasswordMatches(ByteSequence plaintextPassword,
                                      String authInfo, String authValue)
   {
     // This storage scheme does not support the authentication password syntax.
diff --git a/opends/src/server/org/opends/server/extensions/UniqueCharactersPasswordValidator.java b/opends/src/server/org/opends/server/extensions/UniqueCharactersPasswordValidator.java
index e43e374..50ebd51 100644
--- a/opends/src/server/org/opends/server/extensions/UniqueCharactersPasswordValidator.java
+++ b/opends/src/server/org/opends/server/extensions/UniqueCharactersPasswordValidator.java
@@ -37,11 +37,7 @@
 import org.opends.server.admin.server.ConfigurationChangeListener;
 import org.opends.server.admin.std.server.UniqueCharactersPasswordValidatorCfg;
 import org.opends.server.api.PasswordValidator;
-import org.opends.server.types.ConfigChangeResult;
-import org.opends.server.types.ByteString;
-import org.opends.server.types.Entry;
-import org.opends.server.types.Operation;
-import org.opends.server.types.ResultCode;
+import org.opends.server.types.*;
 
 import static org.opends.messages.ExtensionMessages.*;
 import org.opends.messages.MessageBuilder;
@@ -127,7 +123,7 @@
     // Iterate through the characters in the new password and place them in the
     // set as needed.  If we should behave in a case-insensitive manner, then
     // convert all the characters to lowercase first.
-    String passwordString = newPassword.stringValue();
+    String passwordString = newPassword.toString();
     if (! config.isCaseSensitiveValidation())
     {
       passwordString = passwordString.toLowerCase();
diff --git a/opends/src/server/org/opends/server/extensions/UserAttributeNotificationMessageTemplateElement.java b/opends/src/server/org/opends/server/extensions/UserAttributeNotificationMessageTemplateElement.java
index 2d2e80d..6d0e7e1 100644
--- a/opends/src/server/org/opends/server/extensions/UserAttributeNotificationMessageTemplateElement.java
+++ b/opends/src/server/org/opends/server/extensions/UserAttributeNotificationMessageTemplateElement.java
@@ -80,7 +80,7 @@
       {
         for (AttributeValue v : a)
         {
-          buffer.append(v.getStringValue());
+          buffer.append(v.getValue().toString());
           return;
         }
       }
diff --git a/opends/src/server/org/opends/server/extensions/UserDefinedVirtualAttributeProvider.java b/opends/src/server/org/opends/server/extensions/UserDefinedVirtualAttributeProvider.java
index f893cd7..61a2686 100644
--- a/opends/src/server/org/opends/server/extensions/UserDefinedVirtualAttributeProvider.java
+++ b/opends/src/server/org/opends/server/extensions/UserDefinedVirtualAttributeProvider.java
@@ -39,14 +39,7 @@
 import org.opends.server.api.VirtualAttributeProvider;
 import org.opends.server.config.ConfigException;
 import org.opends.server.core.SearchOperation;
-import org.opends.server.types.AttributeType;
-import org.opends.server.types.AttributeValue;
-import org.opends.server.types.ConfigChangeResult;
-import org.opends.server.types.Entry;
-import org.opends.server.types.InitializationException;
-import org.opends.server.types.ResultCode;
-import org.opends.server.types.VirtualAttributeRule;
-
+import org.opends.server.types.*;
 
 
 /**
@@ -130,19 +123,21 @@
   {
     AttributeType attributeType = rule.getAttributeType();
     Set<String> userDefinedValues = currentConfig.getValue();
+
     switch (userDefinedValues.size()) {
     case 0:
       return Collections.emptySet();
     case 1:
       String valueString = userDefinedValues.iterator().next();
-      AttributeValue value = new AttributeValue(attributeType, valueString);
+      AttributeValue value =
+          AttributeValues.create(attributeType, valueString);
       return Collections.singleton(value);
     default:
       HashSet<AttributeValue> values =
           new HashSet<AttributeValue>(userDefinedValues.size());
       for (String valueString2 : userDefinedValues)
       {
-        values.add(new AttributeValue(attributeType, valueString2));
+        values.add(AttributeValues.create(attributeType, valueString2));
       }
       return Collections.unmodifiableSet(values);
     }
diff --git a/opends/src/server/org/opends/server/extensions/VirtualStaticGroup.java b/opends/src/server/org/opends/server/extensions/VirtualStaticGroup.java
index dd93e91..4d8a1a0 100644
--- a/opends/src/server/org/opends/server/extensions/VirtualStaticGroup.java
+++ b/opends/src/server/org/opends/server/extensions/VirtualStaticGroup.java
@@ -169,7 +169,7 @@
             }
 
             Message message = ERR_VIRTUAL_STATIC_GROUP_CANNOT_DECODE_TARGET.
-                get(v.getStringValue(), String.valueOf(groupEntry.getDN()),
+                get(v.getValue().toString(), String.valueOf(groupEntry.getDN()),
                     de.getMessageObject());
             throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX,
                                          message, de);
diff --git a/opends/src/server/org/opends/server/extensions/WhoAmIExtendedOperation.java b/opends/src/server/org/opends/server/extensions/WhoAmIExtendedOperation.java
index f0cb8b9..14be180 100644
--- a/opends/src/server/org/opends/server/extensions/WhoAmIExtendedOperation.java
+++ b/opends/src/server/org/opends/server/extensions/WhoAmIExtendedOperation.java
@@ -29,7 +29,6 @@
 
 
 import java.util.HashSet;
-import java.util.List;
 import java.util.Set;
 
 import org.opends.messages.Message;
@@ -42,16 +41,7 @@
 import org.opends.server.core.DirectoryServer;
 import org.opends.server.core.ExtendedOperation;
 import org.opends.server.loggers.debug.DebugTracer;
-import org.opends.server.protocols.asn1.ASN1OctetString;
-import org.opends.server.types.Control;
-import org.opends.server.types.DebugLogLevel;
-import org.opends.server.types.DirectoryException;
-import org.opends.server.types.DN;
-import org.opends.server.types.Entry;
-import org.opends.server.types.InitializationException;
-import org.opends.server.types.LDAPException;
-import org.opends.server.types.Privilege;
-import org.opends.server.types.ResultCode;
+import org.opends.server.types.*;
 
 import static org.opends.server.loggers.debug.DebugLogger.*;
 import static org.opends.messages.ExtensionMessages.*;
@@ -99,6 +89,7 @@
    *                                   that is not related to the server
    *                                   configuration.
    */
+  @Override
   public void initializeExtendedOperationHandler(
                    WhoAmIExtendedOperationHandlerCfg config)
          throws ConfigException, InitializationException
@@ -151,132 +142,48 @@
     // Process any supported controls for this operation, including the
     // proxied authorization control.
     ClientConnection clientConnection = operation.getClientConnection();
-    List<Control> requestControls = operation.getRequestControls();
-    if (requestControls != null)
+    Entry authorizationEntry;
+    try
     {
-      for (Control c : requestControls)
+      ProxiedAuthV1Control proxyControlV1 =
+          operation.getRequestControl(ProxiedAuthV1Control.DECODER);
+      ProxiedAuthV2Control proxyControlV2 =
+          operation.getRequestControl(ProxiedAuthV2Control.DECODER);
+      if(proxyControlV1 != null || proxyControlV2 != null)
       {
-        String oid = c.getOID();
-        if (oid.equals(OID_PROXIED_AUTH_V1))
+        // The requester must have the PROXIED_AUTH privilige in order to
+        // be able to use this control.
+        if (! clientConnection.hasPrivilege(Privilege.PROXIED_AUTH,
+            operation))
         {
-          // The requester must have the PROXIED_AUTH privilige in order to
-          // be able to use this control.
-          if (! clientConnection.hasPrivilege(Privilege.PROXIED_AUTH,
-                                              operation))
-          {
-
-            operation.appendErrorMessage(
-                    ERR_EXTOP_WHOAMI_PROXYAUTH_INSUFFICIENT_PRIVILEGES.get());
-            operation.setResultCode(ResultCode.AUTHORIZATION_DENIED);
-            return;
-          }
-
-
-          ProxiedAuthV1Control proxyControl;
-          if (c instanceof ProxiedAuthV1Control)
-          {
-            proxyControl = (ProxiedAuthV1Control) c;
-          }
-          else
-          {
-            try
-            {
-              proxyControl = ProxiedAuthV1Control.decodeControl(c);
-            }
-            catch (LDAPException le)
-            {
-              if (debugEnabled())
-              {
-                TRACER.debugCaught(DebugLogLevel.ERROR, le);
-              }
-
-              operation.setResultCode(ResultCode.valueOf(le.getResultCode()));
-              operation.appendErrorMessage(le.getMessageObject());
-              return;
-            }
-          }
-
-
-          Entry authorizationEntry;
-          try
-          {
-            authorizationEntry = proxyControl.getAuthorizationEntry();
-          }
-          catch (DirectoryException de)
-          {
-            if (debugEnabled())
-            {
-              TRACER.debugCaught(DebugLogLevel.ERROR, de);
-            }
-
-            operation.setResultCode(de.getResultCode());
-            operation.appendErrorMessage(de.getMessageObject());
-            return;
-          }
-
-          operation.setAuthorizationEntry(authorizationEntry);
+          operation.appendErrorMessage(
+              ERR_EXTOP_WHOAMI_PROXYAUTH_INSUFFICIENT_PRIVILEGES.get());
+          operation.setResultCode(ResultCode.AUTHORIZATION_DENIED);
+          return;
         }
-        else if (oid.equals(OID_PROXIED_AUTH_V2))
+
+        if(proxyControlV2 != null)
         {
-          // The requester must have the PROXIED_AUTH privilige in order to
-          // be able to use this control.
-          if (! clientConnection.hasPrivilege(Privilege.PROXIED_AUTH,
-                                              operation))
-          {
-
-            operation.appendErrorMessage(
-                    ERR_EXTOP_WHOAMI_PROXYAUTH_INSUFFICIENT_PRIVILEGES.get());
-            operation.setResultCode(ResultCode.AUTHORIZATION_DENIED);
-            return;
-          }
-
-
-          ProxiedAuthV2Control proxyControl;
-          if (c instanceof ProxiedAuthV2Control)
-          {
-            proxyControl = (ProxiedAuthV2Control) c;
-          }
-          else
-          {
-            try
-            {
-              proxyControl = ProxiedAuthV2Control.decodeControl(c);
-            }
-            catch (LDAPException le)
-            {
-              if (debugEnabled())
-              {
-                TRACER.debugCaught(DebugLogLevel.ERROR, le);
-              }
-
-              operation.setResultCode(ResultCode.valueOf(le.getResultCode()));
-              operation.appendErrorMessage(le.getMessageObject());
-              return;
-            }
-          }
-
-
-          Entry authorizationEntry;
-          try
-          {
-            authorizationEntry = proxyControl.getAuthorizationEntry();
-          }
-          catch (DirectoryException de)
-          {
-            if (debugEnabled())
-            {
-              TRACER.debugCaught(DebugLogLevel.ERROR, de);
-            }
-
-            operation.setResultCode(de.getResultCode());
-            operation.appendErrorMessage(de.getMessageObject());
-            return;
-          }
-
-          operation.setAuthorizationEntry(authorizationEntry);
+          authorizationEntry = proxyControlV2.getAuthorizationEntry();
         }
+        else
+        {
+          authorizationEntry = proxyControlV1.getAuthorizationEntry();
+        }
+        operation.setAuthorizationEntry(authorizationEntry);
       }
     }
+    catch (DirectoryException de)
+    {
+      if (debugEnabled())
+      {
+        TRACER.debugCaught(DebugLogLevel.ERROR, de);
+      }
+
+      operation.setResultCode(de.getResultCode());
+      operation.appendErrorMessage(de.getMessageObject());
+      return;
+    }
 
 
     // Get the authorization DN for the operation and add it to the response
@@ -292,7 +199,7 @@
       authzID = "dn:" + authzDN.toString();
     }
 
-    operation.setResponseValue(new ASN1OctetString(authzID));
+    operation.setResponseValue(ByteString.valueOf(authzID));
     operation.appendAdditionalLogMessage(
             Message.raw("authzID=\"" + authzID + "\""));
     operation.setResultCode(ResultCode.SUCCESS);
diff --git a/opends/src/server/org/opends/server/loggers/TextAccessLogPublisher.java b/opends/src/server/org/opends/server/loggers/TextAccessLogPublisher.java
index 751bd5a..1b581b5 100644
--- a/opends/src/server/org/opends/server/loggers/TextAccessLogPublisher.java
+++ b/opends/src/server/org/opends/server/loggers/TextAccessLogPublisher.java
@@ -22,7 +22,7 @@
  * CDDL HEADER END
  *
  *
- *      Copyright 2006-2008 Sun Microsystems, Inc.
+ *      Copyright 2006-2009 Sun Microsystems, Inc.
  */
 package org.opends.server.loggers;
 
@@ -406,7 +406,7 @@
       return;
     }
 
-    StringBuilder buffer = new StringBuilder(50);
+    StringBuilder buffer = new StringBuilder(100);
     appendHeader(abandonOperation, "ABANDON", CATEGORY_REQUEST, buffer);
     buffer.append(" idToAbandon=");
     buffer.append(abandonOperation.getIDToAbandon());
@@ -433,7 +433,7 @@
       return;
     }
 
-    StringBuilder buffer = new StringBuilder(50);
+    StringBuilder buffer = new StringBuilder(100);
     appendHeader(abandonOperation, "ABANDON", CATEGORY_RESPONSE, buffer);
     buffer.append(" result=");
     buffer.append(abandonOperation.getResultCode().getIntValue());
@@ -487,10 +487,10 @@
       return;
     }
 
-    StringBuilder buffer = new StringBuilder(50);
+    StringBuilder buffer = new StringBuilder(100);
     appendHeader(addOperation, "ADD", CATEGORY_REQUEST, buffer);
     buffer.append(" dn=\"");
-    addOperation.getRawEntryDN().toString(buffer);
+    buffer.append(addOperation.getRawEntryDN().toString());
     buffer.append("\"");
     if (addOperation.isSynchronizationOperation())
       buffer.append(" type=synchronization");
@@ -515,7 +515,7 @@
       return;
     }
 
-    StringBuilder buffer = new StringBuilder(50);
+    StringBuilder buffer = new StringBuilder(100);
     appendHeader(addOperation, "ADD", CATEGORY_RESPONSE, buffer);
     buffer.append(" result=");
     buffer.append(addOperation.getResultCode().getIntValue());
@@ -578,7 +578,7 @@
       return;
     }
 
-    StringBuilder buffer = new StringBuilder(50);
+    StringBuilder buffer = new StringBuilder(100);
     appendHeader(bindOperation, "BIND", CATEGORY_REQUEST, buffer);
 
     switch (bindOperation.getAuthenticationType())
@@ -597,7 +597,7 @@
     }
 
     buffer.append(" dn=\"");
-    bindOperation.getRawBindDN().toString(buffer);
+    buffer.append(bindOperation.getRawBindDN().toString());
     buffer.append("\"");
     if (bindOperation.isSynchronizationOperation())
       buffer.append(" type=synchronization");
@@ -622,7 +622,7 @@
       return;
     }
 
-    StringBuilder buffer = new StringBuilder(50);
+    StringBuilder buffer = new StringBuilder(100);
     appendHeader(bindOperation, "BIND", CATEGORY_RESPONSE, buffer);
     buffer.append(" result=");
     buffer.append(bindOperation.getResultCode().getIntValue());
@@ -722,10 +722,10 @@
       return;
     }
 
-    StringBuilder buffer = new StringBuilder(50);
+    StringBuilder buffer = new StringBuilder(100);
     appendHeader(compareOperation, "COMPARE", CATEGORY_REQUEST, buffer);
     buffer.append(" dn=\"");
-    compareOperation.getRawEntryDN().toString(buffer);
+    buffer.append(compareOperation.getRawEntryDN().toString());
     buffer.append("\" attr=");
     buffer.append(compareOperation.getAttributeType());
     if (compareOperation.isSynchronizationOperation())
@@ -751,7 +751,7 @@
       return;
     }
 
-    StringBuilder buffer = new StringBuilder(50);
+    StringBuilder buffer = new StringBuilder(100);
     appendHeader(compareOperation, "COMPARE", CATEGORY_RESPONSE, buffer);
     buffer.append(" result=");
     buffer.append(compareOperation.getResultCode().getIntValue());
@@ -809,7 +809,7 @@
     {
       return;
     }
-    StringBuilder buffer = new StringBuilder(50);
+    StringBuilder buffer = new StringBuilder(100);
     buffer.append("[");
     buffer.append(TimeThread.getLocalTime());
     buffer.append("]");
@@ -854,10 +854,10 @@
       return;
     }
 
-    StringBuilder buffer = new StringBuilder(50);
+    StringBuilder buffer = new StringBuilder(100);
     appendHeader(deleteOperation, "DELETE", CATEGORY_REQUEST, buffer);
     buffer.append(" dn=\"");
-    deleteOperation.getRawEntryDN().toString(buffer);
+    buffer.append(deleteOperation.getRawEntryDN().toString());
     buffer.append("\"");
     if (deleteOperation.isSynchronizationOperation())
       buffer.append(" type=synchronization");
@@ -882,7 +882,7 @@
       return;
     }
 
-    StringBuilder buffer = new StringBuilder(50);
+    StringBuilder buffer = new StringBuilder(100);
     appendHeader(deleteOperation, "DELETE", CATEGORY_RESPONSE, buffer);
     buffer.append(" result=");
     buffer.append(deleteOperation.getResultCode().getIntValue());
@@ -945,7 +945,7 @@
     {
       return;
     }
-    StringBuilder buffer = new StringBuilder(50);
+    StringBuilder buffer = new StringBuilder(100);
     buffer.append("[");
     buffer.append(TimeThread.getLocalTime());
     buffer.append("]");
@@ -994,7 +994,7 @@
       return;
     }
 
-    StringBuilder buffer = new StringBuilder(50);
+    StringBuilder buffer = new StringBuilder(100);
     appendHeader(extendedOperation, "EXTENDED", CATEGORY_REQUEST, buffer);
     buffer.append(" oid=\"");
     buffer.append(extendedOperation.getRequestOID());
@@ -1023,7 +1023,7 @@
       return;
     }
 
-    StringBuilder buffer = new StringBuilder(50);
+    StringBuilder buffer = new StringBuilder(100);
     appendHeader(extendedOperation, "EXTENDED", CATEGORY_RESPONSE, buffer);
 
     String oid = extendedOperation.getResponseOID();
@@ -1094,12 +1094,12 @@
       return;
     }
 
-    StringBuilder buffer = new StringBuilder(50);
+    StringBuilder buffer = new StringBuilder(100);
     appendHeader(modifyDNOperation, "MODIFYDN", CATEGORY_REQUEST, buffer);
     buffer.append(" dn=\"");
-    modifyDNOperation.getRawEntryDN().toString(buffer);
+    buffer.append(modifyDNOperation.getRawEntryDN().toString());
     buffer.append("\" newRDN=\"");
-    modifyDNOperation.getRawNewRDN().toString(buffer);
+    buffer.append(modifyDNOperation.getRawNewRDN().toString());
     buffer.append("\" deleteOldRDN=");
     buffer.append(modifyDNOperation.deleteOldRDN());
 
@@ -1107,7 +1107,7 @@
     if (newSuperior != null)
     {
       buffer.append(" newSuperior=\"");
-      newSuperior.toString(buffer);
+      buffer.append(newSuperior.toString());
     }
     if (modifyDNOperation.isSynchronizationOperation())
       buffer.append(" type=synchronization");
@@ -1133,7 +1133,7 @@
       return;
     }
 
-    StringBuilder buffer = new StringBuilder(50);
+    StringBuilder buffer = new StringBuilder(100);
     appendHeader(modifyDNOperation, "MODIFYDN", CATEGORY_RESPONSE, buffer);
     buffer.append(" result=");
     buffer.append(modifyDNOperation.getResultCode().getIntValue());
@@ -1201,10 +1201,10 @@
       return;
     }
 
-    StringBuilder buffer = new StringBuilder(50);
+    StringBuilder buffer = new StringBuilder(100);
     appendHeader(modifyOperation, "MODIFY", CATEGORY_REQUEST, buffer);
     buffer.append(" dn=\"");
-    modifyOperation.getRawEntryDN().toString(buffer);
+    buffer.append(modifyOperation.getRawEntryDN().toString());
     buffer.append("\"");
     if (modifyOperation.isSynchronizationOperation())
       buffer.append(" type=synchronization");
@@ -1229,7 +1229,7 @@
       return;
     }
 
-    StringBuilder buffer = new StringBuilder(50);
+    StringBuilder buffer = new StringBuilder(100);
     appendHeader(modifyOperation, "MODIFY", CATEGORY_RESPONSE, buffer);
     buffer.append(" result=");
     buffer.append(modifyOperation.getResultCode().getIntValue());
@@ -1297,10 +1297,10 @@
       return;
     }
 
-    StringBuilder buffer = new StringBuilder(50);
+    StringBuilder buffer = new StringBuilder(100);
     appendHeader(searchOperation, "SEARCH", CATEGORY_REQUEST, buffer);
     buffer.append(" base=\"");
-    searchOperation.getRawBaseDN().toString(buffer);
+    buffer.append(searchOperation.getRawBaseDN().toString());
     buffer.append("\" scope=");
     buffer.append(searchOperation.getScope());
     buffer.append(" filter=\"");
@@ -1348,7 +1348,7 @@
       return;
     }
 
-    StringBuilder buffer = new StringBuilder(50);
+    StringBuilder buffer = new StringBuilder(100);
     appendHeader(searchOperation, "SEARCH", CATEGORY_RESPONSE, buffer);
     buffer.append(" result=");
     buffer.append(searchOperation.getResultCode().getIntValue());
@@ -1408,7 +1408,7 @@
       return;
     }
 
-    StringBuilder buffer = new StringBuilder(50);
+    StringBuilder buffer = new StringBuilder(100);
     appendHeader(unbindOperation, "UNBIND", CATEGORY_REQUEST, buffer);
     if (unbindOperation.isSynchronizationOperation())
       buffer.append(" type=synchronization");
@@ -1474,7 +1474,7 @@
       return;
     }
 
-    StringBuilder buffer = new StringBuilder(50);
+    StringBuilder buffer = new StringBuilder(100);
     appendHeader(operation, opType, category, buffer);
 
     for (Map.Entry<String, String> entry : content.entrySet())
diff --git a/opends/src/server/org/opends/server/loggers/TextAuditLogPublisher.java b/opends/src/server/org/opends/server/loggers/TextAuditLogPublisher.java
index a2d41d8a4..f059641 100644
--- a/opends/src/server/org/opends/server/loggers/TextAuditLogPublisher.java
+++ b/opends/src/server/org/opends/server/loggers/TextAuditLogPublisher.java
@@ -49,17 +49,7 @@
 import org.opends.server.core.DirectoryServer;
 import org.opends.server.core.ModifyDNOperation;
 import org.opends.server.core.ModifyOperation;
-import org.opends.server.types.Attribute;
-import org.opends.server.types.AttributeValue;
-import org.opends.server.types.ByteString;
-import org.opends.server.types.ConfigChangeResult;
-import org.opends.server.types.DN;
-import org.opends.server.types.DirectoryException;
-import org.opends.server.types.FilePermission;
-import org.opends.server.types.InitializationException;
-import org.opends.server.types.Modification;
-import org.opends.server.types.Operation;
-import org.opends.server.types.ResultCode;
+import org.opends.server.types.*;
 import org.opends.server.util.Base64;
 import org.opends.server.util.StaticUtils;
 import org.opends.server.util.TimeThread;
@@ -570,18 +560,17 @@
    * @param buffer
    *          The buffer to which to append the value.
    */
-  private void encodeValue(ByteString str, StringBuilder buffer)
+  private void encodeValue(ByteSequence str, StringBuilder buffer)
   {
-    byte[] byteVal = str.value();
-    if (StaticUtils.needsBase64Encoding(byteVal))
+    if(StaticUtils.needsBase64Encoding(str))
     {
       buffer.append(": ");
-      buffer.append(Base64.encode(byteVal));
+      buffer.append(Base64.encode(str));
     }
     else
     {
       buffer.append(" ");
-      str.toString(buffer);
+      buffer.append(str.toString());
     }
   }
 
diff --git a/opends/src/server/org/opends/server/loggers/debug/DebugTracer.java b/opends/src/server/org/opends/server/loggers/debug/DebugTracer.java
index 63358bb..0194cea 100644
--- a/opends/src/server/org/opends/server/loggers/debug/DebugTracer.java
+++ b/opends/src/server/org/opends/server/loggers/debug/DebugTracer.java
@@ -22,12 +22,11 @@
  * CDDL HEADER END
  *
  *
- *      Copyright 2006-2008 Sun Microsystems, Inc.
+ *      Copyright 2006-2009 Sun Microsystems, Inc.
  */
 package org.opends.server.loggers.debug;
 
 import org.opends.server.api.DebugLogPublisher;
-import org.opends.server.api.ProtocolElement;
 import org.opends.server.types.DebugLogCategory;
 import org.opends.server.types.DebugLogLevel;
 import org.opends.server.loggers.LogLevel;
@@ -1001,11 +1000,11 @@
    * Log a protocol element.
    *
    * @param level the level of the log message.
-   * @param element the protocol element to dump.
+   * @param elementStr the string representation of protocol element.
    */
-  public void debugProtocolElement(LogLevel level, ProtocolElement element)
+  public void debugProtocolElement(LogLevel level, String elementStr)
   {
-    if(DebugLogger.debugEnabled() && element != null)
+    if(DebugLogger.debugEnabled() && elementStr != null)
     {
       StackTraceElement[] stackTrace = null;
       StackTraceElement[] filteredStackTrace = null;
@@ -1073,7 +1072,8 @@
           }
 
           settings.debugPublisher.traceProtocolElement(level, activeSettings,
-                                                       signature, sl, element,
+                                                       signature, sl,
+                                                       elementStr,
                                                        filteredStackTrace);
         }
       }
diff --git a/opends/src/server/org/opends/server/loggers/debug/TextDebugLogPublisher.java b/opends/src/server/org/opends/server/loggers/debug/TextDebugLogPublisher.java
index 2557be4..aca7ed5 100644
--- a/opends/src/server/org/opends/server/loggers/debug/TextDebugLogPublisher.java
+++ b/opends/src/server/org/opends/server/loggers/debug/TextDebugLogPublisher.java
@@ -22,7 +22,7 @@
  * CDDL HEADER END
  *
  *
- *      Copyright 2006-2008 Sun Microsystems, Inc.
+ *      Copyright 2006-2009 Sun Microsystems, Inc.
  */
 package org.opends.server.loggers.debug;
 import org.opends.messages.Message;
@@ -745,14 +745,14 @@
                                    TraceSettings settings,
                                    String signature,
                                    String sourceLocation,
-                                   ProtocolElement element,
+                                   String decodedForm,
                                    StackTraceElement[] stackTrace)
   {
     LogCategory category = DebugLogCategory.PROTOCOL;
 
     StringBuilder builder = new StringBuilder();
     builder.append(ServerConstants.EOL);
-    element.toString(builder, 4);
+    builder.append(decodedForm);
 
     String stack = null;
     if(stackTrace != null)
diff --git a/opends/src/server/org/opends/server/loggers/debug/TraceSettings.java b/opends/src/server/org/opends/server/loggers/debug/TraceSettings.java
index 33932e7..fe7dab8 100644
--- a/opends/src/server/org/opends/server/loggers/debug/TraceSettings.java
+++ b/opends/src/server/org/opends/server/loggers/debug/TraceSettings.java
@@ -22,7 +22,7 @@
  * CDDL HEADER END
  *
  *
- *      Copyright 2006-2008 Sun Microsystems, Inc.
+ *      Copyright 2006-2009 Sun Microsystems, Inc.
  */
 
 package org.opends.server.loggers.debug;
@@ -39,10 +39,7 @@
 import org.opends.server.admin.std.server.DebugTargetCfg;
 
 
-import java.util.Set;
-import java.util.HashSet;
-import java.util.ArrayList;
-import java.util.List;
+import java.util.*;
 
 /**
  * This class encapsulates the trace settings in effect at a given traceing
@@ -378,4 +375,52 @@
 
     return settings;
   }
+
+  /**
+   * Get the log level of this setting.
+   * @return the log level of this setting.
+   */
+  public LogLevel getLevel() {
+    return level;
+  }
+
+  /**
+   * Get the log categories for this setting.
+   * @return the log categories for this setting.
+   */
+  public Set<LogCategory> getIncludeCategories() {
+    return Collections.unmodifiableSet(includeCategories);
+  }
+
+  /**
+   * Get whether method arguments should be logged.
+   * @return if method arguments should be logged.
+   */
+  public boolean isNoArgs() {
+    return noArgs;
+  }
+
+  /**
+   * Get whether method return values should be logged.
+   * @return if method return values should be logged.
+   */
+  public boolean isNoRetVal() {
+    return noRetVal;
+  }
+
+  /**
+   * Get the level of stack frames to include.
+   * @return the level of stack frames to include.
+   */
+  public int getStackDepth() {
+    return stackDepth;
+  }
+
+  /**
+   * Get whether the cause exception is included in exception messages.
+   * @return if the cause exception is included in exception messages.
+   */
+  public boolean isIncludeCause() {
+    return includeCause;
+  }
 }
diff --git a/opends/src/server/org/opends/server/monitors/BackendMonitor.java b/opends/src/server/org/opends/server/monitors/BackendMonitor.java
index 3bb2c92..ecfaab1 100644
--- a/opends/src/server/org/opends/server/monitors/BackendMonitor.java
+++ b/opends/src/server/org/opends/server/monitors/BackendMonitor.java
@@ -39,16 +39,7 @@
 import org.opends.server.api.MonitorProvider;
 import org.opends.server.loggers.debug.DebugTracer;
 import org.opends.server.schema.BooleanSyntax;
-import org.opends.server.types.Attribute;
-import org.opends.server.types.AttributeBuilder;
-import org.opends.server.types.AttributeType;
-import org.opends.server.types.AttributeValue;
-import org.opends.server.types.Attributes;
-import org.opends.server.types.DN;
-import org.opends.server.types.DebugLogLevel;
-import org.opends.server.types.DirectoryConfig;
-import org.opends.server.types.ObjectClass;
-
+import org.opends.server.types.*;
 
 
 /**
@@ -196,7 +187,7 @@
     DN[] baseDNs = backend.getBaseDNs();
     for (DN dn : baseDNs)
     {
-      builder.add(new AttributeValue(baseDNType, dn.toString()));
+      builder.add(AttributeValues.create(baseDNType, dn.toString()));
     }
     attrs.add(builder.toAttribute());
 
@@ -225,7 +216,7 @@
           }
         }
         String s = entryCount + " " + dn.toString();
-        builder.add(new AttributeValue(baseDNEntryCountType, s));
+        builder.add(AttributeValues.create(baseDNEntryCountType, s));
       }
     }
     else
@@ -234,7 +225,7 @@
       // using the hasNumSubordinates method in the case where the
       // backend has a single base DN.
       String s = backendCount + " " + baseDNs[0].toString();
-      builder.add(new AttributeValue(baseDNEntryCountType, s));
+      builder.add(AttributeValues.create(baseDNEntryCountType, s));
     }
     attrs.add(builder.toAttribute());
 
diff --git a/opends/src/server/org/opends/server/monitors/ClientConnectionMonitorProvider.java b/opends/src/server/org/opends/server/monitors/ClientConnectionMonitorProvider.java
index 65feaa3..4155e1a 100644
--- a/opends/src/server/org/opends/server/monitors/ClientConnectionMonitorProvider.java
+++ b/opends/src/server/org/opends/server/monitors/ClientConnectionMonitorProvider.java
@@ -39,12 +39,7 @@
 import org.opends.server.api.MonitorProvider;
 import org.opends.server.config.ConfigException;
 import org.opends.server.core.DirectoryServer;
-import org.opends.server.types.Attribute;
-import org.opends.server.types.AttributeBuilder;
-import org.opends.server.types.AttributeType;
-import org.opends.server.types.AttributeValue;
-import org.opends.server.types.InitializationException;
-
+import org.opends.server.types.*;
 
 
 /**
@@ -192,7 +187,7 @@
     AttributeBuilder builder = new AttributeBuilder(attrType);
     for (ClientConnection conn : connMap.values())
     {
-      builder.add(new AttributeValue(attrType, conn.getMonitorSummary()));
+      builder.add(AttributeValues.create(attrType, conn.getMonitorSummary()));
     }
 
     ArrayList<Attribute> attrs = new ArrayList<Attribute>(2);
diff --git a/opends/src/server/org/opends/server/monitors/ConnectionHandlerMonitor.java b/opends/src/server/org/opends/server/monitors/ConnectionHandlerMonitor.java
index 252f3c6..1979ea1 100644
--- a/opends/src/server/org/opends/server/monitors/ConnectionHandlerMonitor.java
+++ b/opends/src/server/org/opends/server/monitors/ConnectionHandlerMonitor.java
@@ -38,15 +38,7 @@
 import org.opends.server.api.ClientConnection;
 import org.opends.server.api.ConnectionHandler;
 import org.opends.server.api.MonitorProvider;
-import org.opends.server.types.Attribute;
-import org.opends.server.types.AttributeBuilder;
-import org.opends.server.types.AttributeType;
-import org.opends.server.types.AttributeValue;
-import org.opends.server.types.Attributes;
-import org.opends.server.types.DirectoryConfig;
-import org.opends.server.types.HostPort;
-import org.opends.server.types.ObjectClass;
-
+import org.opends.server.types.*;
 
 
 /**
@@ -199,7 +191,7 @@
       AttributeBuilder builder = new AttributeBuilder(listenerType);
       for (HostPort hp : listeners)
       {
-        builder.add(new AttributeValue(listenerType, hp.toString()));
+        builder.add(AttributeValues.create(listenerType, hp.toString()));
       }
       attrs.add(builder.toAttribute());
     }
@@ -210,7 +202,7 @@
       for (ClientConnection c : conns)
       {
         numConnections++;
-        builder.add(new AttributeValue(connectionsType, c
+        builder.add(AttributeValues.create(connectionsType, c
             .getMonitorSummary()));
       }
       attrs.add(builder.toAttribute());
diff --git a/opends/src/server/org/opends/server/monitors/MemoryUsageMonitorProvider.java b/opends/src/server/org/opends/server/monitors/MemoryUsageMonitorProvider.java
index 5d53eb0..de443fb 100644
--- a/opends/src/server/org/opends/server/monitors/MemoryUsageMonitorProvider.java
+++ b/opends/src/server/org/opends/server/monitors/MemoryUsageMonitorProvider.java
@@ -39,13 +39,7 @@
 import org.opends.server.api.MonitorProvider;
 import org.opends.server.config.ConfigException;
 import org.opends.server.core.DirectoryServer;
-import org.opends.server.protocols.asn1.ASN1OctetString;
-import org.opends.server.types.Attribute;
-import org.opends.server.types.AttributeBuilder;
-import org.opends.server.types.AttributeType;
-import org.opends.server.types.AttributeValue;
-import org.opends.server.types.InitializationException;
-
+import org.opends.server.types.*;
 
 
 /**
@@ -256,17 +250,8 @@
   {
     AttributeType attrType = DirectoryServer.getDefaultAttributeType(name);
 
-    ASN1OctetString encodedValue = new ASN1OctetString(value);
     AttributeBuilder builder = new AttributeBuilder(attrType);
-    try
-    {
-      builder.add(new AttributeValue(encodedValue,
-                                    attrType.normalize(encodedValue)));
-    }
-    catch (Exception e)
-    {
-      builder.add(new AttributeValue(encodedValue, encodedValue));
-    }
+    builder.add(AttributeValues.create(attrType, value));
 
     return builder.toAttribute();
   }
diff --git a/opends/src/server/org/opends/server/monitors/StackTraceMonitorProvider.java b/opends/src/server/org/opends/server/monitors/StackTraceMonitorProvider.java
index 814678a..de1d970 100644
--- a/opends/src/server/org/opends/server/monitors/StackTraceMonitorProvider.java
+++ b/opends/src/server/org/opends/server/monitors/StackTraceMonitorProvider.java
@@ -36,12 +36,7 @@
 import org.opends.server.api.MonitorProvider;
 import org.opends.server.config.ConfigException;
 import org.opends.server.core.DirectoryServer;
-import org.opends.server.types.Attribute;
-import org.opends.server.types.AttributeBuilder;
-import org.opends.server.types.AttributeType;
-import org.opends.server.types.AttributeValue;
-import org.opends.server.types.InitializationException;
-
+import org.opends.server.types.*;
 
 
 /**
@@ -160,7 +155,7 @@
       buffer.append(" ---------- ");
       buffer.append(t.getName());
       buffer.append(" ----------");
-      builder.add(new AttributeValue(attrType, buffer.toString()));
+      builder.add(AttributeValues.create(attrType, buffer.toString()));
 
       // Create an attribute for the stack trace.
       if (stackElements != null)
@@ -190,7 +185,7 @@
           }
           buffer.append(")");
 
-          builder.add(new AttributeValue(attrType, buffer.toString()));
+          builder.add(AttributeValues.create(attrType, buffer.toString()));
         }
       }
     }
diff --git a/opends/src/server/org/opends/server/monitors/SystemInfoMonitorProvider.java b/opends/src/server/org/opends/server/monitors/SystemInfoMonitorProvider.java
index 42f1efe..daec30c 100644
--- a/opends/src/server/org/opends/server/monitors/SystemInfoMonitorProvider.java
+++ b/opends/src/server/org/opends/server/monitors/SystemInfoMonitorProvider.java
@@ -41,14 +41,7 @@
 import org.opends.server.config.ConfigException;
 import org.opends.server.core.DirectoryServer;
 import org.opends.server.loggers.debug.DebugTracer;
-import org.opends.server.protocols.asn1.ASN1OctetString;
-import org.opends.server.types.Attribute;
-import org.opends.server.types.AttributeBuilder;
-import org.opends.server.types.AttributeType;
-import org.opends.server.types.AttributeValue;
-import org.opends.server.types.DebugLogLevel;
-import org.opends.server.types.InitializationException;
-
+import org.opends.server.types.*;
 
 
 /**
@@ -245,23 +238,9 @@
   {
     AttributeType attrType = DirectoryServer.getDefaultAttributeType(name);
 
-    ASN1OctetString encodedValue = new ASN1OctetString(value);
     AttributeBuilder builder = new AttributeBuilder(attrType);
 
-    try
-    {
-      builder.add(new AttributeValue(encodedValue,
-                                    attrType.normalize(encodedValue)));
-    }
-    catch (Exception e)
-    {
-      if (debugEnabled())
-      {
-        TRACER.debugCaught(DebugLogLevel.ERROR, e);
-      }
-
-      builder.add(new AttributeValue(encodedValue, encodedValue));
-    }
+    builder.add(AttributeValues.create(attrType, value));
 
     return builder.toAttribute();
   }
diff --git a/opends/src/server/org/opends/server/monitors/VersionMonitorProvider.java b/opends/src/server/org/opends/server/monitors/VersionMonitorProvider.java
index 5af2c91..8a814bc 100644
--- a/opends/src/server/org/opends/server/monitors/VersionMonitorProvider.java
+++ b/opends/src/server/org/opends/server/monitors/VersionMonitorProvider.java
@@ -37,13 +37,7 @@
 import org.opends.server.config.ConfigException;
 import org.opends.server.core.DirectoryServer;
 import org.opends.server.loggers.debug.DebugTracer;
-import org.opends.server.protocols.asn1.ASN1OctetString;
-import org.opends.server.types.Attribute;
-import org.opends.server.types.AttributeBuilder;
-import org.opends.server.types.AttributeType;
-import org.opends.server.types.AttributeValue;
-import org.opends.server.types.DebugLogLevel;
-import org.opends.server.types.InitializationException;
+import org.opends.server.types.*;
 import org.opends.server.util.DynamicConstants;
 
 
@@ -280,23 +274,9 @@
   {
     AttributeType attrType = DirectoryServer.getDefaultAttributeType(name);
 
-    ASN1OctetString encodedValue = new ASN1OctetString(value);
     AttributeBuilder builder = new AttributeBuilder(attrType);
 
-    try
-    {
-      builder.add(new AttributeValue(encodedValue,
-                                    attrType.normalize(encodedValue)));
-    }
-    catch (Exception e)
-    {
-      if (debugEnabled())
-      {
-        TRACER.debugCaught(DebugLogLevel.ERROR, e);
-      }
-
-      builder.add(new AttributeValue(encodedValue, encodedValue));
-    }
+    builder.add(AttributeValues.create(attrType, value));
 
     return builder.toAttribute();
   }
diff --git a/opends/src/server/org/opends/server/plugins/ChangeNumberControlPlugin.java b/opends/src/server/org/opends/server/plugins/ChangeNumberControlPlugin.java
index 32480c8..cb17df6 100644
--- a/opends/src/server/org/opends/server/plugins/ChangeNumberControlPlugin.java
+++ b/opends/src/server/org/opends/server/plugins/ChangeNumberControlPlugin.java
@@ -30,6 +30,8 @@
 import java.util.Set;
 
 import java.util.TreeSet;
+import java.io.IOException;
+
 import org.opends.messages.Message;
 import org.opends.server.admin.server.ConfigurationChangeListener;
 import org.opends.server.admin.std.meta.PluginCfgDefn;
@@ -39,7 +41,7 @@
 import org.opends.server.api.plugin.PluginType;
 import org.opends.server.api.plugin.PluginResult;
 import org.opends.server.config.ConfigException;
-import org.opends.server.protocols.asn1.ASN1OctetString;
+import org.opends.server.protocols.asn1.ASN1Writer;
 import org.opends.server.replication.common.ChangeNumber;
 import org.opends.server.replication.protocol.OperationContext;
 import org.opends.server.types.ConfigChangeResult;
@@ -65,6 +67,48 @@
   private ChangeNumberControlPluginCfg currentConfig;
 
   /**
+   * The control used by this plugin.
+   */
+  public static class ChangeNumberControl extends Control
+  {
+    private ChangeNumber cn;
+
+    /**
+     * Constructs a new change number control.
+     *
+     * @param  isCritical   Indicates whether support for this control should be
+     *                      considered a critical part of the server processing.
+     * @param cn          The change number.
+     */
+    public ChangeNumberControl(boolean isCritical, ChangeNumber cn)
+    {
+      super(OID_CSN_CONTROL, isCritical);
+      this.cn = cn;
+    }
+
+    /**
+     * Writes this control's value to an ASN.1 writer. The value (if any) must
+     * be written as an ASN1OctetString.
+     *
+     * @param writer The ASN.1 writer to use.
+     * @throws IOException If a problem occurs while writing to the stream.
+     */
+    protected void writeValue(ASN1Writer writer) throws IOException {
+      writer.writeOctetString(cn.toString());
+    }
+
+    /**
+     * Retrieves the change number.
+     *
+     * @return The change number.
+     */
+    public ChangeNumber getChangeNumber()
+    {
+      return cn;
+    }
+  }
+
+  /**
    * Creates a new instance of this Directory Server plugin.  Every plugin must
    * implement a default constructor (it is the only one that will be used to
    * create plugins defined in the configuration), and every plugin constructor
@@ -273,13 +317,9 @@
           if (ctx != null) {
             ChangeNumber cn = ctx.getChangeNumber();
             if (cn != null) {
-              String csn = cn.toString();
-              if (csn != null) {
-                Control responseControl =
-                  new Control(OID_CSN_CONTROL, c.isCritical(),
-                       new ASN1OctetString(csn));
-                operation.getResponseControls().add(responseControl);
-              }
+              Control responseControl =
+                  new ChangeNumberControl(c.isCritical(), cn);
+              operation.getResponseControls().add(responseControl);
             }
           }
           break;
diff --git a/opends/src/server/org/opends/server/plugins/EntryUUIDPlugin.java b/opends/src/server/org/opends/server/plugins/EntryUUIDPlugin.java
index a9880a4..e3121c4 100644
--- a/opends/src/server/org/opends/server/plugins/EntryUUIDPlugin.java
+++ b/opends/src/server/org/opends/server/plugins/EntryUUIDPlugin.java
@@ -42,17 +42,7 @@
 import org.opends.server.admin.std.server.PluginCfg;
 import org.opends.server.api.plugin.*;
 import org.opends.server.config.ConfigException;
-import org.opends.server.types.Attribute;
-import org.opends.server.types.AttributeType;
-import org.opends.server.types.AttributeUsage;
-import org.opends.server.types.AttributeValue;
-import org.opends.server.types.Attributes;
-import org.opends.server.types.ByteStringFactory;
-import org.opends.server.types.ConfigChangeResult;
-import org.opends.server.types.DirectoryConfig;
-import org.opends.server.types.Entry;
-import org.opends.server.types.LDIFImportConfig;
-import org.opends.server.types.ResultCode;
+import org.opends.server.types.*;
 import org.opends.server.types.operation.PreOperationAddOperation;
 
 import static org.opends.messages.PluginMessages.*;
@@ -188,8 +178,8 @@
     UUID uuid = UUID.nameUUIDFromBytes(dnBytes);
 
     Attribute uuidAttr = Attributes.create(entryUUIDType,
-        new AttributeValue(entryUUIDType, ByteStringFactory.create(uuid
-            .toString())));
+        AttributeValues.create(entryUUIDType,
+            ByteString.valueOf(uuid.toString())));
     uuidList = new ArrayList<Attribute>(1);
     uuidList.add(uuidAttr);
     entry.putAttribute(entryUUIDType, uuidList);
@@ -223,8 +213,7 @@
     // Construct a new random UUID.
     UUID uuid = UUID.randomUUID();
     Attribute uuidAttr = Attributes.create(entryUUIDType,
-        new AttributeValue(entryUUIDType, ByteStringFactory.create(uuid
-            .toString())));
+        AttributeValues.create(entryUUIDType,uuid.toString()));
     uuidList = new ArrayList<Attribute>(1);
     uuidList.add(uuidAttr);
 
diff --git a/opends/src/server/org/opends/server/plugins/LastModPlugin.java b/opends/src/server/org/opends/server/plugins/LastModPlugin.java
index 98949e0..5cd6347 100644
--- a/opends/src/server/org/opends/server/plugins/LastModPlugin.java
+++ b/opends/src/server/org/opends/server/plugins/LastModPlugin.java
@@ -42,20 +42,7 @@
 import org.opends.server.api.plugin.PluginResult;
 import org.opends.server.config.ConfigException;
 import org.opends.server.loggers.debug.DebugTracer;
-import org.opends.server.types.Attribute;
-import org.opends.server.types.AttributeBuilder;
-import org.opends.server.types.AttributeType;
-import org.opends.server.types.AttributeValue;
-import org.opends.server.types.Attributes;
-import org.opends.server.types.ByteStringFactory;
-import org.opends.server.types.ConfigChangeResult;
-import org.opends.server.types.DebugLogLevel;
-import org.opends.server.types.DirectoryConfig;
-import org.opends.server.types.DirectoryException;
-import org.opends.server.types.DN;
-import org.opends.server.types.Modification;
-import org.opends.server.types.ModificationType;
-import org.opends.server.types.ResultCode;
+import org.opends.server.types.*;
 import org.opends.server.types.operation.PreOperationAddOperation;
 import org.opends.server.types.operation.PreOperationModifyOperation;
 import org.opends.server.types.operation.PreOperationModifyDNOperation;
@@ -66,7 +53,6 @@
 import static org.opends.server.util.TimeThread.*;
 
 
-
 /**
  * This class implements a Directory Server plugin that will add the
  * creatorsName and createTimestamp attributes to an entry whenever it is added
@@ -184,13 +170,13 @@
     {
       // This must mean that the operation was performed anonymously.
       // Even so, we still need to update the creatorsName attribute.
-      builder.add(new AttributeValue(creatorsNameType, ByteStringFactory
-          .create()));
+      builder.add(AttributeValues.create(creatorsNameType,
+          ByteString.empty()));
     }
     else
     {
-      builder.add(new AttributeValue(creatorsNameType, ByteStringFactory
-          .create(creatorDN.toString())));
+      builder.add(AttributeValues.create(creatorsNameType,
+          ByteString.valueOf(creatorDN.toString())));
     }
     Attribute nameAttr = builder.toAttribute();
     ArrayList<Attribute> nameList = new ArrayList<Attribute>(1);
@@ -200,8 +186,9 @@
 
     //  Create the attribute list for the createTimestamp attribute.
     Attribute timeAttr = Attributes.create(createTimestampType,
-        OP_ATTR_CREATE_TIMESTAMP, new AttributeValue(createTimestampType,
-            ByteStringFactory.create(getGMTTime())));
+        OP_ATTR_CREATE_TIMESTAMP,
+        AttributeValues.create(createTimestampType,
+            ByteString.valueOf(getGMTTime())));
     ArrayList<Attribute> timeList = new ArrayList<Attribute>(1);
     timeList.add(timeAttr);
     addOperation.setAttribute(createTimestampType, timeList);
@@ -228,13 +215,13 @@
     {
       // This must mean that the operation was performed anonymously.
       // Even so, we still need to update the modifiersName attribute.
-      builder.add(new AttributeValue(modifiersNameType, ByteStringFactory
-          .create()));
+      builder.add(AttributeValues.create(modifiersNameType,
+          ByteString.empty()));
     }
     else
     {
-      builder.add(new AttributeValue(modifiersNameType, ByteStringFactory
-          .create(modifierDN.toString())));
+      builder.add(AttributeValues.create(modifiersNameType,
+          ByteString.valueOf(modifierDN.toString())));
     }
     Attribute nameAttr = builder.toAttribute();
     try
@@ -257,8 +244,9 @@
 
     //  Create the modifyTimestamp attribute.
     Attribute timeAttr = Attributes.create(modifyTimestampType,
-        OP_ATTR_MODIFY_TIMESTAMP, new AttributeValue(modifyTimestampType,
-            ByteStringFactory.create(getGMTTime())));
+        OP_ATTR_MODIFY_TIMESTAMP,
+        AttributeValues.create(modifyTimestampType,
+            ByteString.valueOf(getGMTTime())));
     try
     {
       modifyOperation.addModification(new Modification(ModificationType.REPLACE,
@@ -298,13 +286,13 @@
     {
       // This must mean that the operation was performed anonymously.
       // Even so, we still need to update the modifiersName attribute.
-      builder.add(new AttributeValue(modifiersNameType, ByteStringFactory
-          .create()));
+      builder.add(AttributeValues.create(modifiersNameType,
+          ByteString.empty()));
     }
     else
     {
-      builder.add(new AttributeValue(modifiersNameType, ByteStringFactory
-          .create(modifierDN.toString())));
+      builder.add(AttributeValues.create(modifiersNameType,
+          ByteString.valueOf(modifierDN.toString())));
     }
     Attribute nameAttr = builder.toAttribute();
     modifyDNOperation.addModification(new Modification(
@@ -313,8 +301,9 @@
 
     // Create the modifyTimestamp attribute.
     Attribute timeAttr = Attributes.create(modifyTimestampType,
-        OP_ATTR_MODIFY_TIMESTAMP, new AttributeValue(modifyTimestampType,
-            ByteStringFactory.create(getGMTTime())));
+        OP_ATTR_MODIFY_TIMESTAMP,
+        AttributeValues.create(modifyTimestampType,
+            ByteString.valueOf(getGMTTime())));
     modifyDNOperation.addModification(new Modification(
         ModificationType.REPLACE, timeAttr, true));
 
diff --git a/opends/src/server/org/opends/server/plugins/PasswordPolicyImportPlugin.java b/opends/src/server/org/opends/server/plugins/PasswordPolicyImportPlugin.java
index 56225d6..b258a0b 100644
--- a/opends/src/server/org/opends/server/plugins/PasswordPolicyImportPlugin.java
+++ b/opends/src/server/org/opends/server/plugins/PasswordPolicyImportPlugin.java
@@ -60,19 +60,7 @@
 import org.opends.server.loggers.debug.DebugTracer;
 import org.opends.server.schema.AuthPasswordSyntax;
 import org.opends.server.schema.UserPasswordSyntax;
-import org.opends.server.types.Attribute;
-import org.opends.server.types.AttributeBuilder;
-import org.opends.server.types.AttributeType;
-import org.opends.server.types.AttributeValue;
-import org.opends.server.types.ByteString;
-import org.opends.server.types.ConfigChangeResult;
-import org.opends.server.types.DN;
-import org.opends.server.types.DebugLogLevel;
-import org.opends.server.types.DirectoryException;
-import org.opends.server.types.Entry;
-import org.opends.server.types.LDIFImportConfig;
-import org.opends.server.types.ResultCode;
-
+import org.opends.server.types.*;
 
 
 /**
@@ -400,7 +388,7 @@
                     for (PasswordStorageScheme<?> s : schemes)
                     {
                       ByteString nv = s.encodeAuthPassword(value);
-                      builder.add(new AttributeValue(policy
+                      builder.add(AttributeValues.create(policy
                           .getPasswordAttribute(), nv));
                     }
                   }
@@ -435,7 +423,7 @@
                     for (PasswordStorageScheme<?> s : schemes)
                     {
                       ByteString nv = s.encodePasswordWithScheme(value);
-                      builder.add(new AttributeValue(policy
+                      builder.add(AttributeValues.create(policy
                           .getPasswordAttribute(), nv));
                     }
                   }
@@ -501,7 +489,7 @@
               for (PasswordStorageScheme<?> s : defaultAuthPasswordSchemes)
               {
                 ByteString nv = s.encodeAuthPassword(value);
-                builder.add(new AttributeValue(t, nv));
+                builder.add(AttributeValues.create(t, nv));
               }
             }
             catch (Exception e)
@@ -559,7 +547,7 @@
               for (PasswordStorageScheme<?> s : defaultUserPasswordSchemes)
               {
                 ByteString nv = s.encodePasswordWithScheme(value);
-                builder.add(new AttributeValue(t, nv));
+                builder.add(AttributeValues.create(t, nv));
               }
             }
             catch (Exception e)
diff --git a/opends/src/server/org/opends/server/plugins/ReferentialIntegrityPlugin.java b/opends/src/server/org/opends/server/plugins/ReferentialIntegrityPlugin.java
index d7e49ea..cfc49f6 100644
--- a/opends/src/server/org/opends/server/plugins/ReferentialIntegrityPlugin.java
+++ b/opends/src/server/org/opends/server/plugins/ReferentialIntegrityPlugin.java
@@ -58,22 +58,7 @@
 import org.opends.server.loggers.debug.DebugTracer;
 import org.opends.server.protocols.internal.InternalClientConnection;
 import org.opends.server.protocols.internal.InternalSearchOperation;
-import org.opends.server.types.AttributeType;
-import org.opends.server.types.AttributeValue;
-import org.opends.server.types.Attributes;
-import org.opends.server.types.ConfigChangeResult;
-import org.opends.server.types.DebugLogLevel;
-import org.opends.server.types.DereferencePolicy;
-import org.opends.server.types.DirectoryException;
-import org.opends.server.types.DN;
-import org.opends.server.types.Entry;
-import org.opends.server.types.IndexType;
-import org.opends.server.types.Modification;
-import org.opends.server.types.ModificationType;
-import org.opends.server.types.ResultCode;
-import org.opends.server.types.SearchResultEntry;
-import org.opends.server.types.SearchFilter;
-import org.opends.server.types.SearchScope;
+import org.opends.server.types.*;
 import org.opends.server.types.operation.SubordinateModifyDNOperation;
 import org.opends.server.types.operation.PostOperationModifyDNOperation;
 import org.opends.server.types.operation.PostOperationDeleteOperation;
@@ -637,7 +622,7 @@
     for(AttributeType attributeType : attributeTypes)
     {
       componentFilters.add(SearchFilter.createEqualityFilter(attributeType,
-              new AttributeValue(attributeType, oldEntryDN.toString())));
+          AttributeValues.create(attributeType, oldEntryDN.toString())));
     }
 
     InternalClientConnection conn =
diff --git a/opends/src/server/org/opends/server/plugins/SevenBitCleanPlugin.java b/opends/src/server/org/opends/server/plugins/SevenBitCleanPlugin.java
index 3688041..0cc973c 100644
--- a/opends/src/server/org/opends/server/plugins/SevenBitCleanPlugin.java
+++ b/opends/src/server/org/opends/server/plugins/SevenBitCleanPlugin.java
@@ -39,20 +39,7 @@
 import org.opends.server.api.plugin.*;
 import org.opends.server.config.ConfigException;
 import org.opends.server.core.DirectoryServer;
-import org.opends.server.types.Attribute;
-import org.opends.server.types.AttributeType;
-import org.opends.server.types.AttributeValue;
-import org.opends.server.types.ByteString;
-import org.opends.server.types.ConfigChangeResult;
-import org.opends.server.types.DirectoryException;
-import org.opends.server.types.DN;
-import org.opends.server.types.Entry;
-import org.opends.server.types.LDAPException;
-import org.opends.server.types.LDIFImportConfig;
-import org.opends.server.types.RawAttribute;
-import org.opends.server.types.RawModification;
-import org.opends.server.types.RDN;
-import org.opends.server.types.ResultCode;
+import org.opends.server.types.*;
 import org.opends.server.types.operation.PreParseAddOperation;
 import org.opends.server.types.operation.PreParseModifyOperation;
 import org.opends.server.types.operation.PreParseModifyDNOperation;
@@ -381,7 +368,7 @@
       RDN newRDN;
       try
       {
-        newRDN = RDN.decode(rawNewRDN.stringValue());
+        newRDN = RDN.decode(rawNewRDN.toString());
       }
       catch (DirectoryException de)
       {
@@ -454,10 +441,12 @@
    * @return {@code true} if the provided value is 7-bit clean, or {@code false}
    *         if it is not.
    */
-  private final boolean is7BitClean(ByteString value)
+  private final boolean is7BitClean(ByteSequence value)
   {
-    for (byte b : value.value())
+    byte b;
+    for (int i = 0; i < value.length(); i++)
     {
+      b = value.byteAt(i);
       if ((b & MASK) != b)
       {
         return false;
diff --git a/opends/src/server/org/opends/server/plugins/UniqueAttributePlugin.java b/opends/src/server/org/opends/server/plugins/UniqueAttributePlugin.java
index 2093ca1..fea8161 100644
--- a/opends/src/server/org/opends/server/plugins/UniqueAttributePlugin.java
+++ b/opends/src/server/org/opends/server/plugins/UniqueAttributePlugin.java
@@ -220,7 +220,7 @@
               if (conflictDN != null)
               {
                 Message msg = ERR_PLUGIN_UNIQUEATTR_ATTR_NOT_UNIQUE.get(
-                    t.getNameOrOID(), v.getStringValue(),
+                    t.getNameOrOID(), v.getValue().toString(),
                     conflictDN.toString());
                 return PluginResult.PreOperation.stopProcessing(
                     ResultCode.CONSTRAINT_VIOLATION, msg);
@@ -290,7 +290,7 @@
               if (conflictDN != null)
               {
                 Message msg = ERR_PLUGIN_UNIQUEATTR_ATTR_NOT_UNIQUE.get(
-                    t.getNameOrOID(), v.getStringValue(),
+                    t.getNameOrOID(), v.getValue().toString(),
                     conflictDN.toString());
                 return PluginResult.PreOperation.stopProcessing(
                     ResultCode.CONSTRAINT_VIOLATION, msg);
@@ -337,7 +337,7 @@
                   if (conflictDN != null)
                   {
                     Message msg = ERR_PLUGIN_UNIQUEATTR_ATTR_NOT_UNIQUE.get(
-                        t.getNameOrOID(), v.getStringValue(),
+                        t.getNameOrOID(), v.getValue().toString(),
                         conflictDN.toString());
                     return PluginResult.PreOperation.stopProcessing(
                         ResultCode.CONSTRAINT_VIOLATION, msg);
@@ -409,7 +409,7 @@
         if (conflictDN != null)
         {
           Message msg = ERR_PLUGIN_UNIQUEATTR_ATTR_NOT_UNIQUE.get(
-              t.getNameOrOID(), v.getStringValue(),
+              t.getNameOrOID(), v.getValue().toString(),
               conflictDN.toString());
           return PluginResult.PreOperation.stopProcessing(
               ResultCode.CONSTRAINT_VIOLATION, msg);
@@ -472,7 +472,7 @@
                                  t.getNameOrOID(),
                                  addOperation.getConnectionID(),
                                  addOperation.getOperationID(),
-                                 v.getStringValue(),
+                                 v.getValue().toString(),
                                  entry.getDN().toString(),
                                  conflictDN.toString());
                 DirectoryServer.sendAlertNotification(this,
@@ -546,7 +546,7 @@
                                        t.getNameOrOID(),
                                        modifyOperation.getConnectionID(),
                                        modifyOperation.getOperationID(),
-                                       v.getStringValue(),
+                                       v.getValue().toString(),
                                        entryDN.toString(),
                                        conflictDN.toString());
                 DirectoryServer.sendAlertNotification(this,
@@ -600,7 +600,7 @@
                                            t.getNameOrOID(),
                                            modifyOperation.getConnectionID(),
                                            modifyOperation.getOperationID(),
-                                           v.getStringValue(),
+                                           v.getValue().toString(),
                                            entryDN.toString(),
                                            conflictDN.toString());
                     DirectoryServer.sendAlertNotification(this,
@@ -680,7 +680,7 @@
                     t.getNameOrOID(),
                     modifyDNOperation.getConnectionID(),
                     modifyDNOperation.getOperationID(),
-                    v.getStringValue(),
+                    v.getValue().toString(),
                     modifyDNOperation.getUpdatedEntry().getDN().toString(),
                     conflictDN.toString());
           DirectoryServer.sendAlertNotification(this,
diff --git a/opends/src/server/org/opends/server/plugins/profiler/ProfileStack.java b/opends/src/server/org/opends/server/plugins/profiler/ProfileStack.java
index b0048f0..6f54448 100644
--- a/opends/src/server/org/opends/server/plugins/profiler/ProfileStack.java
+++ b/opends/src/server/org/opends/server/plugins/profiler/ProfileStack.java
@@ -28,10 +28,9 @@
 
 
 
-import java.util.ArrayList;
-import org.opends.server.protocols.asn1.ASN1Element;
-import org.opends.server.protocols.asn1.ASN1OctetString;
-import org.opends.server.protocols.asn1.ASN1Sequence;
+import java.io.IOException;
+
+import org.opends.server.protocols.asn1.*;
 
 import static org.opends.server.loggers.debug.DebugLogger.*;
 import org.opends.server.loggers.debug.DebugTracer;
@@ -306,22 +305,22 @@
 
 
   /**
-   * Encodes this profile stack for writing to the capture file.
+   * Encodes and writes this profile stack to the capture file.
    *
-   * @return  The ASN.1 element containing the encoded representation of this
-   *          profile stack.
+   * @param  writer The writer to use.
+   * @throws IOException if an error occurs while writing.
    */
-  public ASN1Element encode()
+  public void write(ASN1Writer writer) throws IOException
   {
-    ArrayList<ASN1Element> elements = new ArrayList<ASN1Element>(3*numFrames);
+    writer.writeStartSequence();
+    writer.writeInteger(numFrames);
     for (int i=0; i < numFrames; i++)
     {
-      elements.add(new ASN1OctetString(classNames[i]));
-      elements.add(new ASN1OctetString(methodNames[i]));
-      elements.add(new ASN1OctetString(String.valueOf(lineNumbers[i])));
+      writer.writeOctetString(classNames[i]);
+      writer.writeOctetString(methodNames[i]);
+      writer.writeInteger(lineNumbers[i]);
     }
-
-    return new ASN1Sequence(elements);
+    writer.writeEndSequence();
   }
 
 
@@ -329,44 +328,34 @@
   /**
    * Decodes the contents of the provided element as a profile stack.
    *
-   * @param  stackElement  The ASN.1 element containing the encoded profile
-   *                       stack information.
+   * @param  reader  The ASN.1 reader to read the encoded profile stack
+   *                 information from.
    *
-   * @return  The decoded profile stack, or <CODE>null</CODE> if the element
-   *          could not be decoded for some reason.
+   * @return  The decoded profile stack.
+   * @throws ASN1Exception If the element could not be decoded for some reason.
+   *
    */
-  public static ProfileStack decode(ASN1Element stackElement)
+  public static ProfileStack decode(ASN1Reader reader) throws ASN1Exception
   {
-    try
+    reader.readStartSequence();
+
+    int      numFrames   = (int)reader.readInteger();
+    String[] classNames  = new String[numFrames];
+    String[] methodNames = new String[numFrames];
+    int[]    lineNumbers = new int[numFrames];
+
+    int i = 0;
+    while(reader.hasNextElement())
     {
-      ArrayList<ASN1Element> elements =
-           stackElement.decodeAsSequence().elements();
-
-      int      numFrames   = (elements.size() / 3);
-      String[] classNames  = new String[numFrames];
-      String[] methodNames = new String[numFrames];
-      int[]    lineNumbers = new int[numFrames];
-
-      for (int i=0,j=0; i < numFrames; i++, j+=3)
-      {
-        classNames[i]  = elements.get(j).decodeAsOctetString().stringValue();
-        methodNames[i] = elements.get(j+1).decodeAsOctetString().stringValue();
-        lineNumbers[i] =
-             Integer.parseInt(
-                  elements.get(j+2).decodeAsOctetString().stringValue());
-      }
-
-      return new ProfileStack(classNames, methodNames, lineNumbers);
+      classNames[i]  = reader.readOctetStringAsString();
+      methodNames[i] = reader.readOctetStringAsString();
+      lineNumbers[i] = (int)reader.readInteger();
+      i++;
     }
-    catch (Exception e)
-    {
-      if (debugEnabled())
-      {
-        TRACER.debugCaught(DebugLogLevel.ERROR, e);
-      }
 
-      return null;
-    }
+    reader.readEndSequence();
+
+    return new ProfileStack(classNames, methodNames, lineNumbers);
   }
 }
 
diff --git a/opends/src/server/org/opends/server/plugins/profiler/ProfileViewer.java b/opends/src/server/org/opends/server/plugins/profiler/ProfileViewer.java
index d9afd04..d100c4d 100644
--- a/opends/src/server/org/opends/server/plugins/profiler/ProfileViewer.java
+++ b/opends/src/server/org/opends/server/plugins/profiler/ProfileViewer.java
@@ -34,7 +34,6 @@
 import java.awt.Font;
 import java.io.FileInputStream;
 import java.io.IOException;
-import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.HashMap;
 import javax.swing.JEditorPane;
@@ -50,9 +49,7 @@
 import javax.swing.event.TreeSelectionEvent;
 import javax.swing.event.TreeSelectionListener;
 
-import org.opends.server.protocols.asn1.ASN1Element;
-import org.opends.server.protocols.asn1.ASN1Exception;
-import org.opends.server.protocols.asn1.ASN1Reader;
+import org.opends.server.protocols.asn1.*;
 import org.opends.server.util.args.ArgumentException;
 import org.opends.server.util.args.ArgumentParser;
 import org.opends.server.util.args.BooleanArgument;
@@ -231,36 +228,28 @@
          throws IOException, ASN1Exception
   {
     // Try to open the file for reading.
-    ASN1Reader reader = new ASN1Reader(new FileInputStream(filename));
+    ASN1Reader reader = ASN1.getReader(new FileInputStream(filename));
 
 
     try
     {
       // The first element in the file must be a sequence with the header
       // information.
-      ASN1Element element = reader.readElement();
-      ArrayList<ASN1Element> elements = element.decodeAsSequence().elements();
-      totalIntervals += elements.get(0).decodeAsLong().longValue();
+      reader.readStartSequence();
+      totalIntervals += reader.readInteger();
 
-      long startTime = elements.get(1).decodeAsLong().longValue();
-      long stopTime  = elements.get(2).decodeAsLong().longValue();
+      long startTime = reader.readInteger();
+      long stopTime  = reader.readInteger();
       totalDuration += (stopTime - startTime);
+      reader.readEndSequence();
 
 
       // The remaining elements will contain the stack frames.
-      while (true)
+      while (reader.hasNextElement())
       {
-        element = reader.readElement();
-        if (element == null)
-        {
-          break;
-        }
+        ProfileStack stack = ProfileStack.decode(reader);
 
-
-        ProfileStack stack = ProfileStack.decode(element);
-
-        element    = reader.readElement();
-        long count = element.decodeAsLong().longValue();
+        long count = reader.readInteger();
 
         int pos = stack.getNumFrames() - 1;
         if (pos < 0)
diff --git a/opends/src/server/org/opends/server/plugins/profiler/ProfilerThread.java b/opends/src/server/org/opends/server/plugins/profiler/ProfilerThread.java
index 3f0fc55..9d03d62 100644
--- a/opends/src/server/org/opends/server/plugins/profiler/ProfilerThread.java
+++ b/opends/src/server/org/opends/server/plugins/profiler/ProfilerThread.java
@@ -30,15 +30,11 @@
 
 import java.io.FileOutputStream;
 import java.io.IOException;
-import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.Map;
 
 import org.opends.server.api.DirectoryThread;
-import org.opends.server.protocols.asn1.ASN1Element;
-import org.opends.server.protocols.asn1.ASN1Long;
-import org.opends.server.protocols.asn1.ASN1Sequence;
-import org.opends.server.protocols.asn1.ASN1Writer;
+import org.opends.server.protocols.asn1.*;
 
 import static org.opends.server.loggers.debug.DebugLogger.*;
 import org.opends.server.loggers.debug.DebugTracer;
@@ -233,7 +229,7 @@
   {
     // Open the capture file for writing.  We'll use an ASN.1 writer to write
     // the data.
-    ASN1Writer writer = new ASN1Writer(new FileOutputStream(filename));
+    ASN1Writer writer = ASN1.getWriter(new FileOutputStream(filename));
 
 
     try
@@ -251,19 +247,19 @@
 
       // Write a header to the file containing the number of samples and the
       // start and stop times.
-      ArrayList<ASN1Element> headerElements = new ArrayList<ASN1Element>(3);
-      headerElements.add(new ASN1Long(numIntervals));
-      headerElements.add(new ASN1Long(captureStartTime));
-      headerElements.add(new ASN1Long(captureStopTime));
-      writer.writeElement(new ASN1Sequence(headerElements));
+      writer.writeStartSequence();
+      writer.writeInteger(numIntervals);
+      writer.writeInteger(captureStartTime);
+      writer.writeInteger(captureStopTime);
+      writer.writeEndSequence();
 
 
       // For each unique stack captured, write it to the file followed by the
       // number of occurrences.
       for (ProfileStack s : stackTraces.keySet())
       {
-        writer.writeElement(s.encode());
-        writer.writeElement(new ASN1Long(stackTraces.get(s)));
+        s.write(writer);
+        writer.writeInteger(stackTraces.get(s));
       }
     }
     finally
diff --git a/opends/src/server/org/opends/server/protocols/asn1/ASN1.java b/opends/src/server/org/opends/server/protocols/asn1/ASN1.java
new file mode 100644
index 0000000..b74a685
--- /dev/null
+++ b/opends/src/server/org/opends/server/protocols/asn1/ASN1.java
@@ -0,0 +1,302 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License").  You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE
+ * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
+ * add the following below this CDDL 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.server.protocols.asn1;
+
+
+
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.nio.channels.ReadableByteChannel;
+import java.nio.channels.WritableByteChannel;
+
+import org.opends.server.types.ByteSequence;
+import org.opends.server.types.ByteString;
+import org.opends.server.types.ByteStringBuilder;
+import org.opends.server.types.ByteSequenceReader;
+
+
+/**
+ * This class contains various static factory methods for creating
+ * ASN.1 readers and writers.
+ *
+ * @see ASN1Reader
+ * @see ASN1Writer
+ * @see ASN1ByteChannelReader
+ */
+public final class ASN1
+{
+
+  /**
+   * Gets 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(byte[] array)
+  {
+    return getReader(array, 0);
+  }
+
+
+
+  /**
+   * Gets 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</code> to
+   *          indicate that there is no limit.
+   * @return The new ASN.1 reader.
+   */
+  public static ASN1Reader getReader(byte[] array, int maxElementSize)
+  {
+    return getReader(ByteString.wrap(array), maxElementSize);
+  }
+
+
+
+  /**
+   * Gets 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(ByteSequence sequence)
+  {
+    return getReader(sequence, 0);
+  }
+
+
+
+  /**
+   * Gets 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</code> to
+   *          indicate that there is no limit.
+   * @return The new ASN.1 reader.
+   */
+  public static ASN1Reader getReader(ByteSequence sequence, int maxElementSize)
+  {
+    return new ASN1ByteSequenceReader(sequence.asReader(), maxElementSize);
+  }
+
+
+
+  /**
+   * Gets 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(ByteSequenceReader reader)
+  {
+    return getReader(reader, 0);
+  }
+
+
+
+  /**
+   * Gets 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</code> to
+   *          indicate that there is no limit.
+   * @return The new ASN.1 reader.
+   */
+  public static ASN1Reader getReader(ByteSequenceReader reader,
+                                     int maxElementSize)
+  {
+    return new ASN1ByteSequenceReader(reader, maxElementSize);
+  }
+
+
+
+  /**
+   * Gets 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(InputStream stream)
+  {
+    return getReader(stream, 0);
+  }
+
+
+
+  /**
+   * Gets 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</code> to
+   *          indicate that there is no limit.
+   * @return The new ASN.1 reader.
+   */
+  public static ASN1Reader getReader(InputStream stream, int maxElementSize)
+  {
+    return new ASN1InputStreamReader(stream, maxElementSize);
+  }
+
+
+
+  /**
+   * Gets an ASN.1 byte channel reader whose source is the provided
+   * readable byte channel, uses 4KB buffer, and having an unlimited
+   * maximum BER element size.
+   *
+   * @param channel
+   *          The readable byte channel to use.
+   * @return The new ASN.1 byte channel reader.
+   */
+  public static ASN1ByteChannelReader getReader(ReadableByteChannel channel)
+  {
+    return getReader(channel, 4096, 0);
+  }
+
+
+
+  /**
+   * Gets an ASN.1 byte channel reader whose source is the provided
+   * readable byte channel, having a user defined buffer size, and
+   * user defined maximum BER element size.
+   *
+   * @param channel
+   *          The readable byte channel to use.
+   * @param bufferSize
+   *          The buffer size to use when reading from the channel.
+   * @param maxElementSize
+   *          The maximum BER element size, or <code>0</code> to
+   *          indicate that there is no limit.
+   * @return The new ASN.1 byte channel reader.
+   */
+  public static ASN1ByteChannelReader getReader(ReadableByteChannel channel,
+      int bufferSize, int maxElementSize)
+  {
+    return new ASN1ByteChannelReader(channel, bufferSize, maxElementSize);
+  }
+
+
+
+  /**
+   * Gets 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(ByteStringBuilder builder)
+  {
+    ByteSequenceOutputStream outputStream = new ByteSequenceOutputStream(
+        builder);
+    return getWriter(outputStream);
+  }
+
+
+
+  /**
+   * Gets 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(OutputStream stream)
+  {
+    return new ASN1OutputStreamWriter(stream);
+  }
+
+
+
+  /**
+   * Gets an ASN.1 writer whose destination is the provided writable
+   * byte channel and which will use a 4KB buffer.
+   * <p>
+   * The NIO {@code ByteBuffer} will be flushed to the channel
+   * automatically when full or when the {@code ASN1Writer.flush()}
+   * method is called.
+   *
+   * @param channel
+   *          The writable byte channel.
+   * @return The new ASN.1 writer.
+   */
+  public static ASN1Writer getWriter(WritableByteChannel channel)
+  {
+    return new ASN1ByteChannelWriter(channel, 4096);
+  }
+
+
+
+  /**
+   * Gets an ASN.1 writer whose destination is the provided writable
+   * byte channel.
+   * <p>
+   * The NIO {@code ByteBuffer} will be flushed to the channel
+   * automatically when full or when the {@code ASN1Writer.flush()}
+   * method is called.
+   *
+   * @param channel
+   *          The writable byte channel.
+   * @param bufferSize
+   *          The buffer size to use when writing to the channel.
+   * @return The new ASN.1 writer.
+   */
+  public static ASN1Writer getWriter(WritableByteChannel channel,
+                                     int bufferSize)
+  {
+    return new ASN1ByteChannelWriter(channel, bufferSize);
+  }
+
+
+
+  // Prevent instantiation.
+  private ASN1()
+  {
+    // Nothing to do.
+  }
+}
diff --git a/opends/src/server/org/opends/server/protocols/asn1/ASN1Boolean.java b/opends/src/server/org/opends/server/protocols/asn1/ASN1Boolean.java
deleted file mode 100644
index 5d74f95..0000000
--- a/opends/src/server/org/opends/server/protocols/asn1/ASN1Boolean.java
+++ /dev/null
@@ -1,341 +0,0 @@
-/*
- * CDDL HEADER START
- *
- * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
- *
- * You can obtain a copy of the license at
- * trunk/opends/resource/legal-notices/OpenDS.LICENSE
- * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
- * See the License for the specific language governing permissions
- * and limitations under the License.
- *
- * When distributing Covered Code, include this CDDL HEADER in each
- * file and include the License file at
- * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
- * add the following below this CDDL 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.server.protocols.asn1;
-import org.opends.messages.Message;
-
-
-
-import static org.opends.messages.ProtocolMessages.*;
-import static org.opends.server.protocols.asn1.ASN1Constants.*;
-import static org.opends.server.util.ServerConstants.*;
-import static org.opends.server.util.StaticUtils.*;
-
-
-
-/**
- * This class defines the data structures and methods to use when interacting
- * with ASN.1 Boolean elements.
- */
-@org.opends.server.types.PublicAPI(
-     stability=org.opends.server.types.StabilityLevel.UNCOMMITTED,
-     mayInstantiate=true,
-     mayExtend=false,
-     mayInvoke=true)
-public final class ASN1Boolean
-       extends ASN1Element
-{
-  /**
-   * The serial version identifier required to satisfy the compiler because this
-   * class implements the <CODE>java.io.Serializable</CODE> interface.  This
-   * value was generated using the <CODE>serialver</CODE> command-line utility
-   * included with the Java SDK.
-   */
-  private static final long serialVersionUID = -3352160557662933000L;
-
-
-
-  // The boolean value for this element.
-  private boolean booleanValue;
-
-
-
-
-  /**
-   * Creates a new ASN.1 Boolean element with the default type and the provided
-   * value.
-   *
-   * @param  booleanValue  The value for this ASN.1 Boolean element.
-   */
-  public ASN1Boolean(boolean booleanValue)
-  {
-    super(UNIVERSAL_BOOLEAN_TYPE, encodeValue(booleanValue));
-
-
-    this.booleanValue = booleanValue;
-  }
-
-
-
-  /**
-   * Creates a new ASN.1 Boolean element with the specified type and value.
-   *
-   * @param  type          The BER type for this ASN.1 Boolean element.
-   * @param  booleanValue  The value for this ASN.1 Boolean element.
-   */
-  public ASN1Boolean(byte type, boolean booleanValue)
-  {
-    super(type, encodeValue(booleanValue));
-
-
-    this.booleanValue = booleanValue;
-  }
-
-
-
-  /**
-   * Creates a new ASN.1 Boolean element with the specified type and value.
-   *
-   * @param  type          The BER type for this ASN.1 Boolean element.
-   * @param  value         The encoded value for this ASN.1 Boolean element.
-   * @param  booleanValue  The boolean value for this ASN.1 Boolean element.
-   */
-  private ASN1Boolean(byte type, byte[] value, boolean booleanValue)
-  {
-    super(type, value);
-
-
-    this.booleanValue = booleanValue;
-  }
-
-
-
-  /**
-   * Retrieves the boolean value for this ASN.1 Boolean element.
-   *
-   * @return  The boolean value for this ASN.1 Boolean element.
-   */
-  public boolean booleanValue()
-  {
-    return booleanValue;
-  }
-
-
-
-  /**
-   * Specifies the boolean value for this ASN.1 Boolean element.
-   *
-   * @param  booleanValue  The boolean value for this ASN.1 Boolean element.
-   */
-  public void setValue(boolean booleanValue)
-  {
-    this.booleanValue = booleanValue;
-    setValueInternal(encodeValue(booleanValue));
-  }
-
-
-
-  /**
-   * Specifies the value for this ASN.1 Boolean element.
-   *
-   * @param  value  The encoded value for this ASN.1 Boolean element.
-   *
-   * @throws  ASN1Exception  If the provided array is null or does not contain
-   *                         a single byte.
-   */
-  public void setValue(byte[] value)
-         throws ASN1Exception
-  {
-    if (value == null)
-    {
-      Message message = ERR_ASN1_BOOLEAN_SET_VALUE_NULL.get();
-      throw new ASN1Exception(message);
-    }
-
-    if (value.length != 1)
-    {
-      Message message =
-          ERR_ASN1_BOOLEAN_SET_VALUE_INVALID_LENGTH.get(value.length);
-      throw new ASN1Exception(message);
-    }
-
-    booleanValue = (value[0] != 0x00);
-    setValueInternal(value);
-  }
-
-
-
-  /**
-   * Decodes the provided ASN.1 element as a Boolean element.
-   *
-   * @param  element  The ASN.1 element to decode as a Boolean element.
-   *
-   * @return  The decoded ASN.1 Boolean element.
-   *
-   * @throws  ASN1Exception  If the provided ASN.1 element cannot be decoded as
-   *                         a Boolean element.
-   */
-  public static ASN1Boolean decodeAsBoolean(ASN1Element element)
-         throws ASN1Exception
-  {
-    if (element == null)
-    {
-      Message message = ERR_ASN1_BOOLEAN_DECODE_ELEMENT_NULL.get();
-      throw new ASN1Exception(message);
-    }
-
-    byte[] value = element.value();
-    if (value.length != 1)
-    {
-      Message message =
-          ERR_ASN1_BOOLEAN_DECODE_ELEMENT_INVALID_LENGTH.get(value.length);
-      throw new ASN1Exception(message);
-    }
-
-    boolean booleanValue = (value[0] != 0x00);
-    return new ASN1Boolean(element.getType(), value, booleanValue);
-  }
-
-
-
-  /**
-   * Decodes the provided byte array as an ASN.1 Boolean element.
-   *
-   * @param  encodedElement  The byte array to decode as an ASN.1 Boolean
-   *                         element.
-   *
-   * @return  The decoded ASN.1 Boolean element.
-   *
-   * @throws  ASN1Exception  If the provided byte array cannot be decoded as an
-   *                         ASN.1 Boolean element.
-   */
-  public static ASN1Boolean decodeAsBoolean(byte[] encodedElement)
-         throws ASN1Exception
-  {
-    // First make sure that the array is not null and long enough to contain
-    // a valid ASN.1 Boolean element.
-    if (encodedElement == null)
-    {
-      Message message = ERR_ASN1_BOOLEAN_DECODE_ARRAY_NULL.get();
-      throw new ASN1Exception(message);
-    }
-
-    if (encodedElement.length < 3)
-    {
-      Message message =
-          ERR_ASN1_BOOLEAN_SHORT_ELEMENT.get(encodedElement.length);
-      throw new ASN1Exception(message);
-    }
-
-
-    // Next, decode the length.  This allows multi-byte lengths with up to four
-    // bytes used to indicate how many bytes are in the length.
-    byte type = encodedElement[0];
-    int length = (encodedElement[1] & 0x7F);
-    int valueStartPos = 2;
-    if (length != encodedElement[1])
-    {
-      int numLengthBytes = length;
-      if (numLengthBytes > 4)
-      {
-        Message message = ERR_ASN1_INVALID_NUM_LENGTH_BYTES.get(numLengthBytes);
-        throw new ASN1Exception(message);
-      }
-      else if (encodedElement.length < (2 + numLengthBytes))
-      {
-        Message message = ERR_ASN1_TRUNCATED_LENGTH.get(numLengthBytes);
-        throw new ASN1Exception(message);
-      }
-
-      length = 0x00;
-      valueStartPos = 2 + numLengthBytes;
-      for (int i=0; i < numLengthBytes; i++)
-      {
-        length = (length << 8) | (encodedElement[i+2] & 0xFF);
-      }
-    }
-
-
-    // Make sure that the number of bytes left is equal to the number of bytes
-    // in the value.
-    if ((encodedElement.length - valueStartPos) != length)
-    {
-      Message message = ERR_ASN1_LENGTH_MISMATCH.get(
-          length, (encodedElement.length - valueStartPos));
-      throw new ASN1Exception(message);
-    }
-
-
-    // Make sure that the decoded length is exactly one byte.
-    if (length != 1)
-    {
-      Message message =
-          ERR_ASN1_BOOLEAN_DECODE_ARRAY_INVALID_LENGTH.get(length);
-      throw new ASN1Exception(message);
-    }
-
-
-    // Copy the value and construct the element to return.
-    byte[]  value        = new byte[] { encodedElement[valueStartPos] };
-    boolean booleanValue = (value[0] != 0x00);
-    return new ASN1Boolean(type, value, booleanValue);
-  }
-
-
-
-  /**
-   * Appends a string representation of this ASN.1 Boolean element to the
-   * provided buffer.
-   *
-   * @param  buffer  The buffer to which the information should be appended.
-   */
-  public void toString(StringBuilder buffer)
-  {
-    buffer.append("ASN1Boolean(type=");
-    buffer.append(byteToHex(getType()));
-    buffer.append(", value=");
-    buffer.append(booleanValue);
-    buffer.append(")");
-  }
-
-
-
-  /**
-   * Appends a string representation of this protocol element to the provided
-   * buffer.
-   *
-   * @param  buffer  The buffer into which the string representation should be
-   *                 written.
-   * @param  indent  The number of spaces that should be used to indent the
-   *                 resulting string representation.
-   */
-  public void toString(StringBuilder buffer, int indent)
-  {
-    StringBuilder indentBuf = new StringBuilder(indent);
-    for (int i=0 ; i < indent; i++)
-    {
-      indentBuf.append(' ');
-    }
-
-    buffer.append(indentBuf);
-    buffer.append("ASN.1 Boolean");
-    buffer.append(EOL);
-
-    buffer.append(indentBuf);
-    buffer.append("  BER Type:  ");
-    buffer.append(byteToHex(getType()));
-    buffer.append(EOL);
-
-    buffer.append(indentBuf);
-    buffer.append("  Value:  ");
-    buffer.append(booleanValue);
-    buffer.append(" (");
-    buffer.append(byteToHex(value()[0]));
-    buffer.append(")");
-    buffer.append(EOL);
-  }
-}
-
diff --git a/opends/src/server/org/opends/server/protocols/asn1/ASN1ByteChannelReader.java b/opends/src/server/org/opends/server/protocols/asn1/ASN1ByteChannelReader.java
new file mode 100644
index 0000000..93a55fe
--- /dev/null
+++ b/opends/src/server/org/opends/server/protocols/asn1/ASN1ByteChannelReader.java
@@ -0,0 +1,456 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License").  You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE
+ * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
+ * add the following below this CDDL 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.server.protocols.asn1;
+
+import org.opends.server.types.ByteSequenceReader;
+import org.opends.server.types.ByteStringBuilder;
+import org.opends.server.types.ByteString;
+import java.nio.ByteBuffer;
+import java.nio.channels.ReadableByteChannel;
+import java.nio.channels.IllegalBlockingModeException;
+import java.io.IOException;
+import java.io.InputStream;
+
+
+/**
+ * This class is for reading ASN.1 elements from a readable byte
+ * channel. It will handle all partial element reads from the channel
+ * and save any unread ASN.1 elements if required. All data read from
+ * the channel will be ready to be read as ASN.1 elements no matter
+ * how many times the channel is read. However, to minimize the the
+ * amount of memory used by this reader, the client should read ASN.1
+ * elements as soon as they are read off the channel.
+ * <p>
+ * {@code ASN1ByteChannelReader}s are created using the factory
+ * methods in {@link ASN1}.
+ * <p>
+ * The client should use this class in the following manner:
+ *<p>
+ * When NIO signals new data is available in the channel, the client
+ * should call {@link #processChannelData()}.
+ *<p>
+ * If bytes are read from the channel, the client should call
+ * {@link #elementAvailable()} to see if a complete element is ready to
+ * be read. However, if no data is actually read, the client should
+ * wait for the next signal and try again.
+ * <p>
+ * As long as a complete element is ready, the client should read the
+ * appropriate ASN.1 element(s). Once no more complete elements are
+ * available, the client should call {@link #processChannelData()}
+ * again to read more data (if available).
+ * <p>
+ * <b>NOTE:</b> Since this reader is non blocking, reading ASN.1
+ * elements before making sure they are ready could result in
+ * {@link IllegalBlockingModeException}s being thrown while reading
+ * ASN.1 elements. Once an exception is thrown, the state of the reader
+ * is no longer stable and can not be used again.
+ */
+public final class ASN1ByteChannelReader implements ASN1Reader
+{
+  // The byte channel to read from.
+  private final ReadableByteChannel byteChannel;
+
+  // The wrapped ASN.1 InputStream reader.
+  private final ASN1InputStreamReader reader;
+
+  // The NIO ByteStringBuilder that stores any immediate data read off
+  // the channel.
+  private final ByteBuffer byteBuffer;
+
+  // The save buffer used to store any unprocessed data waiting
+  // to be read as ASN.1 elements. (Usually due to reading
+  // incomplete elements from the channel).
+  private final ByteStringBuilder saveBuffer;
+
+  // The save buffer reader.
+  private final ByteSequenceReader saveBufferReader;
+
+  /**
+   * An adaptor class for reading from a save buffer and the NIO byte buffer
+   * sequentially using the InputStream interface.
+   *
+   * Since the NIO byte buffer is re-used when reading off the channel, any
+   * unused data will be appended to the save buffer before reading off the
+   * channel again. This reader will always read the save buffer first before
+   * the actual NIO byte buffer to ensure bytes are read in the same order
+   * as they are received.
+   *
+   * The read methods of this stream will throw an IllegalBlockingModeException
+   * if invoked when there are no data to read from the save buffer or the
+   * channel buffer.
+   *
+   * The stream will not support the mark or reset methods.
+   */
+  private final class CombinedBufferInputStream extends InputStream
+  {
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public int available()
+    {
+      // The number of available bytes is the sum of the save buffer
+      // and the last read data in the NIO ByteStringBuilder.
+      return saveBufferReader.remaining() + byteBuffer.remaining();
+    }
+
+    /**
+     * Reads the next byte of data from the save buffer or channel buffer.
+     * The value byte is returned as an int in the range 0 to 255.
+     * If no byte is available in the save buffer or channel buffer,
+     * IllegalBlockingModeException will be thrown.
+     *
+     * @return the next byte of data.
+     * @throws IllegalBlockingModeException if there are more bytes available.
+     */
+    @Override
+    public int read()
+    {
+      if(saveBufferReader.remaining() > 0)
+      {
+        // Try saved buffer first
+        return 0xFF & saveBufferReader.get();
+      }
+      if(byteBuffer.remaining() > 0)
+      {
+        // Must still be on the channel buffer
+        return 0xFF & byteBuffer.get();
+      }
+
+      throw new IllegalBlockingModeException();
+    }
+
+    /**
+     * Reads up to len bytes of data from the save buffer or channel buffer
+     * into an array of bytes. An attempt is made to read as many as len bytes,
+     * but a smaller number may be read. The number of bytes actually read is
+     * returned as an integer.
+     *
+     * If b is null, a NullPointerException is thrown.
+     *
+     * If the length of b is zero, then no bytes are read and 0 is returned;
+     * otherwise, there is an attempt to read at least one byte. If no byte is
+     * available in the save buffer or channel buffer,
+     * IllegalBlockingModeException will be thrown; otherwise, at least one
+     * byte is read and stored into b.
+     *
+     * The first byte read is stored into element b[0], the next one into
+     * b[o1], and so on. The number of bytes read is, at most, equal to the
+     * length of b. Let k be the number of bytes actually read; these bytes
+     * will be stored in elements b[0] through b[k-1], leaving elements b[k]
+     * through b[b.length-1] unaffected.
+     *
+     * @return the total number of bytes read into the buffer.
+     * @throws IllegalBlockingModeException if there are more bytes available.
+     */
+    @Override
+    public int read(byte[] b)
+    {
+      return read(b, 0, b.length);
+    }
+
+    /**
+     * Reads up to len bytes of data from the save buffer or channel buffer
+     * into an array of bytes. An attempt is made to read as many as len bytes,
+     * but a smaller number may be read. The number of bytes actually read is
+     * returned as an integer.
+     *
+     * If b is null, a NullPointerException is thrown.
+     *
+     * If off is negative, or len is negative, or off+len is greater than the
+     * length of the array b, then an IndexOutOfBoundsException is thrown.
+     *
+     * If len is zero, then no bytes are read and 0 is returned; otherwise,
+     * there is an attempt to read at least one byte. If no byte is available
+     * in the save buffer or channel buffer, IllegalBlockingModeException will
+     * be thrown; otherwise, at least one byte is read and stored into b.
+     *
+     * The first byte read is stored into element b[off], the next one into
+     * b[off+1], and so on. The number of bytes read is, at most, equal to len.
+     * Let k be the number of bytes actually read; these bytes will be stored
+     * in elements b[off] through b[off+k-1], leaving elements b[off+k]
+     * through b[off+len-1] unaffected.
+     *
+     * In every case, elements b[0] through b[off] and elements b[off+len]
+     * through b[b.length-1] are unaffected.
+     *
+     * @return the total number of bytes read into the buffer.
+     * @throws IllegalBlockingModeException if there are more bytes available.
+     */
+    @Override
+    public int read(byte[] b, int off, int len)
+    {
+      if ((off < 0) || (len < 0) || (off + len > b.length))
+      {
+        throw new IndexOutOfBoundsException();
+      }
+
+      if(len == 0)
+      {
+        return 0;
+      }
+
+      int bytesCopied=0;
+      int getLen;
+      if(saveBufferReader.remaining() > 0)
+      {
+        // Copy out of the last saved buffer first
+        getLen = Math.min(saveBufferReader.remaining(), len);
+        saveBufferReader.get(b, off, getLen);
+        bytesCopied += getLen;
+      }
+      if(bytesCopied < len && byteBuffer.remaining() > 0)
+      {
+        // Copy out of the channel buffer if we haven't got
+        // everything we needed.
+        getLen = Math.min(byteBuffer.remaining(), len - bytesCopied);
+        byteBuffer.get(b, off + bytesCopied, getLen);
+        bytesCopied += getLen;
+      }
+      if(bytesCopied < len)
+      {
+        throw new IllegalBlockingModeException();
+      }
+
+      return bytesCopied;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public long skip(long length)
+    {
+      int bytesSkipped=0;
+      int len;
+      if(saveBufferReader.remaining() > 0)
+      {
+        // Skip in the last saved buffer first
+        len = Math.min(saveBufferReader.remaining(), (int)length);
+        saveBufferReader.position(saveBufferReader.position() + len);
+        bytesSkipped += len;
+      }
+      if(bytesSkipped < length && byteBuffer.remaining() > 0)
+      {
+        //Skip in the channel buffer if we haven't skipped enough.
+        len = Math.min(byteBuffer.remaining(), (int)length - bytesSkipped);
+        byteBuffer.position(byteBuffer.position() + len);
+        bytesSkipped += len;
+      }
+      if(bytesSkipped < length)
+      {
+        throw new IllegalBlockingModeException();
+      }
+
+      return bytesSkipped;
+    }
+  }
+
+  /**
+   * Creates a new ASN.1 byte channel reader whose source is the
+   * provided readable byte channel, having a user defined buffer
+   * size, and user defined maximum BER element size.
+   *
+   * @param channel
+   *          The readable byte channel to use.
+   * @param bufferSize
+   *          The buffer size to use when reading from the channel.
+   * @param maxElementSize
+   *          The max ASN.1 element size this reader will read.
+   */
+  ASN1ByteChannelReader(ReadableByteChannel channel, int bufferSize,
+      int maxElementSize)
+  {
+    this.byteChannel = channel;
+    this.byteBuffer = ByteBuffer.allocateDirect(bufferSize);
+    this.byteBuffer.flip();
+    this.saveBuffer = new ByteStringBuilder();
+    this.saveBufferReader = saveBuffer.asReader();
+
+    CombinedBufferInputStream bufferStream = new CombinedBufferInputStream();
+    this.reader = new ASN1InputStreamReader(bufferStream, maxElementSize);
+  }
+
+  /**
+   * Process any new data on the channel so they can be read as ASN.1
+   * elements. This method should only be called when there are no
+   * more complete elements in the reader. Calling this method when
+   * there are complete elements still in the reader will result in
+   * unnecessary memory allocations to store any unread data. This
+   * method will perform the following operations:
+   * <ul>
+   * <li>Clear the save buffer if everything was read.
+   * <li>Append any unread data from the NIO byte buffer to the save
+   * buffer.
+   * <li>Clear the NIO byte buffer and read from the channel.
+   * </ul>
+   *
+   * @return The number of bytes read from the channel or -1 if
+   *         channel is closed.
+   * @throws IOException
+   *           If an exception occurs while reading from the channel.
+   */
+  public int processChannelData() throws IOException
+  {
+    // Clear the save buffer if we have read all of it
+    if (saveBufferReader.remaining() == 0)
+    {
+      saveBuffer.clear();
+      saveBufferReader.rewind();
+    }
+
+    // Append any unused data in the channel buffer to the save buffer
+    if (byteBuffer.remaining() > 0)
+    {
+      saveBuffer.append(byteBuffer, byteBuffer.remaining());
+    }
+
+    byteBuffer.clear();
+    int read = byteChannel.read(byteBuffer);
+    byteBuffer.flip();
+    return read;
+  }
+
+  /**
+   * Determines if a complete ASN.1 element is ready to be read from
+   * channel.
+   *
+   * @return <code>true</code> if another complete element is available or
+   *         <code>false</code> otherwise.
+   * @throws ASN1Exception If an error occurs while trying to decode
+   *                       an ASN1 element.
+   */
+  public boolean elementAvailable() throws ASN1Exception
+  {
+    return reader.elementAvailable();
+  }
+
+  /**
+   * Determines if the channel 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 ASN1Exception If an error occurs while trying to decode
+   *                       an ASN1 element.
+   */
+  public boolean hasNextElement() throws ASN1Exception {
+    return reader.hasNextElement();
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  public int peekLength() throws ASN1Exception {
+    return reader.peekLength();
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  public byte peekType() throws ASN1Exception {
+    return reader.peekType();
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  public boolean readBoolean() throws ASN1Exception {
+    return reader.readBoolean();
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  public void readEndSequence() throws ASN1Exception {
+    reader.readEndSequence();
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  public long readInteger() throws ASN1Exception {
+    return reader.readInteger();
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  public void readNull() throws ASN1Exception {
+    reader.readNull();
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  public ByteString readOctetString() throws ASN1Exception {
+    return reader.readOctetString();
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  public void readOctetString(ByteStringBuilder buffer) throws ASN1Exception {
+    reader.readOctetString(buffer);
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  public String readOctetStringAsString() throws ASN1Exception {
+    return reader.readOctetStringAsString();
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  public String readOctetStringAsString(String charSet) throws ASN1Exception {
+    return reader.readOctetStringAsString(charSet);
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  public void readStartSequence() throws ASN1Exception {
+    reader.readStartSequence();
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  public void close() throws IOException {
+    reader.close();
+    byteChannel.close();
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  public void skipElement() throws ASN1Exception
+  {
+    reader.skipElement();
+  }
+}
diff --git a/opends/src/server/org/opends/server/protocols/asn1/ASN1ByteChannelWriter.java b/opends/src/server/org/opends/server/protocols/asn1/ASN1ByteChannelWriter.java
new file mode 100644
index 0000000..9dfe189
--- /dev/null
+++ b/opends/src/server/org/opends/server/protocols/asn1/ASN1ByteChannelWriter.java
@@ -0,0 +1,318 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License").  You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE
+ * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
+ * add the following below this CDDL 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.server.protocols.asn1;
+
+import org.opends.server.types.ByteSequence;
+
+import java.nio.ByteBuffer;
+import java.nio.channels.WritableByteChannel;
+import java.io.OutputStream;
+import java.io.IOException;
+
+/**
+ * This class is for writing ASN.1 elements directly to an
+ * NIO WritableByteChannel with an embedded ByteBuffer.
+ * The NIO ByteBuffer will be flushed to the channel automatically
+ * when full or when the flush() method is called.
+ */
+final class ASN1ByteChannelWriter implements ASN1Writer
+{
+  // The byte channel to write to.
+  private final WritableByteChannel byteChannel;
+
+  // The wrapped ASN.1 OutputStream writer.
+  private final ASN1OutputStreamWriter writer;
+
+  // The NIO ByteStringBuilder to write to.
+  private final ByteBuffer byteBuffer;
+
+  /**
+   * An adaptor class provides a streaming interface to write to a
+   * NIO ByteBuffer. This class is also responsible for writing
+   * the ByteBuffer out to the channel when full and clearing it.
+   */
+  private class ByteBufferOutputStream extends OutputStream
+  {
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void write(int i) throws IOException {
+      if(!byteBuffer.hasRemaining())
+      {
+        // No more space left in the buffer, send out to the channel.
+        ASN1ByteChannelWriter.this.flush();
+      }
+      byteBuffer.put((byte)i);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void write(byte[] bytes) throws IOException {
+      write(bytes, 0, bytes.length);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void write(byte[] bytes, int i, int i1) throws IOException {
+      if(i < 0 || i1 < 0 || i + i1 > bytes.length)
+        throw new IndexOutOfBoundsException();
+
+      int bytesToWrite = i1;
+      int len;
+      while(bytesToWrite > 0)
+      {
+        len = byteBuffer.remaining();
+        if(len < bytesToWrite)
+        {
+          byteBuffer.put(bytes, i + i1 - bytesToWrite, len);
+          bytesToWrite -= len;
+          ASN1ByteChannelWriter.this.flush();
+        }
+        else
+        {
+          byteBuffer.put(bytes, i + i1 - bytesToWrite, bytesToWrite);
+          bytesToWrite = 0;
+        }
+      }
+    }
+  }
+
+  /**
+   * Constructs a new ASN1ByteChannelWriter.
+   *
+   * @param byteChannel The WritableByteChannel to write to.
+   * @param writeBufferSize The NIO ByteBuffer size.
+   */
+  ASN1ByteChannelWriter(WritableByteChannel byteChannel,
+                               int writeBufferSize)
+  {
+    this.byteChannel = byteChannel;
+    this.byteBuffer = ByteBuffer.allocateDirect(writeBufferSize);
+
+    ByteBufferOutputStream bufferStream = new ByteBufferOutputStream();
+    this.writer = new ASN1OutputStreamWriter(bufferStream);
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  public ASN1Writer writeBoolean(boolean booleanValue) throws IOException {
+    writer.writeBoolean(booleanValue);
+    return this;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  public ASN1Writer writeBoolean(byte type, boolean booleanValue)
+      throws IOException {
+    writer.writeBoolean(type, booleanValue);
+    return this;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  public ASN1Writer writeEndSet() throws IOException {
+    writer.writeEndSet();
+    return this;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  public ASN1Writer writeEndSequence() throws IOException {
+    writer.writeEndSequence();
+    return this;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  public ASN1Writer writeInteger(int intValue) throws IOException {
+    writer.writeInteger(intValue);
+    return this;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  public ASN1Writer writeInteger(long longValue) throws IOException {
+    writer.writeInteger(longValue);
+    return this;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  public ASN1Writer writeInteger(byte type, int intValue) throws IOException {
+    writer.writeInteger(type, intValue);
+    return this;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  public ASN1Writer writeInteger(byte type, long longValue) throws IOException {
+    writer.writeInteger(type, longValue);
+    return this;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  public ASN1Writer writeEnumerated(int intValue) throws IOException {
+    writer.writeEnumerated(intValue);
+    return this;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  public ASN1Writer writeNull() throws IOException {
+    writer.writeNull();
+    return this;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  public ASN1Writer writeNull(byte type) throws IOException {
+    writer.writeNull(type);
+    return this;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  public ASN1Writer writeOctetString(byte type, byte[] value,
+                                     int offset, int length)
+      throws IOException {
+    writer.writeOctetString(type, value, offset, length);
+    return this;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  public ASN1Writer writeOctetString(byte type, ByteSequence value)
+      throws IOException {
+    writer.writeOctetString(type, value);
+    return this;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  public ASN1Writer writeOctetString(byte type, String value)
+      throws IOException {
+    writer.writeOctetString(type, value);
+    return this;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  public ASN1Writer writeOctetString(byte[] value, int offset, int length)
+      throws IOException {
+    writer.writeOctetString(value, offset, length);
+    return this;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  public ASN1Writer writeOctetString(ByteSequence value) throws IOException {
+    writer.writeOctetString(value);
+    return this;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  public ASN1Writer writeOctetString(String value) throws IOException {
+    writer.writeOctetString(value);
+    return this;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  public ASN1Writer writeStartSequence() throws IOException {
+    writer.writeStartSequence();
+    return this;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  public ASN1Writer writeStartSequence(byte type) throws IOException {
+    writer.writeStartSequence(type);
+    return this;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  public ASN1Writer writeStartSet() throws IOException {
+    writer.writeStartSet();
+    return this;
+  }
+
+  /**
+   * Flush the entire contents of the NIO ByteBuffer out to the
+   * channel.
+   *
+   * @throws IOException If an error occurs while flushing.
+   */
+  public void flush() throws IOException
+  {
+    byteBuffer.flip();
+    while(byteBuffer.hasRemaining())
+    {
+      byteChannel.write(byteBuffer);
+    }
+    byteBuffer.clear();
+  }
+
+  /**
+   * Closes this ASN.1 writer and the underlying channel.
+   *
+   * @throws IOException if an error occurs while closing the writer.
+   */
+  public void close() throws IOException {
+    // Close the writer first to flush the writer to the NIO byte buffer.
+    writer.close();
+    flush();
+    byteChannel.close();
+  }
+}
diff --git a/opends/src/server/org/opends/server/protocols/asn1/ASN1ByteSequenceReader.java b/opends/src/server/org/opends/server/protocols/asn1/ASN1ByteSequenceReader.java
new file mode 100644
index 0000000..13d72df
--- /dev/null
+++ b/opends/src/server/org/opends/server/protocols/asn1/ASN1ByteSequenceReader.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 2006-2009 Sun Microsystems, Inc.
+ */
+package org.opends.server.protocols.asn1;
+
+import static org.opends.messages.ProtocolMessages.*;
+import static org.opends.server.protocols.ldap.LDAPConstants.*;
+
+import java.util.LinkedList;
+import java.io.IOException;
+
+import org.opends.messages.Message;
+import org.opends.server.types.ByteSequenceReader;
+import org.opends.server.types.ByteString;
+import org.opends.server.types.ByteStringBuilder;
+
+/**
+ * An ASN.1 reader that reads from a {@link ByteSequenceReader}.
+ */
+final class ASN1ByteSequenceReader 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(ByteSequenceReader reader, int maxElementSize)
+  {
+    this.reader = reader;
+    this.readerStack = new LinkedList<ByteSequenceReader>();
+    this.maxElementSize = maxElementSize;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  public byte peekType() throws ASN1Exception
+  {
+    if(state == ELEMENT_READ_STATE_NEED_TYPE)
+    {
+      // Read just the type.
+      if(reader.remaining() <= 0)
+      {
+        Message message =
+            ERR_ASN1_TRUCATED_TYPE_BYTE.get();
+        throw new ASN1Exception(message);
+      }
+      int type = reader.get();
+
+      peekType = (byte)type;
+      state = ELEMENT_READ_STATE_NEED_FIRST_LENGTH_BYTE;
+    }
+
+    return peekType;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  public int peekLength() throws ASN1Exception
+  {
+    peekType();
+
+    if(state == ELEMENT_READ_STATE_NEED_FIRST_LENGTH_BYTE)
+    {
+      needFirstLengthByteState(true);
+    }
+
+    return peekLength;
+  }
+
+  /**
+   * Determines if a complete ASN.1 element is waiting to be read from the
+   * byte sequence.
+   *
+   * @return <code>true</code> if another complete element is available or
+   *         <code>false</code> otherwise.
+   * @throws ASN1Exception If an error occurs while trying to decode
+   *                       an ASN1 element.
+   */
+  public boolean elementAvailable() throws ASN1Exception
+  {
+    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();
+  }
+
+  /**
+   * Determines if the byte sequence 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 ASN1Exception If an error occurs while trying to decode
+   *                       an ASN1 element.
+   */
+  public boolean hasNextElement() throws ASN1Exception
+  {
+    return state != ELEMENT_READ_STATE_NEED_TYPE || needTypeState(false);
+  }
+
+  /**
+   * 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 ASN1Exception If an error occurs while trying to decode
+   *                       an ASN1 element.
+   */
+  private boolean needTypeState(boolean throwEofException)
+      throws ASN1Exception
+  {
+    // Read just the type.
+    if(reader.remaining() <= 0)
+    {
+      if(throwEofException)
+      {
+        Message message =
+            ERR_ASN1_TRUCATED_TYPE_BYTE.get();
+        throw new ASN1Exception(message);
+      }
+      return false;
+    }
+    int type = reader.get();
+
+    peekType = (byte)type;
+    state = ELEMENT_READ_STATE_NEED_FIRST_LENGTH_BYTE;
+    return true;
+  }
+
+  /**
+   * 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 ASN1Exception If an error occurs while trying to decode
+   *                       an ASN1 element.
+   */
+  private boolean needFirstLengthByteState(boolean throwEofException)
+      throws ASN1Exception
+  {
+    if(reader.remaining() <= 0)
+    {
+      if(throwEofException)
+      {
+        Message message =
+            ERR_ASN1_TRUNCATED_LENGTH_BYTE.get();
+        throw new ASN1Exception(message);
+      }
+      return false;
+    }
+    int readByte = reader.get();
+    peekLength = (readByte & 0x7F);
+    if (peekLength != readByte)
+    {
+      int lengthBytesNeeded = peekLength;
+      if (lengthBytesNeeded > 4)
+      {
+        Message message =
+            ERR_ASN1_INVALID_NUM_LENGTH_BYTES.get(lengthBytesNeeded);
+        throw new ASN1Exception(message);
+      }
+
+      peekLength = 0x00;
+      if(reader.remaining() < lengthBytesNeeded)
+      {
+        if(throwEofException)
+        {
+          Message message =
+              ERR_ASN1_TRUNCATED_LENGTH_BYTES.get(lengthBytesNeeded);
+          throw new ASN1Exception(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))
+    {
+      Message m = ERR_LDAP_CLIENT_DECODE_MAX_REQUEST_SIZE_EXCEEDED.get(
+          peekLength, maxElementSize);
+      throw new ASN1Exception(m);
+    }
+    state = ELEMENT_READ_STATE_NEED_VALUE_BYTES;
+    return true;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  public boolean readBoolean() throws ASN1Exception
+  {
+    // Read the header if haven't done so already
+    peekLength();
+
+    if (peekLength != 1)
+    {
+      Message message =
+          ERR_ASN1_BOOLEAN_INVALID_LENGTH.get(peekLength);
+      throw new ASN1Exception(message);
+    }
+
+    if(reader.remaining() < peekLength)
+    {
+      Message message =
+          ERR_ASN1_BOOLEAN_TRUNCATED_VALUE.get(peekLength);
+      throw new ASN1Exception(message);
+    }
+    int readByte = reader.get();
+
+    state = ELEMENT_READ_STATE_NEED_TYPE;
+    return readByte != 0x00;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  public long readInteger() throws ASN1Exception
+  {
+    // Read the header if haven't done so already
+    peekLength();
+
+    if ((peekLength < 1) || (peekLength > 8))
+    {
+      Message message =
+          ERR_ASN1_INTEGER_INVALID_LENGTH.get(peekLength);
+      throw new ASN1Exception(message);
+    }
+
+    if(reader.remaining() < peekLength)
+    {
+      Message message =
+          ERR_ASN1_INTEGER_TRUNCATED_VALUE.get(peekLength);
+      throw new ASN1Exception(message);
+    }
+    if(peekLength > 4)
+    {
+      long longValue = 0;
+      for (int i=0; i < peekLength; i++)
+      {
+        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++)
+      {
+        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 ASN1Exception
+  {
+    // Read the header if haven't done so already
+    peekLength();
+
+    // Make sure that the decoded length is exactly zero byte.
+    if (peekLength != 0)
+    {
+      Message message =
+          ERR_ASN1_NULL_INVALID_LENGTH.get(peekLength);
+      throw new ASN1Exception(message);
+    }
+
+    state = ELEMENT_READ_STATE_NEED_TYPE;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  public ByteString readOctetString() throws ASN1Exception {
+    // Read the header if haven't done so already
+    peekLength();
+
+    if(reader.remaining() < peekLength)
+    {
+      Message message =
+          ERR_ASN1_OCTET_STRING_TRUNCATED_VALUE.get(peekLength);
+      throw new ASN1Exception(message);
+    }
+
+    state = ELEMENT_READ_STATE_NEED_TYPE;
+    return reader.getByteString(peekLength);
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  public String readOctetStringAsString() throws ASN1Exception
+  {
+    // We could cache the UTF-8 CharSet if performance proves to be an
+    // issue.
+    return readOctetStringAsString("UTF-8");
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  public String readOctetStringAsString(String charSet) throws ASN1Exception
+  {
+    // Read the header if haven't done so already
+    peekLength();
+
+    if(reader.remaining() < peekLength)
+    {
+      Message message =
+          ERR_ASN1_OCTET_STRING_TRUNCATED_VALUE.get(peekLength);
+      throw new ASN1Exception(message);
+    }
+
+    state = ELEMENT_READ_STATE_NEED_TYPE;
+    return reader.getString(peekLength);
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  public void readOctetString(ByteStringBuilder buffer) throws ASN1Exception
+  {
+    // Read the header if haven't done so already
+    peekLength();
+
+    // Copy the value.
+    if(reader.remaining() < peekLength)
+    {
+      Message message =
+          ERR_ASN1_OCTET_STRING_TRUNCATED_VALUE.get(peekLength);
+      throw new ASN1Exception(message);
+    }
+    buffer.append(reader, peekLength);
+
+    state = ELEMENT_READ_STATE_NEED_TYPE;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  public void readStartSequence() throws ASN1Exception
+  {
+    // Read the header if haven't done so already
+    peekLength();
+
+    if(reader.remaining() < peekLength)
+    {
+      Message message =
+          ERR_ASN1_SEQUENCE_SET_TRUNCATED_VALUE.get(peekLength);
+      throw new ASN1Exception(message);
+    }
+
+    ByteSequenceReader subByteString = reader.getByteSequence(peekLength)
+        .asReader();
+    readerStack.addFirst(reader);
+    reader = subByteString;
+
+    // Reset the state
+    state = ELEMENT_READ_STATE_NEED_TYPE;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  public void readEndSequence() throws ASN1Exception
+  {
+    if(readerStack.isEmpty())
+    {
+      Message message = ERR_ASN1_SEQUENCE_READ_NOT_STARTED.get();
+      throw new ASN1Exception(message);
+    }
+
+    if(reader.remaining() > 0)
+    {
+      Message message =
+          ERR_ASN1_SEQUENCE_READ_NOT_ENDED.get(reader.remaining(), peekLength);
+      throw new ASN1Exception(message);
+    }
+
+    reader = readerStack.removeFirst();
+
+    // Reset the state
+    state = ELEMENT_READ_STATE_NEED_TYPE;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  public void skipElement() throws ASN1Exception
+  {
+    // Read the header if haven't done so already
+    peekLength();
+
+    if(reader.remaining() < peekLength)
+    {
+      Message message =
+          ERR_ASN1_SKIP_TRUNCATED_VALUE.get(peekLength);
+      throw new ASN1Exception(message);
+    }
+
+    state = ELEMENT_READ_STATE_NEED_TYPE;
+    reader.skip(peekLength);
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  public void close() throws IOException
+  {
+    readerStack.clear();
+  }
+}
diff --git a/opends/src/server/org/opends/server/protocols/asn1/ASN1Element.java b/opends/src/server/org/opends/server/protocols/asn1/ASN1Element.java
deleted file mode 100644
index 0bf1db5..0000000
--- a/opends/src/server/org/opends/server/protocols/asn1/ASN1Element.java
+++ /dev/null
@@ -1,1247 +0,0 @@
-/*
- * CDDL HEADER START
- *
- * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
- *
- * You can obtain a copy of the license at
- * trunk/opends/resource/legal-notices/OpenDS.LICENSE
- * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
- * See the License for the specific language governing permissions
- * and limitations under the License.
- *
- * When distributing Covered Code, include this CDDL HEADER in each
- * file and include the License file at
- * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
- * add the following below this CDDL 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.server.protocols.asn1;
-import org.opends.messages.Message;
-
-
-
-import java.io.Serializable;
-import java.util.ArrayList;
-import java.util.Arrays;
-
-import org.opends.server.api.ProtocolElement;
-import org.opends.server.types.ByteString;
-
-import static org.opends.messages.ProtocolMessages.*;
-import static org.opends.server.protocols.asn1.ASN1Constants.*;
-import static org.opends.server.util.ServerConstants.*;
-import static org.opends.server.util.StaticUtils.*;
-
-
-
-/**
- * This class defines the data structures and methods to use when interacting
- * with generic ASN.1 elements.  Subclasses may provide more specific
- * functionality for individual element types.
- */
-@org.opends.server.types.PublicAPI(
-     stability=org.opends.server.types.StabilityLevel.UNCOMMITTED,
-     mayInstantiate=true,
-     mayExtend=false,
-     mayInvoke=true)
-public class ASN1Element
-       implements ProtocolElement, Serializable
-{
-  /**
-   * The serial version identifier required to satisfy the compiler because this
-   * class implements the <CODE>java.io.Serializable</CODE> interface.  This
-   * value was generated using the <CODE>serialver</CODE> command-line utility
-   * included with the Java SDK.
-   */
-  private static final long serialVersionUID = -6085322427222358963L;
-
-
-
-  // The BER type for this element.
-  private byte type;
-
-  // The encoded value for this element.
-  private byte[] value;
-
-
-
-  /**
-   * Creates a new ASN.1 element with the specified type and no value.
-   *
-   * @param  type  The BER type for this ASN.1 element.
-   */
-  public ASN1Element(byte type)
-  {
-    this.type  = type;
-    this.value = NO_VALUE;
-  }
-
-
-
-  /**
-   * Creates a new ASN.1 element with the specified type and value.
-   *
-   * @param  type   The BER type for this ASN.1 element.
-   * @param  value  The encoded value for this ASN.1 element.
-   */
-  public ASN1Element(byte type, byte[] value)
-  {
-    this.type  = type;
-
-    if (value == null)
-    {
-      this.value = NO_VALUE;
-    }
-    else
-    {
-      this.value = value;
-    }
-  }
-
-
-
-  /**
-   * Retrieves the BER type for this ASN.1 element.
-   *
-   * @return  The BER type for this ASN.1 element.
-   */
-  public final byte getType()
-  {
-    return type;
-  }
-
-
-
-  /**
-   * Specifies the BER type for this ASN.1 element.
-   *
-   * @param  type  The BER type for this ASN.1 element.
-   */
-  public final void setType(byte type)
-  {
-    this.type = type;
-  }
-
-
-
-  /**
-   * Indicates whether this ASN.1 element is in the universal class.
-   *
-   * @return  <CODE>true</CODE> if this ASN.1 element is in the universal class,
-   *          or <CODE>false</CODE> if not.
-   */
-  public final boolean isUniversal()
-  {
-    return ((type & TYPE_MASK_ALL_BUT_CLASS) == TYPE_MASK_UNIVERSAL);
-  }
-
-
-
-  /**
-   * Indicates whether this ASN.1 element is in the application-specific class.
-   *
-   * @return  <CODE>true</CODE> if this ASN.1 element is in the
-   *          application-specific class, or <CODE>false</CODE> if not.
-   */
-  public final boolean isApplicationSpecific()
-  {
-    return ((type & TYPE_MASK_ALL_BUT_CLASS) == TYPE_MASK_APPLICATION);
-  }
-
-
-
-  /**
-   * Indicates whether this ASN.1 element is in the context-specific class.
-   *
-   * @return  <CODE>true</CODE> if this ASN.1 element is in the context-specific
-   *          class, or <CODE>false</CODE> if not.
-   */
-  public final boolean isContextSpecific()
-  {
-    return ((type & TYPE_MASK_ALL_BUT_CLASS) == TYPE_MASK_CONTEXT);
-  }
-
-
-
-  /**
-   * Indicates whether this ASN.1 element is in the private class.
-   *
-   * @return  <CODE>true</CODE> if this ASN.1 element is in the private class,
-   *          or <CODE>false</CODE> if not.
-   */
-  public final boolean isPrivate()
-  {
-    return ((type & TYPE_MASK_ALL_BUT_CLASS) == TYPE_MASK_PRIVATE);
-  }
-
-
-
-  /**
-   * Indicates whether this ASN.1 element has a primitive value.
-   *
-   * @return  <CODE>true</CODE> if this ASN.1 element has a primitive value, or
-   *          <CODE>false</CODE> if it is constructed.
-   */
-  public final boolean isPrimitive()
-  {
-    return ((type & TYPE_MASK_ALL_BUT_PC) == TYPE_MASK_PRIMITIVE);
-  }
-
-
-
-  /**
-   * Indicates whether this ASN.1 element has a constructed value.
-   *
-   * @return  <CODE>true</CODE> if this ASN.1 element has a constructed value,
-   *          or <CODE>false</CODE> if it is primitive.
-   */
-  public final boolean isConstructed()
-  {
-    return ((type & TYPE_MASK_ALL_BUT_PC) == TYPE_MASK_CONSTRUCTED);
-  }
-
-
-
-  /**
-   * Retrieves the encoded value for this ASN.1 element.
-   *
-   * @return  The encoded value for this ASN.1 element.
-   */
-  public final byte[] value()
-  {
-    return value;
-  }
-
-
-
-  /**
-   * Specifies the encoded value for this ASN.1 element.
-   *
-   * @param  value  The encoded value for this ASN.1 element.
-   *
-   * @throws  ASN1Exception  If the provided value is not appropriate for this
-   *                         type of ASN.1 element.
-   */
-  public void setValue(byte[] value)
-         throws ASN1Exception
-  {
-    if (value == null)
-    {
-      this.value = NO_VALUE;
-    }
-    else
-    {
-      this.value = value;
-    }
-  }
-
-
-
-  /**
-   * Specifies the value to use for this ASN.1 element, but without performing
-   * any validity checks.  This should only be used by subclasses and they must
-   * ensure that it is non-null and conforms to the appropriate requirements of
-   * the underlying type.
-   *
-   * @param  value  The encoded value for this ASN.1 element.
-   */
-  protected final void setValueInternal(byte[] value)
-  {
-    this.value = value;
-  }
-
-
-
-  /**
-   * Encodes 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.
-   *
-   * @return  The byte array containing the encoded length.
-   */
-  public static byte[] encodeLength(int length)
-  {
-    if (length < 128)
-    {
-      return new byte[] { (byte) length };
-    }
-
-    if ((length & 0x000000FF) == length)
-    {
-      return new byte[]
-      {
-        (byte) 0x81,
-        (byte) (length & 0xFF)
-      };
-    }
-    else if ((length & 0x0000FFFF) == length)
-    {
-      return new byte[]
-      {
-        (byte) 0x82,
-        (byte) ((length >> 8) & 0xFF),
-        (byte) (length & 0xFF)
-      };
-    }
-    else if ((length & 0x00FFFFFF) == length)
-    {
-      return new byte[]
-      {
-        (byte) 0x83,
-        (byte) ((length >> 16) & 0xFF),
-        (byte) ((length >>  8) & 0xFF),
-        (byte) (length & 0xFF)
-      };
-    }
-    else
-    {
-      return new byte[]
-      {
-        (byte) 0x84,
-        (byte) ((length >> 24) & 0xFF),
-        (byte) ((length >> 16) & 0xFF),
-        (byte) ((length >>  8) & 0xFF),
-        (byte) (length & 0xFF)
-      };
-    }
-  }
-
-
-
-  /**
-   * Encodes this ASN.1 element to a byte array.
-   *
-   * @return  The byte array containing the encoded ASN.1 element.
-   */
-  public final byte[] encode()
-  {
-    if (value.length == 0)
-    {
-      return new byte[] { type, 0x00 };
-    }
-    else if (value.length < 128)
-    {
-      byte[] encodedElement = new byte[value.length + 2];
-
-      encodedElement[0] = type;
-      encodedElement[1] = (byte) value.length;
-      System.arraycopy(value, 0, encodedElement, 2, value.length);
-
-      return encodedElement;
-    }
-    else
-    {
-      byte[] encodedLength  = encodeLength(value.length);
-      byte[] encodedElement = new byte[1 + value.length + encodedLength.length];
-
-      encodedElement[0] = type;
-      System.arraycopy(encodedLength, 0, encodedElement, 1,
-                       encodedLength.length);
-      System.arraycopy(value, 0, encodedElement, 1+encodedLength.length,
-                       value.length);
-
-      return encodedElement;
-    }
-  }
-
-
-
-  /**
-   * Retrieves a byte array containing the encoded representation of the
-   * provided boolean value.
-   *
-   * @param  booleanValue  The boolean value to encode.
-   *
-   * @return  A byte array containing the encoded representation of the provided
-   *          boolean value.
-   */
-  public static byte[] encodeValue(boolean booleanValue)
-  {
-    return (booleanValue ? BOOLEAN_VALUE_TRUE : BOOLEAN_VALUE_FALSE);
-  }
-
-
-
-  /**
-   * Retrieves a byte array containing the encoded representation of the
-   * provided integer value.
-   *
-   * @param  intValue  The integer value to encode.
-   *
-   * @return  A byte array containing the encoded representation of the provided
-   *          integer value.
-   */
-  public static byte[] encodeValue(int intValue)
-  {
-    if (intValue < 0)
-    {
-      if ((intValue & 0xFFFFFF80) == 0xFFFFFF80)
-      {
-        return new byte[]
-        {
-          (byte) (intValue & 0xFF)
-        };
-      }
-      else if ((intValue & 0xFFFF8000) == 0xFFFF8000)
-      {
-        return new byte[]
-        {
-          (byte) ((intValue >> 8) & 0xFF),
-          (byte) (intValue & 0xFF)
-        };
-      }
-      else if ((intValue & 0xFF800000) == 0xFF800000)
-      {
-        return new byte[]
-        {
-          (byte) ((intValue >> 16) & 0xFF),
-          (byte) ((intValue >>  8) & 0xFF),
-          (byte) (intValue & 0xFF)
-        };
-      }
-      else
-      {
-        return new byte[]
-        {
-          (byte) ((intValue >> 24) & 0xFF),
-          (byte) ((intValue >> 16) & 0xFF),
-          (byte) ((intValue >>  8) & 0xFF),
-          (byte) (intValue & 0xFF)
-        };
-      }
-    }
-    else
-    {
-      if ((intValue & 0x0000007F) == intValue)
-      {
-        return new byte[]
-        {
-          (byte) (intValue & 0xFF)
-        };
-      }
-      else if ((intValue & 0x00007FFF) == intValue)
-      {
-        return new byte[]
-        {
-          (byte) ((intValue >> 8) & 0xFF),
-          (byte) (intValue & 0xFF)
-        };
-      }
-      else if ((intValue & 0x007FFFFF) == intValue)
-      {
-        return new byte[]
-        {
-          (byte) ((intValue >> 16) & 0xFF),
-          (byte) ((intValue >>  8) & 0xFF),
-          (byte) (intValue & 0xFF)
-        };
-      }
-      else
-      {
-        return new byte[]
-        {
-          (byte) ((intValue >> 24) & 0xFF),
-          (byte) ((intValue >> 16) & 0xFF),
-          (byte) ((intValue >>  8) & 0xFF),
-          (byte) (intValue & 0xFF)
-        };
-      }
-    }
-  }
-
-
-
-  /**
-   * Retrieves a byte array containing the encoded representation of the
-   * provided long value.
-   *
-   * @param  longValue  The long value to encode.
-   *
-   * @return  A byte array containing the encoded representation of the provided
-   *          long value.
-   */
-  public static byte[] encodeLongValue(long longValue)
-  {
-    if (longValue < 0)
-    {
-      if ((longValue & 0xFFFFFFFFFFFFFF80L) == 0xFFFFFFFFFFFFFF80L)
-      {
-        return new byte[]
-        {
-          (byte) (longValue & 0xFF)
-        };
-      }
-      else if ((longValue & 0xFFFFFFFFFFFF8000L) == 0xFFFFFFFFFFFF8000L)
-      {
-        return new byte[]
-        {
-          (byte) ((longValue >> 8) & 0xFF),
-          (byte) (longValue & 0xFF)
-        };
-      }
-      else if ((longValue & 0xFFFFFFFFFF800000L) == 0xFFFFFFFFFF800000L)
-      {
-        return new byte[]
-        {
-          (byte) ((longValue >> 16) & 0xFF),
-          (byte) ((longValue >>  8) & 0xFF),
-          (byte) (longValue & 0xFF)
-        };
-      }
-      else if ((longValue & 0xFFFFFFFF80000000L) == 0xFFFFFFFF80000000L)
-      {
-        return new byte[]
-        {
-          (byte) ((longValue >> 24) & 0xFF),
-          (byte) ((longValue >> 16) & 0xFF),
-          (byte) ((longValue >>  8) & 0xFF),
-          (byte) (longValue & 0xFF)
-        };
-      }
-      else if ((longValue & 0xFFFFFF8000000000L) == 0xFFFFFF8000000000L)
-      {
-        return new byte[]
-        {
-          (byte) ((longValue >> 32) & 0xFF),
-          (byte) ((longValue >> 24) & 0xFF),
-          (byte) ((longValue >> 16) & 0xFF),
-          (byte) ((longValue >>  8) & 0xFF),
-          (byte) (longValue & 0xFF)
-        };
-      }
-      else if ((longValue & 0xFFFF800000000000L) == 0xFFFF800000000000L)
-      {
-        return new byte[]
-        {
-          (byte) ((longValue >> 40) & 0xFF),
-          (byte) ((longValue >> 32) & 0xFF),
-          (byte) ((longValue >> 24) & 0xFF),
-          (byte) ((longValue >> 16) & 0xFF),
-          (byte) ((longValue >>  8) & 0xFF),
-          (byte) (longValue & 0xFF)
-        };
-      }
-      else if ((longValue & 0xFF80000000000000L) == 0xFF80000000000000L)
-      {
-        return new byte[]
-        {
-          (byte) ((longValue >> 48) & 0xFF),
-          (byte) ((longValue >> 40) & 0xFF),
-          (byte) ((longValue >> 32) & 0xFF),
-          (byte) ((longValue >> 24) & 0xFF),
-          (byte) ((longValue >> 16) & 0xFF),
-          (byte) ((longValue >>  8) & 0xFF),
-          (byte) (longValue & 0xFF)
-        };
-      }
-      else
-      {
-        return new byte[]
-        {
-          (byte) ((longValue >> 56) & 0xFF),
-          (byte) ((longValue >> 48) & 0xFF),
-          (byte) ((longValue >> 40) & 0xFF),
-          (byte) ((longValue >> 32) & 0xFF),
-          (byte) ((longValue >> 24) & 0xFF),
-          (byte) ((longValue >> 16) & 0xFF),
-          (byte) ((longValue >>  8) & 0xFF),
-          (byte) (longValue & 0xFF)
-        };
-      }
-    }
-    else
-    {
-      if ((longValue & 0x000000000000007FL) == longValue)
-      {
-        return new byte[]
-        {
-          (byte) (longValue & 0xFF)
-        };
-      }
-      else if ((longValue & 0x0000000000007FFFL) == longValue)
-      {
-        return new byte[]
-        {
-          (byte) ((longValue >> 8) & 0xFF),
-          (byte) (longValue & 0xFF)
-        };
-      }
-      else if ((longValue & 0x00000000007FFFFFL) == longValue)
-      {
-        return new byte[]
-        {
-          (byte) ((longValue >> 16) & 0xFF),
-          (byte) ((longValue >>  8) & 0xFF),
-          (byte) (longValue & 0xFF)
-        };
-      }
-      else if ((longValue & 0x000000007FFFFFFFL) == longValue)
-      {
-        return new byte[]
-        {
-          (byte) ((longValue >> 24) & 0xFF),
-          (byte) ((longValue >> 16) & 0xFF),
-          (byte) ((longValue >>  8) & 0xFF),
-          (byte) (longValue & 0xFF)
-        };
-      }
-      else if ((longValue & 0x0000007FFFFFFFFFL) == longValue)
-      {
-        return new byte[]
-        {
-          (byte) ((longValue >> 32) & 0xFF),
-          (byte) ((longValue >> 24) & 0xFF),
-          (byte) ((longValue >> 16) & 0xFF),
-          (byte) ((longValue >>  8) & 0xFF),
-          (byte) (longValue & 0xFF)
-        };
-      }
-      else if ((longValue & 0x00007FFFFFFFFFFFL) == longValue)
-      {
-        return new byte[]
-        {
-          (byte) ((longValue >> 40) & 0xFF),
-          (byte) ((longValue >> 32) & 0xFF),
-          (byte) ((longValue >> 24) & 0xFF),
-          (byte) ((longValue >> 16) & 0xFF),
-          (byte) ((longValue >>  8) & 0xFF),
-          (byte) (longValue & 0xFF)
-        };
-      }
-      else if ((longValue & 0x007FFFFFFFFFFFFFL) == longValue)
-      {
-        return new byte[]
-        {
-          (byte) ((longValue >> 48) & 0xFF),
-          (byte) ((longValue >> 40) & 0xFF),
-          (byte) ((longValue >> 32) & 0xFF),
-          (byte) ((longValue >> 24) & 0xFF),
-          (byte) ((longValue >> 16) & 0xFF),
-          (byte) ((longValue >>  8) & 0xFF),
-          (byte) (longValue & 0xFF)
-        };
-      }
-      else
-      {
-        return new byte[]
-        {
-          (byte) ((longValue >> 56) & 0xFF),
-          (byte) ((longValue >> 48) & 0xFF),
-          (byte) ((longValue >> 40) & 0xFF),
-          (byte) ((longValue >> 32) & 0xFF),
-          (byte) ((longValue >> 24) & 0xFF),
-          (byte) ((longValue >> 16) & 0xFF),
-          (byte) ((longValue >>  8) & 0xFF),
-          (byte) (longValue & 0xFF)
-        };
-      }
-    }
-  }
-
-
-
-  /**
-   * Retrieves a byte array containing the encoded representation of the
-   * provided set of ASN.1 elements.
-   *
-   * @param  elements  The set of ASN.1 elements to encode into the value.
-   *
-   * @return  A byte array containing the encoded representation of the
-   *          provided set of ASN.1 elements.
-   */
-  public static byte[] encodeValue(ArrayList<ASN1Element> elements)
-  {
-    if (elements == null)
-    {
-      return NO_VALUE;
-    }
-
-
-    int totalLength = 0;
-    byte[][] encodedElements = new byte[elements.size()][];
-    for (int i=0; i < encodedElements.length; i++)
-    {
-      encodedElements[i] = elements.get(i).encode();
-      totalLength += encodedElements[i].length;
-    }
-
-    byte[] encodedValue = new byte[totalLength];
-    int startPos = 0;
-    for (byte[] b : encodedElements)
-    {
-      System.arraycopy(b, 0, encodedValue, startPos, b.length);
-      startPos += b.length;
-    }
-
-    return encodedValue;
-  }
-
-
-
-  /**
-   * Decodes the contents of the provided byte array as an ASN.1 element.
-   *
-   * @param  encodedElement  The byte array containing the ASN.1 element to
-   *                         decode.
-   *
-   * @return  The decoded ASN.1 element.
-   *
-   * @throws  ASN1Exception  If a problem occurs while attempting to decode the
-   *                         byte array as an ASN.1 element.
-   */
-  public static ASN1Element decode(byte[] encodedElement)
-         throws ASN1Exception
-  {
-    // First make sure that the array is not null and long enough to contain
-    // a valid ASN.1 element.
-    if (encodedElement == null)
-    {
-      Message message = ERR_ASN1_NULL_ELEMENT.get();
-      throw new ASN1Exception(message);
-    }
-    else if (encodedElement.length < 2)
-    {
-      Message message = ERR_ASN1_SHORT_ELEMENT.get(encodedElement.length);
-      throw new ASN1Exception(message);
-    }
-
-
-    // Next, decode the length.  This allows multi-byte lengths with up to four
-    // bytes used to indicate how many bytes are in the length.
-    byte type = encodedElement[0];
-    int length = (encodedElement[1] & 0x7F);
-    int valueStartPos = 2;
-    if (length != encodedElement[1])
-    {
-      int numLengthBytes = length;
-      if (numLengthBytes > 4)
-      {
-        Message message = ERR_ASN1_INVALID_NUM_LENGTH_BYTES.get(numLengthBytes);
-        throw new ASN1Exception(message);
-      }
-      else if (encodedElement.length < (2 + numLengthBytes))
-      {
-        Message message = ERR_ASN1_TRUNCATED_LENGTH.get(numLengthBytes);
-        throw new ASN1Exception(message);
-      }
-
-      length = 0x00;
-      valueStartPos = 2 + numLengthBytes;
-      for (int i=0; i < numLengthBytes; i++)
-      {
-        length = (length << 8) | (encodedElement[i+2] & 0xFF);
-      }
-    }
-
-
-    // Make sure that the number of bytes left is equal to the number of bytes
-    // in the value.
-    if ((encodedElement.length - valueStartPos) != length)
-    {
-      Message message = ERR_ASN1_LENGTH_MISMATCH.get(
-          length, (encodedElement.length - valueStartPos));
-      throw new ASN1Exception(message);
-    }
-
-
-    // Copy the value and construct the element to return.
-    byte[] value = new byte[length];
-    System.arraycopy(encodedElement, valueStartPos, value, 0, length);
-    return new ASN1Element(type, value);
-  }
-
-
-
-  /**
-   * Decodes the specified portion of the provided byte array as an ASN.1
-   * element.
-   *
-   * @param  encodedElement  The byte array containing the ASN.1 element to
-   *                         decode.
-   * @param  startPos        The position in the provided array at which to
-   *                         start decoding.
-   * @param  length          The number of bytes in the set of data to decode as
-   *                         an ASN.1 element.
-   *
-   * @return  The decoded ASN.1 element.
-   *
-   * @throws  ASN1Exception  If a problem occurs while attempting to decode the
-   *                         byte array as an ASN.1 element.
-   */
-  public static ASN1Element decode(byte[] encodedElement, int startPos,
-                                   int length)
-         throws ASN1Exception
-  {
-    // First make sure that the array is not null and long enough to contain
-    // a valid ASN.1 element.
-    if (encodedElement == null)
-    {
-      Message message = ERR_ASN1_NULL_ELEMENT.get();
-      throw new ASN1Exception(message);
-    }
-    else if ((startPos < 0) || (startPos+length > encodedElement.length) ||
-             (length < 2))
-    {
-      Message message = ERR_ASN1_SHORT_ELEMENT.get(encodedElement.length);
-      throw new ASN1Exception(message);
-    }
-
-
-    // Next, decode the length.  This allows multi-byte lengths with up to four
-    // bytes used to indicate how many bytes are in the length.
-    byte type = encodedElement[startPos];
-    int elementLength = (encodedElement[startPos+1] & 0x7F);
-    int valueStartPos = startPos + 2;
-    if (elementLength != encodedElement[startPos+1])
-    {
-      int numLengthBytes = elementLength;
-      if (numLengthBytes > 4)
-      {
-        Message message = ERR_ASN1_INVALID_NUM_LENGTH_BYTES.get(numLengthBytes);
-        throw new ASN1Exception(message);
-      }
-      else if (startPos+length < (2 + numLengthBytes))
-      {
-        Message message = ERR_ASN1_TRUNCATED_LENGTH.get(numLengthBytes);
-        throw new ASN1Exception(message);
-      }
-
-      elementLength = 0x00;
-      valueStartPos = startPos + 2 + numLengthBytes;
-      for (int i=0; i < numLengthBytes; i++)
-      {
-        elementLength = (elementLength << 8) | (encodedElement[i+2] & 0xFF);
-      }
-    }
-
-
-    // Make sure that the number of bytes left is equal to the number of bytes
-    // in the value.
-    if ((startPos+length - valueStartPos) != elementLength)
-    {
-      Message message = ERR_ASN1_LENGTH_MISMATCH.get(
-          elementLength, (startPos+length - valueStartPos));
-      throw new ASN1Exception(message);
-    }
-
-
-    // Copy the value and construct the element to return.
-    byte[] value = new byte[elementLength];
-    System.arraycopy(encodedElement, valueStartPos, value, 0, elementLength);
-    return new ASN1Element(type, value);
-  }
-
-
-
-  /**
-   * Decodes this ASN.1 element as an ASN.1 Boolean element.
-   *
-   * @return  The ASN.1 Boolean element decoded from this element.
-   *
-   * @throws  ASN1Exception  If a problem occurs while attempting to decode this
-   *                         element as an ASN.1 Boolean element.
-   */
-  public final ASN1Boolean decodeAsBoolean()
-         throws ASN1Exception
-  {
-    return ASN1Boolean.decodeAsBoolean(this);
-  }
-
-
-
-  /**
-   * Decodes this ASN.1 element as an ASN.1 enumerated element.
-   *
-   * @return  The ASN.1 enumerated element decoded from this element.
-   *
-   * @throws  ASN1Exception  If a problem occurs while attempting to decode this
-   *                         element as an ASN.1 enumerated element.
-   */
-  public final ASN1Enumerated decodeAsEnumerated()
-         throws ASN1Exception
-  {
-    return ASN1Enumerated.decodeAsEnumerated(this);
-  }
-
-
-
-  /**
-   * Decodes this ASN.1 element as an ASN.1 integer element.
-   *
-   * @return  The ASN.1 integer element decoded from this element.
-   *
-   * @throws  ASN1Exception  If a problem occurs while attempting to decode this
-   *                         element as an ASN.1 integer element.
-   */
-  public final ASN1Integer decodeAsInteger()
-         throws ASN1Exception
-  {
-    return ASN1Integer.decodeAsInteger(this);
-  }
-
-
-
-  /**
-   * Decodes this ASN.1 element as an ASN.1 long element.
-   *
-   * @return  The ASN.1 long element decoded from this element.
-   *
-   * @throws  ASN1Exception  If a problem occurs while attempting to decode this
-   *                         element as an ASN.1 long element.
-   */
-  public final ASN1Long decodeAsLong()
-         throws ASN1Exception
-  {
-    return ASN1Long.decodeAsLong(this);
-  }
-
-
-
-  /**
-   * Decodes this ASN.1 element as an ASN.1 null element.
-   *
-   * @return  The ASN.1 null element decoded from this element.
-   *
-   * @throws  ASN1Exception  If a problem occurs while attempting to decode this
-   *                         element as an ASN.1 null element.
-   */
-  public final ASN1Null decodeAsNull()
-         throws ASN1Exception
-  {
-    return ASN1Null.decodeAsNull(this);
-  }
-
-
-
-  /**
-   * Decodes this ASN.1 element as an ASN.1 octet string element.
-   *
-   * @return  The ASN.1 octet string element decoded from this element.
-   *
-   * @throws  ASN1Exception  If a problem occurs while attempting to decode this
-   *                         element as an ASN.1 octet string element.
-   */
-  public final ASN1OctetString decodeAsOctetString()
-         throws ASN1Exception
-  {
-    return ASN1OctetString.decodeAsOctetString(this);
-  }
-
-
-
-  /**
-   * Decodes this ASN.1 element as an ASN.1 sequence element.
-   *
-   * @return  The ASN.1 sequence element decoded from this element.
-   *
-   * @throws  ASN1Exception  If a problem occurs while attempting to decode this
-   *                         element as an ASN.1 sequence element.
-   */
-  public final ASN1Sequence decodeAsSequence()
-         throws ASN1Exception
-  {
-    return ASN1Sequence.decodeAsSequence(this);
-  }
-
-
-
-  /**
-   * Decodes this ASN.1 element as an ASN.1 set element.
-   *
-   * @return  The ASN.1 set element decoded from this element.
-   *
-   * @throws  ASN1Exception  If a problem occurs while attempting to decode this
-   *                         element as an ASN.1 set element.
-   */
-  public final ASN1Set decodeAsSet()
-         throws ASN1Exception
-  {
-    return ASN1Set.decodeAsSet(this);
-  }
-
-
-
-  /**
-   * Decodes the provided byte array as a collection of ASN.1 elements as would
-   * be found in the value of a sequence or set.
-   *
-   * @param  encodedElements  The byte array containing the data to decode.
-   *
-   * @return  The set of decoded ASN.1 elements.
-   *
-   * @throws  ASN1Exception  If a problem occurs while attempting to decode the
-   *                         set of ASN.1 elements from the provided byte array.
-   */
-  public static ArrayList<ASN1Element> decodeElements(byte[] encodedElements)
-         throws ASN1Exception
-  {
-    // Make sure that the element array is not null.
-    if (encodedElements == null)
-    {
-      Message message = ERR_ASN1_ELEMENT_SET_NULL.get();
-      throw new ASN1Exception(message);
-    }
-
-
-    // Iterate through the array and keep reading elements until the end is
-    // reached.
-    ArrayList<ASN1Element> elements = new ArrayList<ASN1Element>();
-    int startPos = 0;
-    while (startPos < encodedElements.length)
-    {
-      byte type = encodedElements[startPos++];
-      if (startPos >= encodedElements.length)
-      {
-        Message message = ERR_ASN1_ELEMENT_SET_NO_LENGTH.get();
-        throw new ASN1Exception(message);
-      }
-
-
-      byte firstLengthByte = encodedElements[startPos++];
-      int length = (byte) (firstLengthByte & 0x7F);
-      if (length != firstLengthByte)
-      {
-        int numLengthBytes = length;
-        if (numLengthBytes > 4)
-        {
-          Message message =
-              ERR_ASN1_ELEMENT_SET_INVALID_NUM_LENGTH_BYTES.get(numLengthBytes);
-          throw new ASN1Exception(message);
-        }
-
-        if (numLengthBytes > encodedElements.length - startPos)
-        {
-          Message message =
-              ERR_ASN1_ELEMENT_SET_TRUNCATED_LENGTH.get(numLengthBytes);
-          throw new ASN1Exception(message);
-        }
-
-        length = 0x00;
-        for (int i=0; i < numLengthBytes; i++)
-        {
-          length = (length << 8) | (encodedElements[startPos++] & 0xFF);
-        }
-      }
-
-
-      // Make sure that there are at least enough bytes to hold the value.
-      if (length > encodedElements.length - startPos)
-      {
-        Message message = ERR_ASN1_ELEMENT_SET_TRUNCATED_VALUE.get(
-            length, (encodedElements.length-startPos));
-        throw new ASN1Exception(message);
-      }
-
-
-      // Create the element and add it to the list.
-      byte[] value = new byte[length];
-      System.arraycopy(encodedElements, startPos, value, 0, length);
-      elements.add(new ASN1Element(type, value));
-      startPos += length;
-    }
-
-
-    return elements;
-  }
-
-
-
-  /**
-   * Retrieves the name of the protocol associated with this protocol element.
-   *
-   * @return  The name of the protocol associated with this protocol element.
-   */
-  public final String getProtocolElementName()
-  {
-    return "ASN.1";
-  }
-
-
-
-  /**
-   * Indicates whether the provided object is equal to this ASN.1 element.
-   *
-   * @param  o  The object for which to make the determination.
-   *
-   * @return  <CODE>true</CODE> if the provided object is an ASN.1 element that
-   *          is equal to this element, or <CODE>false</CODE> if not.  The
-   *          object will be considered equal if it is an ASN.1 element (or a
-   *          subclass) with the same type and encoded value.
-   */
-  @Override
-  public final boolean equals(Object o)
-  {
-    if (this == o)
-    {
-      return true;
-    }
-
-    if ((o == null) || (! (o instanceof ASN1Element)))
-    {
-      return false;
-    }
-
-    ASN1Element e = (ASN1Element) o;
-    return ((type == e.type) && Arrays.equals(value, e.value));
-  }
-
-
-
-  /**
-   * Indicates whether the provided ASN.1 element has a value that is equal to
-   * the value of this ASN.1 element.
-   *
-   * @param  element  The ASN.1 element whose value should be compared against
-   *                  the value of this element.
-   *
-   * @return  <CODE>true</CODE> if the values of the elements are equal, or
-   *          <CODE>false</CODE> if not.
-   */
-  public final boolean equalsIgnoreType(ASN1Element element)
-  {
-    return Arrays.equals(value, element.value);
-  }
-
-
-
-  /**
-   * Indicates whether the provided byte string has a value that is equal to
-   * the value of this ASN.1 element.
-   *
-   * @param  byteString  The byte string whose value should be compared against
-   *                     the value of this element.
-   *
-   * @return  <CODE>true</CODE> if the values are equal, or <CODE>false</CODE>
-   *          if not.
-   */
-  public final boolean equalsIgnoreType(ByteString byteString)
-  {
-    return Arrays.equals(value, byteString.value());
-  }
-
-
-
-  /**
-   * Indicates whether the provided ASN.1 element is equal to this element.
-   *
-   * @param  e  The ASN.1 element for which to make the determination.
-   *
-   * @return  <CODE>true</CODE> ASN.1 element is equal to this element,
-   *          or <CODE>false</CODE> if not.  The elements will be considered
-   *          equal if they have the same type and encoded value.
-   */
-  public final boolean equalsElement(ASN1Element e)
-  {
-    if (this == e)
-    {
-      return true;
-    }
-
-    if (e == null)
-    {
-      return false;
-    }
-
-    return ((type == e.type) && Arrays.equals(value, e.value));
-  }
-
-
-
-  /**
-   * Retrieves the hash code for this ASN.1 element.  It will be constructed
-   * from the sum of the type and up to the first twenty bytes of the value.
-   *
-   * @return  The hash code for this ASN.1 element.
-   */
-  @Override
-  public final int hashCode()
-  {
-    int hashCode = type;
-    int length = Math.min(20, value.length);
-    for (int i=0; i < length; i++)
-    {
-      hashCode += value[i];
-    }
-
-    return hashCode;
-  }
-
-
-
-  /**
-   * Retrieves a string representation of this ASN.1 element.
-   *
-   * @return  A string representation of this ASN.1 element.
-   */
-  @Override
-  public final String toString()
-  {
-    StringBuilder buffer = new StringBuilder();
-    toString(buffer);
-    return buffer.toString();
-  }
-
-
-
-  /**
-   * Appends a string representation of this ASN.1 element to the provided
-   * buffer.
-   *
-   * @param  buffer  The buffer to which the information should be appended.
-   */
-  public void toString(StringBuilder buffer)
-  {
-    buffer.append("ASN1Element(type=");
-    buffer.append(byteToHex(type));
-    buffer.append(", length=");
-    buffer.append(value.length);
-    buffer.append(")");
-  }
-
-
-
-  /**
-   * Appends a string representation of this protocol element to the provided
-   * buffer.
-   *
-   * @param  buffer  The buffer into which the string representation should be
-   *                 written.
-   * @param  indent  The number of spaces that should be used to indent the
-   *                 resulting string representation.
-   */
-  public void toString(StringBuilder buffer, int indent)
-  {
-    StringBuilder indentBuf = new StringBuilder(indent);
-    for (int i=0 ; i < indent; i++)
-    {
-      indentBuf.append(' ');
-    }
-
-    buffer.append(indentBuf);
-    buffer.append("ASN.1 Element");
-    buffer.append(EOL);
-
-    buffer.append(indentBuf);
-    buffer.append("  BER Type:  ");
-    buffer.append(byteToHex(type));
-    buffer.append(EOL);
-
-    buffer.append(indentBuf);
-    buffer.append("  Value (");
-    buffer.append(value.length);
-    buffer.append(" bytes)");
-    buffer.append(EOL);
-
-    byteArrayToHexPlusAscii(buffer, value, indent+2);
-  }
-}
-
diff --git a/opends/src/server/org/opends/server/protocols/asn1/ASN1Enumerated.java b/opends/src/server/org/opends/server/protocols/asn1/ASN1Enumerated.java
deleted file mode 100644
index 132c0a2..0000000
--- a/opends/src/server/org/opends/server/protocols/asn1/ASN1Enumerated.java
+++ /dev/null
@@ -1,358 +0,0 @@
-/*
- * CDDL HEADER START
- *
- * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
- *
- * You can obtain a copy of the license at
- * trunk/opends/resource/legal-notices/OpenDS.LICENSE
- * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
- * See the License for the specific language governing permissions
- * and limitations under the License.
- *
- * When distributing Covered Code, include this CDDL HEADER in each
- * file and include the License file at
- * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
- * add the following below this CDDL 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.server.protocols.asn1;
-import org.opends.messages.Message;
-
-
-
-import static org.opends.messages.ProtocolMessages.*;
-import static org.opends.server.protocols.asn1.ASN1Constants.*;
-import static org.opends.server.util.ServerConstants.*;
-import static org.opends.server.util.StaticUtils.*;
-
-
-
-/**
- * This class defines the data structures and methods to use when interacting
- * with ASN.1 enumerated elements.
- */
-@org.opends.server.types.PublicAPI(
-     stability=org.opends.server.types.StabilityLevel.UNCOMMITTED,
-     mayInstantiate=true,
-     mayExtend=false,
-     mayInvoke=true)
-public final class ASN1Enumerated
-       extends ASN1Element
-{
-  /**
-   * The serial version identifier required to satisfy the compiler because this
-   * class implements the <CODE>java.io.Serializable</CODE> interface.  This
-   * value was generated using the <CODE>serialver</CODE> command-line utility
-   * included with the Java SDK.
-   */
-  private static final long serialVersionUID = -8686345111964945130L;
-
-
-
-  // The integer value for this element.
-  private int intValue;
-
-
-
-
-  /**
-   * Creates a new ASN.1 enumerated element with the default type and the
-   * provided value.
-   *
-   * @param  intValue  The value for this ASN.1 enumerated element.
-   */
-  public ASN1Enumerated(int intValue)
-  {
-    super(UNIVERSAL_ENUMERATED_TYPE, encodeValue(intValue));
-
-
-    this.intValue = intValue;
-  }
-
-
-
-  /**
-   * Creates a new ASN.1 enumerated element with the specified type and value.
-   *
-   * @param  type      The BER type for this ASN.1 enumerated element.
-   * @param  intValue  The value for this ASN.1 enumerated element.
-   */
-  public ASN1Enumerated(byte type, int intValue)
-  {
-    super(type, encodeValue(intValue));
-
-
-    this.intValue = intValue;
-  }
-
-
-
-  /**
-   * Creates a new ASN.1 enumerated element with the specified type and value.
-   *
-   * @param  type      The BER type for this ASN.1 enumerated element.
-   * @param  value     The encoded value for this ASN.1 enumerated element.
-   * @param  intValue  The int value for this ASN.1 enumerated element.
-   */
-  private ASN1Enumerated(byte type, byte[] value, int intValue)
-  {
-    super(type, value);
-
-
-    this.intValue = intValue;
-  }
-
-
-
-  /**
-   * Retrieves the integer value for this ASN.1 enumerated element.
-   *
-   * @return  The integer value for this ASN.1 enumerated element.
-   */
-  public int intValue()
-  {
-    return intValue;
-  }
-
-
-
-  /**
-   * Specifies the integer value for this ASN.1 enumerated element.
-   *
-   * @param  intValue  The integer value for this ASN.1 enumerated element.
-   */
-  public void setValue(int intValue)
-  {
-    this.intValue = intValue;
-    setValueInternal(encodeValue(intValue));
-  }
-
-
-
-  /**
-   * Specifies the value for this ASN.1 enumerated element.
-   *
-   * @param  value  The encoded value for this ASN.1 enumerated element.
-   *
-   * @throws  ASN1Exception  If the provided array is null or is not between one
-   *                         and four bytes in length.
-   */
-  public void setValue(byte[] value)
-         throws ASN1Exception
-  {
-    if (value == null)
-    {
-      Message message = ERR_ASN1_ENUMERATED_SET_VALUE_NULL.get();
-      throw new ASN1Exception(message);
-    }
-
-    if ((value.length < 1) || (value.length > 4))
-    {
-      Message message =
-          ERR_ASN1_ENUMERATED_SET_VALUE_INVALID_LENGTH.get(value.length);
-      throw new ASN1Exception(message);
-    }
-
-    intValue = 0;
-    for (byte b : value)
-    {
-      intValue = (intValue << 8) | (b & 0xFF);
-    }
-
-    setValueInternal(value);
-  }
-
-
-
-  /**
-   * Decodes the provided ASN.1 element as an enumerated element.
-   *
-   * @param  element  The ASN.1 element to decode as an enumerated element.
-   *
-   * @return  The decoded ASN.1 enumerated element.
-   *
-   * @throws  ASN1Exception  If the provided ASN.1 element cannot be decoded as
-   *                         an enumerated element.
-   */
-  public static ASN1Enumerated decodeAsEnumerated(ASN1Element element)
-         throws ASN1Exception
-  {
-    if (element == null)
-    {
-      Message message = ERR_ASN1_ENUMERATED_DECODE_ELEMENT_NULL.get();
-      throw new ASN1Exception(message);
-    }
-
-    byte[] value = element.value();
-    if ((value.length < 1) || (value.length > 4))
-    {
-      Message message =
-          ERR_ASN1_ENUMERATED_DECODE_ELEMENT_INVALID_LENGTH.get(value.length);
-      throw new ASN1Exception(message);
-    }
-
-    int intValue = 0;
-    for (byte b : value)
-    {
-      intValue = (intValue << 8) | (b & 0xFF);
-    }
-
-    return new ASN1Enumerated(element.getType(), value, intValue);
-  }
-
-
-
-  /**
-   * Decodes the provided byte array as an ASN.1 enumerated element.
-   *
-   * @param  encodedElement  The byte array to decode as an ASN.1 enumerated
-   *                         element.
-   *
-   * @return  The decoded ASN.1 enumerated element.
-   *
-   * @throws  ASN1Exception  If the provided byte array cannot be decoded as an
-   *                         ASN.1 enumerated element.
-   */
-  public static ASN1Enumerated decodeAsEnumerated(byte[] encodedElement)
-         throws ASN1Exception
-  {
-    // First make sure that the array is not null and long enough to contain
-    // a valid ASN.1 enumerated element.
-    if (encodedElement == null)
-    {
-      Message message = ERR_ASN1_ENUMERATED_DECODE_ARRAY_NULL.get();
-      throw new ASN1Exception(message);
-    }
-
-    if (encodedElement.length < 3)
-    {
-      Message message =
-          ERR_ASN1_ENUMERATED_SHORT_ELEMENT.get(encodedElement.length);
-      throw new ASN1Exception(message);
-    }
-
-
-    // Next, decode the length.  This allows multi-byte lengths with up to four
-    // bytes used to indicate how many bytes are in the length.
-    byte type = encodedElement[0];
-    int length = (encodedElement[1] & 0x7F);
-    int valueStartPos = 2;
-    if (length != encodedElement[1])
-    {
-      int numLengthBytes = length;
-      if (numLengthBytes > 4)
-      {
-        Message message = ERR_ASN1_INVALID_NUM_LENGTH_BYTES.get(numLengthBytes);
-        throw new ASN1Exception(message);
-      }
-      else if (encodedElement.length < (2 + numLengthBytes))
-      {
-        Message message = ERR_ASN1_TRUNCATED_LENGTH.get(numLengthBytes);
-        throw new ASN1Exception(message);
-      }
-
-      length = 0x00;
-      valueStartPos = 2 + numLengthBytes;
-      for (int i=0; i < numLengthBytes; i++)
-      {
-        length = (length << 8) | (encodedElement[i+2] & 0xFF);
-      }
-    }
-
-
-    // Make sure that the number of bytes left is equal to the number of bytes
-    // in the value.
-    if ((encodedElement.length - valueStartPos) != length)
-    {
-      Message message = ERR_ASN1_LENGTH_MISMATCH.get(
-          length, (encodedElement.length - valueStartPos));
-      throw new ASN1Exception(message);
-    }
-
-
-    // Make sure that the decoded length is between 1 and 4 bytes.
-    if ((length < 1) || (length > 4))
-    {
-      Message message =
-          ERR_ASN1_ENUMERATED_DECODE_ARRAY_INVALID_LENGTH.get(length);
-      throw new ASN1Exception(message);
-    }
-
-
-    // Copy the value and construct the element to return.
-    byte[] value = new byte[length];
-    System.arraycopy(encodedElement, valueStartPos, value, 0, length);
-
-    int intValue = 0;
-    for (byte b : value)
-    {
-      intValue = (intValue << 8) | (b & 0xFF);
-    }
-
-    return new ASN1Enumerated(type, value, intValue);
-  }
-
-
-
-  /**
-   * Appends a string representation of this ASN.1 enumerated element to the
-   * provided buffer.
-   *
-   * @param  buffer  The buffer to which the information should be appended.
-   */
-  public void toString(StringBuilder buffer)
-  {
-    buffer.append("ASN1Enumerated(type=");
-    buffer.append(byteToHex(getType()));
-    buffer.append(", value=");
-    buffer.append(intValue);
-    buffer.append(")");
-  }
-
-
-
-  /**
-   * Appends a string representation of this protocol element to the provided
-   * buffer.
-   *
-   * @param  buffer  The buffer into which the string representation should be
-   *                 written.
-   * @param  indent  The number of spaces that should be used to indent the
-   *                 resulting string representation.
-   */
-  public void toString(StringBuilder buffer, int indent)
-  {
-    StringBuilder indentBuf = new StringBuilder(indent);
-    for (int i=0 ; i < indent; i++)
-    {
-      indentBuf.append(' ');
-    }
-
-    buffer.append(indentBuf);
-    buffer.append("ASN.1 Enumerated");
-    buffer.append(EOL);
-
-    buffer.append(indentBuf);
-    buffer.append("  BER Type:  ");
-    buffer.append(byteToHex(getType()));
-    buffer.append(EOL);
-
-    buffer.append(indentBuf);
-    buffer.append("  Value:  ");
-    buffer.append(intValue);
-    buffer.append(" (");
-    buffer.append(bytesToHex(value()));
-    buffer.append(")");
-    buffer.append(EOL);
-  }
-}
-
diff --git a/opends/src/server/org/opends/server/protocols/asn1/ASN1InputStreamReader.java b/opends/src/server/org/opends/server/protocols/asn1/ASN1InputStreamReader.java
new file mode 100644
index 0000000..7124abb
--- /dev/null
+++ b/opends/src/server/org/opends/server/protocols/asn1/ASN1InputStreamReader.java
@@ -0,0 +1,793 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License").  You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE
+ * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
+ * add the following below this CDDL 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.server.protocols.asn1;
+
+import static org.opends.messages.ProtocolMessages.*;
+import static org.opends.server.loggers.debug.DebugLogger.*;
+import static org.opends.server.protocols.ldap.LDAPConstants.*;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.LinkedList;
+
+import org.opends.messages.Message;
+import org.opends.server.loggers.debug.DebugTracer;
+import org.opends.server.types.ByteString;
+import org.opends.server.types.ByteStringBuilder;
+import org.opends.server.types.DebugLogLevel;
+import org.opends.server.util.SizeLimitInputStream;
+
+/**
+ * An ASN1Reader that reads from an input stream.
+ */
+final class ASN1InputStreamReader implements ASN1Reader
+{
+
+  private static final DebugTracer TRACER = getTracer();
+
+  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(InputStream stream, int maxElementSize)
+  {
+    this.in = stream;
+    this.streamStack = new LinkedList<InputStream>();
+    this.buffer = new byte[512];
+    this.maxElementSize = maxElementSize;
+  }
+
+  /**
+   * Determines if a complete ASN.1 element is ready to be read from the
+   * input stream without blocking.
+   *
+   * @return <code>true</code> if another complete element is available or
+   *         <code>false</code> otherwise.
+   * @throws ASN1Exception If an error occurs while trying to decode
+   *                       an ASN1 element.
+   */
+  public boolean elementAvailable() throws ASN1Exception
+  {
+    try
+    {
+      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();
+    }
+    catch(IOException ioe)
+    {
+      Message message =
+          ERR_ASN1_READ_ERROR.get(ioe.toString());
+      throw new ASN1Exception(message, ioe);
+    }
+  }
+
+  /**
+   * Determines if the input stream contains at least one ASN.1 element to
+   * be read. This method will block until enough data is available on the
+   * stream to determine if an element is available.
+   *
+   * @return <code>true</code> if another element is available or
+   *         <code>false</code> otherwise.
+   * @throws ASN1Exception If an error occurs while trying to decode
+   *                       an ASN1 element.
+   */
+  public boolean hasNextElement() throws ASN1Exception
+  {
+    try
+    {
+      if(!streamStack.isEmpty())
+      {
+        // We are reading a sub sequence. Return true as long as we haven't
+        // exausted the size limit for the sub sequence sub input stream.
+        SizeLimitInputStream subSq = (SizeLimitInputStream)in;
+        return (subSq.getSizeLimit() - subSq.getBytesRead() > 0);
+      }
+
+      return state != ELEMENT_READ_STATE_NEED_TYPE ||
+          needTypeState(true, false);
+    }
+    catch(IOException ioe)
+    {
+      Message message =
+          ERR_ASN1_READ_ERROR.get(ioe.toString());
+      throw new ASN1Exception(message, ioe);
+    }
+  }
+
+  /**
+   * 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.
+   * @throws ASN1Exception If an error occurs while trying to decode
+   *                       an ASN1 element.
+   */
+  private boolean needTypeState(boolean isBlocking, boolean throwEofException)
+      throws IOException, ASN1Exception
+  {
+    // Read just the type.
+    if(!isBlocking && in.available() <= 0)
+    {
+      return false;
+    }
+
+    int type = in.read();
+    if(type == -1)
+    {
+      if(throwEofException)
+      {
+        Message message =
+            ERR_ASN1_TRUCATED_TYPE_BYTE.get();
+        throw new ASN1Exception(message);
+      }
+      return false;
+    }
+
+    peekType = (byte)type;
+    state = ELEMENT_READ_STATE_NEED_FIRST_LENGTH_BYTE;
+    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.
+   * @throws ASN1Exception If an error occurs while trying to decode
+   *                       an ASN1 element.
+   */
+  private boolean needFirstLengthByteState(boolean isBlocking,
+                                           boolean throwEofException)
+      throws IOException, ASN1Exception
+  {
+    if(!isBlocking && in.available() <= 0)
+    {
+      return false;
+    }
+
+    int readByte = in.read();
+    if(readByte == -1)
+    {
+      if(throwEofException)
+      {
+        Message message =
+            ERR_ASN1_TRUNCATED_LENGTH_BYTE.get();
+        throw new ASN1Exception(message);
+      }
+      return false;
+    }
+    peekLength = (readByte & 0x7F);
+    if (peekLength != readByte)
+    {
+      lengthBytesNeeded = peekLength;
+      if (lengthBytesNeeded > 4)
+      {
+        Message message =
+            ERR_ASN1_INVALID_NUM_LENGTH_BYTES.get(lengthBytesNeeded);
+        throw new ASN1Exception(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)
+          {
+            Message message =
+                ERR_ASN1_TRUNCATED_LENGTH_BYTES.get(lengthBytesNeeded);
+            throw new ASN1Exception(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))
+    {
+      Message m = ERR_LDAP_CLIENT_DECODE_MAX_REQUEST_SIZE_EXCEEDED.get(
+          peekLength, maxElementSize);
+      throw new ASN1Exception(m);
+    }
+    state = ELEMENT_READ_STATE_NEED_VALUE_BYTES;
+    return true;
+  }
+
+  /**
+   * 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.
+   * @throws ASN1Exception If an error occurs while trying to decode
+   *                       an ASN1 element.
+   */
+  private boolean needAdditionalLengthBytesState(boolean isBlocking,
+                                                 boolean throwEofException)
+      throws IOException, ASN1Exception
+  {
+    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)
+        {
+          Message message =
+              ERR_ASN1_TRUNCATED_LENGTH_BYTES.get(lengthBytesNeeded);
+          throw new ASN1Exception(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))
+    {
+      Message m = ERR_LDAP_CLIENT_DECODE_MAX_REQUEST_SIZE_EXCEEDED.get(
+          peekLength, maxElementSize);
+      throw new ASN1Exception(m);
+    }
+    state = ELEMENT_READ_STATE_NEED_VALUE_BYTES;
+    return true;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  public byte peekType() throws ASN1Exception
+  {
+    try
+    {
+      if(state == ELEMENT_READ_STATE_NEED_TYPE)
+      {
+        needTypeState(true, true);
+      }
+
+      return peekType;
+    }
+    catch(IOException ioe)
+    {
+      Message message =
+          ERR_ASN1_READ_ERROR.get(ioe.toString());
+      throw new ASN1Exception(message, ioe);
+    }
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  public int peekLength() throws ASN1Exception
+  {
+    peekType();
+
+    try
+    {
+      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;
+    }
+    catch(IOException ioe)
+    {
+      Message message =
+          ERR_ASN1_READ_ERROR.get(ioe.toString());
+      throw new ASN1Exception(message, ioe);
+    }
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  public boolean readBoolean() throws ASN1Exception
+  {
+    // Read the header if haven't done so already
+    peekLength();
+
+    if (peekLength != 1)
+    {
+      Message message =
+          ERR_ASN1_BOOLEAN_INVALID_LENGTH.get(peekLength);
+      throw new ASN1Exception(message);
+    }
+
+    try
+    {
+      int readByte = in.read();
+      if(readByte == -1)
+      {
+        Message message = ERR_ASN1_BOOLEAN_TRUNCATED_VALUE.get(peekLength);
+        throw new ASN1Exception(message);
+      }
+
+      if(debugEnabled())
+      {
+        TRACER.debugProtocolElement(DebugLogLevel.VERBOSE,
+            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;
+    }
+    catch(IOException ioe)
+    {
+      Message message =
+          ERR_ASN1_READ_ERROR.get(ioe.toString());
+      throw new ASN1Exception(message, ioe);
+    }
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  public long readInteger() throws ASN1Exception
+  {
+    // Read the header if haven't done so already
+    peekLength();
+
+    if ((peekLength < 1) || (peekLength > 8))
+    {
+      Message message =
+          ERR_ASN1_INTEGER_INVALID_LENGTH.get(peekLength);
+      throw new ASN1Exception(message);
+    }
+
+    try
+    {
+      if(peekLength > 4)
+      {
+        long longValue = 0;
+        for (int i=0; i < peekLength; i++)
+        {
+          int readByte = in.read();
+          if(readByte == -1)
+          {
+            Message message =
+                ERR_ASN1_INTEGER_TRUNCATED_VALUE.get(peekLength);
+            throw new ASN1Exception(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++)
+        {
+          int readByte = in.read();
+          if(readByte == -1)
+          {
+            Message message =
+                ERR_ASN1_INTEGER_TRUNCATED_VALUE.get(peekLength);
+            throw new ASN1Exception(message);
+          }
+          if (i == 0 && ((byte)readByte) < 0)
+          {
+            intValue = 0xFFFFFFFF;
+          }
+          intValue = (intValue << 8) | (readByte & 0xFF);
+        }
+
+        if(debugEnabled())
+        {
+          TRACER.debugProtocolElement(DebugLogLevel.VERBOSE,
+              String.format("READ ASN.1 INTEGER(type=0x%x, length=%d, " +
+                  "value=%d)", peekType, peekLength, intValue));
+        }
+
+        state = ELEMENT_READ_STATE_NEED_TYPE;
+        return intValue;
+      }
+    }
+    catch(IOException ioe)
+    {
+      Message message =
+          ERR_ASN1_READ_ERROR.get(ioe.toString());
+      throw new ASN1Exception(message, ioe);
+    }
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  public void readNull() throws ASN1Exception
+  {
+    // Read the header if haven't done so already
+    peekLength();
+
+    // Make sure that the decoded length is exactly zero byte.
+    if (peekLength != 0)
+    {
+      Message message =
+          ERR_ASN1_NULL_INVALID_LENGTH.get(peekLength);
+      throw new ASN1Exception(message);
+    }
+
+    if(debugEnabled())
+    {
+      TRACER.debugProtocolElement(DebugLogLevel.VERBOSE,
+          String.format("READ ASN.1 NULL(type=0x%x, length=%d)",
+              peekType, peekLength));
+    }
+
+    state = ELEMENT_READ_STATE_NEED_TYPE;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  public ByteString readOctetString() throws ASN1Exception {
+    // Read the header if haven't done so already
+    peekLength();
+
+    if(peekLength == 0)
+    {
+      state = ELEMENT_READ_STATE_NEED_TYPE;
+      return ByteString.empty();
+    }
+
+    try
+    {
+      // Copy the value and construct the element to return.
+      byte[] value = new byte[peekLength];
+      int bytesNeeded = peekLength;
+      int bytesRead;
+      while(bytesNeeded > 0)
+      {
+        bytesRead = in.read(value, peekLength - bytesNeeded, bytesNeeded);
+        if(bytesRead < 0)
+        {
+          Message message =
+            ERR_ASN1_OCTET_STRING_TRUNCATED_VALUE.get(peekLength);
+          throw new ASN1Exception(message);
+        }
+
+        bytesNeeded -= bytesRead;
+      }
+
+      if(debugEnabled())
+      {
+        TRACER.debugProtocolElement(DebugLogLevel.VERBOSE,
+            String.format("READ ASN.1 OCTETSTRING(type=0x%x, length=%d)",
+                peekType, peekLength));
+      }
+
+      state = ELEMENT_READ_STATE_NEED_TYPE;
+      return ByteString.wrap(value);
+    }
+    catch(IOException ioe)
+    {
+      Message message =
+          ERR_ASN1_READ_ERROR.get(ioe.toString());
+      throw new ASN1Exception(message, ioe);
+    }
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  public String readOctetStringAsString() throws ASN1Exception
+  {
+    // We could cache the UTF-8 CharSet if performance proves to be an
+    // issue.
+    return readOctetStringAsString("UTF-8");
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  public String readOctetStringAsString(String charSet) throws ASN1Exception
+  {
+    // 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];
+    }
+
+    try
+    {
+      int bytesNeeded = peekLength;
+      int bytesRead;
+      while(bytesNeeded > 0)
+      {
+        bytesRead = in.read(buffer, peekLength - bytesNeeded, bytesNeeded);
+        if(bytesRead < 0)
+        {
+          Message message =
+            ERR_ASN1_OCTET_STRING_TRUNCATED_VALUE.get(peekLength);
+          throw new ASN1Exception(message);
+        }
+        bytesNeeded -= bytesRead;
+      }
+
+      state = ELEMENT_READ_STATE_NEED_TYPE;
+    }
+    catch(IOException ioe)
+    {
+      Message message =
+          ERR_ASN1_READ_ERROR.get(ioe.toString());
+      throw new ASN1Exception(message, ioe);
+    }
+
+    String str;
+    try
+    {
+      str = new String(buffer, 0, peekLength, charSet);
+    }
+    catch (Exception e)
+    {
+      if (debugEnabled())
+      {
+        TRACER.debugCaught(DebugLogLevel.ERROR, e);
+      }
+
+      str = new String(buffer, 0, peekLength);
+    }
+
+    if(debugEnabled())
+    {
+      TRACER.debugProtocolElement(DebugLogLevel.VERBOSE,
+          String.format("READ ASN.1 OCTETSTRING(type=0x%x, length=%d, " +
+              "value=%s)", peekType, peekLength, str));
+    }
+
+    return str;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  public void readOctetString(ByteStringBuilder buffer) throws ASN1Exception
+  {
+    // Read the header if haven't done so already
+    peekLength();
+
+    if(peekLength == 0)
+    {
+      state = ELEMENT_READ_STATE_NEED_TYPE;
+      return;
+    }
+
+    try
+    {
+      // Copy the value and construct the element to return.
+      int bytesNeeded = peekLength;
+      int bytesRead;
+      while(bytesNeeded > 0)
+      {
+        bytesRead = buffer.append(in, bytesNeeded);
+        if(bytesRead < 0)
+        {
+          Message message =
+            ERR_ASN1_OCTET_STRING_TRUNCATED_VALUE.get(peekLength);
+          throw new ASN1Exception(message);
+        }
+        bytesNeeded -= bytesRead;
+      }
+
+      if(debugEnabled())
+      {
+        TRACER.debugProtocolElement(DebugLogLevel.VERBOSE,
+            String.format("READ ASN.1 OCTETSTRING(type=0x%x, length=%d)",
+                peekType, peekLength));
+      }
+
+      state = ELEMENT_READ_STATE_NEED_TYPE;
+    }
+    catch(IOException ioe)
+    {
+      Message message =
+          ERR_ASN1_READ_ERROR.get(ioe.toString());
+      throw new ASN1Exception(message, ioe);
+    }
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  public void readStartSequence() throws ASN1Exception
+  {
+    // Read the header if haven't done so already
+    peekLength();
+
+    SizeLimitInputStream subStream =
+        new SizeLimitInputStream(in, peekLength);
+
+    if(debugEnabled())
+    {
+      TRACER.debugProtocolElement(DebugLogLevel.VERBOSE,
+          String.format("READ ASN.1 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 readEndSequence() throws ASN1Exception
+  {
+    if(streamStack.isEmpty())
+    {
+      Message message = ERR_ASN1_SEQUENCE_READ_NOT_STARTED.get();
+      throw new ASN1Exception(message);
+    }
+
+    // If not everything was read, throw error
+    SizeLimitInputStream subSq = (SizeLimitInputStream)in;
+    if(subSq.getSizeLimit() - subSq.getBytesRead() > 0)
+    {
+      Message message =
+          ERR_ASN1_SEQUENCE_READ_NOT_ENDED.get(subSq.getSizeLimit() -
+              subSq.getBytesRead(), subSq.getSizeLimit());
+      throw new ASN1Exception(message);
+    }
+
+    in = streamStack.removeFirst();
+
+    // Reset the state
+    state = ELEMENT_READ_STATE_NEED_TYPE;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  public void skipElement() throws ASN1Exception
+  {
+    // Read the header if haven't done so already
+    peekLength();
+
+    try
+    {
+      long bytesSkipped = in.skip(peekLength);
+      if(bytesSkipped != peekLength)
+      {
+        Message message =
+            ERR_ASN1_SKIP_TRUNCATED_VALUE.get(peekLength);
+        throw new ASN1Exception(message);
+      }
+      state = ELEMENT_READ_STATE_NEED_TYPE;
+    }
+    catch(IOException ioe)
+    {
+      Message message =
+          ERR_ASN1_READ_ERROR.get(ioe.toString());
+      throw new ASN1Exception(message, ioe);
+    }
+  }
+
+  /**
+   * Closes this ASN.1 reader and the underlying stream.
+   *
+   * @throws IOException if an I/O error occurs
+   */
+  public void close() throws IOException
+  {
+    // Calling close of SizeLimitInputStream should close the parent stream.
+    in.close();
+    streamStack.clear();
+  }
+}
diff --git a/opends/src/server/org/opends/server/protocols/asn1/ASN1Integer.java b/opends/src/server/org/opends/server/protocols/asn1/ASN1Integer.java
deleted file mode 100644
index 43c3f60..0000000
--- a/opends/src/server/org/opends/server/protocols/asn1/ASN1Integer.java
+++ /dev/null
@@ -1,373 +0,0 @@
-/*
- * CDDL HEADER START
- *
- * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
- *
- * You can obtain a copy of the license at
- * trunk/opends/resource/legal-notices/OpenDS.LICENSE
- * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
- * See the License for the specific language governing permissions
- * and limitations under the License.
- *
- * When distributing Covered Code, include this CDDL HEADER in each
- * file and include the License file at
- * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
- * add the following below this CDDL 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.server.protocols.asn1;
-import org.opends.messages.Message;
-
-
-
-import static org.opends.messages.ProtocolMessages.*;
-import static org.opends.server.protocols.asn1.ASN1Constants.*;
-import static org.opends.server.util.ServerConstants.*;
-import static org.opends.server.util.StaticUtils.*;
-
-
-
-/**
- * This class defines the data structures and methods to use when interacting
- * with ASN.1 integer elements.
- */
-@org.opends.server.types.PublicAPI(
-     stability=org.opends.server.types.StabilityLevel.UNCOMMITTED,
-     mayInstantiate=true,
-     mayExtend=false,
-     mayInvoke=true)
-public final class ASN1Integer
-       extends ASN1Element
-{
-  /**
-   * The serial version identifier required to satisfy the compiler because this
-   * class implements the <CODE>java.io.Serializable</CODE> interface.  This
-   * value was generated using the <CODE>serialver</CODE> command-line utility
-   * included with the Java SDK.
-   */
-  private static final long serialVersionUID = 7352628713339746558L;
-
-
-
-  // The integer value for this element.
-  private int intValue;
-
-
-
-
-  /**
-   * Creates a new ASN.1 integer element with the default type and the provided
-   * value.
-   *
-   * @param  intValue  The value for this ASN.1 integer element.
-   */
-  public ASN1Integer(int intValue)
-  {
-    super(UNIVERSAL_INTEGER_TYPE, encodeValue(intValue));
-
-
-    this.intValue = intValue;
-  }
-
-
-
-  /**
-   * Creates a new ASN.1 integer element with the specified type and value.
-   *
-   * @param  type      The BER type for this ASN.1 integer element.
-   * @param  intValue  The value for this ASN.1 integer element.
-   */
-  public ASN1Integer(byte type, int intValue)
-  {
-    super(type, encodeValue(intValue));
-
-
-    this.intValue = intValue;
-  }
-
-
-
-  /**
-   * Creates a new ASN.1 integer element with the specified type and value.
-   *
-   * @param  type      The BER type for this ASN.1 integer element.
-   * @param  value     The encoded value for this ASN.1 integer element.
-   * @param  intValue  The int value for this ASN.1 integer element.
-   */
-  private ASN1Integer(byte type, byte[] value, int intValue)
-  {
-    super(type, value);
-
-
-    this.intValue = intValue;
-  }
-
-
-
-  /**
-   * Retrieves the integer value for this ASN.1 integer element.
-   *
-   * @return  The integer value for this ASN.1 integer element.
-   */
-  public int intValue()
-  {
-    return intValue;
-  }
-
-
-
-  /**
-   * Specifies the integer value for this ASN.1 integer element.
-   *
-   * @param  intValue  The integer value for this ASN.1 integer element.
-   */
-  public void setValue(int intValue)
-  {
-    this.intValue = intValue;
-    setValueInternal(encodeValue(intValue));
-  }
-
-
-
-  /**
-   * Specifies the value for this ASN.1 integer element.
-   *
-   * @param  value  The encoded value for this ASN.1 integer element.
-   *
-   * @throws  ASN1Exception  If the provided array is null or is not between one
-   *                         and four bytes in length.
-   */
-  @Override
-  public void setValue(byte[] value)
-         throws ASN1Exception
-  {
-    if (value == null)
-    {
-      Message message = ERR_ASN1_INTEGER_SET_VALUE_NULL.get();
-      throw new ASN1Exception(message);
-    }
-
-    if ((value.length < 1) || (value.length > 4))
-    {
-      Message message =
-          ERR_ASN1_INTEGER_SET_VALUE_INVALID_LENGTH.get(value.length);
-      throw new ASN1Exception(message);
-    }
-
-    intValue = 0;
-    for (byte b : value)
-    {
-      intValue = (intValue << 8) | (b & 0xFF);
-    }
-
-    setValueInternal(value);
-  }
-
-
-
-  /**
-   * Decodes the provided ASN.1 element as an integer element.
-   *
-   * @param  element  The ASN.1 element to decode as an integer element.
-   *
-   * @return  The decoded ASN.1 integer element.
-   *
-   * @throws  ASN1Exception  If the provided ASN.1 element cannot be decoded as
-   *                         an integer element.
-   */
-  public static ASN1Integer decodeAsInteger(ASN1Element element)
-         throws ASN1Exception
-  {
-    if (element == null)
-    {
-      Message message = ERR_ASN1_INTEGER_DECODE_ELEMENT_NULL.get();
-      throw new ASN1Exception(message);
-    }
-
-    byte[] value = element.value();
-    if ((value.length < 1) || (value.length > 4))
-    {
-      Message message =
-          ERR_ASN1_INTEGER_DECODE_ELEMENT_INVALID_LENGTH.get(value.length);
-      throw new ASN1Exception(message);
-    }
-
-    int intValue = 0;
-
-    if (value[0] < 0)
-    {
-      intValue = 0xFFFFFFFF;
-    }
-
-    for (byte b : value)
-    {
-      intValue = (intValue << 8) | (b & 0xFF);
-    }
-
-    return new ASN1Integer(element.getType(), value, intValue);
-  }
-
-
-
-  /**
-   * Decodes the provided byte array as an ASN.1 integer element.
-   *
-   * @param  encodedElement  The byte array to decode as an ASN.1 integer
-   *                         element.
-   *
-   * @return  The decoded ASN.1 integer element.
-   *
-   * @throws  ASN1Exception  If the provided byte array cannot be decoded as an
-   *                         ASN.1 integer element.
-   */
-  public static ASN1Integer decodeAsInteger(byte[] encodedElement)
-         throws ASN1Exception
-  {
-    // First make sure that the array is not null and long enough to contain
-    // a valid ASN.1 integer element.
-    if (encodedElement == null)
-    {
-      Message message = ERR_ASN1_INTEGER_DECODE_ARRAY_NULL.get();
-      throw new ASN1Exception(message);
-    }
-
-    if (encodedElement.length < 3)
-    {
-      Message message =
-          ERR_ASN1_INTEGER_SHORT_ELEMENT.get(encodedElement.length);
-      throw new ASN1Exception(message);
-    }
-
-
-    // Next, decode the length.  This allows multi-byte lengths with up to four
-    // bytes used to indicate how many bytes are in the length.
-    byte type = encodedElement[0];
-    int length = (encodedElement[1] & 0x7F);
-    int valueStartPos = 2;
-    if (length != encodedElement[1])
-    {
-      int numLengthBytes = length;
-      if (numLengthBytes > 4)
-      {
-        Message message = ERR_ASN1_INVALID_NUM_LENGTH_BYTES.get(numLengthBytes);
-        throw new ASN1Exception(message);
-      }
-      else if (encodedElement.length < (2 + numLengthBytes))
-      {
-        Message message = ERR_ASN1_TRUNCATED_LENGTH.get(numLengthBytes);
-        throw new ASN1Exception(message);
-      }
-
-      length = 0x00;
-      valueStartPos = 2 + numLengthBytes;
-      for (int i=0; i < numLengthBytes; i++)
-      {
-        length = (length << 8) | (encodedElement[i+2] & 0xFF);
-      }
-    }
-
-
-    // Make sure that the number of bytes left is equal to the number of bytes
-    // in the value.
-    if ((encodedElement.length - valueStartPos) != length)
-    {
-      Message message = ERR_ASN1_LENGTH_MISMATCH.get(
-          length, (encodedElement.length - valueStartPos));
-      throw new ASN1Exception(message);
-    }
-
-
-    // Make sure that the decoded length is between 1 and 4 bytes.
-    if ((length < 1) || (length > 4))
-    {
-      Message message =
-          ERR_ASN1_INTEGER_DECODE_ARRAY_INVALID_LENGTH.get(length);
-      throw new ASN1Exception(message);
-    }
-
-
-    // Copy the value and construct the element to return.
-    byte[] value = new byte[length];
-    System.arraycopy(encodedElement, valueStartPos, value, 0, length);
-
-    int intValue = 0;
-
-    if (value[0] < 0)
-    {
-      intValue = 0xFFFFFFFF;
-    }
-
-    for (byte b : value)
-    {
-      intValue = (intValue << 8) | (b & 0xFF);
-    }
-
-    return new ASN1Integer(type, value, intValue);
-  }
-
-
-
-  /**
-   * Appends a string representation of this ASN.1 integer element to the
-   * provided buffer.
-   *
-   * @param  buffer  The buffer to which the information should be appended.
-   */
-  @Override
-  public void toString(StringBuilder buffer)
-  {
-    buffer.append("ASN1Integer(type=");
-    buffer.append(byteToHex(getType()));
-    buffer.append(", value=");
-    buffer.append(intValue);
-    buffer.append(")");
-  }
-
-
-
-  /**
-   * Appends a string representation of this protocol element to the provided
-   * buffer.
-   *
-   * @param  buffer  The buffer into which the string representation should be
-   *                 written.
-   * @param  indent  The number of spaces that should be used to indent the
-   *                 resulting string representation.
-   */
-  @Override
-  public void toString(StringBuilder buffer, int indent)
-  {
-    StringBuilder indentBuf = new StringBuilder(indent);
-    for (int i=0 ; i < indent; i++)
-    {
-      indentBuf.append(' ');
-    }
-
-    buffer.append(indentBuf);
-    buffer.append("ASN.1 Integer");
-    buffer.append(EOL);
-
-    buffer.append(indentBuf);
-    buffer.append("  BER Type:  ");
-    buffer.append(byteToHex(getType()));
-    buffer.append(EOL);
-
-    buffer.append(indentBuf);
-    buffer.append("  Value:  ");
-    buffer.append(intValue);
-    buffer.append(" (");
-    buffer.append(bytesToHex(value()));
-    buffer.append(")");
-    buffer.append(EOL);
-  }
-}
-
diff --git a/opends/src/server/org/opends/server/protocols/asn1/ASN1Long.java b/opends/src/server/org/opends/server/protocols/asn1/ASN1Long.java
deleted file mode 100644
index 6bfc595..0000000
--- a/opends/src/server/org/opends/server/protocols/asn1/ASN1Long.java
+++ /dev/null
@@ -1,384 +0,0 @@
-/*
- * CDDL HEADER START
- *
- * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
- *
- * You can obtain a copy of the license at
- * trunk/opends/resource/legal-notices/OpenDS.LICENSE
- * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
- * See the License for the specific language governing permissions
- * and limitations under the License.
- *
- * When distributing Covered Code, include this CDDL HEADER in each
- * file and include the License file at
- * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
- * add the following below this CDDL 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.server.protocols.asn1;
-import org.opends.messages.Message;
-
-
-
-import static org.opends.messages.ProtocolMessages.*;
-import static org.opends.server.protocols.asn1.ASN1Constants.*;
-import static org.opends.server.util.ServerConstants.*;
-import static org.opends.server.util.StaticUtils.*;
-
-
-
-/**
- * This class defines the data structures and methods to use when interacting
- * with ASN.1 integer elements that may need to hold values greater than will
- * fit in the scope of a Java <CODE>int</CODE> structure.
- * <BR><BR>
- * Note that the difference between the <CODE>ASN1Integer</CODE> and
- * <CODE>ASN1Long</CODE> classes is purely artificial.  The ASN.1 specification
- * does not define any size limits for integer values, but the
- * <CODE>ASN1Integer</CODE> class uses an <CODE>int</CODE> data type behind the
- * scenes and therefore is only capable of representing values up to
- * 2<SUP>31</SUP> - 1 (a little over two billion).  This class uses a
- * <CODE>long</CODE> data type behind the scenes and therefore is capable of
- * holding much larger values.  Because of the need to deal with larger values,
- * this class may have a small performance disadvantage over the
- * <CODE>ASN1Integer</CODE> class and therefore that class should be used for
- * cases in which there is no danger of overflowing an <CODE>int</CODE> value.
- */
-@org.opends.server.types.PublicAPI(
-     stability=org.opends.server.types.StabilityLevel.UNCOMMITTED,
-     mayInstantiate=true,
-     mayExtend=false,
-     mayInvoke=true)
-public final class ASN1Long
-       extends ASN1Element
-{
-  /**
-   * The serial version identifier required to satisfy the compiler because this
-   * class implements the <CODE>java.io.Serializable</CODE> interface.  This
-   * value was generated using the <CODE>serialver</CODE> command-line utility
-   * included with the Java SDK.
-   */
-  private static final long serialVersionUID = -6015600344725970947L;
-
-
-
-  // The long value for this element.
-  private long longValue;
-
-
-
-
-  /**
-   * Creates a new ASN.1 long element with the default type and the provided
-   * value.
-   *
-   * @param  longValue  The value for this ASN.1 long element.
-   */
-  public ASN1Long (long longValue)
-  {
-    super(UNIVERSAL_INTEGER_TYPE, encodeLongValue(longValue));
-
-
-    this.longValue = longValue;
-  }
-
-
-
-  /**
-   * Creates a new ASN.1 long element with the specified type and value.
-   *
-   * @param  type       The BER type for this ASN.1 long element.
-   * @param  longValue  The value for this ASN.1 long element.
-   */
-  public ASN1Long(byte type, long longValue)
-  {
-    super(type, encodeLongValue(longValue));
-
-
-    this.longValue = longValue;
-  }
-
-
-
-  /**
-   * Creates a new ASN.1 long element with the specified type and value.
-   *
-   * @param  type       The BER type for this ASN.1 long element.
-   * @param  value      The encoded value for this ASN.1 long element.
-   * @param  longValue  The long value for this ASN.1 long element.
-   */
-  private ASN1Long(byte type, byte[] value, long longValue)
-  {
-    super(type, value);
-
-
-    this.longValue = longValue;
-  }
-
-
-
-  /**
-   * Retrieves the long value for this ASN.1 long element.
-   *
-   * @return  The long value for this ASN.1 long element.
-   */
-  public long longValue()
-  {
-    return longValue;
-  }
-
-
-
-  /**
-   * Specifies the long value for this ASN.1 long element.
-   *
-   * @param  longValue  The long value for this ASN.1 long element.
-   */
-  public void setValue(long longValue)
-  {
-    this.longValue = longValue;
-    setValueInternal(encodeLongValue(longValue));
-  }
-
-
-
-  /**
-   * Specifies the value for this ASN.1 long element.
-   *
-   * @param  value  The encoded value for this ASN.1 long element.
-   *
-   * @throws  ASN1Exception  If the provided array is null or is not between one
-   *                         and four bytes in length.
-   */
-  @Override
-  public void setValue(byte[] value)
-         throws ASN1Exception
-  {
-    if (value == null)
-    {
-      Message message = ERR_ASN1_INTEGER_SET_VALUE_NULL.get();
-      throw new ASN1Exception(message);
-    }
-
-    if ((value.length < 1) || (value.length > 8))
-    {
-      Message message =
-          ERR_ASN1_LONG_SET_VALUE_INVALID_LENGTH.get(value.length);
-      throw new ASN1Exception(message);
-    }
-
-    longValue = 0;
-    for (byte b : value)
-    {
-      longValue = (longValue << 8) | (b & 0xFF);
-    }
-
-    setValueInternal(value);
-  }
-
-
-
-  /**
-   * Decodes the provided ASN.1 element as a long element.
-   *
-   * @param  element  The ASN.1 element to decode as a long element.
-   *
-   * @return  The decoded ASN.1 long element.
-   *
-   * @throws  ASN1Exception  If the provided ASN.1 element cannot be decoded as
-   *                         a long element.
-   */
-  public static ASN1Long decodeAsLong(ASN1Element element)
-         throws ASN1Exception
-  {
-    if (element == null)
-    {
-      Message message = ERR_ASN1_INTEGER_DECODE_ELEMENT_NULL.get();
-      throw new ASN1Exception(message);
-    }
-
-    byte[] value = element.value();
-    if ((value.length < 1) || (value.length > 8))
-    {
-      Message message =
-          ERR_ASN1_LONG_DECODE_ELEMENT_INVALID_LENGTH.get(value.length);
-      throw new ASN1Exception(message);
-    }
-
-    long longValue = 0;
-
-    if (value[0] < 0)
-    {
-      longValue = 0xFFFFFFFFFFFFFFFFL;
-    }
-
-    for (byte b : value)
-    {
-      longValue = (longValue << 8) | (b & 0xFF);
-    }
-
-    return new ASN1Long(element.getType(), value, longValue);
-  }
-
-
-
-  /**
-   * Decodes the provided byte array as an ASN.1 long element.
-   *
-   * @param  encodedElement  The byte array to decode as an ASN.1 long element.
-   *
-   * @return  The decoded ASN.1 long element.
-   *
-   * @throws  ASN1Exception  If the provided byte array cannot be decoded as an
-   *                         ASN.1 long element.
-   */
-  public static ASN1Long decodeAsLong(byte[] encodedElement)
-         throws ASN1Exception
-  {
-    // First make sure that the array is not null and long enough to contain
-    // a valid ASN.1 long element.
-    if (encodedElement == null)
-    {
-      Message message = ERR_ASN1_INTEGER_DECODE_ARRAY_NULL.get();
-      throw new ASN1Exception(message);
-    }
-
-    if (encodedElement.length < 3)
-    {
-      Message message =
-          ERR_ASN1_INTEGER_SHORT_ELEMENT.get(encodedElement.length);
-      throw new ASN1Exception(message);
-    }
-
-
-    // Next, decode the length.  This allows multi-byte lengths with up to four
-    // bytes used to indicate how many bytes are in the length.
-    byte type = encodedElement[0];
-    int length = (encodedElement[1] & 0x7F);
-    int valueStartPos = 2;
-    if (length != encodedElement[1])
-    {
-      int numLengthBytes = length;
-      if (numLengthBytes > 4)
-      {
-        Message message = ERR_ASN1_INVALID_NUM_LENGTH_BYTES.get(numLengthBytes);
-        throw new ASN1Exception(message);
-      }
-      else if (encodedElement.length < (2 + numLengthBytes))
-      {
-        Message message = ERR_ASN1_TRUNCATED_LENGTH.get(numLengthBytes);
-        throw new ASN1Exception(message);
-      }
-
-      length = 0x00;
-      valueStartPos = 2 + numLengthBytes;
-      for (int i=0; i < numLengthBytes; i++)
-      {
-        length = (length << 8) | (encodedElement[i+2] & 0xFF);
-      }
-    }
-
-
-    // Make sure that the number of bytes left is equal to the number of bytes
-    // in the value.
-    if ((encodedElement.length - valueStartPos) != length)
-    {
-      Message message = ERR_ASN1_LENGTH_MISMATCH.get(
-          length, (encodedElement.length - valueStartPos));
-      throw new ASN1Exception(message);
-    }
-
-
-    // Make sure that the decoded length is between 1 and 8 bytes.
-    if ((length < 1) || (length > 8))
-    {
-      Message message = ERR_ASN1_LONG_DECODE_ARRAY_INVALID_LENGTH.get(length);
-      throw new ASN1Exception(message);
-    }
-
-
-    // Copy the value and construct the element to return.
-    byte[] value = new byte[length];
-    System.arraycopy(encodedElement, valueStartPos, value, 0, length);
-
-    long longValue = 0;
-
-    if (value[0] < 0)
-    {
-      longValue = 0xFFFFFFFFFFFFFFFFL;
-    }
-
-    for (byte b : value)
-    {
-      longValue = (longValue << 8) | (b & 0xFF);
-    }
-
-    return new ASN1Long(type, value, longValue);
-  }
-
-
-
-  /**
-   * Appends a string representation of this ASN.1 integer element to the
-   * provided buffer.
-   *
-   * @param  buffer  The buffer to which the information should be appended.
-   */
-  @Override
-  public void toString(StringBuilder buffer)
-  {
-    buffer.append("ASN1Long(type=");
-    buffer.append(byteToHex(getType()));
-    buffer.append(", value=");
-    buffer.append(longValue);
-    buffer.append(")");
-  }
-
-
-
-  /**
-   * Appends a string representation of this protocol element to the provided
-   * buffer.
-   *
-   * @param  buffer  The buffer into which the string representation should be
-   *                 written.
-   * @param  indent  The number of spaces that should be used to indent the
-   *                 resulting string representation.
-   */
-  @Override
-  public void toString(StringBuilder buffer, int indent)
-  {
-    StringBuilder indentBuf = new StringBuilder(indent);
-    for (int i=0 ; i < indent; i++)
-    {
-      indentBuf.append(' ');
-    }
-
-    buffer.append(indentBuf);
-    buffer.append("ASN.1 Long");
-    buffer.append(EOL);
-
-    buffer.append(indentBuf);
-    buffer.append("  BER Type:  ");
-    buffer.append(byteToHex(getType()));
-    buffer.append(EOL);
-
-    buffer.append(indentBuf);
-    buffer.append("  Value:  ");
-    buffer.append(longValue);
-    buffer.append(" (");
-    buffer.append(bytesToHex(value()));
-    buffer.append(")");
-    buffer.append(EOL);
-  }
-}
-
diff --git a/opends/src/server/org/opends/server/protocols/asn1/ASN1Null.java b/opends/src/server/org/opends/server/protocols/asn1/ASN1Null.java
deleted file mode 100644
index ec78f4a..0000000
--- a/opends/src/server/org/opends/server/protocols/asn1/ASN1Null.java
+++ /dev/null
@@ -1,259 +0,0 @@
-/*
- * CDDL HEADER START
- *
- * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
- *
- * You can obtain a copy of the license at
- * trunk/opends/resource/legal-notices/OpenDS.LICENSE
- * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
- * See the License for the specific language governing permissions
- * and limitations under the License.
- *
- * When distributing Covered Code, include this CDDL HEADER in each
- * file and include the License file at
- * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
- * add the following below this CDDL 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.server.protocols.asn1;
-import org.opends.messages.Message;
-
-
-
-import static org.opends.messages.ProtocolMessages.*;
-import static org.opends.server.protocols.asn1.ASN1Constants.*;
-import static org.opends.server.util.ServerConstants.*;
-import static org.opends.server.util.StaticUtils.*;
-
-
-
-/**
- * This class defines the data structures and methods to use when interacting
- * with ASN.1 null elements.
- */
-@org.opends.server.types.PublicAPI(
-     stability=org.opends.server.types.StabilityLevel.UNCOMMITTED,
-     mayInstantiate=true,
-     mayExtend=false,
-     mayInvoke=true)
-public final class ASN1Null
-       extends ASN1Element
-{
-  /**
-   * The serial version identifier required to satisfy the compiler because this
-   * class implements the <CODE>java.io.Serializable</CODE> interface.  This
-   * value was generated using the <CODE>serialver</CODE> command-line utility
-   * included with the Java SDK.
-   */
-  private static final long serialVersionUID = 8921787912269145125L;
-
-
-
-  /**
-   * Creates a new ASN.1 null element with the default type.
-   */
-  public ASN1Null()
-  {
-    super(UNIVERSAL_NULL_TYPE);
-
-  }
-
-
-
-  /**
-   * Creates a new ASN.1 null element with the specified type.
-   *
-   * @param  type  The BER type to use for this ASN.1 null element.
-   */
-  public ASN1Null(byte type)
-  {
-    super(type);
-
-  }
-
-
-
-  /**
-   * Specifies the value for this ASN.1 null element.
-   *
-   * @param  value  The encoded value for this ASN.1 null element.
-   *
-   * @throws  ASN1Exception  If the provided array is not empty.
-   */
-  public void setValue(byte[] value)
-         throws ASN1Exception
-  {
-    if ((value != null) && (value.length != 0))
-    {
-      Message message =
-          ERR_ASN1_NULL_SET_VALUE_INVALID_LENGTH.get(value.length);
-      throw new ASN1Exception(message);
-    }
-  }
-
-
-
-  /**
-   * Decodes the provided ASN.1 element as a null element.
-   *
-   * @param  element  The ASN.1 element to decode as a null element.
-   *
-   * @return  The decoded ASN.1 null element.
-   *
-   * @throws  ASN1Exception  If the provided ASN.1 element cannot be decoded as
-   *                         a null element.
-   */
-  public static ASN1Null decodeAsNull(ASN1Element element)
-         throws ASN1Exception
-  {
-    if (element == null)
-    {
-      Message message = ERR_ASN1_NULL_DECODE_ELEMENT_NULL.get();
-      throw new ASN1Exception(message);
-    }
-
-    byte[] value = element.value();
-    if (value.length != 0)
-    {
-      Message message =
-          ERR_ASN1_NULL_DECODE_ELEMENT_INVALID_LENGTH.get(value.length);
-      throw new ASN1Exception(message);
-    }
-
-    return new ASN1Null(element.getType());
-  }
-
-
-
-  /**
-   * Decodes the provided byte array as an ASN.1 null element.
-   *
-   * @param  encodedElement  The byte array to decode as an ASN.1 null element.
-   *
-   * @return  The decoded ASN.1 null element.
-   *
-   * @throws  ASN1Exception  If the provided byte array cannot be decoded as an
-   *                         ASN.1 null element.
-   */
-  public static ASN1Null decodeAsNull(byte[] encodedElement)
-         throws ASN1Exception
-  {
-    // First make sure that the array is not null and long enough to contain
-    // a valid ASN.1 null element.
-    if (encodedElement == null)
-    {
-      Message message = ERR_ASN1_NULL_DECODE_ARRAY_NULL.get();
-      throw new ASN1Exception(message);
-    }
-
-    if (encodedElement.length < 2)
-    {
-      Message message = ERR_ASN1_SHORT_ELEMENT.get(encodedElement.length);
-      throw new ASN1Exception(message);
-    }
-
-
-    // Next, decode the length.  This allows multi-byte lengths with up to four
-    // bytes used to indicate how many bytes are in the length.
-    byte type = encodedElement[0];
-    int length = (encodedElement[1] & 0x7F);
-    int valueStartPos = 2;
-    if (length != encodedElement[1])
-    {
-      int numLengthBytes = length;
-      if (numLengthBytes > 4)
-      {
-        Message message = ERR_ASN1_INVALID_NUM_LENGTH_BYTES.get(numLengthBytes);
-        throw new ASN1Exception(message);
-      }
-      else if (encodedElement.length < (2 + numLengthBytes))
-      {
-        Message message = ERR_ASN1_TRUNCATED_LENGTH.get(numLengthBytes);
-        throw new ASN1Exception(message);
-      }
-
-      length = 0x00;
-      valueStartPos = 2 + numLengthBytes;
-      for (int i=0; i < numLengthBytes; i++)
-      {
-        length = (length << 8) | (encodedElement[i+2] & 0xFF);
-      }
-    }
-
-
-    // Make sure that the number of bytes left is equal to the number of bytes
-    // in the value.
-    if ((encodedElement.length - valueStartPos) != length)
-    {
-      Message message = ERR_ASN1_LENGTH_MISMATCH.get(
-          length, (encodedElement.length - valueStartPos));
-      throw new ASN1Exception(message);
-    }
-
-
-    // Make sure that the decoded length is exactly zero byte.
-    if (length != 0)
-    {
-      Message message = ERR_ASN1_NULL_DECODE_ARRAY_INVALID_LENGTH.get(length);
-      throw new ASN1Exception(message);
-    }
-
-
-    // Copy the value and construct the element to return.
-    return new ASN1Null(type);
-  }
-
-
-
-  /**
-   * Appends a string representation of this ASN.1 null element to the provided
-   * buffer.
-   *
-   * @param  buffer  The buffer to which the information should be appended.
-   */
-  public void toString(StringBuilder buffer)
-  {
-    buffer.append("ASN1Null(type=");
-    buffer.append(byteToHex(getType()));
-    buffer.append(")");
-  }
-
-
-
-  /**
-   * Appends a string representation of this protocol element to the provided
-   * buffer.
-   *
-   * @param  buffer  The buffer into which the string representation should be
-   *                 written.
-   * @param  indent  The number of spaces that should be used to indent the
-   *                 resulting string representation.
-   */
-  public void toString(StringBuilder buffer, int indent)
-  {
-    StringBuilder indentBuf = new StringBuilder(indent);
-    for (int i=0 ; i < indent; i++)
-    {
-      indentBuf.append(' ');
-    }
-
-    buffer.append(indentBuf);
-    buffer.append("ASN.1 Null");
-    buffer.append(EOL);
-
-    buffer.append(indentBuf);
-    buffer.append("  BER Type:  ");
-    buffer.append(byteToHex(getType()));
-    buffer.append(EOL);
-  }
-}
-
diff --git a/opends/src/server/org/opends/server/protocols/asn1/ASN1OctetString.java b/opends/src/server/org/opends/server/protocols/asn1/ASN1OctetString.java
deleted file mode 100644
index 4fd239f..0000000
--- a/opends/src/server/org/opends/server/protocols/asn1/ASN1OctetString.java
+++ /dev/null
@@ -1,515 +0,0 @@
-/*
- * CDDL HEADER START
- *
- * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
- *
- * You can obtain a copy of the license at
- * trunk/opends/resource/legal-notices/OpenDS.LICENSE
- * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
- * See the License for the specific language governing permissions
- * and limitations under the License.
- *
- * When distributing Covered Code, include this CDDL HEADER in each
- * file and include the License file at
- * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
- * add the following below this CDDL 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.server.protocols.asn1;
-import org.opends.messages.Message;
-
-
-
-import org.opends.server.types.ByteString;
-import org.opends.server.types.DebugLogLevel;
-
-import static org.opends.server.loggers.debug.DebugLogger.*;
-import org.opends.server.loggers.debug.DebugTracer;
-import static org.opends.messages.ProtocolMessages.*;
-import static org.opends.server.protocols.asn1.ASN1Constants.*;
-import static org.opends.server.util.ServerConstants.*;
-import static org.opends.server.util.StaticUtils.*;
-
-
-
-/**
- * This class defines the data structures and methods to use when interacting
- * with ASN.1 octet string elements.
- * <BR><BR>
- * Note that this class also implements the <CODE>ByteString</CODE> interface,
- * but in most cases whenever it is necessary to create an instance of a
- * <CODE>ByteString</CODE> object, the caller should use one of the
- * <CODE>ByteStringFactory.create</CODE> methods rather than creating an
- * <CODE>ASN1OctetString</CODE> object directly.  In general, direct references
- * to ASN.1 elements should be limited to cases in which ASN.1 is actually
- * involved.
- */
-@org.opends.server.types.PublicAPI(
-     stability=org.opends.server.types.StabilityLevel.UNCOMMITTED,
-     mayInstantiate=true,
-     mayExtend=false,
-     mayInvoke=true)
-public final class ASN1OctetString
-       extends ASN1Element
-       implements ByteString
-{
-  /**
-   * The tracer object for the debug logger.
-   */
-  private static final DebugTracer TRACER = getTracer();
-
-
-
-
-  /**
-   * The serial version identifier required to satisfy the compiler because this
-   * class implements the <CODE>java.io.Serializable</CODE> interface.  This
-   * value was generated using the <CODE>serialver</CODE> command-line utility
-   * included with the Java SDK.
-   */
-  private static final long serialVersionUID = -6101268916754431502L;
-
-
-
-  // The string value for this element.  It may be null due to lazy
-  // initialization.
-  private String stringValue;
-
-
-
-  /**
-   * Creates a new ASN.1 octet string element with the default type and no
-   * value.
-   */
-  public ASN1OctetString()
-  {
-    super(UNIVERSAL_OCTET_STRING_TYPE);
-
-  }
-
-
-
-  /**
-   * Creates a new ASN.1 octet string element with the specified type and no
-   * value.
-   *
-   * @param  type  The BER type for this ASN.1 octet string element.
-   */
-  public ASN1OctetString(byte type)
-  {
-    super(type);
-
-  }
-
-
-
-  /**
-   * Creates a new ASN.1 octet string element with the default type and the
-   * provided value.
-   *
-   * @param  value  The value for this ASN.1 octet string element.
-   */
-  public ASN1OctetString(byte[] value)
-  {
-    super(UNIVERSAL_OCTET_STRING_TYPE, value);
-
-
-    this.stringValue = null;
-  }
-
-
-
-  /**
-   * Creates a new ASN.1 octet string element with the default type and the
-   * provided value.
-   *
-   * @param  messageValue  The value for this ASN.1 octet string element as a
-   *                      string.
-   */
-  public ASN1OctetString(Message messageValue)
-  {
-    this(messageValue != null ? messageValue.toString() : null);
-  }
-
-
-
-  /**
-   * Creates a new ASN.1 octet string element with the default type and the
-   * provided value.
-   *
-   * @param  stringValue  The value for this ASN.1 octet string element as a
-   *                      string.
-   */
-  public ASN1OctetString(String stringValue)
-  {
-    super(UNIVERSAL_OCTET_STRING_TYPE, getBytes(stringValue));
-
-
-    this.stringValue = stringValue;
-  }
-
-
-
-  /**
-   * Creates a new ASN.1 octet string element with the specified type and the
-   * provided value.
-   *
-   * @param  type   The BER type for this ASN.1 octet string element.
-   * @param  value  The value for this ASN.1 octet string element.
-   */
-  public ASN1OctetString(byte type, byte[] value)
-  {
-    super(type, value);
-
-
-    this.stringValue = null;
-  }
-
-
-
-  /**
-   * Creates a new ASN.1 octet string element with the specified type and the
-   * provided value.
-   *
-   * @param  type         The BER type for this ASN.1 octet string element.
-   * @param  stringValue  The value for this ASN.1 octet string element as a
-   *                      string.
-   */
-  public ASN1OctetString(byte type, String stringValue)
-  {
-    super(type, getBytes(stringValue));
-
-
-    this.stringValue = stringValue;
-  }
-
-
-
-  /**
-   * Retrieves the string representation of the value for this ASN.1 octet
-   * string element.  The behavior of this method when the bytes are not
-   * valid in the UTF-8 charset is unspecified.  In particular the behavior for
-   * binary values is unspecified.
-   *
-   * @return  The string representation of the value for this ASN.1 octet string
-   *          element.
-   */
-  public String stringValue()
-  {
-    if (stringValue == null)
-    {
-/*
-      // This code could be used to explicitly detect and handle binary values.
-      Charset charset = Charset.forName("UTF-8");
-      CharsetDecoder decoder = charset.newDecoder();
-      ByteBuffer bb = ByteBuffer.wrap(value());
-      try
-      {
-        CharBuffer cb = decoder.decode(bb);
-        stringValue = cb.toString();
-      }
-      catch (CharacterCodingException e)
-      {
-        // Handle binary values here.
-        return "[Binary]";
-      }
-*/
-      try
-      {
-        stringValue = new String(value(), "UTF-8");
-      }
-      catch (Exception e)
-      {
-        if (debugEnabled())
-        {
-          TRACER.debugCaught(DebugLogLevel.ERROR, e);
-        }
-
-        stringValue = new String(value());
-      }
-    }
-
-    return stringValue;
-  }
-
-
-
-  /**
-   * Appends a string representation of the value for this ASN.1 octet string
-   * element to the provided buffer.
-   *
-   * @param  buffer  The buffer to which the string representation should be
-   *                 appended.
-   */
-  public void stringValue(StringBuilder buffer)
-  {
-    if (stringValue != null)
-    {
-      buffer.append(stringValue);
-      return;
-    }
-
-    byte[] value  = value();
-    int    length = value.length;
-
-    for (int i=0; i < length; i++)
-    {
-      if ((value[i] & 0x7F) == value[i])
-      {
-        buffer.append((char) value[i]);
-      }
-      else
-      {
-        String s;
-        try
-        {
-          s = new String(value, i, (length-i), "UTF-8");
-        }
-        catch (Exception e)
-        {
-          if (debugEnabled())
-          {
-            TRACER.debugCaught(DebugLogLevel.ERROR, e);
-          }
-
-          s = new String(value, i, (length - i));
-        }
-
-        buffer.append(s);
-        return;
-      }
-    }
-  }
-
-
-
-  /**
-   * Specifies the string value for this ASN.1 octet string element.
-   *
-   * @param  stringValue  The string value for this ASN.1 octet string element.
-   */
-  public void setValue(String stringValue)
-  {
-    if (stringValue == null)
-    {
-      this.stringValue = null;
-      setValueInternal(new byte[0]);
-    }
-    else
-    {
-      this.stringValue = stringValue;
-      setValueInternal(getBytes(stringValue));
-    }
-  }
-
-
-
-  /**
-   * Specifies the value for this ASN.1 octet string element.
-   *
-   * @param  value  The encoded value for this ASN.1 octet string element.
-   */
-  public void setValue(byte[] value)
-  {
-    if (value == null)
-    {
-      setValueInternal(NO_VALUE);
-    }
-    else
-    {
-      setValueInternal(value);
-    }
-
-    stringValue = null;
-  }
-
-
-
-  /**
-   * Decodes the provided ASN.1 element as an octet string element.
-   *
-   * @param  element  The ASN.1 element to decode as an octet string element.
-   *
-   * @return  The decoded ASN.1 octet string element.
-   *
-   * @throws  ASN1Exception  If the provided ASN.1 element cannot be decoded as
-   *                         an octet string element.
-   */
-  public static ASN1OctetString decodeAsOctetString(ASN1Element element)
-         throws ASN1Exception
-  {
-    if (element == null)
-    {
-      Message message = ERR_ASN1_OCTET_STRING_DECODE_ELEMENT_NULL.get();
-      throw new ASN1Exception(message);
-    }
-
-    return new ASN1OctetString(element.getType(), element.value());
-  }
-
-
-
-  /**
-   * Decodes the provided byte array as an ASN.1 octet string element.
-   *
-   * @param  encodedElement  The byte array to decode as an ASN.1 octet string
-   *                         element.
-   *
-   * @return  The decoded ASN.1 octet string element.
-   *
-   * @throws  ASN1Exception  If the provided byte array cannot be decoded as an
-   *                         ASN.1 octet string element.
-   */
-  public static ASN1OctetString decodeAsOctetString(byte[] encodedElement)
-         throws ASN1Exception
-  {
-    // First make sure that the array is not null and long enough to contain
-    // a valid ASN.1 element.
-    if (encodedElement == null)
-    {
-      Message message = ERR_ASN1_OCTET_STRING_DECODE_ARRAY_NULL.get();
-      throw new ASN1Exception(message);
-    }
-
-    if (encodedElement.length < 2)
-    {
-      Message message = ERR_ASN1_SHORT_ELEMENT.get(encodedElement.length);
-      throw new ASN1Exception(message);
-    }
-
-
-    // Next, decode the length.  This allows multi-byte lengths with up to four
-    // bytes used to indicate how many bytes are in the length.
-    byte type = encodedElement[0];
-    int length = (encodedElement[1] & 0x7F);
-    int valueStartPos = 2;
-    if (length != encodedElement[1])
-    {
-      int numLengthBytes = length;
-      if (numLengthBytes > 4)
-      {
-        Message message = ERR_ASN1_INVALID_NUM_LENGTH_BYTES.get(numLengthBytes);
-        throw new ASN1Exception(message);
-      }
-      else if (encodedElement.length < (2 + numLengthBytes))
-      {
-        Message message = ERR_ASN1_TRUNCATED_LENGTH.get(numLengthBytes);
-        throw new ASN1Exception(message);
-      }
-
-      length = 0x00;
-      valueStartPos = 2 + numLengthBytes;
-      for (int i=0; i < numLengthBytes; i++)
-      {
-        length = (length << 8) | (encodedElement[i+2] & 0xFF);
-      }
-    }
-
-
-    // Make sure that the number of bytes left is equal to the number of bytes
-    // in the value.
-    if ((encodedElement.length - valueStartPos) != length)
-    {
-      Message message = ERR_ASN1_LENGTH_MISMATCH.get(
-          length, (encodedElement.length - valueStartPos));
-      throw new ASN1Exception(message);
-    }
-
-
-    // Copy the value and construct the element to return.
-    byte[] value = new byte[length];
-    System.arraycopy(encodedElement, valueStartPos, value, 0, length);
-    return new ASN1OctetString(type, value);
-  }
-
-
-
-  /**
-   * Creates a duplicate of this ASN.1 octet string.
-   *
-   * @return  A duplicate of this ASN.1 octet string.
-   */
-  public ASN1OctetString duplicate()
-  {
-    byte[] value = value();
-    int length = value.length;
-
-    byte[] duplicateValue = new byte[length];
-    System.arraycopy(value, 0, duplicateValue, 0, length);
-
-    return new ASN1OctetString(getType(), value);
-  }
-
-
-
-  /**
-   * Appends a string representation of this ASN.1 octet string element to the
-   * provided buffer.
-   *
-   * @param  buffer  The buffer to which the information should be appended.
-   */
-  public void toString(StringBuilder buffer)
-  {
-    buffer.append(stringValue());
-  }
-
-
-
-  /**
-   * Appends a string representation of this protocol element to the provided
-   * buffer.
-   *
-   * @param  buffer  The buffer into which the string representation should be
-   *                 written.
-   * @param  indent  The number of spaces that should be used to indent the
-   *                 resulting string representation.
-   */
-  public void toString(StringBuilder buffer, int indent)
-  {
-    StringBuilder indentBuf = new StringBuilder(indent);
-    for (int i=0 ; i < indent; i++)
-    {
-      indentBuf.append(' ');
-    }
-
-    buffer.append(indentBuf);
-    buffer.append("ASN.1 Octet String");
-    buffer.append(EOL);
-
-    buffer.append(indentBuf);
-    buffer.append("  BER Type:  ");
-    buffer.append(byteToHex(getType()));
-    buffer.append(EOL);
-
-    byte[] value = value();
-    buffer.append(indentBuf);
-    buffer.append("  Value (");
-    buffer.append(value.length);
-    buffer.append(" bytes)");
-    buffer.append(EOL);
-
-    byteArrayToHexPlusAscii(buffer, value, indent+2);
-  }
-
-
-
-  /**
-   * Retrieves this byte string as an ASN.1 octet string.
-   *
-   * @return  An ASN.1 octet string with the value of this byte string.
-   */
-  public ASN1OctetString toASN1OctetString()
-  {
-    return this;
-  }
-}
-
diff --git a/opends/src/server/org/opends/server/protocols/asn1/ASN1OutputStreamWriter.java b/opends/src/server/org/opends/server/protocols/asn1/ASN1OutputStreamWriter.java
new file mode 100644
index 0000000..1466696
--- /dev/null
+++ b/opends/src/server/org/opends/server/protocols/asn1/ASN1OutputStreamWriter.java
@@ -0,0 +1,591 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License").  You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE
+ * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
+ * add the following below this CDDL 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.server.protocols.asn1;
+
+import static org.opends.server.protocols.asn1.ASN1Constants.*;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.ArrayList;
+
+import org.opends.server.types.ByteSequence;
+import org.opends.server.types.ByteStringBuilder;
+import org.opends.server.types.DebugLogLevel;
+import org.opends.server.util.StaticUtils;
+import static org.opends.server.loggers.debug.DebugLogger.debugEnabled;
+import static org.opends.server.loggers.debug.DebugLogger.getTracer;
+import org.opends.server.loggers.debug.DebugTracer;
+
+/**
+ * An ASN1Writer implementation that outputs to an outputstream.
+ */
+final class ASN1OutputStreamWriter implements ASN1Writer
+{
+  private static final DebugTracer TRACER = getTracer();
+
+  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(OutputStream stream)
+  {
+    this.out = stream;
+    this.rootStream = stream;
+    this.streamStack = new ArrayList<ByteSequenceOutputStream>();
+    this.stackDepth = -1;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  public ASN1Writer writeInteger(int intValue) throws IOException
+  {
+    return writeInteger(UNIVERSAL_INTEGER_TYPE, intValue);
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  public ASN1Writer writeInteger(byte type, int intValue) throws IOException
+  {
+    out.write(type);
+    if ((intValue < 0 && ((intValue & 0xFFFFFF80) == 0xFFFFFF80)) ||
+        (intValue & 0x0000007F) == intValue)
+    {
+      writeLength(1);
+      out.write((byte) (intValue & 0xFF));
+      if(debugEnabled())
+      {
+        TRACER.debugProtocolElement(DebugLogLevel.VERBOSE,
+            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(debugEnabled())
+      {
+        TRACER.debugProtocolElement(DebugLogLevel.VERBOSE,
+            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(debugEnabled())
+      {
+        TRACER.debugProtocolElement(DebugLogLevel.VERBOSE,
+            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(debugEnabled())
+      {
+        TRACER.debugProtocolElement(DebugLogLevel.VERBOSE,
+            String.format("WRITE ASN.1 INTEGER(type=0x%x, length=%d, value=%d)",
+                type, 4, intValue));
+      }
+    }
+    return this;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  public ASN1Writer writeInteger(long longValue) throws IOException
+  {
+    return writeInteger(UNIVERSAL_INTEGER_TYPE, longValue);
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  public ASN1Writer writeInteger(byte type, long longValue) throws IOException
+  {
+    out.write(type);
+    if ((longValue < 0 &&
+         ((longValue & 0xFFFFFFFFFFFFFF80L) == 0xFFFFFFFFFFFFFF80L)) ||
+        (longValue & 0x000000000000007FL) == longValue)
+    {
+      writeLength(1);
+      out.write((byte) (longValue & 0xFF));
+      if(debugEnabled())
+      {
+        TRACER.debugProtocolElement(DebugLogLevel.VERBOSE,
+            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(debugEnabled())
+      {
+        TRACER.debugProtocolElement(DebugLogLevel.VERBOSE,
+            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(debugEnabled())
+      {
+        TRACER.debugProtocolElement(DebugLogLevel.VERBOSE,
+            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(debugEnabled())
+      {
+        TRACER.debugProtocolElement(DebugLogLevel.VERBOSE,
+            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(debugEnabled())
+      {
+        TRACER.debugProtocolElement(DebugLogLevel.VERBOSE,
+            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(debugEnabled())
+      {
+        TRACER.debugProtocolElement(DebugLogLevel.VERBOSE,
+            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(debugEnabled())
+      {
+        TRACER.debugProtocolElement(DebugLogLevel.VERBOSE,
+            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(debugEnabled())
+      {
+        TRACER.debugProtocolElement(DebugLogLevel.VERBOSE,
+            String.format("WRITE ASN.1 INTEGER(type=0x%x, length=%d, value=%d)",
+                type, 8, longValue));
+      }
+    }
+    return this;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  public ASN1Writer writeEnumerated(int intValue) throws IOException {
+    return writeInteger(UNIVERSAL_ENUMERATED_TYPE, intValue);
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  public ASN1Writer writeBoolean(boolean booleanValue) throws IOException
+  {
+    return writeBoolean(UNIVERSAL_BOOLEAN_TYPE, booleanValue);
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  public ASN1Writer writeBoolean(byte type, boolean booleanValue)
+      throws IOException
+  {
+    out.write(type);
+    writeLength(1);
+    out.write(booleanValue ? BOOLEAN_VALUE_TRUE : BOOLEAN_VALUE_FALSE);
+
+    if(debugEnabled())
+    {
+      TRACER.debugProtocolElement(DebugLogLevel.VERBOSE,
+          String.format("WRITE ASN.1 BOOLEAN(type=0x%x, length=%d, value=%s)",
+              type, 1, String.valueOf(booleanValue)));
+    }
+    return this;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  public ASN1Writer writeNull(byte type) throws IOException
+  {
+    out.write(type);
+    writeLength(0);
+
+    if(debugEnabled())
+    {
+      TRACER.debugProtocolElement(DebugLogLevel.VERBOSE,
+          String.format("WRITE ASN.1 NULL(type=0x%x, length=%d)",
+              type, 0));
+    }
+    return this;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  public ASN1Writer writeNull() throws IOException
+  {
+    return writeNull(UNIVERSAL_NULL_TYPE);
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  public ASN1Writer writeOctetString(byte type, byte[] value,
+                                     int offset, int length)
+      throws IOException
+  {
+    out.write(type);
+    writeLength(length);
+    out.write(value, offset, length);
+
+    if(debugEnabled())
+    {
+      TRACER.debugProtocolElement(DebugLogLevel.VERBOSE,
+          String.format("WRITE ASN.1 OCTETSTRING(type=0x%x, length=%d)",
+              type, length));
+    }
+    return this;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  public ASN1Writer writeOctetString(byte[] value, int offset, int length)
+      throws IOException
+  {
+    return writeOctetString(UNIVERSAL_OCTET_STRING_TYPE, value, offset, length);
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  public ASN1Writer writeOctetString(byte type, String value) throws IOException
+  {
+    out.write(type);
+
+    if(value == null)
+    {
+      writeLength(0);
+      return this;
+    }
+
+    byte[] bytes = StaticUtils.getBytes(value);
+    writeLength(bytes.length);
+    out.write(bytes);
+
+    if(debugEnabled())
+    {
+      TRACER.debugProtocolElement(DebugLogLevel.VERBOSE,
+          String.format("WRITE ASN.1 OCTETSTRING(type=0x%x, length=%d, " +
+              "value=%s)", type, bytes.length, value));
+    }
+    return this;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  public ASN1Writer writeOctetString(String value) throws IOException
+  {
+    return writeOctetString(UNIVERSAL_OCTET_STRING_TYPE, value);
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  public ASN1Writer writeOctetString(byte type, ByteSequence value)
+      throws IOException {
+    out.write(type);
+    writeLength(value.length());
+    value.copyTo(out);
+
+    if(debugEnabled())
+    {
+      TRACER.debugProtocolElement(DebugLogLevel.VERBOSE,
+          String.format("WRITE ASN.1 OCTETSTRING(type=0x%x, length=%d)",
+              type, value.length()));
+    }
+    return this;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  public ASN1Writer writeOctetString(ByteSequence value) throws IOException {
+    return writeOctetString(UNIVERSAL_OCTET_STRING_TYPE, value);
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  public ASN1Writer writeStartSet() throws IOException
+  {
+    return writeStartSequence(UNIVERSAL_SET_TYPE);
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  public ASN1Writer writeStartSequence() throws IOException
+  {
+    return writeStartSequence(UNIVERSAL_SEQUENCE_TYPE);
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  public ASN1Writer writeStartSequence(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())
+    {
+      ByteSequenceOutputStream subStream =
+          new ByteSequenceOutputStream(new ByteStringBuilder());
+      streamStack.add(subStream);
+      out = subStream;
+    }
+    else
+    {
+      out = streamStack.get(stackDepth);
+    }
+
+    if(debugEnabled())
+    {
+      TRACER.debugProtocolElement(DebugLogLevel.VERBOSE,
+          String.format("WRITE ASN.1 START SEQUENCE(type=0x%x)",
+              type));
+    }
+    return this;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  public ASN1Writer writeEndSet() throws IOException
+  {
+    return writeEndSequence();
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  public ASN1Writer writeEndSequence() throws IOException
+  {
+    if(stackDepth < 0)
+    {
+      throw new IOException();
+    }
+
+    ByteSequenceOutputStream childStream = streamStack.get(stackDepth);
+
+    // Decrement the stack depth and get the parent stream
+    --stackDepth;
+
+    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(debugEnabled())
+    {
+      TRACER.debugProtocolElement(DebugLogLevel.VERBOSE,
+          String.format("WRITE ASN.1 END SEQUENCE(length=%d)",
+              childStream.length()));
+    }
+
+    childStream.reset();
+    return this;
+  }
+
+  /**
+   * 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 {
+    while(stackDepth >= 0)
+    {
+      writeEndSequence();
+    }
+    rootStream.flush();
+
+    streamStack.clear();
+    rootStream.close();
+  }
+
+  /**
+   * Flushes the stream.
+   *
+   * @throws IOException If an I/O error occurs
+   */
+  public void flush() throws IOException {
+    rootStream.flush();
+  }
+
+  /**
+   * 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(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/opends/src/server/org/opends/server/protocols/asn1/ASN1Reader.java b/opends/src/server/org/opends/server/protocols/asn1/ASN1Reader.java
index 512dfd2..b67a5f5 100644
--- a/opends/src/server/org/opends/server/protocols/asn1/ASN1Reader.java
+++ b/opends/src/server/org/opends/server/protocols/asn1/ASN1Reader.java
@@ -25,299 +25,209 @@
  *      Copyright 2006-2008 Sun Microsystems, Inc.
  */
 package org.opends.server.protocols.asn1;
-import org.opends.messages.Message;
 
 
 
-import java.io.InputStream;
+import java.io.Closeable;
 import java.io.IOException;
-import java.net.Socket;
 
-import static org.opends.server.loggers.debug.DebugLogger.*;
-import org.opends.server.loggers.debug.DebugTracer;
-import org.opends.server.types.DebugLogLevel;
-import static org.opends.messages.ProtocolMessages.*;
-
+import org.opends.server.types.ByteString;
+import org.opends.server.types.ByteStringBuilder;
 
 
 /**
- * This class defines a utility that can be used to read ASN.1 elements from a
- * provided socket or input stream.
+ * 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.
  */
-@org.opends.server.types.PublicAPI(
-     stability=org.opends.server.types.StabilityLevel.UNCOMMITTED,
-     mayInstantiate=true,
-     mayExtend=false,
-     mayInvoke=true)
-public final class ASN1Reader
+public interface ASN1Reader extends Closeable
 {
+
   /**
-   * The tracer object for the debug logger.
+   * Closes this ASN.1 reader.
+   *
+   * @throws IOException if an I/O error occurs
    */
-  private static final DebugTracer TRACER = getTracer();
-
-
-
-
-  // The input stream from which to read the ASN.1 elements.
-  private InputStream inputStream;
-
-  // The largest element size (in bytes) that will be allowed.
-  private int maxElementSize;
-
-  // The socket with which the input stream is associated.
-  private Socket socket;
+  void close() throws IOException;
 
 
 
   /**
-   * Creates a new ASN.1 reader that will read elements from the provided
-   * socket.
+   * Determines if a complete ASN.1 element is waiting to be read.
    *
-   * @param  socket  The socket from which to read the ASN.1 elements.
-   *
-   * @throws  IOException  If a problem occurs while attempting to obtain the
-   *                       input stream for the socket.
+   * @return <code>true</code> if another complete element is available or
+   *         <code>false</code> otherwise.
+   * @throws ASN1Exception If an error occurs while trying to decode
+   *                       an ASN1 element.
    */
-  public ASN1Reader(Socket socket)
-         throws IOException
-  {
-    this.socket = socket;
-    inputStream = socket.getInputStream();
-
-    maxElementSize = -1;
-  }
+  public boolean elementAvailable() throws ASN1Exception;
 
 
 
   /**
-   * Creates a new ASN.1 reader that will read elements from the provided input
-   * stream.
+   * Determines if at least one ASN.1 element is waiting to be read.
    *
-   * @param  inputStream  The input stream from which to read the ASN.1
-   *                      elements.
+   * @return <code>true</code> if another element is available or
+   *         <code>false</code> if the EOF is reached.
+   * @throws ASN1Exception
+   *           If an error occurs while trying to decode an ASN1
+   *           element.
    */
-  public ASN1Reader(InputStream inputStream)
-  {
-    this.inputStream = inputStream;
-    socket           = null;
-    maxElementSize   = -1;
-  }
+  boolean hasNextElement() throws ASN1Exception;
 
 
 
   /**
-   * Retrieves the maximum size in bytes that will be allowed for elements read
-   * using this reader.  A negative value indicates that no limit should be
-   * enforced.
+   * Gets the data length of the next element without actually reading
+   * the element and advancing the cursor.
    *
-   * @return  The maximum size in bytes that will be allowed for elements.
+   * @return The data length of the next element or -1 if the EOF is
+   *         encountered.
+   * @throws ASN1Exception
+   *           If an error occurs while determining the length.
    */
-  public int getMaxElementSize()
-  {
-    return maxElementSize;
-  }
+  int peekLength() throws ASN1Exception;
 
 
 
   /**
-   * Specifies the maximum size in bytes that will be allowed for elements.  A
-   * negative value indicates that no limit should be enforced.
+   * Gets the BER type of the next element without actually reading
+   * the element and advancing the cursor.
    *
-   * @param  maxElementSize  The maximum size in bytes that will be allowed for
-   *                         elements read using this reader.
+   * @return The BER type of the next element or -1 if the EOF is
+   *         encountered.
+   * @throws ASN1Exception
+   *           If an error occurs while determining the BER type.
    */
-  public void setMaxElementSize(int maxElementSize)
-  {
-    this.maxElementSize = maxElementSize;
-  }
+  byte peekType() throws ASN1Exception;
 
 
 
   /**
-   * Retrieves the maximum length of time in milliseconds that this reader will
-   * be allowed to block while waiting to read data.  This is only applicable
-   * for readers created with sockets rather than input streams.
+   * Reads the next ASN.1 element as a boolean and advance the cursor.
    *
-   * @return  The maximum length of time in milliseconds that this reader will
-   *          be allowed to block while waiting to read data, or 0 if there is
-   *          no limit, or -1 if this ASN.1 reader is not associated with a
-   *          socket and no timeout can be enforced.
-   *
-   * @throws  IOException  If a problem occurs while polling the socket to
-   *                       determine the timeout.
+   * @return The decoded boolean value.
+   * @throws ASN1Exception
+   *           If the element cannot be decoded as a boolean.
    */
-  public int getIOTimeout()
-         throws IOException
-  {
-    if (socket == null)
-    {
-      return -1;
-    }
-    else
-    {
-      return socket.getSoTimeout();
-    }
-  }
+  boolean readBoolean() throws ASN1Exception;
 
 
 
   /**
-   * Specifies the maximum length of time in milliseconds that this reader
-   * should be allowed to block while waiting to read data.  This will only be
-   * applicable for readers created with sockets and will have no effect on
-   * readers created with input streams.
+   * Finishes reading a sequence. Any elements not read in the
+   * sequence will be discarded.
    *
-   * @param  ioTimeout  The maximum length of time in milliseconds that this
-   *                    reader should be allowed to block while waiting to read
-   *                    data, or 0 if there should be no limit.
-   *
-   * @throws  IOException  If a problem occurs while setting the underlying
-   *                       socket option.
+   * @throws ASN1Exception
+   *           If an error occurs while advancing to the end of the
+   *           sequence.
    */
-  public void setIOTimeout(int ioTimeout)
-         throws IOException
-  {
-    if (socket == null)
-    {
-      return;
-    }
-
-    socket.setSoTimeout(Math.max(0, ioTimeout));
-  }
+  void readEndSequence() throws ASN1Exception;
 
 
 
   /**
-   * Reads an ASN.1 element from the associated input stream.
+   * Reads the next ASN.1 element as an integer and advances the
+   * cursor.
    *
-   * @return  The ASN.1 element read from the associated input stream, or
-   *          <CODE>null</CODE> if the end of the stream has been reached.
-   *
-   * @throws  IOException  If a problem occurs while attempting to read from the
-   *                       input stream.
-   *
-   * @throws  ASN1Exception  If a problem occurs while attempting to decode the
-   *                         data read as an ASN.1 element.
+   * @return The decoded integer value.
+   * @throws ASN1Exception
+   *           If the element cannot be decoded as a integer.
    */
-  public ASN1Element readElement()
-         throws IOException, ASN1Exception
-  {
-    // First, read the BER type, which should be the first byte.
-    int typeValue = inputStream.read();
-    if (typeValue < 0)
-    {
-      return null;
-    }
-
-    byte type = (byte) (typeValue & 0xFF);
-
-
-
-    // Next, read the first byte of the length, and see if we need to read more.
-    int length         = inputStream.read();
-    int numLengthBytes = (length & 0x7F);
-    if (length != numLengthBytes)
-    {
-      // Make sure that there are an acceptable number of bytes in the length.
-      if (numLengthBytes > 4)
-      {
-        Message message =
-            ERR_ASN1_ELEMENT_SET_INVALID_NUM_LENGTH_BYTES.get(numLengthBytes);
-        throw new ASN1Exception(message);
-      }
-
-
-      length = 0;
-      for (int i=0; i < numLengthBytes; i++)
-      {
-        int lengthByte = inputStream.read();
-        if (lengthByte < 0)
-        {
-          // We've reached the end of the stream in the middle of the value.
-          // This is not good, so throw an exception.
-          Message message =
-              ERR_ASN1_ELEMENT_SET_TRUNCATED_LENGTH.get(numLengthBytes);
-          throw new IOException(message.toString());
-        }
-
-        length = (length << 8) | lengthByte;
-      }
-    }
-
-
-    // See how many bytes there are in the value.  If there are none, then just
-    // create an empty element with only a type.  If the length is larger than
-    // the maximum allowed, then fail.
-    if (length == 0)
-    {
-      return new ASN1Element(type);
-    }
-    else if ((maxElementSize > 0) && (length > maxElementSize))
-    {
-      Message message =
-          ERR_ASN1_READER_MAX_SIZE_EXCEEDED.get(length, maxElementSize);
-      throw new ASN1Exception(message);
-    }
-
-
-    // There is a value for the element, so create an array to hold it and read
-    // it from the stream.
-    byte[] value       = new byte[length];
-    int    readPos     = 0;
-    int    bytesNeeded = length;
-    while (bytesNeeded > 0)
-    {
-      int bytesRead = inputStream.read(value, readPos, bytesNeeded);
-      if (bytesRead < 0)
-      {
-        Message message =
-            ERR_ASN1_ELEMENT_SET_TRUNCATED_VALUE.get(length, bytesNeeded);
-        throw new IOException(message.toString());
-      }
-
-      bytesNeeded -= bytesRead;
-      readPos     += bytesRead;
-    }
-
-
-    // Return the constructed element.
-    return new ASN1Element(type, value);
-  }
+  long readInteger() throws ASN1Exception;
 
 
 
   /**
-   * Closes this ASN.1 reader and the underlying input stream and/or socket.
+   * Reads the next ASN.1 element as a null element and advances the
+   * cursor.
+   *
+   * @throws ASN1Exception
+   *           If the element cannot be decoded as an null element.
    */
-  public void close()
-  {
-    try
-    {
-      inputStream.close();
-    }
-    catch (Exception e)
-    {
-      if (debugEnabled())
-      {
-        TRACER.debugCaught(DebugLogLevel.ERROR, e);
-      }
-    }
+  void readNull() throws ASN1Exception;
 
-    if (socket != null)
-    {
-      try
-      {
-        socket.close();
-      }
-      catch (Exception e)
-      {
-        if (debugEnabled())
-        {
-          TRACER.debugCaught(DebugLogLevel.ERROR, e);
-        }
-      }
-    }
-  }
+
+
+  /**
+   * Reads the next ASN.1 element as an octet string and advances the
+   * cursor.
+   *
+   * @return The decoded octet string value represented using a
+   *         {@link ByteString}.
+   * @throws ASN1Exception
+   *           If the element cannot be decoded as an octet string.
+   */
+  ByteString readOctetString() throws ASN1Exception;
+
+
+
+  /**
+   * Reads the next ASN.1 element as an octet string and advances the
+   * cursor. The data will be appended to the provided
+   * {@link ByteStringBuilder}.
+   *
+   * @param buffer
+   *          The {@link ByteStringBuilder} to append the data to.
+   * @throws ASN1Exception
+   *           If the element cannot be decoded as an octet string.
+   */
+  void readOctetString(ByteStringBuilder buffer) throws ASN1Exception;
+
+
+
+  /**
+   * Reads the next ASN.1 element as an octet string and advances the
+   * cursor. The data will be decoded to a UTF-8 string. This method
+   * is equivalent to:
+   *
+   * <pre>
+   * readOctetStringAsString(&quot;UTF-8&quot;);
+   * </pre>
+   *
+   * @return The string representation of the octet string data.
+   * @throws ASN1Exception
+   *           If the element cannot be decoded as an octet string.
+   */
+  String readOctetStringAsString() throws ASN1Exception;
+
+
+
+  /**
+   * Reads the next ASN.1 element as an octet string and advances the
+   * cursor. The data will be decoded to a string using the provided
+   * character set.
+   *
+   * @param charSet
+   *          The character set to use in order to decode the data
+   *          into a string.
+   * @return The string representation of the octet string data.
+   * @throws ASN1Exception
+   *           If the element cannot be decoded as an octet string.
+   */
+  String readOctetStringAsString(String charSet) throws ASN1Exception;
+
+
+
+  /**
+   * Reads the next ASN.1 element as a sequence. All further reads
+   * will read the elements in the sequence until
+   * {@link #readEndSequence()} is called.
+   *
+   * @throws ASN1Exception
+   *           If the next element is not a sequence.
+   */
+  void readStartSequence() throws ASN1Exception;
+
+
+
+  /**
+   * Advances this ASN.1 reader beyond the next ASN.1 element without
+   * decoding it.
+   *
+   * @throws ASN1Exception
+   *           If the next ASN.1 element could not be skipped.
+   */
+  void skipElement() throws ASN1Exception;
 }
-
diff --git a/opends/src/server/org/opends/server/protocols/asn1/ASN1Sequence.java b/opends/src/server/org/opends/server/protocols/asn1/ASN1Sequence.java
deleted file mode 100644
index b2418d9..0000000
--- a/opends/src/server/org/opends/server/protocols/asn1/ASN1Sequence.java
+++ /dev/null
@@ -1,436 +0,0 @@
-/*
- * CDDL HEADER START
- *
- * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
- *
- * You can obtain a copy of the license at
- * trunk/opends/resource/legal-notices/OpenDS.LICENSE
- * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
- * See the License for the specific language governing permissions
- * and limitations under the License.
- *
- * When distributing Covered Code, include this CDDL HEADER in each
- * file and include the License file at
- * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
- * add the following below this CDDL 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.server.protocols.asn1;
-import org.opends.messages.Message;
-
-
-
-import java.util.ArrayList;
-import java.util.Iterator;
-
-import static org.opends.messages.ProtocolMessages.*;
-import static org.opends.server.protocols.asn1.ASN1Constants.*;
-import static org.opends.server.util.ServerConstants.*;
-import static org.opends.server.util.StaticUtils.*;
-
-
-
-/**
- * This class defines the data structures and methods to use when interacting
- * with ASN.1 sequence elements.
- */
-@org.opends.server.types.PublicAPI(
-     stability=org.opends.server.types.StabilityLevel.UNCOMMITTED,
-     mayInstantiate=true,
-     mayExtend=false,
-     mayInvoke=true)
-public final class ASN1Sequence
-       extends ASN1Element
-{
-  /**
-   * The serial version identifier required to satisfy the compiler because this
-   * class implements the <CODE>java.io.Serializable</CODE> interface.  This
-   * value was generated using the <CODE>serialver</CODE> command-line utility
-   * included with the Java SDK.
-   */
-  private static final long serialVersionUID = 694649828357992307L;
-
-
-
-  // The set of ASN.1 elements contained in this sequence.
-  private ArrayList<ASN1Element> elements;
-
-
-
-
-  /**
-   * Creates a new ASN.1 sequence element with the default type no value.
-   */
-  public ASN1Sequence()
-  {
-    super(UNIVERSAL_SEQUENCE_TYPE);
-
-
-    this.elements = new ArrayList<ASN1Element>();
-  }
-
-
-
-  /**
-   * Creates a new ASN.1 sequence element with the specified type and no value.
-   *
-   * @param  type  The BER type for this ASN.1 sequence.
-   */
-  public ASN1Sequence(byte type)
-  {
-    super(type);
-
-
-    this.elements = new ArrayList<ASN1Element>();
-  }
-
-
-
-  /**
-   * Creates a new ASN.1 sequence with the default type and the provided set of
-   * elements.
-   *
-   * @param  elements  The set of elements to include in this sequence.
-   */
-  public ASN1Sequence(ArrayList<ASN1Element> elements)
-  {
-    super(UNIVERSAL_SEQUENCE_TYPE, encodeValue(elements));
-
-
-    if (elements == null)
-    {
-      this.elements = new ArrayList<ASN1Element>();
-    }
-    else
-    {
-      this.elements = elements;
-    }
-  }
-
-
-
-  /**
-   * Creates a new ASN.1 sequence with the specified type and the provided set
-   * of elements.
-   *
-   * @param  type      The BER type for this sequence.
-   * @param  elements  The set of elements to include in this sequence.
-   */
-  public ASN1Sequence(byte type, ArrayList<ASN1Element> elements)
-  {
-    super(type, encodeValue(elements));
-
-
-    if (elements == null)
-    {
-      this.elements = new ArrayList<ASN1Element>();
-    }
-    else
-    {
-      this.elements = elements;
-    }
-  }
-
-
-
-  /**
-   * Creates a new ASN.1 sequence with the specified type and value and the
-   * provided set of elements.
-   *
-   * @param  type      The BER type for this sequence.
-   * @param  value     The encoded value for this sequence.
-   * @param  elements  The set of elements to include in this sequence.
-   */
-  private ASN1Sequence(byte type, byte[] value, ArrayList<ASN1Element> elements)
-  {
-    super(type, value);
-
-
-    if (elements == null)
-    {
-      this.elements = new ArrayList<ASN1Element>();
-    }
-    else
-    {
-      this.elements = elements;
-    }
-  }
-
-
-
-  /**
-   * Retrieves the set of elements contained in this ASN.1 sequence.  The
-   * returned list must not be modified by the caller.
-   *
-   * @return  The set of elements contained in this ASN.1 sequence.
-   */
-  public ArrayList<ASN1Element> elements()
-  {
-    return elements;
-  }
-
-
-
-  /**
-   * Specifies the set of elements for this ASN.1 sequence.
-   *
-   * @param  elements  The set of elements for this ASN.1 sequence.
-   */
-  public void setElements(ArrayList<ASN1Element> elements)
-  {
-    if (elements == null)
-    {
-      this.elements.clear();
-      setValueInternal(NO_VALUE);
-    }
-    else
-    {
-      this.elements = elements;
-      setValueInternal(encodeValue(elements));
-    }
-  }
-
-
-
-  /**
-   * Specifies the value for this ASN.1 sequence element.
-   *
-   * @param  value  The encoded value for this ASN.1 sequence element.
-   *
-   * @throws  ASN1Exception  If the provided array is null or cannot be decoded
-   *                         as a set of ASN.1 elements.
-   */
-  public void setValue(byte[] value)
-         throws ASN1Exception
-  {
-    if (value == null)
-    {
-      Message message = ERR_ASN1_SEQUENCE_SET_VALUE_NULL.get();
-      throw new ASN1Exception(message);
-    }
-
-    elements = decodeElements(value);
-    setValueInternal(value);
-  }
-
-
-
-  /**
-   * Decodes the provided ASN.1 element as a sequence element.
-   *
-   * @param  element  The ASN.1 element to decode as a sequence element.
-   *
-   * @return  The decoded ASN.1 sequence element.
-   *
-   * @throws  ASN1Exception  If the provided ASN.1 element cannot be decoded as
-   *                         a sequence element.
-   */
-  public static ASN1Sequence decodeAsSequence(ASN1Element element)
-         throws ASN1Exception
-  {
-    if (element == null)
-    {
-      Message message = ERR_ASN1_SEQUENCE_DECODE_ELEMENT_NULL.get();
-      throw new ASN1Exception(message);
-    }
-
-    byte[] value = element.value();
-    ArrayList<ASN1Element> elements = decodeElements(value);
-    return new ASN1Sequence(element.getType(), value, elements);
-  }
-
-
-
-  /**
-   * Decodes the provided byte array as an ASN.1 sequence element.
-   *
-   * @param  encodedElement  The byte array to decode as an ASN.1 sequence
-   *                         element.
-   *
-   * @return  The decoded ASN.1 sequence element.
-   *
-   * @throws  ASN1Exception  If the provided byte array cannot be decoded as an
-   *                         ASN.1 sequence element.
-   */
-  public static ASN1Sequence decodeAsSequence(byte[] encodedElement)
-         throws ASN1Exception
-  {
-    // First make sure that the array is not null and long enough to contain
-    // a valid ASN.1 sequence element.
-    if (encodedElement == null)
-    {
-      Message message = ERR_ASN1_SEQUENCE_DECODE_ARRAY_NULL.get();
-      throw new ASN1Exception(message);
-    }
-
-    if (encodedElement.length < 2)
-    {
-      Message message = ERR_ASN1_SHORT_ELEMENT.get(encodedElement.length);
-      throw new ASN1Exception(message);
-    }
-
-
-    // Next, decode the length.  This allows multi-byte lengths with up to four
-    // bytes used to indicate how many bytes are in the length.
-    byte type = encodedElement[0];
-    int length = (encodedElement[1] & 0x7F);
-    int valueStartPos = 2;
-    if (length != encodedElement[1])
-    {
-      int numLengthBytes = length;
-      if (numLengthBytes > 4)
-      {
-        Message message = ERR_ASN1_INVALID_NUM_LENGTH_BYTES.get(numLengthBytes);
-        throw new ASN1Exception(message);
-      }
-      else if (encodedElement.length < (2 + numLengthBytes))
-      {
-        Message message = ERR_ASN1_TRUNCATED_LENGTH.get(numLengthBytes);
-        throw new ASN1Exception(message);
-      }
-
-      length = 0x00;
-      valueStartPos = 2 + numLengthBytes;
-      for (int i=0; i < numLengthBytes; i++)
-      {
-        length = (length << 8) | (encodedElement[i+2] & 0xFF);
-      }
-    }
-
-
-    // Make sure that the number of bytes left is equal to the number of bytes
-    // in the value.
-    if ((encodedElement.length - valueStartPos) != length)
-    {
-      Message message = ERR_ASN1_LENGTH_MISMATCH.get(
-          length, (encodedElement.length - valueStartPos));
-      throw new ASN1Exception(message);
-    }
-
-
-    // Copy the value, decode the elements it contains, and construct the
-    // sequence to return.
-    byte[] value = new byte[length];
-    System.arraycopy(encodedElement, valueStartPos, value, 0, length);
-    ArrayList<ASN1Element> elements = decodeElements(value);
-    return new ASN1Sequence(type, value, elements);
-  }
-
-
-
-  /**
-   * Decodes the provided information as an ASN.1 sequence.
-   *
-   * @param  type          The BER type to use for the sequence.
-   * @param  encodedValue  The encoded value to decode as the set of elements
-   *                       for the sequence.
-   *
-   * @return  The decoded ASN.1 sequence element.
-   *
-   * @throws  ASN1Exception  If the provided byte array cannot be decoded as an
-   *                         ASN.1 sequence element.
-   */
-  public static ASN1Sequence decodeAsSequence(byte type, byte[] encodedValue)
-         throws ASN1Exception
-  {
-    ArrayList<ASN1Element> elements = decodeElements(encodedValue);
-    return new ASN1Sequence(type, encodedValue, elements);
-  }
-
-
-
-  /**
-   * Appends a string representation of this ASN.1 sequence element to the
-   * provided buffer.
-   *
-   * @param  buffer  The buffer to which the information should be appended.
-   */
-  public void toString(StringBuilder buffer)
-  {
-    buffer.append("ASN1Sequence(type=");
-    buffer.append(byteToHex(getType()));
-    buffer.append(", values={ ");
-
-    if (! elements.isEmpty())
-    {
-      Iterator<ASN1Element> iterator = elements.iterator();
-
-      iterator.next().toString(buffer);
-
-      while (iterator.hasNext())
-      {
-        buffer.append(", ");
-        iterator.next().toString(buffer);
-      }
-    }
-
-    buffer.append(" })");
-  }
-
-
-
-  /**
-   * Appends a string representation of this protocol element to the provided
-   * buffer.
-   *
-   * @param  buffer  The buffer into which the string representation should be
-   *                 written.
-   * @param  indent  The number of spaces that should be used to indent the
-   *                 resulting string representation.
-   */
-  public void toString(StringBuilder buffer, int indent)
-  {
-    StringBuilder indentBuf = new StringBuilder(indent);
-    for (int i=0 ; i < indent; i++)
-    {
-      indentBuf.append(' ');
-    }
-
-    buffer.append(indentBuf);
-    buffer.append("ASN.1 Sequence");
-    buffer.append(EOL);
-
-    buffer.append(indentBuf);
-    buffer.append("  BER Type:  ");
-    buffer.append(byteToHex(getType()));
-    buffer.append(EOL);
-
-    if (! elements.isEmpty())
-    {
-      buffer.append(indentBuf);
-      buffer.append("  Decoded Values:");
-      buffer.append(EOL);
-
-      Iterator<ASN1Element> iterator = elements.iterator();
-
-      buffer.append(indentBuf);
-      buffer.append("  ");
-      iterator.next().toString(buffer);
-      buffer.append(EOL);
-
-      while (iterator.hasNext())
-      {
-        buffer.append(indentBuf);
-        buffer.append("  ");
-        iterator.next().toString(buffer);
-        buffer.append(EOL);
-      }
-    }
-
-
-    buffer.append(indentBuf);
-    buffer.append("  Value:  ");
-    buffer.append(EOL);
-    byteArrayToHexPlusAscii(buffer, value(), indent+2);
-  }
-}
-
diff --git a/opends/src/server/org/opends/server/protocols/asn1/ASN1Set.java b/opends/src/server/org/opends/server/protocols/asn1/ASN1Set.java
deleted file mode 100644
index 28519cb..0000000
--- a/opends/src/server/org/opends/server/protocols/asn1/ASN1Set.java
+++ /dev/null
@@ -1,414 +0,0 @@
-/*
- * CDDL HEADER START
- *
- * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
- *
- * You can obtain a copy of the license at
- * trunk/opends/resource/legal-notices/OpenDS.LICENSE
- * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
- * See the License for the specific language governing permissions
- * and limitations under the License.
- *
- * When distributing Covered Code, include this CDDL HEADER in each
- * file and include the License file at
- * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
- * add the following below this CDDL 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.server.protocols.asn1;
-import org.opends.messages.Message;
-
-
-
-import java.util.ArrayList;
-import java.util.Iterator;
-
-import static org.opends.messages.ProtocolMessages.*;
-import static org.opends.server.protocols.asn1.ASN1Constants.*;
-import static org.opends.server.util.ServerConstants.*;
-import static org.opends.server.util.StaticUtils.*;
-
-
-
-/**
- * This class defines the data structures and methods to use when interacting
- * with ASN.1 set elements.
- */
-@org.opends.server.types.PublicAPI(
-     stability=org.opends.server.types.StabilityLevel.UNCOMMITTED,
-     mayInstantiate=true,
-     mayExtend=false,
-     mayInvoke=true)
-public final class ASN1Set
-       extends ASN1Element
-{
-  /**
-   * The serial version identifier required to satisfy the compiler because this
-   * class implements the <CODE>java.io.Serializable</CODE> interface.  This
-   * value was generated using the <CODE>serialver</CODE> command-line utility
-   * included with the Java SDK.
-   */
-  private static final long serialVersionUID = 2197633272056656073L;
-
-
-
-  // The set of ASN.1 elements contained in this set.
-  private ArrayList<ASN1Element> elements;
-
-
-
-
-  /**
-   * Creates a new ASN.1 set element with the default type no value.
-   */
-  public ASN1Set()
-  {
-    super(UNIVERSAL_SET_TYPE);
-
-
-    this.elements = new ArrayList<ASN1Element>();
-  }
-
-
-
-  /**
-   * Creates a new ASN.1 set element with the specified type and no value.
-   *
-   * @param  type  The BER type for this ASN.1 set.
-   */
-  public ASN1Set(byte type)
-  {
-    super(type);
-
-
-    this.elements = new ArrayList<ASN1Element>();
-  }
-
-
-
-  /**
-   * Creates a new ASN.1 set with the default type and the provided set of
-   * elements.
-   *
-   * @param  elements  The set of elements to include in this set.
-   */
-  public ASN1Set(ArrayList<ASN1Element> elements)
-  {
-    super(UNIVERSAL_SET_TYPE, encodeValue(elements));
-
-
-    if (elements == null)
-    {
-      this.elements = new ArrayList<ASN1Element>();
-    }
-    else
-    {
-      this.elements = elements;
-    }
-  }
-
-
-
-  /**
-   * Creates a new ASN.1 set with the specified type and the provided set of
-   * elements.
-   *
-   * @param  type      The BER type for this set.
-   * @param  elements  The set of elements to include in this set.
-   */
-  public ASN1Set(byte type, ArrayList<ASN1Element> elements)
-  {
-    super(type, encodeValue(elements));
-
-
-    if (elements == null)
-    {
-      this.elements = new ArrayList<ASN1Element>();
-    }
-    else
-    {
-      this.elements = elements;
-    }
-  }
-
-
-
-  /**
-   * Creates a new ASN.1 set with the specified type and value and the
-   * provided set of elements.
-   *
-   * @param  type      The BER type for this set.
-   * @param  value     The encoded value for this set.
-   * @param  elements  The set of elements to include in this set.
-   */
-  private ASN1Set(byte type, byte[] value, ArrayList<ASN1Element> elements)
-  {
-    super(type, value);
-
-
-    if (elements == null)
-    {
-      this.elements = new ArrayList<ASN1Element>();
-    }
-    else
-    {
-      this.elements = elements;
-    }
-  }
-
-
-
-  /**
-   * Retrieves the set of elements contained in this ASN.1 set.  The returned
-   * list must not be modified by the caller.
-   *
-   * @return  The set of elements contained in this ASN.1 set.
-   */
-  public ArrayList<ASN1Element> elements()
-  {
-    return elements;
-  }
-
-
-
-  /**
-   * Specifies the set of elements for this ASN.1 set.
-   *
-   * @param  elements  The set of elements for this ASN.1 set.
-   */
-  public void setElements(ArrayList<ASN1Element> elements)
-  {
-    if (elements == null)
-    {
-      this.elements.clear();
-      setValueInternal(NO_VALUE);
-    }
-    else
-    {
-      this.elements = elements;
-      setValueInternal(encodeValue(elements));
-    }
-  }
-
-
-
-  /**
-   * Specifies the value for this ASN.1 set element.
-   *
-   * @param  value  The encoded value for this ASN.1 set element.
-   *
-   * @throws  ASN1Exception  If the provided array is null or cannot be decoded
-   *                         as a set of ASN.1 elements.
-   */
-  public void setValue(byte[] value)
-         throws ASN1Exception
-  {
-    if (value == null)
-    {
-      Message message = ERR_ASN1_SET_SET_VALUE_NULL.get();
-      throw new ASN1Exception(message);
-    }
-
-    elements = decodeElements(value);
-    setValueInternal(value);
-  }
-
-
-
-  /**
-   * Decodes the provided ASN.1 element as a set element.
-   *
-   * @param  element  The ASN.1 element to decode as a set element.
-   *
-   * @return  The decoded ASN.1 set element.
-   *
-   * @throws  ASN1Exception  If the provided ASN.1 element cannot be decoded as
-   *                         a set element.
-   */
-  public static ASN1Set decodeAsSet(ASN1Element element)
-         throws ASN1Exception
-  {
-    if (element == null)
-    {
-      Message message = ERR_ASN1_SET_DECODE_ELEMENT_NULL.get();
-      throw new ASN1Exception(message);
-    }
-
-    byte[] value = element.value();
-    ArrayList<ASN1Element> elements = decodeElements(value);
-    return new ASN1Set(element.getType(), value, elements);
-  }
-
-
-
-  /**
-   * Decodes the provided byte array as an ASN.1 set element.
-   *
-   * @param  encodedElement  The byte array to decode as an ASN.1 set element.
-   *
-   * @return  The decoded ASN.1 set element.
-   *
-   * @throws  ASN1Exception  If the provided byte array cannot be decoded as an
-   *                         ASN.1 set element.
-   */
-  public static ASN1Set decodeAsSet(byte[] encodedElement)
-         throws ASN1Exception
-  {
-    // First make sure that the array is not null and long enough to contain
-    // a valid ASN.1 set element.
-    if (encodedElement == null)
-    {
-      Message message = ERR_ASN1_SET_DECODE_ARRAY_NULL.get();
-      throw new ASN1Exception(message);
-    }
-
-    if (encodedElement.length < 2)
-    {
-      Message message = ERR_ASN1_SHORT_ELEMENT.get(encodedElement.length);
-      throw new ASN1Exception(message);
-    }
-
-
-    // Next, decode the length.  This allows multi-byte lengths with up to four
-    // bytes used to indicate how many bytes are in the length.
-    byte type = encodedElement[0];
-    int length = (encodedElement[1] & 0x7F);
-    int valueStartPos = 2;
-    if (length != encodedElement[1])
-    {
-      int numLengthBytes = length;
-      if (numLengthBytes > 4)
-      {
-        Message message = ERR_ASN1_INVALID_NUM_LENGTH_BYTES.get(numLengthBytes);
-        throw new ASN1Exception(message);
-      }
-      else if (encodedElement.length < (2 + numLengthBytes))
-      {
-        Message message = ERR_ASN1_TRUNCATED_LENGTH.get(numLengthBytes);
-        throw new ASN1Exception(message);
-      }
-
-      length = 0x00;
-      valueStartPos = 2 + numLengthBytes;
-      for (int i=0; i < numLengthBytes; i++)
-      {
-        length = (length << 8) | (encodedElement[i+2] & 0xFF);
-      }
-    }
-
-
-    // Make sure that the number of bytes left is equal to the number of bytes
-    // in the value.
-    if ((encodedElement.length - valueStartPos) != length)
-    {
-      Message message = ERR_ASN1_LENGTH_MISMATCH.get(
-          length, (encodedElement.length - valueStartPos));
-      throw new ASN1Exception(message);
-    }
-
-
-    // Copy the value, decode the elements it contains, and construct the set to
-    // return.
-    byte[] value = new byte[length];
-    System.arraycopy(encodedElement, valueStartPos, value, 0, length);
-    ArrayList<ASN1Element> elements = decodeElements(value);
-    return new ASN1Set(type, value, elements);
-  }
-
-
-
-  /**
-   * Appends a string representation of this ASN.1 set element to the
-   * provided buffer.
-   *
-   * @param  buffer  The buffer to which the information should be appended.
-   */
-  public void toString(StringBuilder buffer)
-  {
-    buffer.append("ASN1Set(type=");
-    buffer.append(byteToHex(getType()));
-    buffer.append(", values={ ");
-
-    if (! elements.isEmpty())
-    {
-      Iterator<ASN1Element> iterator = elements.iterator();
-
-      iterator.next().toString(buffer);
-
-      while (iterator.hasNext())
-      {
-        buffer.append(", ");
-        iterator.next().toString(buffer);
-      }
-    }
-
-    buffer.append(" })");
-  }
-
-
-
-  /**
-   * Appends a string representation of this protocol element to the provided
-   * buffer.
-   *
-   * @param  buffer  The buffer into which the string representation should be
-   *                 written.
-   * @param  indent  The number of spaces that should be used to indent the
-   *                 resulting string representation.
-   */
-  public void toString(StringBuilder buffer, int indent)
-  {
-    StringBuilder indentBuf = new StringBuilder(indent);
-    for (int i=0 ; i < indent; i++)
-    {
-      indentBuf.append(' ');
-    }
-
-    buffer.append(indentBuf);
-    buffer.append("ASN.1 Set");
-    buffer.append(EOL);
-
-    buffer.append(indentBuf);
-    buffer.append("  BER Type:  ");
-    buffer.append(byteToHex(getType()));
-    buffer.append(EOL);
-
-    if (! elements.isEmpty())
-    {
-      buffer.append(indentBuf);
-      buffer.append("  Decoded Values:");
-      buffer.append(EOL);
-
-      Iterator<ASN1Element> iterator = elements.iterator();
-
-      buffer.append(indentBuf);
-      buffer.append("  ");
-      iterator.next().toString(buffer);
-      buffer.append(EOL);
-
-      while (iterator.hasNext())
-      {
-        buffer.append(indentBuf);
-        buffer.append("  ");
-        iterator.next().toString(buffer);
-        buffer.append(EOL);
-      }
-    }
-
-
-    buffer.append(indentBuf);
-    buffer.append("  Value:  ");
-    buffer.append(EOL);
-    byteArrayToHexPlusAscii(buffer, value(), indent+2);
-  }
-}
-
diff --git a/opends/src/server/org/opends/server/protocols/asn1/ASN1Writer.java b/opends/src/server/org/opends/server/protocols/asn1/ASN1Writer.java
index 1c04d4c..2e54c39 100644
--- a/opends/src/server/org/opends/server/protocols/asn1/ASN1Writer.java
+++ b/opends/src/server/org/opends/server/protocols/asn1/ASN1Writer.java
@@ -22,135 +22,340 @@
  * CDDL HEADER END
  *
  *
- *      Copyright 2006-2008 Sun Microsystems, Inc.
+ *      Copyright 2006-2009 Sun Microsystems, Inc.
  */
 package org.opends.server.protocols.asn1;
 
 
 
-import java.io.IOException;
-import java.io.OutputStream;
-import java.net.Socket;
+import org.opends.server.types.ByteSequence;
 
-import static org.opends.server.loggers.debug.DebugLogger.*;
-import org.opends.server.loggers.debug.DebugTracer;
-import org.opends.server.types.DebugLogLevel;
+import java.io.Closeable;
+import java.io.IOException;
+import java.io.Flushable;
 
 
 /**
- * This class defines a utility that can be used to write ASN.1 elements over a
- * provided socket or output stream.
+ * 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.
  */
-@org.opends.server.types.PublicAPI(
-     stability=org.opends.server.types.StabilityLevel.UNCOMMITTED,
-     mayInstantiate=true,
-     mayExtend=false,
-     mayInvoke=true)
-public final class ASN1Writer
+public interface ASN1Writer extends Closeable, Flushable
 {
+
   /**
-   * The tracer object for the debug logger.
+   * 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 the writer.
    */
-  private static final DebugTracer TRACER = getTracer();
+  public void close() throws IOException;
 
-
-
-
-  // The output stream to which the encoded elements should be written.
-  private OutputStream outputStream;
-
-  // The socket with which the output stream is associated.
-  private Socket socket;
+  /**
+   * Flushes the writer. If the writer has saved any elements from the
+   * previous write methods in a buffer, write them immediately to their
+   * intended destination. Then, if that destination is another byte stream,
+   * flush it. Thus one 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 I/O error occurs
+   */
+  public void flush() throws IOException;
 
 
 
   /**
-   * Creates a new ASN.1 writer that will write elements over the provided
-   * socket.
+   * Writes a boolean element using the Universal Boolean ASN.1 type
+   * tag.
    *
-   * @param  socket  The socket to use to write ASN.1 elements.
-   *
-   * @throws  IOException  If a problem occurs while trying to get the output
-   *                       stream for the socket.
+   * @param booleanValue
+   *          The boolean value to write.
+   * @return a reference to this object.
+   * @throws IOException
+   *           If an error occurs while writing.
    */
-  public ASN1Writer(Socket socket)
-         throws IOException
-  {
-    this.socket  = socket;
-    outputStream = socket.getOutputStream();
-  }
+  ASN1Writer writeBoolean(boolean booleanValue) throws IOException;
 
 
 
   /**
-   * Creates a new ASN.1 writer that will write elements over the provided
-   * output stream.
+   * Writes a boolean element using the provided type tag.
    *
-   * @param  outputStream  The output stream to use to write ASN.1 elements.
+   * @param type
+   *          The type tag to use.
+   * @param booleanValue
+   *          The boolean value to write.
+   * @return a reference to this object.
+   * @throws IOException
+   *           If an error occurs while writing.
    */
-  public ASN1Writer(OutputStream outputStream)
-  {
-    this.outputStream = outputStream;
-    socket            = null;
-  }
+  ASN1Writer writeBoolean(byte type, boolean booleanValue) throws IOException;
 
 
 
   /**
-   * Writes the provided ASN.1 element over the output stream associated with
-   * this ASN.1 writer.
+   * Finish writing a sequence.
    *
-   * @param  element  The element to be written.
-   *
-   * @return  The number of bytes actually written over the output stream.
-   *
-   * @throws  IOException  If a problem occurs while trying to write the
-   *                       information over the output stream.
+   * @return a reference to this object.
+   * @throws IOException
+   *           If an error occurs while writing.
    */
-  public int writeElement(ASN1Element element)
-         throws IOException
-  {
-    byte[] elementBytes = element.encode();
-    outputStream.write(elementBytes);
-    outputStream.flush();
-
-    return elementBytes.length;
-  }
+  ASN1Writer writeEndSequence() throws IOException;
 
 
 
   /**
-   * Closes this ASN.1 writer and the underlying output stream/socket.
+   * Finish writing a set.
+   *
+   * @return a reference to this object.
+   * @throws IOException
+   *           If an error occurs while writing.
    */
-  public void close()
-  {
-    try
-    {
-      outputStream.close();
-    }
-    catch (Exception e)
-    {
-      if (debugEnabled())
-      {
-        TRACER.debugCaught(DebugLogLevel.ERROR, e);
-      }
-    }
+  ASN1Writer writeEndSet() throws IOException;
 
 
-    if (socket != null)
-    {
-      try
-      {
-        socket.close();
-      }
-      catch (Exception e)
-      {
-        if (debugEnabled())
-        {
-          TRACER.debugCaught(DebugLogLevel.ERROR, e);
-        }
-      }
-    }
-  }
+
+  /**
+   * Writes an integer element using the provided type tag.
+   *
+   * @param type
+   *          The type tag to use.
+   * @param intValue
+   *          The integer value to write.
+   * @return a reference to this object.
+   * @throws IOException
+   *           If an error occurs while writing.
+   */
+  ASN1Writer writeInteger(byte type, int intValue) throws IOException;
+
+
+
+  /**
+   * Writes an integer element using the provided type tag.
+   *
+   * @param type
+   *          The type tag to use.
+   * @param longValue
+   *          The integer value to write.
+   * @return a reference to this object.
+   * @throws IOException
+   *           If an error occurs while writing.
+   */
+  ASN1Writer writeInteger(byte type, long longValue) throws IOException;
+
+
+
+  /**
+   * Writes an integer element using the Universal Integer ASN.1 type
+   * tag.
+   *
+   * @param intValue
+   *          The integer value to write.
+   * @return a reference to this object.
+   * @throws IOException
+   *           If an error occurs while writing.
+   */
+  ASN1Writer writeInteger(int intValue) throws IOException;
+
+
+
+  /**
+   * Writes an integer element using the Universal Integer ASN.1 type
+   * tag.
+   *
+   * @param longValue
+   *          The integer value to write.
+   * @return a reference to this object.
+   * @throws IOException
+   *           If an error occurs while writing.
+   */
+  ASN1Writer writeInteger(long longValue) throws IOException;
+
+
+
+  /**
+   * Writes an enumerated element using the Universal Enumerated ASN.1 type
+   * tag.
+   *
+   * @param intValue
+   *          The integer value of the enumeration to write.
+   * @return a reference to this object.
+   * @throws IOException
+   *           If an error occurs while writing.
+   */
+  ASN1Writer writeEnumerated(int intValue) throws IOException;
+
+
+  /**
+   * Writes a null element using the Universal Null ASN.1 type tag.
+   *
+   * @return a reference to this object.
+   * @throws IOException
+   *           If an error occurs while writing.
+   */
+  ASN1Writer writeNull() throws IOException;
+
+
+
+  /**
+   * Writes a null element using the provided type tag.
+   *
+   * @param type
+   *          The type tag to use.
+   * @return a reference to this object.
+   * @throws IOException
+   *           If an error occurs while writing.
+   */
+  ASN1Writer writeNull(byte type) throws IOException;
+
+
+
+  /**
+   * Writes an octet string element using the provided type tag and
+   * byte array.
+   *
+   * @param type
+   *          The type tag to use.
+   * @param value
+   *          The byte array containing the data to write.
+   * @param offset
+   *          The offset in the byte array.
+   * @param length
+   *          The number of bytes to write.
+   * @return a reference to this object.
+   * @throws IOException
+   *           If an error occurs while writing.
+   */
+  ASN1Writer writeOctetString(byte type, byte[] value, int offset, int length)
+      throws IOException;
+
+
+
+  /**
+   * Writes an octet string element using the provided type tag and
+   * byte sequence.
+   *
+   * @param type
+   *          The type tag to use.
+   * @param value
+   *          The byte sequence containing the data to write.
+   * @return a reference to this object.
+   * @throws IOException
+   *           If an error occurs while writing.
+   */
+  ASN1Writer writeOctetString(byte type, ByteSequence value) throws IOException;
+
+
+
+  /**
+   * Writes an octet string element using the provided type tag and
+   * the UTF-8 encoded bytes of the provided string.
+   *
+   * @param type
+   *          The type tag to use.
+   * @param value
+   *          The string to write.
+   * @return a reference to this object.
+   * @throws IOException
+   *           If an error occurs while writing.
+   */
+  ASN1Writer writeOctetString(byte type, String value) throws IOException;
+
+
+
+  /**
+   * Writes an octet string element using the Universal Octet String
+   * ASN.1 type tag and the provided byte array.
+   *
+   * @param value
+   *          The byte array containing the data to write.
+   * @param offset
+   *          The offset in the byte array.
+   * @param length
+   *          The number of bytes to write.
+   * @return a reference to this object.
+   * @throws IOException
+   *           If an error occurs while writing.
+   */
+  ASN1Writer writeOctetString(byte[] value, int offset, int length)
+      throws IOException;
+
+
+
+  /**
+   * Writes an octet string element using the Universal Octet String
+   * ASN.1 type tag and the provided byte sequence.
+   *
+   * @param value
+   *          The byte sequence containing the data to write.
+   * @return a reference to this object.
+   * @throws IOException
+   *           If an error occurs while writing.
+   */
+  ASN1Writer writeOctetString(ByteSequence value) throws IOException;
+
+
+
+  /**
+   * Writes an octet string element using the Universal Octet String
+   * ASN.1 type tag and the UTF-8 encoded bytes of the provided
+   * string.
+   *
+   * @param value
+   *          The string to write.
+   * @return a reference to this object.
+   * @throws IOException
+   *           If an error occurs while writing.
+   */
+  ASN1Writer writeOctetString(String value) throws IOException;
+
+
+
+  /**
+   * Writes a sequence element using the Universal Sequence ASN.1 type
+   * tag. All further writes will be part of this set until
+   * {@link #writeEndSequence()} is called.
+   *
+   * @return a reference to this object.
+   * @throws IOException
+   *           If an error occurs while writing.
+   */
+  ASN1Writer writeStartSequence() throws IOException;
+
+
+
+  /**
+   * Writes a sequence element using the provided type tag. All
+   * further writes will be part of this set until
+   * {@link #writeEndSequence()} is called.
+   *
+   * @param type
+   *          The type tag to use.
+   * @return a reference to this object.
+   * @throws IOException
+   *           If an error occurs while writing.
+   */
+  ASN1Writer writeStartSequence(byte type) throws IOException;
+
+
+
+  /**
+   * Writes a set element using the Universal Set type tag. All
+   * further writes will be part of this set until
+   * {@link #writeEndSet()} is called.
+   *
+   * @return a reference to this object.
+   * @throws IOException
+   *           If an error occurs while writing.
+   */
+  ASN1Writer writeStartSet() throws IOException;
 }
-
diff --git a/opends/src/server/org/opends/server/protocols/asn1/ByteSequenceOutputStream.java b/opends/src/server/org/opends/server/protocols/asn1/ByteSequenceOutputStream.java
new file mode 100644
index 0000000..ae04d5b
--- /dev/null
+++ b/opends/src/server/org/opends/server/protocols/asn1/ByteSequenceOutputStream.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 2006-2008 Sun Microsystems, Inc.
+ */
+package org.opends.server.protocols.asn1;
+
+import org.opends.server.types.ByteStringBuilder;
+
+import java.io.OutputStream;
+import java.io.IOException;
+
+/**
+ * An adapter class that allows writing to an byte string builder
+ * with the outputstream interface.
+ */
+final class ByteSequenceOutputStream extends OutputStream {
+
+  private final ByteStringBuilder buffer;
+
+  /**
+   * Creates a new byte string builder output stream.
+   *
+   * @param buffer
+   *          The underlying byte string builder.
+   */
+  ByteSequenceOutputStream(ByteStringBuilder buffer)
+  {
+    this.buffer = buffer;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  public void write(int i) throws IOException {
+    buffer.append(((byte) (i & 0xFF)));
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  public void write(byte[] bytes) throws IOException {
+    buffer.append(bytes);
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  public void write(byte[] bytes, int i, int i1) throws IOException {
+    buffer.append(bytes, i, i1);
+  }
+
+  /**
+   * Gets the length of the underlying byte string builder.
+   *
+   * @return The length of the underlying byte string builder.
+   */
+  int length() {
+    return buffer.length();
+  }
+
+
+
+  /**
+   * 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.
+   */
+  void writeTo(OutputStream stream) throws IOException
+  {
+    buffer.copyTo(stream);
+  }
+
+  /**
+   * Resets this output stream such that the underlying byte string
+   * builder is empty.
+   */
+  void reset()
+  {
+    buffer.clear();
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  public void close() throws IOException {
+    buffer.clear();
+  }
+}
diff --git a/opends/src/server/org/opends/server/protocols/internal/InternalClientConnection.java b/opends/src/server/org/opends/server/protocols/internal/InternalClientConnection.java
index 69c1571..d8cd2b9 100644
--- a/opends/src/server/org/opends/server/protocols/internal/InternalClientConnection.java
+++ b/opends/src/server/org/opends/server/protocols/internal/InternalClientConnection.java
@@ -43,44 +43,10 @@
 import org.opends.messages.Message;
 import org.opends.server.api.ClientConnection;
 import org.opends.server.api.ConnectionHandler;
-import org.opends.server.api.ConnectionSecurityProvider;
 import org.opends.server.core.*;
 import org.opends.server.core.networkgroups.NetworkGroup;
-import org.opends.server.extensions.*;
 import org.opends.server.loggers.debug.DebugTracer;
-import org.opends.server.protocols.asn1.ASN1OctetString;
-import org.opends.server.types.AbstractOperation;
-import org.opends.server.types.Attribute;
-import org.opends.server.types.AttributeBuilder;
-import org.opends.server.types.AttributeType;
-import org.opends.server.types.AttributeValue;
-import org.opends.server.types.Attributes;
-import org.opends.server.types.AuthenticationInfo;
-import org.opends.server.types.ByteString;
-import org.opends.server.types.CancelRequest;
-import org.opends.server.types.CancelResult;
-import org.opends.server.types.Control;
-import org.opends.server.types.DN;
-import org.opends.server.types.DebugLogLevel;
-import org.opends.server.types.DereferencePolicy;
-import org.opends.server.types.DirectoryException;
-import org.opends.server.types.DisconnectReason;
-import org.opends.server.types.Entry;
-import org.opends.server.types.IntermediateResponse;
-import org.opends.server.types.LDAPException;
-import org.opends.server.types.Modification;
-import org.opends.server.types.ObjectClass;
-import org.opends.server.types.Operation;
-import org.opends.server.types.Privilege;
-import org.opends.server.types.RDN;
-import org.opends.server.types.RawAttribute;
-import org.opends.server.types.RawFilter;
-import org.opends.server.types.RawModification;
-import org.opends.server.types.ResultCode;
-import org.opends.server.types.SearchFilter;
-import org.opends.server.types.SearchResultEntry;
-import org.opends.server.types.SearchResultReference;
-import org.opends.server.types.SearchScope;
+import org.opends.server.types.*;
 import org.opends.server.util.AddChangeRecordEntry;
 import org.opends.server.util.DeleteChangeRecordEntry;
 import org.opends.server.util.ModifyChangeRecordEntry;
@@ -131,9 +97,6 @@
   // connection.
   private static AtomicLong nextOperationID;
 
-  // The connection security provider for this client connection.
-  private ConnectionSecurityProvider securityProvider;
-
   // The static connection for root-based connections.
   private static InternalClientConnection rootConnection;
 
@@ -225,7 +188,7 @@
       AttributeBuilder builder = new AttributeBuilder(privType);
       for (Privilege p : Privilege.getDefaultRootPrivileges())
       {
-        builder.add(new AttributeValue(privType, p.getName()));
+        builder.add(AttributeValues.create(privType, p.getName()));
       }
       attrList = new LinkedList<Attribute>();
       attrList.add(builder.toAttribute());
@@ -259,19 +222,6 @@
 
     connectionID  = nextConnectionID.getAndDecrement();
     operationList = new LinkedList<Operation>();
-
-    try
-    {
-      securityProvider = new InternalConnectionSecurityProvider();
-      securityProvider.initializeConnectionSecurityProvider(null);
-    }
-    catch (Exception e)
-    {
-      if (debugEnabled())
-      {
-        TRACER.debugCaught(DebugLogLevel.ERROR, e);
-      }
-    }
   }
 
 
@@ -299,19 +249,6 @@
 
     connectionID  = nextConnectionID.getAndDecrement();
     operationList = new LinkedList<Operation>();
-
-    try
-    {
-      securityProvider = new InternalConnectionSecurityProvider();
-      securityProvider.initializeConnectionSecurityProvider(null);
-    }
-    catch (Exception e)
-    {
-      if (debugEnabled())
-      {
-        TRACER.debugCaught(DebugLogLevel.ERROR, e);
-      }
-    }
   }
 
 
@@ -691,69 +628,10 @@
   @Override()
   public boolean isSecure()
   {
-    // Internal connections will generally be considered secure, but
-    // they may be declared insecure if they are accessed through some
-    // external mechanism (e.g., a DSML handler that runs the server
-    // in a Servlet engine and using internal operations for
-    // processing requests).
-    return securityProvider.isSecure();
+      return true;
   }
 
 
-
-  /**
-   * Retrieves the connection security provider for this client
-   * connection.
-   *
-   * @return  The connection security provider for this client
-   *          connection.
-   */
-  @Override()
-  public ConnectionSecurityProvider getConnectionSecurityProvider()
-  {
-    return securityProvider;
-  }
-
-
-
-  /**
-   * Specifies the connection security provider for this client
-   * connection.
-   *
-   * @param  securityProvider  The connection security provider to use
-   *                           for communication on this client
-   *                           connection.
-   */
-  @org.opends.server.types.PublicAPI(
-       stability=org.opends.server.types.StabilityLevel.PRIVATE,
-       mayInstantiate=false,
-       mayExtend=false,
-       mayInvoke=false)
-  @Override()
-  public void setConnectionSecurityProvider(ConnectionSecurityProvider
-                                                 securityProvider)
-  {
-    this.securityProvider = securityProvider;
-  }
-
-
-
-  /**
-   * Retrieves the human-readable name of the security mechanism that
-   * is used to protect communication with this client.
-   *
-   * @return  The human-readable name of the security mechanism that
-   *          is used to protect communication with this client, or
-   *          <CODE>null</CODE> if no security is in place.
-   */
-  @Override()
-  public String getSecurityMechanism()
-  {
-    return securityProvider.getSecurityMechanismName();
-  }
-
-
-
   /**
    * Indicates that the data in the provided buffer has been read from
    * the client and should be processed.  The contents of the provided
@@ -880,7 +758,7 @@
   public AddOperation processAdd(String rawEntryDN,
                                  List<RawAttribute> rawAttributes)
   {
-    return processAdd(new ASN1OctetString(rawEntryDN), rawAttributes,
+    return processAdd(ByteString.valueOf(rawEntryDN), rawAttributes,
                       null);
   }
 
@@ -1081,7 +959,7 @@
       {
         for (AttributeValue v : a)
         {
-          String ocName = v.getStringValue();
+          String ocName = v.getValue().toString();
           String lowerName = toLowerCase(ocName);
           ObjectClass oc = DirectoryServer.getObjectClass(lowerName,
                                                           true);
@@ -1115,8 +993,8 @@
   public BindOperation processSimpleBind(String rawBindDN,
                                          String password)
   {
-    return processSimpleBind(new ASN1OctetString(rawBindDN),
-                             new ASN1OctetString(password),
+    return processSimpleBind(ByteString.valueOf(rawBindDN),
+        ByteString.valueOf(password),
                              null);
   }
 
@@ -1140,8 +1018,8 @@
                                          String password,
                                          List<Control> controls)
   {
-    return processSimpleBind(new ASN1OctetString(rawBindDN),
-                             new ASN1OctetString(password), controls);
+    return processSimpleBind(ByteString.valueOf(rawBindDN),
+        ByteString.valueOf(password), controls);
   }
 
 
@@ -1269,7 +1147,7 @@
    */
   public BindOperation processSASLBind(ByteString rawBindDN,
                             String saslMechanism,
-                            ASN1OctetString saslCredentials)
+                            ByteString saslCredentials)
   {
     return processSASLBind(rawBindDN, saslMechanism, saslCredentials,
                            null);
@@ -1294,7 +1172,7 @@
    */
   public BindOperation processSASLBind(ByteString rawBindDN,
                             String saslMechanism,
-                            ASN1OctetString saslCredentials,
+                            ByteString saslCredentials,
                             List<Control> controls)
   {
     if (controls == null)
@@ -1330,7 +1208,7 @@
    */
   public BindOperation processSASLBind(DN bindDN,
                             String saslMechanism,
-                            ASN1OctetString saslCredentials)
+                            ByteString saslCredentials)
   {
     return processSASLBind(bindDN, saslMechanism, saslCredentials,
                            null);
@@ -1355,7 +1233,7 @@
    */
   public BindOperation processSASLBind(DN bindDN,
                             String saslMechanism,
-                            ASN1OctetString saslCredentials,
+                            ByteString saslCredentials,
                             List<Control> controls)
   {
     if (controls == null)
@@ -1394,9 +1272,9 @@
                                          String attributeType,
                                          String assertionValue)
   {
-    return processCompare(new ASN1OctetString(rawEntryDN),
+    return processCompare(ByteString.valueOf(rawEntryDN),
                           attributeType,
-                          new ASN1OctetString(assertionValue), null);
+        ByteString.valueOf(assertionValue), null);
   }
 
 
@@ -1422,9 +1300,9 @@
                                          String assertionValue,
                                          List<Control> controls)
   {
-    return processCompare(new ASN1OctetString(rawEntryDN),
+    return processCompare(ByteString.valueOf(rawEntryDN),
                           attributeType,
-                          new ASN1OctetString(assertionValue),
+        ByteString.valueOf(assertionValue),
                           controls);
   }
 
@@ -1566,7 +1444,7 @@
    */
   public DeleteOperation processDelete(String rawEntryDN)
   {
-    return processDelete(new ASN1OctetString(rawEntryDN), null);
+    return processDelete(ByteString.valueOf(rawEntryDN), null);
   }
 
 
@@ -1586,7 +1464,7 @@
   public DeleteOperation processDelete(String rawEntryDN,
                                        List<Control> controls)
   {
-    return processDelete(new ASN1OctetString(rawEntryDN), controls);
+    return processDelete(ByteString.valueOf(rawEntryDN), controls);
   }
 
 
@@ -1720,7 +1598,7 @@
    */
   public ExtendedOperation processExtendedOperation(
                                 String requestOID,
-                                ASN1OctetString requestValue)
+                                ByteString requestValue)
   {
     return processExtendedOperation(requestOID, requestValue, null);
   }
@@ -1744,7 +1622,7 @@
    */
   public ExtendedOperation processExtendedOperation(
                                 String requestOID,
-                                ASN1OctetString requestValue,
+                                ByteString requestValue,
                                 List<Control> controls)
   {
     if (controls == null)
@@ -1779,7 +1657,7 @@
   public ModifyOperation processModify(String rawEntryDN,
                               List<RawModification> rawModifications)
   {
-    return processModify(new ASN1OctetString(rawEntryDN),
+    return processModify(ByteString.valueOf(rawEntryDN),
                          rawModifications, null);
   }
 
@@ -1804,7 +1682,7 @@
                               List<RawModification> rawModifications,
                               List<Control> controls)
   {
-    return processModify(new ASN1OctetString(rawEntryDN),
+    return processModify(ByteString.valueOf(rawEntryDN),
                          rawModifications, controls);
   }
 
@@ -1959,8 +1837,8 @@
                                            String rawNewRDN,
                                            boolean deleteOldRDN)
   {
-    return processModifyDN(new ASN1OctetString(rawEntryDN),
-                           new ASN1OctetString(rawNewRDN),
+    return processModifyDN(ByteString.valueOf(rawEntryDN),
+        ByteString.valueOf(rawNewRDN),
                            deleteOldRDN, null, null);
   }
 
@@ -1986,8 +1864,8 @@
                                            boolean deleteOldRDN,
                                            List<Control> controls)
   {
-    return processModifyDN(new ASN1OctetString(rawEntryDN),
-                           new ASN1OctetString(rawNewRDN),
+    return processModifyDN(ByteString.valueOf(rawEntryDN),
+        ByteString.valueOf(rawNewRDN),
                            deleteOldRDN, null, controls);
   }
 
@@ -2037,10 +1915,10 @@
                                            boolean deleteOldRDN,
                                            String rawNewSuperior)
   {
-    return processModifyDN(new ASN1OctetString(rawEntryDN),
-                           new ASN1OctetString(rawNewRDN),
+    return processModifyDN(ByteString.valueOf(rawEntryDN),
+        ByteString.valueOf(rawNewRDN),
                            deleteOldRDN,
-                           new ASN1OctetString(rawNewSuperior), null);
+        ByteString.valueOf(rawNewSuperior), null);
   }
 
 
@@ -2069,10 +1947,10 @@
                                            String rawNewSuperior,
                                            List<Control> controls)
   {
-    return processModifyDN(new ASN1OctetString(rawEntryDN),
-                           new ASN1OctetString(rawNewRDN),
+    return processModifyDN(ByteString.valueOf(rawEntryDN),
+        ByteString.valueOf(rawNewRDN),
                            deleteOldRDN,
-                           new ASN1OctetString(rawNewSuperior),
+        ByteString.valueOf(rawNewSuperior),
                            controls);
   }
 
@@ -2296,7 +2174,7 @@
                      le.getErrorMessage(), le);
     }
 
-    return processSearch(new ASN1OctetString(rawBaseDN), scope,
+    return processSearch(ByteString.valueOf(rawBaseDN), scope,
                          rawFilter);
   }
 
@@ -2435,7 +2313,7 @@
                      le.getErrorMessage(), le);
     }
 
-    return processSearch(new ASN1OctetString(rawBaseDN), scope,
+    return processSearch(ByteString.valueOf(rawBaseDN), scope,
                          derefPolicy, sizeLimit, timeLimit, typesOnly,
                          rawFilter, attributes, controls,
                          searchListener);
@@ -3117,5 +2995,13 @@
     // Internal operations will not be limited.
     return 0;
   }
+
+  /**
+   * {@inheritDoc}
+   */
+  public int getSSF() {
+      //Always return strongest value.
+      return 256;
+  }
 }
 
diff --git a/opends/src/server/org/opends/server/protocols/internal/InternalLDAPInputStream.java b/opends/src/server/org/opends/server/protocols/internal/InternalLDAPInputStream.java
index a8104ec..f2ab4f5 100644
--- a/opends/src/server/org/opends/server/protocols/internal/InternalLDAPInputStream.java
+++ b/opends/src/server/org/opends/server/protocols/internal/InternalLDAPInputStream.java
@@ -28,13 +28,15 @@
 
 
 
-import java.io.InputStream;
 import java.io.IOException;
-import java.nio.ByteBuffer;
+import java.io.InputStream;
 import java.util.concurrent.ArrayBlockingQueue;
 
+import org.opends.server.protocols.asn1.ASN1;
+import org.opends.server.protocols.asn1.ASN1Writer;
 import org.opends.server.protocols.ldap.LDAPMessage;
-
+import org.opends.server.types.ByteSequenceReader;
+import org.opends.server.types.ByteStringBuilder;
 
 
 /**
@@ -54,16 +56,22 @@
 {
   // The queue of LDAP messages providing the data to be made
   // available to the client.
-  private ArrayBlockingQueue<LDAPMessage> messageQueue;
+  private final ArrayBlockingQueue<LDAPMessage> messageQueue;
 
   // Indicates whether this stream has been closed.
   private boolean closed;
 
   // The byte buffer with partial data to be written to the client.
-  private ByteBuffer partialMessageBuffer;
+  private final ByteStringBuilder messageBuffer;
+
+  // The byte buffer reader.
+  private final ByteSequenceReader messageReader;
+
+  // The byte buffer writer.
+  private final ASN1Writer writer;
 
   // The internal LDAP socket serviced by this input stream.
-  private InternalLDAPSocket socket;
+  private final InternalLDAPSocket socket;
 
 
 
@@ -77,10 +85,11 @@
   public InternalLDAPInputStream(InternalLDAPSocket socket)
   {
     this.socket = socket;
-
-    messageQueue = new ArrayBlockingQueue<LDAPMessage>(10);
-    partialMessageBuffer = null;
-    closed = false;
+    this.messageQueue = new ArrayBlockingQueue<LDAPMessage>(10);
+    this.messageBuffer = new ByteStringBuilder();
+    this.messageReader = messageBuffer.asReader();
+    this.writer = ASN1.getWriter(messageBuffer);
+    this.closed = false;
   }
 
 
@@ -136,17 +145,19 @@
    *
    * @return  The number of bytes that can be read (or skipped over)
    *          from this input stream wihtout blocking.
+   * @throws IOException if an I/O error occurs.
    */
   @Override()
-  public synchronized int available()
+  public synchronized int available() throws IOException
   {
-    if (partialMessageBuffer == null)
+    if (messageReader.remaining() < 1)
     {
       LDAPMessage message = messageQueue.poll();
       if ((message == null) || (message instanceof NullLDAPMessage))
       {
-        if (message instanceof NullLDAPMessage)
+        if (message != null)
         {
+          messageQueue.clear();
           closed = true;
         }
 
@@ -154,15 +165,13 @@
       }
       else
       {
-        partialMessageBuffer =
-             ByteBuffer.wrap(message.encode().encode());
-        return partialMessageBuffer.remaining();
+        messageBuffer.clear();
+        messageReader.rewind();
+        message.write(writer);
       }
     }
-    else
-    {
-      return partialMessageBuffer.remaining();
-    }
+
+    return messageReader.remaining();
   }
 
 
@@ -256,47 +265,39 @@
   public synchronized int read()
          throws IOException
   {
-    if (partialMessageBuffer != null)
+    if (messageReader.remaining() < 1)
     {
-      if (partialMessageBuffer.remaining() > 0)
+      LDAPMessage message;
+      try
       {
-        int i = (0xFF & partialMessageBuffer.get());
-        if (partialMessageBuffer.remaining() == 0)
+        message = messageQueue.take();
+      }
+      catch(InterruptedException ie)
+      {
+        // Probably because a shutdown was started. EOF
+        message = new NullLDAPMessage();
+      }
+
+      if ((message == null) || (message instanceof NullLDAPMessage))
+      {
+        if (message instanceof NullLDAPMessage)
         {
-          partialMessageBuffer = null;
+          messageQueue.clear();
+          closed = true;
+          return -1;
         }
 
-        return i;
+        return 0;
       }
       else
       {
-        partialMessageBuffer = null;
+        messageBuffer.clear();
+        messageReader.rewind();
+        message.write(writer);
       }
     }
 
-    if (closed)
-    {
-      return -1;
-    }
-
-    try
-    {
-      LDAPMessage message = messageQueue.take();
-      if (message instanceof NullLDAPMessage)
-      {
-        messageQueue.clear();
-        closed = true;
-        return -1;
-      }
-
-      partialMessageBuffer =
-           ByteBuffer.wrap(message.encode().encode());
-      return (0xFF & partialMessageBuffer.get());
-    }
-    catch (Exception e)
-    {
-      throw new IOException(e.getMessage());
-    }
+    return (0xFF & messageReader.get());
   }
 
 
@@ -346,70 +347,41 @@
   public synchronized int read(byte[] b, int off, int len)
          throws IOException
   {
-    if (partialMessageBuffer != null)
+    if (messageReader.remaining() < 1)
     {
-      int remaining = partialMessageBuffer.remaining();
-      if (remaining > 0)
+      LDAPMessage message;
+      try
       {
-        if (remaining <= len)
+        message = messageQueue.take();
+      }
+      catch(InterruptedException ie)
+      {
+        // Probably because a shutdown was started. EOF
+        message = new NullLDAPMessage();
+      }
+
+      if ((message == null) || (message instanceof NullLDAPMessage))
+      {
+        if (message instanceof NullLDAPMessage)
         {
-          // We can fit all the remaining data in the provided array,
-          // so that's all we'll try to put in it.
-          partialMessageBuffer.get(b, off, remaining);
-          partialMessageBuffer = null;
-          return remaining;
+          messageQueue.clear();
+          closed = true;
+          return -1;
         }
-        else
-        {
-          // The array is too small to hold the rest of the data, so
-          // only take as much as we can.
-          partialMessageBuffer.get(b, off, len);
-          return len;
-        }
+
+        return 0;
       }
       else
       {
-        partialMessageBuffer = null;
+        messageBuffer.clear();
+        messageReader.rewind();
+        message.write(writer);
       }
     }
 
-    if (closed)
-    {
-      return -1;
-    }
-
-    try
-    {
-      LDAPMessage message = messageQueue.take();
-      if (message instanceof NullLDAPMessage)
-      {
-        messageQueue.clear();
-        closed = true;
-        return -1;
-      }
-
-      byte[] encodedMessage = message.encode().encode();
-      if (encodedMessage.length <= len)
-      {
-        // We can fit the entire message in the array.
-        System.arraycopy(encodedMessage, 0, b, off,
-                         encodedMessage.length);
-        return encodedMessage.length;
-      }
-      else
-      {
-        // We can only fit part of the message in the array,
-        // so we need to save the rest for later.
-        System.arraycopy(encodedMessage, 0, b, off, len);
-        partialMessageBuffer = ByteBuffer.wrap(encodedMessage);
-        partialMessageBuffer.position(len);
-        return len;
-      }
-    }
-    catch (Exception e)
-    {
-      throw new IOException(e.getMessage());
-    }
+    int actualLen = Math.min(len, messageReader.remaining());
+    messageReader.get(b, off, actualLen);
+    return actualLen;
   }
 
 
diff --git a/opends/src/server/org/opends/server/protocols/internal/InternalLDAPOutputStream.java b/opends/src/server/org/opends/server/protocols/internal/InternalLDAPOutputStream.java
index 8eb9a94..860c925 100644
--- a/opends/src/server/org/opends/server/protocols/internal/InternalLDAPOutputStream.java
+++ b/opends/src/server/org/opends/server/protocols/internal/InternalLDAPOutputStream.java
@@ -22,7 +22,7 @@
  * CDDL HEADER END
  *
  *
- *      Copyright 2008 Sun Microsystems, Inc.
+ *      Copyright 2009 Sun Microsystems, Inc.
  */
 package org.opends.server.protocols.internal;
 
@@ -30,16 +30,15 @@
 
 import java.io.OutputStream;
 import java.io.IOException;
-import java.util.ArrayList;
+import java.io.InputStream;
+import java.util.List;
 
 import org.opends.messages.Message;
 import org.opends.server.core.*;
-import org.opends.server.protocols.asn1.ASN1Element;
+import org.opends.server.protocols.asn1.ASN1;
+import org.opends.server.protocols.asn1.ASN1Reader;
 import org.opends.server.protocols.ldap.*;
-import org.opends.server.types.AuthenticationType;
-import org.opends.server.types.Control;
-import org.opends.server.types.SearchResultEntry;
-import org.opends.server.types.SearchResultReference;
+import org.opends.server.types.*;
 
 import static org.opends.messages.ProtocolMessages.*;
 import static org.opends.server.protocols.ldap.LDAPConstants.*;
@@ -69,28 +68,126 @@
   // Indicates whether this stream has been closed.
   private boolean closed;
 
-  // Indicates whether the type of the ASN.1 element is needed.
-  private boolean needType;
-
-  // The BER type for the ASN.1 element being read.
-  private byte elementType;
-
-  // The data for the ASN.1 element being read.
-  private byte[] elementBytes;
-
-  // The length bytes for the ASN.1 element being read.
-  private byte[] lengthBytes;
-
-  // The offset in the appropriate array at which we should begin
-  // writing data.  This could either refer to the length or data
-  // array, depending on the stage of the encoding process.
-  private int arrayOffset;
+  private final ASN1Reader reader;
 
   // The internal LDAP socket with which this output stream is
   // associated.
-  private InternalLDAPSocket socket;
+  private final InternalLDAPSocket socket;
 
+  // The immediate data being written.
+  private ByteSequenceReader byteBuffer;
 
+  // The save buffer used to store any unprocessed data waiting
+  // to be read as ASN.1 elements. (Usually due to writing incomplete
+  // ASN.1 elements.)
+  private final ByteStringBuilder saveBuffer;
+
+  private final ByteSequenceReader saveBufferReader;
+
+  /**
+   * An adaptor class for reading from a save buffer and the bytes
+   * being written sequentially using the InputStream interface.
+   *
+   * Since the bytes being written are only available duing the write
+   * call, any unused data will be appended to the save buffer before
+   * returning from the write method. This reader will always read the
+   * save buffer first before the actual bytes being written to ensure
+   * bytes are read in the same order as they are written.
+   */
+  private class CombinedBufferInputStream extends InputStream
+  {
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public int available()
+    {
+      // The number of available bytes is the sum of the save buffer
+      // and the last read data in the NIO ByteStringBuilder.
+      return saveBufferReader.remaining() + byteBuffer.remaining();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public int read()
+    {
+      if(saveBufferReader.remaining() > 0)
+      {
+        // Try saved buffer first
+        return 0xFF & saveBufferReader.get();
+      }
+      if(byteBuffer.remaining() > 0)
+      {
+        // Must still be on the channel buffer
+        return 0xFF & byteBuffer.get();
+      }
+
+      return -1;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public int read(byte[] bytes)
+    {
+      return read(bytes, 0, bytes.length);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public int read(byte[] value, int off, int length)
+    {
+      int bytesCopied=0;
+      int len;
+      if(saveBufferReader.remaining() > 0)
+      {
+        // Copy out of the last saved buffer first
+        len = Math.min(saveBufferReader.remaining(), length);
+        saveBufferReader.get(value, off, len);
+        bytesCopied += len;
+      }
+      if(bytesCopied < length && byteBuffer.remaining() > 0)
+      {
+        // Copy out of the channel buffer if we haven't got
+        // everything we needed.
+        len = Math.min(byteBuffer.remaining(), length - bytesCopied);
+        byteBuffer.get(value, off + bytesCopied, len);
+        bytesCopied += len;
+      }
+      return bytesCopied;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public long skip(long length)
+    {
+      int bytesSkipped=0;
+      int len;
+      if(saveBufferReader.remaining() > 0)
+      {
+        // Skip in the last saved buffer first
+        len = Math.min(saveBufferReader.remaining(), (int)length);
+        saveBufferReader.position(saveBufferReader.position() + len);
+        bytesSkipped += len;
+      }
+      if(bytesSkipped < length && byteBuffer.remaining() > 0)
+      {
+        //Skip in the channel buffer if we haven't skipped enough.
+        len = Math.min(byteBuffer.remaining(),
+            (int)length - bytesSkipped);
+        byteBuffer.position(byteBuffer.position() + len);
+        bytesSkipped += len;
+      }
+      return bytesSkipped;
+    }
+  }
 
   /**
    * Creates a new instance of an internal LDAP output stream that is
@@ -102,14 +199,13 @@
   public InternalLDAPOutputStream(InternalLDAPSocket socket)
   {
     this.socket = socket;
+    this.closed = false;
+    this.saveBuffer = new ByteStringBuilder();
+    this.saveBufferReader = saveBuffer.asReader();
 
-    closed = false;
-
-    needType = true;
-    elementType = 0x00;
-    elementBytes = null;
-    lengthBytes = null;
-    arrayOffset = 0;
+    CombinedBufferInputStream bufferStream =
+        new CombinedBufferInputStream();
+    this.reader = ASN1.getReader(bufferStream);
   }
 
 
@@ -199,125 +295,32 @@
       throw new IOException(m.toString());
     }
 
-    if (len == 0)
+    byteBuffer = ByteString.wrap(b, off, len).asReader();
+
+    try
     {
-      return;
-    }
-
-
-    // See if we need to read the BER type.
-    int position  = off;
-    int remaining = len;
-    if (needType)
-    {
-      elementType = b[position++];
-      needType = false;
-
-      if (--remaining <= 0)
+      while(reader.elementAvailable())
       {
-        return;
+        LDAPMessage msg = LDAPReader.readMessage(reader);
+        processMessage(msg);
       }
     }
-
-
-    // See if we need to read the first length byte.
-    if ((lengthBytes == null) && (elementBytes == null))
+    catch(Exception e)
     {
-      int length = b[position++];
-      if (length == (length & 0x7F))
-      {
-        // It's a single-byte length, so we can create the value
-        // array.
-        elementBytes = new byte[length];
-      }
-      else
-      {
-        // It's a multi-byte length, so we can create the length
-        // array.
-        lengthBytes = new byte[length & 0x7F];
-      }
-
-      arrayOffset = 0;
-      if (--remaining <= 0)
-      {
-        return;
-      }
+      throw new IOException(e.getMessage());
     }
 
-
-    // See if we need to continue reading part of a multi-byte length.
-    if (lengthBytes != null)
+    // Clear the save buffer if we have read all of it
+    if(saveBufferReader.remaining() == 0)
     {
-      // See if we have enough to read the full length.  If so, then
-      // do it.  Otherwise, read what we can and return.
-      int needed = lengthBytes.length - arrayOffset;
-      if (remaining >= needed)
-      {
-        System.arraycopy(b, position, lengthBytes, arrayOffset,
-                         needed);
-        position += needed;
-        remaining -= needed;
-
-        int length = 0;
-        for (byte lb : lengthBytes)
-        {
-          length <<= 8;
-          length |= (lb & 0xFF);
-        }
-
-        elementBytes = new byte[length];
-        lengthBytes = null;
-        arrayOffset = 0;
-        if (remaining <= 0)
-        {
-          return;
-        }
-      }
-      else
-      {
-        System.arraycopy(b, position, lengthBytes, arrayOffset,
-                         remaining);
-        arrayOffset += remaining;
-        return;
-      }
+      saveBuffer.clear();
+      saveBufferReader.rewind();
     }
 
-
-    // See if we need to read data for the element value.
-    if (elementBytes != null)
+    // Append any unused data in the channel buffer to the save buffer
+    if(byteBuffer.remaining() > 0)
     {
-      // See if we have enough to read the full value.  If so, then
-      // do it, create the element, and process it.  Otherwise, read
-      // what we can and return.
-      int needed = elementBytes.length - arrayOffset;
-      if (remaining >= needed)
-      {
-        System.arraycopy(b, position, elementBytes, arrayOffset,
-                         needed);
-        position += needed;
-        remaining -= needed;
-        processElement(new ASN1Element(elementType, elementBytes));
-
-        needType     = true;
-        arrayOffset  = 0;
-        lengthBytes  = null;
-        elementBytes = null;
-      }
-      else
-      {
-        System.arraycopy(b, position, lengthBytes, arrayOffset,
-                         remaining);
-        arrayOffset += remaining;
-        return;
-      }
-    }
-
-
-    // If there is still more data available, then call this method
-    // again to process it.
-    if (remaining > 0)
-    {
-      write(b, position, remaining);
+      saveBuffer.append(byteBuffer, byteBuffer.remaining());
     }
   }
 
@@ -339,73 +342,7 @@
   public synchronized void write(int b)
          throws IOException
   {
-    if (closed)
-    {
-      Message m = ERR_INTERNALOS_CLOSED.get();
-      throw new IOException(m.toString());
-    }
-
-    if (needType)
-    {
-      elementType = (byte) (b & 0xFF);
-      needType = false;
-      return;
-    }
-    else if (elementBytes != null)
-    {
-      // The byte should be part of the element value.
-      elementBytes[arrayOffset++] = (byte) (b & 0xFF);
-      if (arrayOffset == elementBytes.length)
-      {
-        // The element has been completed, so process it.
-        processElement(new ASN1Element(elementType, elementBytes));
-      }
-
-      lengthBytes  = null;
-      elementBytes = null;
-      arrayOffset  = 0;
-      needType     = true;
-
-      return;
-    }
-    else if (lengthBytes != null)
-    {
-      // The byte should be part of a multi-byte length.
-      lengthBytes[arrayOffset++] = (byte) (b & 0xFF);
-      if (arrayOffset == lengthBytes.length)
-      {
-        int length = 0;
-        for (int i=0; i < lengthBytes.length; i++)
-        {
-          length <<= 8;
-          length |= (lengthBytes[i] & 0xFF);
-        }
-
-        elementBytes = new byte[length];
-        lengthBytes  = null;
-        arrayOffset   = 0;
-      }
-
-      return;
-    }
-    else
-    {
-      if ((b & 0x7F) == b)
-      {
-        // It's the complete length.
-        elementBytes = new byte[b];
-        lengthBytes  = null;
-        arrayOffset = 0;
-      }
-      else
-      {
-        lengthBytes  = new byte[b & 0x7F];
-        elementBytes = null;
-        arrayOffset  = 0;
-      }
-
-      return;
-    }
+    write(new byte[]{(byte)b}, 0, 1);
   }
 
 
@@ -416,25 +353,15 @@
    * the appropriate response message(s) to the client through the
    * corresponding internal LDAP input stream.
    *
-   * @param  element  The ASN.1 element to be processed.
+   * @param  message The LDAP message to process.
    *
    * @throws  IOException  If a problem occurs while attempting to
    *                       decode the provided ASN.1 element as an
    *                       LDAP message.
    */
-  private void processElement(ASN1Element element)
+  private void processMessage(LDAPMessage message)
           throws IOException
   {
-    LDAPMessage message;
-    try
-    {
-      message = LDAPMessage.decode(element.decodeAsSequence());
-    }
-    catch (Exception e)
-    {
-      throw new IOException(e.getMessage());
-    }
-
     switch (message.getProtocolOpType())
     {
       case OP_TYPE_ABANDON_REQUEST:
@@ -509,19 +436,10 @@
     int messageID = message.getMessageID();
     AddRequestProtocolOp request = message.getAddRequestProtocolOp();
 
-    ArrayList<Control> requestControls = new ArrayList<Control>();
-    if (message.getControls() != null)
-    {
-      for (LDAPControl c : message.getControls())
-      {
-        requestControls.add(c.getControl());
-      }
-    }
-
     InternalClientConnection conn = socket.getConnection();
     AddOperationBasis op =
          new AddOperationBasis(conn, conn.nextOperationID(),
-                               messageID, requestControls,
+                               messageID, message.getControls(),
                                request.getDN(),
                                request.getAttributes());
     op.run();
@@ -531,12 +449,7 @@
                                    op.getErrorMessage().toMessage(),
                                    op.getMatchedDN(),
                                    op.getReferralURLs());
-    ArrayList<LDAPControl> responseControls =
-         new ArrayList<LDAPControl>();
-    for (Control c : op.getResponseControls())
-    {
-      responseControls.add(new LDAPControl(c));
-    }
+    List<Control> responseControls = op.getResponseControls();
 
     socket.getInputStream().addLDAPMessage(
          new LDAPMessage(messageID, addResponse, responseControls));
@@ -572,19 +485,10 @@
       return;
     }
 
-    ArrayList<Control> requestControls = new ArrayList<Control>();
-    if (message.getControls() != null)
-    {
-      for (LDAPControl c : message.getControls())
-      {
-        requestControls.add(c.getControl());
-      }
-    }
-
     InternalClientConnection conn = socket.getConnection();
     BindOperationBasis op =
          new BindOperationBasis(conn, conn.nextOperationID(),
-                  messageID, requestControls,
+                  messageID, message.getControls(),
                   String.valueOf(request.getProtocolVersion()),
                   request.getDN(), request.getSimplePassword());
     op.run();
@@ -594,12 +498,7 @@
                                     op.getErrorMessage().toMessage(),
                                     op.getMatchedDN(),
                                     op.getReferralURLs());
-    ArrayList<LDAPControl> responseControls =
-         new ArrayList<LDAPControl>();
-    for (Control c : op.getResponseControls())
-    {
-      responseControls.add(new LDAPControl(c));
-    }
+    List<Control> responseControls = op.getResponseControls();
 
     if (bindResponse.getResultCode() == LDAPResultCode.SUCCESS)
     {
@@ -630,19 +529,10 @@
     CompareRequestProtocolOp request =
          message.getCompareRequestProtocolOp();
 
-    ArrayList<Control> requestControls = new ArrayList<Control>();
-    if (message.getControls() != null)
-    {
-      for (LDAPControl c : message.getControls())
-      {
-        requestControls.add(c.getControl());
-      }
-    }
-
     InternalClientConnection conn = socket.getConnection();
     CompareOperationBasis op =
          new CompareOperationBasis(conn, conn.nextOperationID(),
-                  messageID, requestControls, request.getDN(),
+                  messageID, message.getControls(), request.getDN(),
                   request.getAttributeType(),
                   request.getAssertionValue());
     op.run();
@@ -653,12 +543,7 @@
                   op.getErrorMessage().toMessage(),
                   op.getMatchedDN(),
                   op.getReferralURLs());
-    ArrayList<LDAPControl> responseControls =
-         new ArrayList<LDAPControl>();
-    for (Control c : op.getResponseControls())
-    {
-      responseControls.add(new LDAPControl(c));
-    }
+    List<Control> responseControls = op.getResponseControls();
 
     socket.getInputStream().addLDAPMessage(
          new LDAPMessage(messageID, compareResponse,
@@ -684,19 +569,10 @@
     DeleteRequestProtocolOp request =
          message.getDeleteRequestProtocolOp();
 
-    ArrayList<Control> requestControls = new ArrayList<Control>();
-    if (message.getControls() != null)
-    {
-      for (LDAPControl c : message.getControls())
-      {
-        requestControls.add(c.getControl());
-      }
-    }
-
     InternalClientConnection conn = socket.getConnection();
     DeleteOperationBasis op =
          new DeleteOperationBasis(conn, conn.nextOperationID(),
-                  messageID, requestControls, request.getDN());
+                  messageID, message.getControls(), request.getDN());
     op.run();
 
     DeleteResponseProtocolOp deleteResponse =
@@ -705,12 +581,7 @@
                   op.getErrorMessage().toMessage(),
                   op.getMatchedDN(),
                   op.getReferralURLs());
-    ArrayList<LDAPControl> responseControls =
-         new ArrayList<LDAPControl>();
-    for (Control c : op.getResponseControls())
-    {
-      responseControls.add(new LDAPControl(c));
-    }
+    List<Control> responseControls = op.getResponseControls();
 
     socket.getInputStream().addLDAPMessage(
          new LDAPMessage(messageID, deleteResponse,
@@ -746,19 +617,10 @@
       return;
     }
 
-    ArrayList<Control> requestControls = new ArrayList<Control>();
-    if (message.getControls() != null)
-    {
-      for (LDAPControl c : message.getControls())
-      {
-        requestControls.add(c.getControl());
-      }
-    }
-
     InternalClientConnection conn = socket.getConnection();
     ExtendedOperationBasis op =
          new ExtendedOperationBasis(conn, conn.nextOperationID(),
-                  messageID, requestControls, request.getOID(),
+                  messageID, message.getControls(), request.getOID(),
                   request.getValue());
     op.run();
 
@@ -769,12 +631,7 @@
                   op.getMatchedDN(),
                   op.getReferralURLs(), op.getResponseOID(),
                   op.getResponseValue());
-    ArrayList<LDAPControl> responseControls =
-         new ArrayList<LDAPControl>();
-    for (Control c : op.getResponseControls())
-    {
-      responseControls.add(new LDAPControl(c));
-    }
+    List<Control> responseControls = op.getResponseControls();
 
     socket.getInputStream().addLDAPMessage(
          new LDAPMessage(messageID, extendedResponse,
@@ -800,19 +657,10 @@
     ModifyRequestProtocolOp request =
          message.getModifyRequestProtocolOp();
 
-    ArrayList<Control> requestControls = new ArrayList<Control>();
-    if (message.getControls() != null)
-    {
-      for (LDAPControl c : message.getControls())
-      {
-        requestControls.add(c.getControl());
-      }
-    }
-
     InternalClientConnection conn = socket.getConnection();
     ModifyOperationBasis op =
          new ModifyOperationBasis(conn, conn.nextOperationID(),
-                  messageID, requestControls, request.getDN(),
+                  messageID, message.getControls(), request.getDN(),
                   request.getModifications());
     op.run();
 
@@ -822,12 +670,7 @@
                   op.getErrorMessage().toMessage(),
                   op.getMatchedDN(),
                   op.getReferralURLs());
-    ArrayList<LDAPControl> responseControls =
-         new ArrayList<LDAPControl>();
-    for (Control c : op.getResponseControls())
-    {
-      responseControls.add(new LDAPControl(c));
-    }
+    List<Control> responseControls = op.getResponseControls();
 
     socket.getInputStream().addLDAPMessage(
          new LDAPMessage(messageID, modifyResponse,
@@ -853,21 +696,12 @@
     ModifyDNRequestProtocolOp request =
          message.getModifyDNRequestProtocolOp();
 
-    ArrayList<Control> requestControls = new ArrayList<Control>();
-    if (message.getControls() != null)
-    {
-      for (LDAPControl c : message.getControls())
-      {
-        requestControls.add(c.getControl());
-      }
-    }
-
     InternalClientConnection conn = socket.getConnection();
     ModifyDNOperationBasis op =
          new ModifyDNOperationBasis(conn, conn.nextOperationID(),
-                  messageID, requestControls, request.getEntryDN(),
-                  request.getNewRDN(), request.deleteOldRDN(),
-                  request.getNewSuperior());
+               messageID, message.getControls(), request.getEntryDN(),
+               request.getNewRDN(), request.deleteOldRDN(),
+               request.getNewSuperior());
     op.run();
 
     ModifyDNResponseProtocolOp modifyDNResponse =
@@ -876,12 +710,7 @@
                   op.getErrorMessage().toMessage(),
                   op.getMatchedDN(),
                   op.getReferralURLs());
-    ArrayList<LDAPControl> responseControls =
-         new ArrayList<LDAPControl>();
-    for (Control c : op.getResponseControls())
-    {
-      responseControls.add(new LDAPControl(c));
-    }
+    List<Control> responseControls = op.getResponseControls();
 
     socket.getInputStream().addLDAPMessage(
          new LDAPMessage(messageID, modifyDNResponse,
@@ -907,23 +736,14 @@
     SearchRequestProtocolOp request =
          message.getSearchRequestProtocolOp();
 
-    ArrayList<Control> requestControls = new ArrayList<Control>();
-    if (message.getControls() != null)
-    {
-      for (LDAPControl c : message.getControls())
-      {
-        requestControls.add(c.getControl());
-      }
-    }
-
     InternalClientConnection conn = socket.getConnection();
     InternalSearchOperation op =
          new InternalSearchOperation(conn, conn.nextOperationID(),
-                  messageID, requestControls, request.getBaseDN(),
-                  request.getScope(), request.getDereferencePolicy(),
-                  request.getSizeLimit(), request.getTimeLimit(),
-                  request.getTypesOnly(), request.getFilter(),
-                  request.getAttributes(), this);
+                messageID, message.getControls(), request.getBaseDN(),
+                request.getScope(), request.getDereferencePolicy(),
+                request.getSizeLimit(), request.getTimeLimit(),
+                request.getTypesOnly(), request.getFilter(),
+                request.getAttributes(), this);
     op.run();
 
     SearchResultDoneProtocolOp searchDone =
@@ -932,12 +752,7 @@
                   op.getErrorMessage().toMessage(),
                   op.getMatchedDN(),
                   op.getReferralURLs());
-    ArrayList<LDAPControl> responseControls =
-         new ArrayList<LDAPControl>();
-    for (Control c : op.getResponseControls())
-    {
-      responseControls.add(new LDAPControl(c));
-    }
+    List<Control> responseControls = op.getResponseControls();
 
     socket.getInputStream().addLDAPMessage(
          new LDAPMessage(messageID, searchDone, responseControls));
@@ -963,12 +778,7 @@
                    InternalSearchOperation searchOperation,
                    SearchResultEntry searchEntry)
   {
-    ArrayList<LDAPControl> entryControls =
-         new ArrayList<LDAPControl>();
-    for (Control c : searchEntry.getControls())
-    {
-      entryControls.add(new LDAPControl(c));
-    }
+    List<Control> entryControls = searchEntry.getControls();
 
     SearchResultEntryProtocolOp entry =
          new SearchResultEntryProtocolOp(searchEntry);
@@ -998,12 +808,7 @@
                    InternalSearchOperation searchOperation,
                    SearchResultReference searchReference)
   {
-    ArrayList<LDAPControl> entryControls =
-         new ArrayList<LDAPControl>();
-    for (Control c : searchReference.getControls())
-    {
-      entryControls.add(new LDAPControl(c));
-    }
+    List<Control> entryControls = searchReference.getControls();
 
     SearchResultReferenceProtocolOp reference =
          new SearchResultReferenceProtocolOp(searchReference);
diff --git a/opends/src/server/org/opends/server/protocols/jmx/JmxClientConnection.java b/opends/src/server/org/opends/server/protocols/jmx/JmxClientConnection.java
index 62f5abd..9345d0f 100644
--- a/opends/src/server/org/opends/server/protocols/jmx/JmxClientConnection.java
+++ b/opends/src/server/org/opends/server/protocols/jmx/JmxClientConnection.java
@@ -39,35 +39,11 @@
 import org.opends.server.api.*;
 import org.opends.server.core.*;
 import org.opends.server.extensions.*;
-import org.opends.server.protocols.asn1.*;
 import org.opends.server.protocols.ldap.*;
 import org.opends.server.protocols.internal.InternalSearchOperation ;
 import org.opends.server.protocols.internal.InternalSearchListener;
 
-import org.opends.server.types.AbstractOperation;
-import org.opends.server.types.Attribute;
-import org.opends.server.types.AttributeType;
-import org.opends.server.types.DebugLogLevel;
-import org.opends.server.types.AuthenticationInfo;
-import org.opends.server.types.CancelRequest;
-import org.opends.server.types.CancelResult;
-import org.opends.server.types.Control;
-import org.opends.server.types.DN;
-import org.opends.server.types.DereferencePolicy;
-import org.opends.server.types.DirectoryException;
-import org.opends.server.types.DisconnectReason;
-import org.opends.server.types.IntermediateResponse;
-import org.opends.server.types.Modification;
-import org.opends.server.types.ObjectClass;
-import org.opends.server.types.Operation;
-import org.opends.server.types.Privilege;
-import org.opends.server.types.RDN;
-import org.opends.server.types.RawAttribute;
-import org.opends.server.types.RawModification;
-import org.opends.server.types.ResultCode;
-import org.opends.server.types.SearchResultEntry;
-import org.opends.server.types.SearchResultReference;
-import org.opends.server.types.SearchScope;
+import org.opends.server.types.*;
 
 import static org.opends.server.loggers.debug.DebugLogger.*;
 import org.opends.server.loggers.debug.DebugTracer;
@@ -96,9 +72,6 @@
   // The operation ID counter to use for operations on this connection.
   private AtomicLong nextOperationID;
 
-  // The connection security provider for this client connection.
-  private ConnectionSecurityProvider securityProvider;
-
   // The empty operation list for this connection.
   private LinkedList<Operation> operationList;
 
@@ -157,19 +130,6 @@
     }
     operationList = new LinkedList<Operation>();
 
-    try
-    {
-      securityProvider = new NullConnectionSecurityProvider();
-      securityProvider.initializeConnectionSecurityProvider(null);
-    }
-    catch (Exception e)
-    {
-      if (debugEnabled())
-      {
-        TRACER.debugCaught(DebugLogLevel.ERROR, e);
-      }
-    }
-
     //
     // Register the Jmx Notification listener (this)
     jmxConnectionHandler.getRMIConnector().jmxRmiConnectorNoClientCertificate
@@ -412,37 +372,10 @@
    */
   public boolean isSecure()
   {
-    return securityProvider.isSecure();
+      return false;
   }
 
 
-
-  /**
-   * Retrieves the connection security provider for this client connection.
-   *
-   * @return  The connection security provider for this client connection.
-   */
-  public ConnectionSecurityProvider getConnectionSecurityProvider()
-  {
-    return securityProvider;
-  }
-
-
-
-  /**
-   * Specifies the connection security provider for this client connection.
-   *
-   * @param  securityProvider  The connection security provider to use for
-   *                           communication on this client connection.
-   */
-  public void setConnectionSecurityProvider(ConnectionSecurityProvider
-                                                 securityProvider)
-  {
-    this.securityProvider = securityProvider;
-  }
-
-
-
   /**
    * Retrieves the human-readable name of the security mechanism that is used to
    * protect communication with this client.
@@ -453,7 +386,7 @@
    */
   public String getSecurityMechanism()
   {
-    return securityProvider.getSecurityMechanismName();
+    return "NULL";
   }
 
 
@@ -508,7 +441,7 @@
    * @return  A reference to the add operation that was processed and contains
    *          information about the result of the processing.
    */
-  public AddOperation processAdd(ASN1OctetString rawEntryDN,
+  public AddOperation processAdd(ByteString rawEntryDN,
                                  ArrayList<RawAttribute> rawAttributes)
   {
     AddOperationBasis addOperation =
@@ -613,9 +546,9 @@
    * @return  A reference to the compare operation that was processed and
    *          contains information about the result of the processing.
    */
-  public CompareOperation processCompare(ASN1OctetString rawEntryDN,
-                                        String attributeType,
-                                        ASN1OctetString assertionValue)
+  public CompareOperation processCompare(ByteString rawEntryDN,
+                                         String attributeType,
+                                         ByteString assertionValue)
   {
     CompareOperationBasis compareOperation =
          new CompareOperationBasis(this, nextOperationID(), nextMessageID(),
@@ -646,7 +579,7 @@
    * @return  A reference to the delete operation that was processed and
    *          contains information about the result of the processing.
    */
-  public DeleteOperation processDelete(ASN1OctetString rawEntryDN)
+  public DeleteOperation processDelete(ByteString rawEntryDN)
   {
     DeleteOperationBasis deleteOperation =
          new DeleteOperationBasis(this, nextOperationID(), nextMessageID(),
@@ -679,7 +612,7 @@
    *          contains information about the result of the processing.
    */
   public ExtendedOperation processExtendedOperation(String requestOID,
-                                ASN1OctetString requestValue)
+                                ByteString requestValue)
   {
     ExtendedOperationBasis extendedOperation =
          new ExtendedOperationBasis(this, nextOperationID(), nextMessageID(),
@@ -702,7 +635,7 @@
    * @return  A reference to the modify operation that was processed and
    *          contains information about the result of the processing
    */
-  public ModifyOperation processModify(ASN1OctetString rawEntryDN,
+  public ModifyOperation processModify(ByteString rawEntryDN,
                               ArrayList<RawModification> rawModifications)
   {
     ModifyOperationBasis modifyOperation =
@@ -768,8 +701,8 @@
    * @return  A reference to the modify DN operation that was processed and
    *          contains information about the result of the processing.
    */
-  public ModifyDNOperation processModifyDN(ASN1OctetString rawEntryDN,
-                                           ASN1OctetString rawNewRDN,
+  public ModifyDNOperation processModifyDN(ByteString rawEntryDN,
+                                           ByteString rawNewRDN,
                                            boolean deleteOldRDN)
   {
     return processModifyDN(rawEntryDN, rawNewRDN, deleteOldRDN, null);
@@ -791,10 +724,10 @@
    * @return  A reference to the modify DN operation that was processed and
    *          contains information about the result of the processing.
    */
-  public ModifyDNOperation processModifyDN(ASN1OctetString rawEntryDN,
-                                           ASN1OctetString rawNewRDN,
+  public ModifyDNOperation processModifyDN(ByteString rawEntryDN,
+                                           ByteString rawNewRDN,
                                            boolean deleteOldRDN,
-                                           ASN1OctetString rawNewSuperior)
+                                           ByteString rawNewSuperior)
   {
     ModifyDNOperationBasis modifyDNOperation =
          new ModifyDNOperationBasis(this, nextOperationID(), nextMessageID(),
@@ -866,7 +799,7 @@
    *          and contains information about the result of the processing as
    *          well as lists of the matching entries and search references.
    */
-  public InternalSearchOperation processSearch(ASN1OctetString rawBaseDN,
+  public InternalSearchOperation processSearch(ByteString rawBaseDN,
                                       SearchScope scope, LDAPFilter filter)
   {
     return processSearch(rawBaseDN, scope,
@@ -892,7 +825,7 @@
    *          and contains information about the result of the processing as
    *          well as lists of the matching entries and search references.
    */
-  public InternalSearchOperation processSearch(ASN1OctetString rawBaseDN,
+  public InternalSearchOperation processSearch(ByteString rawBaseDN,
                                       SearchScope scope,
                                       DereferencePolicy derefPolicy,
                                       int sizeLimit, int timeLimit,
@@ -937,7 +870,7 @@
    * @return  A reference to the internal search operation that was processed
    *          and contains information about the result of the processing.
    */
-  public InternalSearchOperation processSearch(ASN1OctetString rawBaseDN,
+  public InternalSearchOperation processSearch(ByteString rawBaseDN,
                                       SearchScope scope,
                                       DereferencePolicy derefPolicy,
                                       int sizeLimit, int timeLimit,
@@ -1064,7 +997,7 @@
 
       unbindOp.run();
     }
-    catch (Exception e)
+   catch (Exception e)
     {
       // TODO print a message ?
       if (debugEnabled())
@@ -1245,17 +1178,6 @@
     {
       authDN.toString(buffer);
     }
-
-    buffer.append("\" security=\"");
-    if (securityProvider.isSecure())
-    {
-      buffer.append(securityProvider.getSecurityMechanismName());
-    }
-    else
-    {
-      buffer.append("none");
-    }
-
     buffer.append("\"");
 
     return buffer.toString();
@@ -1299,5 +1221,12 @@
     // JMX connections will not be limited.
     return 0;
   }
+
+  /**
+   * {@inheritDoc}
+   */
+  public int getSSF() {
+      return 0;
+  }
 }
 
diff --git a/opends/src/server/org/opends/server/protocols/jmx/RmiAuthenticator.java b/opends/src/server/org/opends/server/protocols/jmx/RmiAuthenticator.java
index 2cf741a..5467b40 100644
--- a/opends/src/server/org/opends/server/protocols/jmx/RmiAuthenticator.java
+++ b/opends/src/server/org/opends/server/protocols/jmx/RmiAuthenticator.java
@@ -37,21 +37,13 @@
 import org.opends.server.core.DirectoryServer;
 import org.opends.server.core.PluginConfigManager;
 import org.opends.messages.CoreMessages;
-import org.opends.server.protocols.asn1.ASN1OctetString;
 import org.opends.server.protocols.ldap.LDAPResultCode;
-import org.opends.server.types.Control;
-import org.opends.server.types.DisconnectReason;
-import org.opends.server.types.Privilege;
-import org.opends.server.types.ResultCode;
-import org.opends.server.types.DN;
-import org.opends.server.types.AuthenticationInfo;
-import org.opends.server.types.LDAPException;
 
 import static org.opends.server.loggers.debug.DebugLogger.*;
 import static org.opends.messages.ProtocolMessages.*;
 
 import org.opends.server.loggers.debug.DebugTracer;
-import org.opends.server.types.DebugLogLevel;
+import org.opends.server.types.*;
 
 /**
  * A <code>RMIAuthenticator</code> manages authentication for the secure
@@ -263,14 +255,14 @@
       se.initCause(ldapEx);
       throw se;
     }
-    ASN1OctetString bindPW;
+    ByteString bindPW;
     if (password == null)
     {
       bindPW = null;
     }
     else
     {
-      bindPW = new ASN1OctetString(password);
+      bindPW = ByteString.valueOf(password);
     }
 
     AuthenticationInfo authInfo = new AuthenticationInfo();
@@ -281,7 +273,7 @@
         jmxClientConnection.nextOperationID(),
         jmxClientConnection.nextMessageID(), requestControls,
         jmxConnectionHandler.getRMIConnector().getProtocolVersion(),
-        new ASN1OctetString(authcID), bindPW);
+        ByteString.valueOf(authcID), bindPW);
 
     bindOp.run();
     if (bindOp.getResultCode() == ResultCode.SUCCESS)
diff --git a/opends/src/server/org/opends/server/protocols/ldap/AbandonRequestProtocolOp.java b/opends/src/server/org/opends/server/protocols/ldap/AbandonRequestProtocolOp.java
index f6221f1..e360dcf 100644
--- a/opends/src/server/org/opends/server/protocols/ldap/AbandonRequestProtocolOp.java
+++ b/opends/src/server/org/opends/server/protocols/ldap/AbandonRequestProtocolOp.java
@@ -25,22 +25,17 @@
  *      Copyright 2006-2008 Sun Microsystems, Inc.
  */
 package org.opends.server.protocols.ldap;
-import org.opends.messages.Message;
 
 
 
-import org.opends.server.protocols.asn1.ASN1Element;
-import org.opends.server.protocols.asn1.ASN1Integer;
-import org.opends.server.types.DebugLogLevel;
-import org.opends.server.types.LDAPException;
+import org.opends.server.protocols.asn1.ASN1Writer;
 
 import static org.opends.server.loggers.debug.DebugLogger.*;
 import org.opends.server.loggers.debug.DebugTracer;
-import static org.opends.messages.ProtocolMessages.*;
 import static org.opends.server.protocols.ldap.LDAPConstants.*;
-import static org.opends.server.protocols.ldap.LDAPResultCode.*;
 import static org.opends.server.util.ServerConstants.*;
 
+import java.io.IOException;
 
 
 /**
@@ -87,18 +82,6 @@
 
 
   /**
-   * Specifies the message ID of the operation to abandon.
-   *
-   * @param  idToAbandon  The message ID of the operation to abandon.
-   */
-  public void setIDToAbandon(int idToAbandon)
-  {
-    this.idToAbandon = idToAbandon;
-  }
-
-
-
-  /**
    * Retrieves the BER type for this protocol op.
    *
    * @return  The BER type for this protocol op.
@@ -120,57 +103,18 @@
     return "Abandon Request";
   }
 
-
-
   /**
-   * Encodes this protocol op to an ASN.1 element suitable for including in an
-   * LDAP message.
+   * Writes this protocol op to an ASN.1 output stream.
    *
-   * @return  The ASN.1 element containing the encoded protocol op.
+   * @param stream The ASN.1 output stream to write to.
+   * @throws IOException If a problem occurs while writing to the stream.
    */
-  public ASN1Element encode()
+  public void write(ASN1Writer stream) throws IOException
   {
-    return new ASN1Integer(OP_TYPE_ABANDON_REQUEST, idToAbandon);
+    stream.writeInteger(OP_TYPE_ABANDON_REQUEST, idToAbandon);
   }
 
 
-
-  /**
-   * Decodes the provided ASN.1 element as an abandon request protocol op.
-   *
-   * @param  element  The ASN.1 element to decode.
-   *
-   * @return  The decoded abandon request protocol op.
-   *
-   * @throws  LDAPException  If the provided ASN.1 element cannot be decoded as
-   *                         an abandon request protocol op.
-   */
-  public static AbandonRequestProtocolOp decodeAbandonRequest(ASN1Element
-                                                                   element)
-         throws LDAPException
-  {
-    int idToAbandon;
-    try
-    {
-      idToAbandon = element.decodeAsInteger().intValue();
-    }
-    catch (Exception e)
-    {
-      if (debugEnabled())
-      {
-        TRACER.debugCaught(DebugLogLevel.ERROR, e);
-      }
-
-      Message message =
-          ERR_LDAP_ABANDON_REQUEST_DECODE_ID.get(String.valueOf(e));
-      throw new LDAPException(PROTOCOL_ERROR, message, e);
-    }
-
-    return new AbandonRequestProtocolOp(idToAbandon);
-  }
-
-
-
   /**
    * Appends a string representation of this LDAP protocol op to the provided
    * buffer.
diff --git a/opends/src/server/org/opends/server/protocols/ldap/AddRequestProtocolOp.java b/opends/src/server/org/opends/server/protocols/ldap/AddRequestProtocolOp.java
index f3feaa1..9fc264a 100644
--- a/opends/src/server/org/opends/server/protocols/ldap/AddRequestProtocolOp.java
+++ b/opends/src/server/org/opends/server/protocols/ldap/AddRequestProtocolOp.java
@@ -25,28 +25,22 @@
  *      Copyright 2006-2008 Sun Microsystems, Inc.
  */
 package org.opends.server.protocols.ldap;
-import org.opends.messages.Message;
-
 
 
 import java.util.ArrayList;
 import java.util.Iterator;
 import java.util.List;
+import java.io.IOException;
 
-import org.opends.server.protocols.asn1.ASN1Element;
-import org.opends.server.protocols.asn1.ASN1OctetString;
-import org.opends.server.protocols.asn1.ASN1Sequence;
-import org.opends.server.types.DebugLogLevel;
-import org.opends.server.types.LDAPException;
+import org.opends.server.protocols.asn1.*;
 import org.opends.server.types.RawAttribute;
+import org.opends.server.types.ByteString;
 import org.opends.server.util.Base64;
 
 
 import static org.opends.server.loggers.debug.DebugLogger.*;
 import org.opends.server.loggers.debug.DebugTracer;
-import static org.opends.messages.ProtocolMessages.*;
 import static org.opends.server.protocols.ldap.LDAPConstants.*;
-import static org.opends.server.protocols.ldap.LDAPResultCode.*;
 import static org.opends.server.util.ServerConstants.*;
 import static org.opends.server.util.StaticUtils.*;
 
@@ -68,7 +62,7 @@
   private List<RawAttribute> attributes;
 
   // The DN for this add request.
-  private ASN1OctetString dn;
+  private ByteString dn;
 
 
 
@@ -78,7 +72,7 @@
    *
    * @param  dn  The DN for this add request.
    */
-  public AddRequestProtocolOp(ASN1OctetString dn)
+  public AddRequestProtocolOp(ByteString dn)
   {
     this.dn         = dn;
     this.attributes = new ArrayList<RawAttribute>();
@@ -93,7 +87,7 @@
    * @param  dn          The DN for this add request.
    * @param  attributes  The set of attributes for this add request.
    */
-  public AddRequestProtocolOp(ASN1OctetString dn,
+  public AddRequestProtocolOp(ByteString dn,
                               ArrayList<RawAttribute> attributes)
   {
     this.dn = dn;
@@ -115,25 +109,12 @@
    *
    * @return  The DN for this add request.
    */
-  public ASN1OctetString getDN()
+  public ByteString getDN()
   {
     return dn;
   }
 
 
-
-  /**
-   * Specifies the DN for this add request.
-   *
-   * @param  dn  The DN for this add request.
-   */
-  public void setDN(ASN1OctetString dn)
-  {
-    this.dn = dn;
-  }
-
-
-
   /**
    * Retrieves the set of attributes for this add request.  The returned list
    * may be altered by the caller.
@@ -169,117 +150,26 @@
     return "Add Request";
   }
 
-
-
   /**
-   * Encodes this protocol op to an ASN.1 element suitable for including in an
-   * LDAP message.
+   * Writes this protocol op to an ASN.1 output stream.
    *
-   * @return  The ASN.1 element containing the encoded protocol op.
+   * @param stream The ASN.1 output stream to write to.
+   * @throws IOException If a problem occurs while writing to the stream.
    */
-  public ASN1Element encode()
+  public void write(ASN1Writer stream) throws IOException
   {
-    ArrayList<ASN1Element> elements = new ArrayList<ASN1Element>(2);
-    elements.add(dn);
+    stream.writeStartSequence(OP_TYPE_ADD_REQUEST);
+    stream.writeOctetString(dn);
 
-
-    ArrayList<ASN1Element> attrElements =
-         new ArrayList<ASN1Element>(attributes.size());
-    for (RawAttribute attr : attributes)
+    // Write the attributes
+    stream.writeStartSequence();
+    for(RawAttribute attr : attributes)
     {
-      attrElements.add(attr.encode());
+      attr.write(stream);
     }
-    elements.add(new ASN1Sequence(attrElements));
+    stream.writeEndSequence();
 
-
-    return new ASN1Sequence(OP_TYPE_ADD_REQUEST, elements);
-  }
-
-
-
-  /**
-   * Decodes the provided ASN.1 element as an LDAP add request protocol op.
-   *
-   * @param  element  The ASN.1 element to be decoded.
-   *
-   * @return  The decoded add request protocol op.
-   *
-   * @throws  LDAPException  If a problem occurs while decoding the provided
-   *                         ASN.1 element as an LDAP add request protocol op.
-   */
-  public static AddRequestProtocolOp decodeAddRequest(ASN1Element element)
-         throws LDAPException
-  {
-    ArrayList<ASN1Element> elements;
-    try
-    {
-      elements = element.decodeAsSequence().elements();
-    }
-    catch (Exception e)
-    {
-      if (debugEnabled())
-      {
-        TRACER.debugCaught(DebugLogLevel.ERROR, e);
-      }
-
-      Message message =
-          ERR_LDAP_ADD_REQUEST_DECODE_SEQUENCE.get(String.valueOf(e));
-      throw new LDAPException(PROTOCOL_ERROR, message, e);
-    }
-
-
-    int numElements = elements.size();
-    if (numElements != 2)
-    {
-      Message message =
-          ERR_LDAP_ADD_REQUEST_DECODE_INVALID_ELEMENT_COUNT.get(numElements);
-      throw new LDAPException(PROTOCOL_ERROR, message);
-    }
-
-
-    ASN1OctetString dn;
-    try
-    {
-      dn = elements.get(0).decodeAsOctetString();
-    }
-    catch (Exception e)
-    {
-      if (debugEnabled())
-      {
-        TRACER.debugCaught(DebugLogLevel.ERROR, e);
-      }
-
-      Message message = ERR_LDAP_ADD_REQUEST_DECODE_DN.get(String.valueOf(e));
-      throw new LDAPException(PROTOCOL_ERROR, message, e);
-    }
-
-
-
-    ArrayList<RawAttribute> attributes;
-    try
-    {
-      ArrayList<ASN1Element> attrElements =
-           elements.get(1).decodeAsSequence().elements();
-      attributes = new ArrayList<RawAttribute>(attrElements.size());
-      for (ASN1Element e : attrElements)
-      {
-        attributes.add(LDAPAttribute.decode(e));
-      }
-    }
-    catch (Exception e)
-    {
-      if (debugEnabled())
-      {
-        TRACER.debugCaught(DebugLogLevel.ERROR, e);
-      }
-
-      Message message =
-          ERR_LDAP_ADD_REQUEST_DECODE_ATTRS.get(String.valueOf(e));
-      throw new LDAPException(PROTOCOL_ERROR, message, e);
-    }
-
-
-    return new AddRequestProtocolOp(dn, attributes);
+    stream.writeEndSequence();
   }
 
 
@@ -293,7 +183,7 @@
   public void toString(StringBuilder buffer)
   {
     buffer.append("AddRequest(dn=");
-    dn.toString(buffer);
+    buffer.append(dn.toString());
     buffer.append(", attrs={");
 
     if (! attributes.isEmpty())
@@ -335,7 +225,7 @@
 
     buffer.append(indentBuf);
     buffer.append("  DN:  ");
-    dn.toString(buffer);
+    buffer.append(dn.toString());
     buffer.append(EOL);
 
     buffer.append("  Attributes:");
@@ -360,16 +250,16 @@
     // Add the DN to the buffer.
     String dnString;
     int    colsRemaining;
-    if (needsBase64Encoding(dn.value()))
+    if (needsBase64Encoding(dn))
     {
-      dnString = Base64.encode(dn.value());
+      dnString = Base64.encode(dn);
       buffer.append("dn:: ");
 
       colsRemaining = wrapColumn - 5;
     }
     else
     {
-      dnString = dn.stringValue();
+      dnString = dn.toString();
       buffer.append("dn: ");
 
       colsRemaining = wrapColumn - 4;
@@ -411,12 +301,12 @@
       String name       = a.getAttributeType();
       int    nameLength = name.length();
 
-      for (ASN1OctetString v : a.getValues())
+      for (ByteString v : a.getValues())
       {
         String valueString;
-        if (needsBase64Encoding(v.value()))
+        if (needsBase64Encoding(v))
         {
-          valueString = Base64.encode(v.value());
+          valueString = Base64.encode(v);
           buffer.append(name);
           buffer.append(":: ");
 
@@ -424,7 +314,7 @@
         }
         else
         {
-          valueString = v.stringValue();
+          valueString = v.toString();
           buffer.append(name);
           buffer.append(": ");
 
diff --git a/opends/src/server/org/opends/server/protocols/ldap/AddResponseProtocolOp.java b/opends/src/server/org/opends/server/protocols/ldap/AddResponseProtocolOp.java
index 6ca2416..5db57bc 100644
--- a/opends/src/server/org/opends/server/protocols/ldap/AddResponseProtocolOp.java
+++ b/opends/src/server/org/opends/server/protocols/ldap/AddResponseProtocolOp.java
@@ -28,24 +28,16 @@
 import org.opends.messages.Message;
 
 
-
-import java.util.ArrayList;
 import java.util.Iterator;
 import java.util.List;
+import java.io.IOException;
 
-import org.opends.server.protocols.asn1.ASN1Element;
-import org.opends.server.protocols.asn1.ASN1Enumerated;
-import org.opends.server.protocols.asn1.ASN1OctetString;
-import org.opends.server.protocols.asn1.ASN1Sequence;
-import org.opends.server.types.DebugLogLevel;
+import org.opends.server.protocols.asn1.*;
 import org.opends.server.types.DN;
-import org.opends.server.types.LDAPException;
 
 import static org.opends.server.loggers.debug.DebugLogger.*;
 import org.opends.server.loggers.debug.DebugTracer;
-import static org.opends.messages.ProtocolMessages.*;
 import static org.opends.server.protocols.ldap.LDAPConstants.*;
-import static org.opends.server.protocols.ldap.LDAPResultCode.*;
 import static org.opends.server.util.ServerConstants.*;
 
 
@@ -143,18 +135,6 @@
 
 
   /**
-   * Specifies the result code for this response.
-   *
-   * @param  resultCode  The result code for this response.
-   */
-  public void setResultCode(int resultCode)
-  {
-    this.resultCode = resultCode;
-  }
-
-
-
-  /**
    * Retrieves the error message for this response.
    *
    * @return  The error message for this response, or <CODE>null</CODE> if none
@@ -166,19 +146,6 @@
   }
 
 
-
-  /**
-   * Specifies the error message for this response.
-   *
-   * @param  errorMessage  The error message for this response.
-   */
-  public void setErrorMessage(Message errorMessage)
-  {
-    this.errorMessage = errorMessage;
-  }
-
-
-
   /**
    * Retrieves the matched DN for this response.
    *
@@ -193,18 +160,6 @@
 
 
   /**
-   * Specifies the matched DN for this response.
-   *
-   * @param  matchedDN  The matched DN for this response.
-   */
-  public void setMatchedDN(DN matchedDN)
-  {
-    this.matchedDN = matchedDN;
-  }
-
-
-
-  /**
    * Retrieves the set of referral URLs for this response.
    *
    * @return  The set of referral URLs for this response, or <CODE>null</CODE>
@@ -218,18 +173,6 @@
 
 
   /**
-   * Specifies the set of referral URLs for this response.
-   *
-   * @param  referralURLs  The set of referral URLs for this response.
-   */
-  public void setReferralURLs(List<String> referralURLs)
-  {
-    this.referralURLs = referralURLs;
-  }
-
-
-
-  /**
    * Retrieves the BER type for this protocol op.
    *
    * @return  The BER type for this protocol op.
@@ -251,188 +194,46 @@
     return "Add Response";
   }
 
-
-
   /**
-   * Encodes this protocol op to an ASN.1 element suitable for including in an
-   * LDAP message.
+   * Writes this protocol op to an ASN.1 output stream.
    *
-   * @return  The ASN.1 element containing the encoded protocol op.
+   * @param stream The ASN.1 output stream to write to.
+   * @throws IOException If a problem occurs while writing to the stream.
    */
-  public ASN1Element encode()
+  public void write(ASN1Writer stream) throws IOException
   {
-    ArrayList<ASN1Element> elements = new ArrayList<ASN1Element>(4);
-    elements.add(new ASN1Enumerated(resultCode));
+    stream.writeStartSequence(OP_TYPE_ADD_RESPONSE);
+    stream.writeEnumerated(resultCode);
 
-    if (matchedDN == null)
+    if(matchedDN == null)
     {
-      elements.add(new ASN1OctetString());
+      stream.writeOctetString((String)null);
     }
     else
     {
-      elements.add(new ASN1OctetString(matchedDN.toString()));
+      stream.writeOctetString(matchedDN.toString());
     }
 
-    elements.add(new ASN1OctetString(errorMessage));
+    if(errorMessage == null)
+    {
+      stream.writeOctetString((String)null);
+    }
+    else
+    {
+      stream.writeOctetString(errorMessage.toString());
+    }
 
     if ((referralURLs != null) && (! referralURLs.isEmpty()))
     {
-      ArrayList<ASN1Element> referralElements =
-           new ArrayList<ASN1Element>(referralURLs.size());
-
+      stream.writeStartSequence(TYPE_REFERRAL_SEQUENCE);
       for (String s : referralURLs)
       {
-        referralElements.add(new ASN1OctetString(s));
+        stream.writeOctetString(s);
       }
-
-      elements.add(new ASN1Sequence(TYPE_REFERRAL_SEQUENCE, referralElements));
+      stream.writeEndSequence();
     }
 
-    return new ASN1Sequence(OP_TYPE_ADD_RESPONSE, elements);
-  }
-
-
-
-  /**
-   * Decodes the provided ASN.1 element as an add response protocol op.
-   *
-   * @param  element  The ASN.1 element to decode.
-   *
-   * @return  The decoded add response protocol op.
-   *
-   * @throws  LDAPException  If a problem occurs while attempting to decode the
-   *                         ASN.1 element to a protocol op.
-   */
-  public static AddResponseProtocolOp decodeAddResponse(ASN1Element element)
-         throws LDAPException
-  {
-    ArrayList<ASN1Element> elements;
-    try
-    {
-      elements = element.decodeAsSequence().elements();
-    }
-    catch (Exception e)
-    {
-      if (debugEnabled())
-      {
-        TRACER.debugCaught(DebugLogLevel.ERROR, e);
-      }
-
-      Message message = ERR_LDAP_RESULT_DECODE_SEQUENCE.get(String.valueOf(e));
-      throw new LDAPException(PROTOCOL_ERROR, message, e);
-    }
-
-
-    int numElements = elements.size();
-    if ((numElements < 3) || (numElements > 4))
-    {
-      Message message =
-          ERR_LDAP_RESULT_DECODE_INVALID_ELEMENT_COUNT.get(numElements);
-      throw new LDAPException(PROTOCOL_ERROR, message);
-    }
-
-
-    int resultCode;
-    try
-    {
-      resultCode = elements.get(0).decodeAsInteger().intValue();
-    }
-    catch (Exception e)
-    {
-      if (debugEnabled())
-      {
-        TRACER.debugCaught(DebugLogLevel.ERROR, e);
-      }
-
-      Message message =
-          ERR_LDAP_RESULT_DECODE_RESULT_CODE.get(String.valueOf(e));
-      throw new LDAPException(PROTOCOL_ERROR, message, e);
-    }
-
-
-    DN matchedDN;
-    try
-    {
-      String dnString = elements.get(1).decodeAsOctetString().stringValue();
-      if (dnString.length() == 0)
-      {
-        matchedDN = null;
-      }
-      else
-      {
-        matchedDN = DN.decode(dnString);
-      }
-    }
-    catch (Exception e)
-    {
-      if (debugEnabled())
-      {
-        TRACER.debugCaught(DebugLogLevel.ERROR, e);
-      }
-
-      Message message =
-          ERR_LDAP_RESULT_DECODE_MATCHED_DN.get(String.valueOf(e));
-      throw new LDAPException(PROTOCOL_ERROR, message, e);
-    }
-
-
-    Message errorMessage;
-    try
-    {
-      errorMessage = Message.raw(
-              elements.get(2).decodeAsOctetString().stringValue());
-      if (errorMessage.length() == 0)
-      {
-        errorMessage = null;
-      }
-    }
-    catch (Exception e)
-    {
-      if (debugEnabled())
-      {
-        TRACER.debugCaught(DebugLogLevel.ERROR, e);
-      }
-
-      Message message =
-          ERR_LDAP_RESULT_DECODE_ERROR_MESSAGE.get(String.valueOf(e));
-      throw new LDAPException(PROTOCOL_ERROR, message, e);
-    }
-
-
-    ArrayList<String> referralURLs;
-    if (numElements == 3)
-    {
-      referralURLs = null;
-    }
-    else
-    {
-      try
-      {
-        ArrayList<ASN1Element> referralElements =
-             elements.get(3).decodeAsSequence().elements();
-        referralURLs = new ArrayList<String>(referralElements.size());
-
-        for (ASN1Element e : referralElements)
-        {
-          referralURLs.add(e.decodeAsOctetString().stringValue());
-        }
-      }
-      catch (Exception e)
-      {
-        if (debugEnabled())
-        {
-          TRACER.debugCaught(DebugLogLevel.ERROR, e);
-        }
-
-        Message message =
-            ERR_LDAP_RESULT_DECODE_REFERRALS.get(String.valueOf(e));
-        throw new LDAPException(PROTOCOL_ERROR, message, e);
-      }
-    }
-
-
-    return new AddResponseProtocolOp(resultCode, errorMessage, matchedDN,
-                                     referralURLs);
+    stream.writeEndSequence();
   }
 
 
diff --git a/opends/src/server/org/opends/server/protocols/ldap/BindRequestProtocolOp.java b/opends/src/server/org/opends/server/protocols/ldap/BindRequestProtocolOp.java
index d8ccb43..2e98987 100644
--- a/opends/src/server/org/opends/server/protocols/ldap/BindRequestProtocolOp.java
+++ b/opends/src/server/org/opends/server/protocols/ldap/BindRequestProtocolOp.java
@@ -25,25 +25,17 @@
  *      Copyright 2006-2008 Sun Microsystems, Inc.
  */
 package org.opends.server.protocols.ldap;
-import org.opends.messages.Message;
 
 
+import java.io.IOException;
 
-import java.util.ArrayList;
-
-import org.opends.server.protocols.asn1.ASN1Element;
-import org.opends.server.protocols.asn1.ASN1Integer;
-import org.opends.server.protocols.asn1.ASN1OctetString;
-import org.opends.server.protocols.asn1.ASN1Sequence;
+import org.opends.server.protocols.asn1.*;
 import org.opends.server.types.AuthenticationType;
-import org.opends.server.types.DebugLogLevel;
-import org.opends.server.types.LDAPException;
+import org.opends.server.types.ByteString;
 
 import static org.opends.server.loggers.debug.DebugLogger.*;
 import org.opends.server.loggers.debug.DebugTracer;
-import static org.opends.messages.ProtocolMessages.*;
 import static org.opends.server.protocols.ldap.LDAPConstants.*;
-import static org.opends.server.protocols.ldap.LDAPResultCode.*;
 import static org.opends.server.util.ServerConstants.*;
 
 
@@ -61,13 +53,13 @@
   private static final DebugTracer TRACER = getTracer();
 
   // The bind DN for this request.
-  private ASN1OctetString dn;
+  private ByteString dn;
 
   // The SASL credentials for this request.
-  private ASN1OctetString saslCredentials;
+  private ByteString saslCredentials;
 
   // The simple authentication password for this request.
-  private ASN1OctetString simplePassword;
+  private ByteString simplePassword;
 
   // The authentication type for this request.
   private AuthenticationType authenticationType;
@@ -88,8 +80,8 @@
    * @param  protocolVersion  The LDAP protocol version for this bind request.
    * @param  simplePassword   The password for this bind request.
    */
-  public BindRequestProtocolOp(ASN1OctetString dn, int protocolVersion,
-                               ASN1OctetString simplePassword)
+  public BindRequestProtocolOp(ByteString dn, int protocolVersion,
+                               ByteString simplePassword)
   {
     this.dn              = dn;
     this.protocolVersion = protocolVersion;
@@ -110,8 +102,8 @@
    * @param  saslMechanism    The SASL mechanism for this bind request.
    * @param  saslCredentials  The SASL credentials for this bind request.
    */
-  public BindRequestProtocolOp(ASN1OctetString dn, String saslMechanism,
-                               ASN1OctetString saslCredentials)
+  public BindRequestProtocolOp(ByteString dn, String saslMechanism,
+                               ByteString saslCredentials)
   {
     this.dn              = dn;
     this.saslMechanism   = saslMechanism;
@@ -125,38 +117,11 @@
 
 
   /**
-   * Creates a new bind request protocol op to perform SASL authentication with
-   * the provided information.
-   *
-   * @param  dn                  The DN for this bind request.
-   * @param  protocolVersion     The protocol version for this bind request.
-   * @param  authenticationType  The authentication type for this bind request.
-   * @param  simplePassword      The password for this bind request.
-   * @param  saslMechanism       The SASL mechanism for this bind request.
-   * @param  saslCredentials     The SASL credentials for this bind request.
-   */
-  private BindRequestProtocolOp(ASN1OctetString dn, int protocolVersion,
-                                AuthenticationType authenticationType,
-                                ASN1OctetString simplePassword,
-                                String saslMechanism,
-                                ASN1OctetString saslCredentials)
-  {
-    this.dn                 = dn;
-    this.protocolVersion    = protocolVersion;
-    this.authenticationType = authenticationType;
-    this.simplePassword     = simplePassword;
-    this.saslMechanism      = saslMechanism;
-    this.saslCredentials    = saslCredentials;
-  }
-
-
-
-  /**
    * Retrieves the DN for this bind request.
    *
    * @return  The DN for this bind request.
    */
-  public ASN1OctetString getDN()
+  public ByteString getDN()
   {
     return dn;
   }
@@ -164,18 +129,6 @@
 
 
   /**
-   * Specifies the DN for this bind request.
-   *
-   * @param  dn  The DN for this bind request.
-   */
-  public void setDN(ASN1OctetString dn)
-  {
-    this.dn = dn;
-  }
-
-
-
-  /**
    * Retrieves the protocol version for this bind request.
    *
    * @return  The protocol version for this bind request.
@@ -188,18 +141,6 @@
 
 
   /**
-   * Specifies the protocol version for this bind request.
-   *
-   * @param  protocolVersion  The protocol version for this bind request.
-   */
-  public void setProtocolVersion(int protocolVersion)
-  {
-    this.protocolVersion = protocolVersion;
-  }
-
-
-
-  /**
    * Retrieves the authentication type for this bind request.
    *
    * @return  The authentication type for this bind request.
@@ -217,7 +158,7 @@
    * @return  The simple authentication password for this bind request, or
    *          <CODE>null</CODE> if this is a SASL bind request.
    */
-  public ASN1OctetString getSimplePassword()
+  public ByteString getSimplePassword()
   {
     return simplePassword;
   }
@@ -225,23 +166,6 @@
 
 
   /**
-   * Indicates that this bind request should use simple authentication with the
-   * provided password.
-   *
-   * @param  simplePassword  The simple authentication password for this bind
-   *                         request.
-   */
-  public void setSimplePassword(ASN1OctetString simplePassword)
-  {
-    this.simplePassword = simplePassword;
-    authenticationType  = AuthenticationType.SIMPLE;
-    saslMechanism       = null;
-    saslCredentials     = null;
-  }
-
-
-
-  /**
    * Retrieves the SASL mechanism for this bind request.
    *
    * @return  The SASL mechanism for this bind request, or <CODE>null</CODE> if
@@ -260,31 +184,13 @@
    * @return  The SASL credentials for this bind request, or <CODE>null</CODE>
    *          if there are none or if this is a simple bind request.
    */
-  public ASN1OctetString getSASLCredentials()
+  public ByteString getSASLCredentials()
   {
     return saslCredentials;
   }
 
 
 
-  /**
-   * Indicates that this bind request should use SASL authentication with the
-   * provided information.
-   *
-   * @param  saslMechanism    The SASL mechanism for this bind request.
-   * @param  saslCredentials  The SASL credentials for this bind request.
-   */
-  public void setSASLAuthenticationInfo(String saslMechanism,
-                                        ASN1OctetString saslCredentials)
-  {
-    this.saslMechanism   = saslMechanism;
-    this.saslCredentials = saslCredentials;
-    authenticationType   = AuthenticationType.SASL;
-    simplePassword       = null;
-  }
-
-
-
 
   /**
    * Retrieves the BER type for this protocol op.
@@ -308,189 +214,34 @@
     return "Bind Request";
   }
 
-
-
   /**
-   * Encodes this protocol op to an ASN.1 element suitable for including in an
-   * LDAP message.
+   * Writes this protocol op to an ASN.1 output stream.
    *
-   * @return  The ASN.1 element containing the encoded protocol op.
+   * @param stream The ASN.1 output stream to write to.
+   * @throws IOException If a problem occurs while writing to the stream.
    */
-  public ASN1Element encode()
+  public void write(ASN1Writer stream) throws IOException
   {
-    ArrayList<ASN1Element> elements = new ArrayList<ASN1Element>(3);
+    stream.writeStartSequence(OP_TYPE_BIND_REQUEST);
+    stream.writeInteger(protocolVersion);
+    stream.writeOctetString(dn);
 
-    elements.add(new ASN1Integer(protocolVersion));
-    elements.add(dn);
-
-    if (authenticationType == AuthenticationType.SIMPLE)
+    if(authenticationType == AuthenticationType.SIMPLE)
     {
-      simplePassword.setType(TYPE_AUTHENTICATION_SIMPLE);
-      elements.add(simplePassword);
+      stream.writeOctetString(TYPE_AUTHENTICATION_SIMPLE, simplePassword);
     }
     else
     {
-      ArrayList<ASN1Element> saslElements = new ArrayList<ASN1Element>(2);
-      saslElements.add(new ASN1OctetString(saslMechanism));
-      if (saslCredentials != null)
+      stream.writeStartSequence(TYPE_AUTHENTICATION_SASL);
+      stream.writeOctetString(saslMechanism);
+      if(saslCredentials != null)
       {
-        saslElements.add(saslCredentials);
+        stream.writeOctetString(saslCredentials);
       }
-
-      elements.add(new ASN1Sequence(TYPE_AUTHENTICATION_SASL, saslElements));
+      stream.writeEndSequence();
     }
 
-    return new ASN1Sequence(OP_TYPE_BIND_REQUEST, elements);
-  }
-
-
-
-  /**
-   * Decodes the provided ASN.1 element as an LDAP bind request protocol op.
-   *
-   * @param  element  The ASN.1 element to decode.
-   *
-   * @return  The decoded LDAP bind request protocol op.
-   *
-   * @throws  LDAPException  If a problem occurs while trying to decode the
-   *                         provided ASN.1 element as an LDAP bind request.
-   */
-  public static BindRequestProtocolOp decodeBindRequest(ASN1Element element)
-         throws LDAPException
-  {
-    ArrayList<ASN1Element> elements;
-    try
-    {
-      elements = element.decodeAsSequence().elements();
-    }
-    catch (Exception e)
-    {
-      if (debugEnabled())
-      {
-        TRACER.debugCaught(DebugLogLevel.ERROR, e);
-      }
-
-      Message message =
-          ERR_LDAP_BIND_REQUEST_DECODE_SEQUENCE.get(String.valueOf(e));
-      throw new LDAPException(PROTOCOL_ERROR, message, e);
-    }
-
-
-    int numElements = elements.size();
-    if (numElements != 3)
-    {
-      Message message = ERR_LDAP_BIND_REQUEST_DECODE_INVALID_ELEMENT_COUNT.get(
-          numElements);
-      throw new LDAPException(PROTOCOL_ERROR, message);
-    }
-
-
-    int protocolVersion;
-    try
-    {
-      protocolVersion = elements.get(0).decodeAsInteger().intValue();
-    }
-    catch (Exception e)
-    {
-      if (debugEnabled())
-      {
-        TRACER.debugCaught(DebugLogLevel.ERROR, e);
-      }
-
-      Message message =
-          ERR_LDAP_BIND_REQUEST_DECODE_VERSION.get(String.valueOf(e));
-      throw new LDAPException(PROTOCOL_ERROR, message, e);
-    }
-
-
-    ASN1OctetString dn;
-    try
-    {
-      dn = elements.get(1).decodeAsOctetString();
-    }
-    catch (Exception e)
-    {
-      if (debugEnabled())
-      {
-        TRACER.debugCaught(DebugLogLevel.ERROR, e);
-      }
-
-      Message message = ERR_LDAP_BIND_REQUEST_DECODE_DN.get(String.valueOf(e));
-      throw new LDAPException(PROTOCOL_ERROR, message, e);
-    }
-
-
-    AuthenticationType authenticationType;
-    ASN1OctetString    simplePassword  = null;
-    String             saslMechanism   = null;
-    ASN1OctetString    saslCredentials = null;
-    try
-    {
-      element = elements.get(2);
-      switch (element.getType())
-      {
-        case TYPE_AUTHENTICATION_SIMPLE:
-          authenticationType = AuthenticationType.SIMPLE;
-
-          try
-          {
-            simplePassword = element.decodeAsOctetString();
-          }
-          catch (Exception e)
-          {
-            Message message =
-                ERR_LDAP_BIND_REQUEST_DECODE_PASSWORD.get(String.valueOf(e));
-            throw new LDAPException(PROTOCOL_ERROR, message, e);
-          }
-
-          break;
-        case TYPE_AUTHENTICATION_SASL:
-          authenticationType = AuthenticationType.SASL;
-
-          try
-          {
-            elements = element.decodeAsSequence().elements();
-
-            saslMechanism = elements.get(0).decodeAsOctetString().stringValue();
-            if (elements.size() == 2)
-            {
-              saslCredentials = elements.get(1).decodeAsOctetString();
-            }
-          }
-          catch (Exception e)
-          {
-            Message message =
-                ERR_LDAP_BIND_REQUEST_DECODE_SASL_INFO.get(String.valueOf(e));
-            throw new LDAPException(PROTOCOL_ERROR, message, e);
-          }
-
-          break;
-        default:
-          Message message = ERR_LDAP_BIND_REQUEST_DECODE_INVALID_CRED_TYPE.get(
-              element.getType());
-          throw new LDAPException(AUTH_METHOD_NOT_SUPPORTED, message);
-      }
-    }
-    catch (LDAPException le)
-    {
-      throw le;
-    }
-    catch (Exception e)
-    {
-      if (debugEnabled())
-      {
-        TRACER.debugCaught(DebugLogLevel.ERROR, e);
-      }
-
-      Message message =
-          ERR_LDAP_BIND_REQUEST_DECODE_CREDENTIALS.get(String.valueOf(e));
-      throw new LDAPException(PROTOCOL_ERROR, message, e);
-    }
-
-
-    return new BindRequestProtocolOp(dn, protocolVersion, authenticationType,
-                                     simplePassword, saslMechanism,
-                                     saslCredentials);
+    stream.writeEndSequence();
   }
 
 
@@ -508,13 +259,13 @@
 
     if (dn != null)
     {
-      dn.toString(buffer);
+      buffer.append(dn.toString());
     }
 
     if (authenticationType == AuthenticationType.SIMPLE)
     {
       buffer.append(", password=");
-      simplePassword.toString(buffer);
+      buffer.append(simplePassword.toString());
     }
     else
     {
@@ -524,7 +275,7 @@
       if (saslCredentials != null)
       {
         buffer.append(", saslCredentials=");
-        saslCredentials.toString(buffer);
+        buffer.append(saslCredentials.toString());
       }
     }
 
@@ -562,7 +313,7 @@
     buffer.append("  DN:  ");
     if (dn != null)
     {
-      dn.toString(buffer);
+      buffer.append(dn.toString());
     }
     buffer.append(EOL);
 
@@ -585,7 +336,7 @@
         buffer.append(indentBuf);
         buffer.append("  SASL Credentials:");
         buffer.append(EOL);
-        saslCredentials.toString(buffer, indent+4);
+        saslCredentials.toHexPlusAscii(buffer, indent+4);
       }
     }
   }
diff --git a/opends/src/server/org/opends/server/protocols/ldap/BindResponseProtocolOp.java b/opends/src/server/org/opends/server/protocols/ldap/BindResponseProtocolOp.java
index 3d195f2..ed0ca8a 100644
--- a/opends/src/server/org/opends/server/protocols/ldap/BindResponseProtocolOp.java
+++ b/opends/src/server/org/opends/server/protocols/ldap/BindResponseProtocolOp.java
@@ -28,24 +28,17 @@
 import org.opends.messages.Message;
 
 
-
-import java.util.ArrayList;
 import java.util.Iterator;
 import java.util.List;
+import java.io.IOException;
 
-import org.opends.server.protocols.asn1.ASN1Element;
-import org.opends.server.protocols.asn1.ASN1Enumerated;
-import org.opends.server.protocols.asn1.ASN1OctetString;
-import org.opends.server.protocols.asn1.ASN1Sequence;
+import org.opends.server.protocols.asn1.*;
 import org.opends.server.types.DN;
-import org.opends.server.types.DebugLogLevel;
-import org.opends.server.types.LDAPException;
+import org.opends.server.types.ByteString;
 
 import static org.opends.server.loggers.debug.DebugLogger.*;
 import org.opends.server.loggers.debug.DebugTracer;
-import static org.opends.messages.ProtocolMessages.*;
 import static org.opends.server.protocols.ldap.LDAPConstants.*;
-import static org.opends.server.protocols.ldap.LDAPResultCode.*;
 import static org.opends.server.util.ServerConstants.*;
 
 
@@ -64,7 +57,7 @@
   private static final DebugTracer TRACER = getTracer();
 
   // The server SASL credentials for this response.
-  private ASN1OctetString serverSASLCredentials;
+  private ByteString serverSASLCredentials;
 
   // The matched DN for this response.
   private DN matchedDN;
@@ -148,7 +141,7 @@
    */
   public BindResponseProtocolOp(int resultCode, Message errorMessage,
                                 DN matchedDN, List<String> referralURLs,
-                                ASN1OctetString serverSASLCredentials)
+                                ByteString serverSASLCredentials)
   {
     this.resultCode            = resultCode;
     this.errorMessage          = errorMessage;
@@ -172,18 +165,6 @@
 
 
   /**
-   * Specifies the result code for this response.
-   *
-   * @param  resultCode  The result code for this response.
-   */
-  public void setResultCode(int resultCode)
-  {
-    this.resultCode = resultCode;
-  }
-
-
-
-  /**
    * Retrieves the error message for this response.
    *
    * @return  The error message for this response, or <CODE>null</CODE> if none
@@ -197,18 +178,6 @@
 
 
   /**
-   * Specifies the error message for this response.
-   *
-   * @param  errorMessage  The error message for this response.
-   */
-  public void setErrorMessage(Message errorMessage)
-  {
-    this.errorMessage = errorMessage;
-  }
-
-
-
-  /**
    * Retrieves the matched DN for this response.
    *
    * @return  The matched DN for this response, or <CODE>null</CODE> if none is
@@ -222,18 +191,6 @@
 
 
   /**
-   * Specifies the matched DN for this response.
-   *
-   * @param  matchedDN  The matched DN for this response.
-   */
-  public void setMatchedDN(DN matchedDN)
-  {
-    this.matchedDN = matchedDN;
-  }
-
-
-
-  /**
    * Retrieves the set of referral URLs for this response.
    *
    * @return  The set of referral URLs for this response, or <CODE>null</CODE>
@@ -247,24 +204,12 @@
 
 
   /**
-   * Specifies the set of referral URLs for this response.
-   *
-   * @param  referralURLs  The set of referral URLs for this response.
-   */
-  public void setReferralURLs(List<String> referralURLs)
-  {
-    this.referralURLs = referralURLs;
-  }
-
-
-
-  /**
    * Retrieves the server SASL credentials for this response.
    *
    * @return  The server SASL credentials for this response, or
    *          <CODE>null</CODE> if there are none.
    */
-  public ASN1OctetString getServerSASLCredentials()
+  public ByteString getServerSASLCredentials()
   {
     return serverSASLCredentials;
   }
@@ -272,19 +217,6 @@
 
 
   /**
-   * Specifies the server SASL credentials for this response.
-   *
-   * @param  serverSASLCredentials  The server SASL credentials for this
-   *                                response.
-   */
-  public void setServerSASLCredentials(ASN1OctetString serverSASLCredentials)
-  {
-    this.serverSASLCredentials = serverSASLCredentials;
-  }
-
-
-
-  /**
    * Retrieves the BER type for this protocol op.
    *
    * @return  The BER type for this protocol op.
@@ -306,272 +238,52 @@
     return "Bind Response";
   }
 
-
-
   /**
-   * Encodes this protocol op to an ASN.1 element suitable for including in an
-   * LDAP message.
+   * Writes this protocol op to an ASN.1 output stream.
    *
-   * @return  The ASN.1 element containing the encoded protocol op.
+   * @param stream The ASN.1 output stream to write to.
+   * @throws IOException If a problem occurs while writing to the stream.
    */
-  public ASN1Element encode()
+  public void write(ASN1Writer stream) throws IOException
   {
-    ArrayList<ASN1Element> elements = new ArrayList<ASN1Element>(5);
-    elements.add(new ASN1Enumerated(resultCode));
+    stream.writeStartSequence(OP_TYPE_BIND_RESPONSE);
+    stream.writeEnumerated(resultCode);
 
-    if (matchedDN == null)
+    if(matchedDN == null)
     {
-      elements.add(new ASN1OctetString());
+      stream.writeOctetString((String)null);
     }
     else
     {
-      elements.add(new ASN1OctetString(matchedDN.toString()));
+      stream.writeOctetString(matchedDN.toString());
     }
 
-    elements.add(new ASN1OctetString(errorMessage));
+    if(errorMessage == null)
+    {
+      stream.writeOctetString((String)null);
+    }
+    else
+    {
+      stream.writeOctetString(errorMessage.toString());
+    }
 
     if ((referralURLs != null) && (! referralURLs.isEmpty()))
     {
-      ArrayList<ASN1Element> referralElements =
-           new ArrayList<ASN1Element>(referralURLs.size());
-
+      stream.writeStartSequence(TYPE_REFERRAL_SEQUENCE);
       for (String s : referralURLs)
       {
-        referralElements.add(new ASN1OctetString(s));
+        stream.writeOctetString(s);
       }
-
-      elements.add(new ASN1Sequence(TYPE_REFERRAL_SEQUENCE, referralElements));
+      stream.writeEndSequence();
     }
 
     if (serverSASLCredentials != null)
     {
-      serverSASLCredentials.setType(TYPE_SERVER_SASL_CREDENTIALS);
-      elements.add(serverSASLCredentials);
+      stream.writeOctetString(TYPE_SERVER_SASL_CREDENTIALS,
+          serverSASLCredentials);
     }
 
-    return new ASN1Sequence(OP_TYPE_BIND_RESPONSE, elements);
-  }
-
-
-
-  /**
-   * Decodes the provided ASN.1 element as a bind response protocol op.
-   *
-   * @param  element  The ASN.1 element to decode.
-   *
-   * @return  The decoded bind response protocol op.
-   *
-   * @throws  LDAPException  If a problem occurs while attempting to decode the
-   *                         ASN.1 element to a protocol op.
-   */
-  public static BindResponseProtocolOp decodeBindResponse(ASN1Element element)
-         throws LDAPException
-  {
-    ArrayList<ASN1Element> elements;
-    try
-    {
-      elements = element.decodeAsSequence().elements();
-    }
-    catch (Exception e)
-    {
-      if (debugEnabled())
-      {
-        TRACER.debugCaught(DebugLogLevel.ERROR, e);
-      }
-
-      Message message = ERR_LDAP_RESULT_DECODE_SEQUENCE.get(String.valueOf(e));
-      throw new LDAPException(PROTOCOL_ERROR, message, e);
-    }
-
-
-    int numElements = elements.size();
-    if ((numElements < 3) || (numElements > 5))
-    {
-      Message message =
-          ERR_LDAP_BIND_RESULT_DECODE_INVALID_ELEMENT_COUNT.get(numElements);
-      throw new LDAPException(PROTOCOL_ERROR, message);
-    }
-
-
-    int resultCode;
-    try
-    {
-      resultCode = elements.get(0).decodeAsInteger().intValue();
-    }
-    catch (Exception e)
-    {
-      if (debugEnabled())
-      {
-        TRACER.debugCaught(DebugLogLevel.ERROR, e);
-      }
-
-      Message message =
-          ERR_LDAP_RESULT_DECODE_RESULT_CODE.get(String.valueOf(e));
-      throw new LDAPException(PROTOCOL_ERROR, message, e);
-    }
-
-
-    DN matchedDN;
-    try
-    {
-      String dnString = elements.get(1).decodeAsOctetString().stringValue();
-      if (dnString.length() == 0)
-      {
-        matchedDN = null;
-      }
-      else
-      {
-        matchedDN = DN.decode(dnString);
-      }
-    }
-    catch (Exception e)
-    {
-      if (debugEnabled())
-      {
-        TRACER.debugCaught(DebugLogLevel.ERROR, e);
-      }
-
-      Message message =
-          ERR_LDAP_RESULT_DECODE_MATCHED_DN.get(String.valueOf(e));
-      throw new LDAPException(PROTOCOL_ERROR, message, e);
-    }
-
-
-    Message errorMessage;
-    try
-    {
-      errorMessage =
-              Message.raw(elements.get(2).decodeAsOctetString().stringValue());
-      if (errorMessage.length() == 0)
-      {
-        errorMessage = null;
-      }
-    }
-    catch (Exception e)
-    {
-      if (debugEnabled())
-      {
-        TRACER.debugCaught(DebugLogLevel.ERROR, e);
-      }
-
-      Message message =
-          ERR_LDAP_RESULT_DECODE_ERROR_MESSAGE.get(String.valueOf(e));
-      throw new LDAPException(PROTOCOL_ERROR, message, e);
-    }
-
-
-    ArrayList<String> referralURLs;
-    ASN1OctetString   serverSASLCredentials;
-    switch (numElements)
-    {
-      case 4:
-        element = elements.get(3);
-        switch (element.getType())
-        {
-          case TYPE_REFERRAL_SEQUENCE:
-            serverSASLCredentials = null;
-
-            try
-            {
-              ArrayList<ASN1Element> referralElements =
-                   element.decodeAsSequence().elements();
-              referralURLs = new ArrayList<String>(referralElements.size());
-
-              for (ASN1Element e : referralElements)
-              {
-                referralURLs.add(e.decodeAsOctetString().stringValue());
-              }
-            }
-            catch (Exception e)
-            {
-              if (debugEnabled())
-              {
-                TRACER.debugCaught(DebugLogLevel.ERROR, e);
-              }
-
-              Message message =
-                  ERR_LDAP_RESULT_DECODE_REFERRALS.get(String.valueOf(e));
-              throw new LDAPException(PROTOCOL_ERROR, message, e);
-            }
-
-            break;
-          case TYPE_SERVER_SASL_CREDENTIALS:
-            referralURLs = null;
-
-            try
-            {
-              serverSASLCredentials = element.decodeAsOctetString();
-            }
-            catch (Exception e)
-            {
-              if (debugEnabled())
-              {
-                TRACER.debugCaught(DebugLogLevel.ERROR, e);
-              }
-
-              Message message =
-                  ERR_LDAP_BIND_RESULT_DECODE_SERVER_SASL_CREDENTIALS.
-                    get(String.valueOf(e));
-              throw new LDAPException(PROTOCOL_ERROR, message, e);
-            }
-
-            break;
-          default:
-            Message message =
-                ERR_LDAP_BIND_RESULT_DECODE_INVALID_TYPE.get(element.getType());
-            throw new LDAPException(PROTOCOL_ERROR, message);
-        }
-        break;
-      case 5:
-        try
-        {
-          ArrayList<ASN1Element> referralElements =
-               elements.get(3).decodeAsSequence().elements();
-          referralURLs = new ArrayList<String>(referralElements.size());
-
-          for (ASN1Element e : referralElements)
-          {
-            referralURLs.add(e.decodeAsOctetString().stringValue());
-          }
-        }
-        catch (Exception e)
-        {
-          if (debugEnabled())
-          {
-            TRACER.debugCaught(DebugLogLevel.ERROR, e);
-          }
-
-          Message message =
-              ERR_LDAP_RESULT_DECODE_REFERRALS.get(String.valueOf(e));
-          throw new LDAPException(PROTOCOL_ERROR, message, e);
-        }
-
-        try
-        {
-          serverSASLCredentials = elements.get(4).decodeAsOctetString();
-        }
-        catch (Exception e)
-        {
-          if (debugEnabled())
-          {
-            TRACER.debugCaught(DebugLogLevel.ERROR, e);
-          }
-
-          Message message = ERR_LDAP_BIND_RESULT_DECODE_SERVER_SASL_CREDENTIALS.
-              get(String.valueOf(e));
-          throw new LDAPException(PROTOCOL_ERROR, message, e);
-        }
-
-        break;
-      default:
-        referralURLs          = null;
-        serverSASLCredentials = null;
-        break;
-    }
-
-
-    return new BindResponseProtocolOp(resultCode, errorMessage, matchedDN,
-                                      referralURLs, serverSASLCredentials);
+    stream.writeEndSequence();
   }
 
 
@@ -618,7 +330,7 @@
     if (serverSASLCredentials != null)
     {
       buffer.append(", serverSASLCredentials=");
-      serverSASLCredentials.toString(buffer);
+      buffer.append(serverSASLCredentials.toString());
     }
 
     buffer.append(")");
@@ -688,7 +400,7 @@
       buffer.append("  Server SASL Credentials:");
       buffer.append(EOL);
 
-      serverSASLCredentials.toString(buffer, indent+4);
+      serverSASLCredentials.toHexPlusAscii(buffer, indent+4);
     }
   }
 }
diff --git a/opends/src/server/org/opends/server/protocols/ldap/CompareRequestProtocolOp.java b/opends/src/server/org/opends/server/protocols/ldap/CompareRequestProtocolOp.java
index 63c39fb..ea70e71 100644
--- a/opends/src/server/org/opends/server/protocols/ldap/CompareRequestProtocolOp.java
+++ b/opends/src/server/org/opends/server/protocols/ldap/CompareRequestProtocolOp.java
@@ -25,23 +25,16 @@
  *      Copyright 2006-2008 Sun Microsystems, Inc.
  */
 package org.opends.server.protocols.ldap;
-import org.opends.messages.Message;
 
 
+import java.io.IOException;
 
-import java.util.ArrayList;
-
-import org.opends.server.protocols.asn1.ASN1Element;
-import org.opends.server.protocols.asn1.ASN1OctetString;
-import org.opends.server.protocols.asn1.ASN1Sequence;
-import org.opends.server.types.DebugLogLevel;
-import org.opends.server.types.LDAPException;
+import org.opends.server.protocols.asn1.*;
+import org.opends.server.types.ByteString;
 
 import static org.opends.server.loggers.debug.DebugLogger.*;
 import org.opends.server.loggers.debug.DebugTracer;
-import static org.opends.messages.ProtocolMessages.*;
 import static org.opends.server.protocols.ldap.LDAPConstants.*;
-import static org.opends.server.protocols.ldap.LDAPResultCode.*;
 import static org.opends.server.util.ServerConstants.*;
 
 
@@ -59,10 +52,10 @@
   private static final DebugTracer TRACER = getTracer();
 
   // The assertion value for this compare request.
-  private ASN1OctetString assertionValue;
+  private ByteString assertionValue;
 
   // The DN for this compare request.
-  private ASN1OctetString dn;
+  private ByteString dn;
 
   // The attribute type for this compare request.
   private String attributeType;
@@ -76,8 +69,8 @@
    * @param  attributeType   The attribute type for this compare request.
    * @param  assertionValue  The assertion value for this compare request.
    */
-  public CompareRequestProtocolOp(ASN1OctetString dn, String attributeType,
-                                  ASN1OctetString assertionValue)
+  public CompareRequestProtocolOp(ByteString dn, String attributeType,
+                                  ByteString assertionValue)
   {
     this.dn             = dn;
     this.attributeType  = attributeType;
@@ -91,7 +84,7 @@
    *
    * @return  The DN for this compare request.
    */
-  public ASN1OctetString getDN()
+  public ByteString getDN()
   {
     return dn;
   }
@@ -99,18 +92,6 @@
 
 
   /**
-   * Specifies the DN for this compare request.
-   *
-   * @param  dn  The DN for this compare request.
-   */
-  public void setDN(ASN1OctetString dn)
-  {
-    this.dn = dn;
-  }
-
-
-
-  /**
    * Retrieves the attribute type for this compare request.
    *
    * @return  The attribute type for this compare request.
@@ -123,23 +104,11 @@
 
 
   /**
-   * Specifies the attribute type for this compare request.
-   *
-   * @param  attributeType  The attribute type for this compare request.
-   */
-  public void setAttributeType(String attributeType)
-  {
-    this.attributeType = attributeType;
-  }
-
-
-
-  /**
    * Retrieves the assertion value for this compare request.
    *
    * @return  The assertion value for this compare request.
    */
-  public ASN1OctetString getAssertionValue()
+  public ByteString getAssertionValue()
   {
     return assertionValue;
   }
@@ -147,18 +116,6 @@
 
 
   /**
-   * Specifies the assertion value for this compare request.
-   *
-   * @param  assertionValue  The assertion value for this compare request.
-   */
-  public void setAssertionValue(ASN1OctetString assertionValue)
-  {
-    this.assertionValue = assertionValue;
-  }
-
-
-
-  /**
    * Retrieves the BER type for this protocol op.
    *
    * @return  The BER type for this protocol op.
@@ -180,152 +137,23 @@
     return "Compare Request";
   }
 
-
-
   /**
-   * Encodes this protocol op to an ASN.1 element suitable for including in an
-   * LDAP message.
+   * Writes this protocol op to an ASN.1 output stream.
    *
-   * @return  The ASN.1 element containing the encoded protocol op.
+   * @param stream The ASN.1 output stream to write to.
+   * @throws IOException If a problem occurs while writing to the stream.
    */
-  public ASN1Element encode()
+  public void write(ASN1Writer stream) throws IOException
   {
-    ArrayList<ASN1Element> elements = new ArrayList<ASN1Element>(2);
-    elements.add(dn);
+    stream.writeStartSequence(OP_TYPE_COMPARE_REQUEST);
+    stream.writeOctetString(dn);
 
-    ArrayList<ASN1Element> avaElements = new ArrayList<ASN1Element>(2);
-    avaElements.add(new ASN1OctetString(attributeType));
-    avaElements.add(assertionValue);
-    elements.add(new ASN1Sequence(avaElements));
+    stream.writeStartSequence();
+    stream.writeOctetString(attributeType);
+    stream.writeOctetString(assertionValue);
+    stream.writeEndSequence();
 
-    return new ASN1Sequence(OP_TYPE_COMPARE_REQUEST, elements);
-  }
-
-
-
-  /**
-   * Decodes the provided ASN.1 element as an LDAP compare request protocol op.
-   *
-   * @param  element  The ASN.1 element to decode.
-   *
-   * @return  The decoded LDAP compare request protocol op.
-   *
-   * @throws  LDAPException  If a problem occurs while attempting to decode the
-   *                         ASN.1 element as a compare request protocol op.
-   */
-  public static CompareRequestProtocolOp decodeCompareRequest(ASN1Element
-                                                                   element)
-         throws LDAPException
-  {
-    ArrayList<ASN1Element> elements;
-    try
-    {
-      elements = element.decodeAsSequence().elements();
-    }
-    catch (Exception e)
-    {
-      if (debugEnabled())
-      {
-        TRACER.debugCaught(DebugLogLevel.ERROR, e);
-      }
-
-      Message message =
-          ERR_LDAP_COMPARE_REQUEST_DECODE_SEQUENCE.get(String.valueOf(e));
-      throw new LDAPException(PROTOCOL_ERROR, message, e);
-    }
-
-
-    int numElements = elements.size();
-    if (numElements != 2)
-    {
-      Message message = ERR_LDAP_COMPARE_REQUEST_DECODE_INVALID_ELEMENT_COUNT.
-          get(numElements);
-      throw new LDAPException(PROTOCOL_ERROR, message);
-    }
-
-
-    ASN1OctetString dn;
-    try
-    {
-      dn = elements.get(0).decodeAsOctetString();
-    }
-    catch (Exception e)
-    {
-      if (debugEnabled())
-      {
-        TRACER.debugCaught(DebugLogLevel.ERROR, e);
-      }
-
-      Message message =
-          ERR_LDAP_COMPARE_REQUEST_DECODE_DN.get(String.valueOf(e));
-      throw new LDAPException(PROTOCOL_ERROR, message, e);
-    }
-
-
-    ArrayList<ASN1Element> avaElements;
-    try
-    {
-      avaElements = elements.get(1).decodeAsSequence().elements();
-    }
-    catch (Exception e)
-    {
-      if (debugEnabled())
-      {
-        TRACER.debugCaught(DebugLogLevel.ERROR, e);
-      }
-
-      Message message =
-          ERR_LDAP_COMPARE_REQUEST_DECODE_AVA.get(String.valueOf(e));
-      throw new LDAPException(PROTOCOL_ERROR, message, e);
-    }
-
-
-    numElements = avaElements.size();
-    if (numElements != 2)
-    {
-      Message message =
-          ERR_LDAP_COMPARE_REQUEST_DECODE_AVA_COUNT.get(numElements);
-      throw new LDAPException(PROTOCOL_ERROR, message);
-    }
-
-
-    String attributeType;
-    try
-    {
-      attributeType = avaElements.get(0).decodeAsOctetString().stringValue();
-    }
-    catch (Exception e)
-    {
-      if (debugEnabled())
-      {
-        TRACER.debugCaught(DebugLogLevel.ERROR, e);
-      }
-
-      Message message =
-          ERR_LDAP_COMPARE_REQUEST_DECODE_TYPE.get(String.valueOf(e));
-      throw new LDAPException(PROTOCOL_ERROR, message, e);
-    }
-
-
-    ASN1OctetString assertionValue;
-    try
-    {
-      assertionValue = avaElements.get(1).decodeAsOctetString();
-    }
-    catch (Exception e)
-    {
-      if (debugEnabled())
-      {
-        TRACER.debugCaught(DebugLogLevel.ERROR, e);
-      }
-
-      Message message =
-          ERR_LDAP_COMPARE_REQUEST_DECODE_VALUE.get(String.valueOf(e));
-      throw new LDAPException(PROTOCOL_ERROR, message, e);
-    }
-
-
-    return new CompareRequestProtocolOp(dn, attributeType, assertionValue);
+    stream.writeEndSequence();
   }
 
 
@@ -339,11 +167,11 @@
   public void toString(StringBuilder buffer)
   {
     buffer.append("CompareRequest(dn=");
-    dn.toString(buffer);
+    buffer.append(dn.toString());
     buffer.append(", attribute=");
     buffer.append(attributeType);
     buffer.append(", value=");
-    assertionValue.toString(buffer);
+    buffer.append(assertionValue.toString());
     buffer.append(")");
   }
 
@@ -371,7 +199,7 @@
 
     buffer.append(indentBuf);
     buffer.append("  Target DN:  ");
-    dn.toString(buffer);
+    buffer.append(dn.toString());
     buffer.append(EOL);
 
     buffer.append(indentBuf);
@@ -382,7 +210,7 @@
     buffer.append(indentBuf);
     buffer.append("  Assertion Value:");
     buffer.append(EOL);
-    assertionValue.toString(buffer, indent+4);
+    assertionValue.toHexPlusAscii(buffer, indent+4);
   }
 }
 
diff --git a/opends/src/server/org/opends/server/protocols/ldap/CompareResponseProtocolOp.java b/opends/src/server/org/opends/server/protocols/ldap/CompareResponseProtocolOp.java
index 9809869..cc94c85 100644
--- a/opends/src/server/org/opends/server/protocols/ldap/CompareResponseProtocolOp.java
+++ b/opends/src/server/org/opends/server/protocols/ldap/CompareResponseProtocolOp.java
@@ -28,24 +28,16 @@
 import org.opends.messages.Message;
 
 
-
-import java.util.ArrayList;
 import java.util.Iterator;
 import java.util.List;
+import java.io.IOException;
 
-import org.opends.server.protocols.asn1.ASN1Element;
-import org.opends.server.protocols.asn1.ASN1Enumerated;
-import org.opends.server.protocols.asn1.ASN1OctetString;
-import org.opends.server.protocols.asn1.ASN1Sequence;
-import org.opends.server.types.DebugLogLevel;
+import org.opends.server.protocols.asn1.*;
 import org.opends.server.types.DN;
-import org.opends.server.types.LDAPException;
 
 import static org.opends.server.loggers.debug.DebugLogger.*;
 import org.opends.server.loggers.debug.DebugTracer;
-import static org.opends.messages.ProtocolMessages.*;
 import static org.opends.server.protocols.ldap.LDAPConstants.*;
-import static org.opends.server.protocols.ldap.LDAPResultCode.*;
 import static org.opends.server.util.ServerConstants.*;
 
 
@@ -143,18 +135,6 @@
 
 
   /**
-   * Specifies the result code for this response.
-   *
-   * @param  resultCode  The result code for this response.
-   */
-  public void setResultCode(int resultCode)
-  {
-    this.resultCode = resultCode;
-  }
-
-
-
-  /**
    * Retrieves the error message for this response.
    *
    * @return  The error message for this response, or <CODE>null</CODE> if none
@@ -168,18 +148,6 @@
 
 
   /**
-   * Specifies the error message for this response.
-   *
-   * @param  errorMessage  The error message for this response.
-   */
-  public void setErrorMessage(Message errorMessage)
-  {
-    this.errorMessage = errorMessage;
-  }
-
-
-
-  /**
    * Retrieves the matched DN for this response.
    *
    * @return  The matched DN for this response, or <CODE>null</CODE> if none is
@@ -193,18 +161,6 @@
 
 
   /**
-   * Specifies the matched DN for this response.
-   *
-   * @param  matchedDN  The matched DN for this response.
-   */
-  public void setMatchedDN(DN matchedDN)
-  {
-    this.matchedDN = matchedDN;
-  }
-
-
-
-  /**
    * Retrieves the set of referral URLs for this response.
    *
    * @return  The set of referral URLs for this response, or <CODE>null</CODE>
@@ -218,18 +174,6 @@
 
 
   /**
-   * Specifies the set of referral URLs for this response.
-   *
-   * @param  referralURLs  The set of referral URLs for this response.
-   */
-  public void setReferralURLs(List<String> referralURLs)
-  {
-    this.referralURLs = referralURLs;
-  }
-
-
-
-  /**
    * Retrieves the BER type for this protocol op.
    *
    * @return  The BER type for this protocol op.
@@ -251,189 +195,46 @@
     return "Compare Response";
   }
 
-
-
   /**
-   * Encodes this protocol op to an ASN.1 element suitable for including in an
-   * LDAP message.
+   * Writes this protocol op to an ASN.1 output stream.
    *
-   * @return  The ASN.1 element containing the encoded protocol op.
+   * @param stream The ASN.1 output stream to write to.
+   * @throws IOException If a problem occurs while writing to the stream.
    */
-  public ASN1Element encode()
+  public void write(ASN1Writer stream) throws IOException
   {
-    ArrayList<ASN1Element> elements = new ArrayList<ASN1Element>(4);
-    elements.add(new ASN1Enumerated(resultCode));
+    stream.writeStartSequence(OP_TYPE_COMPARE_RESPONSE);
+    stream.writeEnumerated(resultCode);
 
-    if (matchedDN == null)
+    if(matchedDN == null)
     {
-      elements.add(new ASN1OctetString());
+      stream.writeOctetString((String)null);
     }
     else
     {
-      elements.add(new ASN1OctetString(matchedDN.toString()));
+      stream.writeOctetString(matchedDN.toString());
     }
 
-    elements.add(new ASN1OctetString(errorMessage));
+    if(errorMessage == null)
+    {
+      stream.writeOctetString((String)null);
+    }
+    else
+    {
+      stream.writeOctetString(errorMessage.toString());
+    }
 
     if ((referralURLs != null) && (! referralURLs.isEmpty()))
     {
-      ArrayList<ASN1Element> referralElements =
-           new ArrayList<ASN1Element>(referralURLs.size());
-
+      stream.writeStartSequence(TYPE_REFERRAL_SEQUENCE);
       for (String s : referralURLs)
       {
-        referralElements.add(new ASN1OctetString(s));
+        stream.writeOctetString(s);
       }
-
-      elements.add(new ASN1Sequence(TYPE_REFERRAL_SEQUENCE, referralElements));
+      stream.writeEndSequence();
     }
 
-    return new ASN1Sequence(OP_TYPE_COMPARE_RESPONSE, elements);
-  }
-
-
-
-  /**
-   * Decodes the provided ASN.1 element as a compare response protocol op.
-   *
-   * @param  element  The ASN.1 element to decode.
-   *
-   * @return  The decoded compare response protocol op.
-   *
-   * @throws  LDAPException  If a problem occurs while attempting to decode the
-   *                         ASN.1 element to a protocol op.
-   */
-  public static CompareResponseProtocolOp decodeCompareResponse(ASN1Element
-                                                                     element)
-         throws LDAPException
-  {
-    ArrayList<ASN1Element> elements;
-    try
-    {
-      elements = element.decodeAsSequence().elements();
-    }
-    catch (Exception e)
-    {
-      if (debugEnabled())
-      {
-        TRACER.debugCaught(DebugLogLevel.ERROR, e);
-      }
-
-      Message message = ERR_LDAP_RESULT_DECODE_SEQUENCE.get(String.valueOf(e));
-      throw new LDAPException(PROTOCOL_ERROR, message, e);
-    }
-
-
-    int numElements = elements.size();
-    if ((numElements < 3) || (numElements > 4))
-    {
-      Message message =
-          ERR_LDAP_RESULT_DECODE_INVALID_ELEMENT_COUNT.get(numElements);
-      throw new LDAPException(PROTOCOL_ERROR, message);
-    }
-
-
-    int resultCode;
-    try
-    {
-      resultCode = elements.get(0).decodeAsInteger().intValue();
-    }
-    catch (Exception e)
-    {
-      if (debugEnabled())
-      {
-        TRACER.debugCaught(DebugLogLevel.ERROR, e);
-      }
-
-      Message message =
-          ERR_LDAP_RESULT_DECODE_RESULT_CODE.get(String.valueOf(e));
-      throw new LDAPException(PROTOCOL_ERROR, message, e);
-    }
-
-
-    DN matchedDN;
-    try
-    {
-      String dnString = elements.get(1).decodeAsOctetString().stringValue();
-      if (dnString.length() == 0)
-      {
-        matchedDN = null;
-      }
-      else
-      {
-        matchedDN = DN.decode(dnString);
-      }
-    }
-    catch (Exception e)
-    {
-      if (debugEnabled())
-      {
-        TRACER.debugCaught(DebugLogLevel.ERROR, e);
-      }
-
-      Message message =
-          ERR_LDAP_RESULT_DECODE_MATCHED_DN.get(String.valueOf(e));
-      throw new LDAPException(PROTOCOL_ERROR, message, e);
-    }
-
-
-    Message errorMessage;
-    try
-    {
-      errorMessage =
-              Message.raw(elements.get(2).decodeAsOctetString().stringValue());
-      if (errorMessage.length() == 0)
-      {
-        errorMessage = null;
-      }
-    }
-    catch (Exception e)
-    {
-      if (debugEnabled())
-      {
-        TRACER.debugCaught(DebugLogLevel.ERROR, e);
-      }
-
-      Message message =
-          ERR_LDAP_RESULT_DECODE_ERROR_MESSAGE.get(String.valueOf(e));
-      throw new LDAPException(PROTOCOL_ERROR, message, e);
-    }
-
-
-    ArrayList<String> referralURLs;
-    if (numElements == 3)
-    {
-      referralURLs = null;
-    }
-    else
-    {
-      try
-      {
-        ArrayList<ASN1Element> referralElements =
-             elements.get(3).decodeAsSequence().elements();
-        referralURLs = new ArrayList<String>(referralElements.size());
-
-        for (ASN1Element e : referralElements)
-        {
-          referralURLs.add(e.decodeAsOctetString().stringValue());
-        }
-      }
-      catch (Exception e)
-      {
-        if (debugEnabled())
-        {
-          TRACER.debugCaught(DebugLogLevel.ERROR, e);
-        }
-
-        Message message =
-            ERR_LDAP_RESULT_DECODE_REFERRALS.get(String.valueOf(e));
-        throw new LDAPException(PROTOCOL_ERROR, message, e);
-      }
-    }
-
-
-    return new CompareResponseProtocolOp(resultCode, errorMessage, matchedDN,
-                                         referralURLs);
+    stream.writeEndSequence();
   }
 
 
diff --git a/opends/src/server/org/opends/server/protocols/ldap/DeleteRequestProtocolOp.java b/opends/src/server/org/opends/server/protocols/ldap/DeleteRequestProtocolOp.java
index 1f7986b..d95b5ae 100644
--- a/opends/src/server/org/opends/server/protocols/ldap/DeleteRequestProtocolOp.java
+++ b/opends/src/server/org/opends/server/protocols/ldap/DeleteRequestProtocolOp.java
@@ -25,22 +25,19 @@
  *      Copyright 2006-2008 Sun Microsystems, Inc.
  */
 package org.opends.server.protocols.ldap;
-import org.opends.messages.Message;
 
 
 
-import org.opends.server.protocols.asn1.ASN1Element;
-import org.opends.server.protocols.asn1.ASN1OctetString;
-import org.opends.server.types.DebugLogLevel;
-import org.opends.server.types.LDAPException;
+import org.opends.server.protocols.asn1.ASN1Writer;
+import org.opends.server.types.ByteString;
 
 import static org.opends.server.loggers.debug.DebugLogger.*;
 import org.opends.server.loggers.debug.DebugTracer;
-import static org.opends.messages.ProtocolMessages.*;
 import static org.opends.server.protocols.ldap.LDAPConstants.*;
-import static org.opends.server.protocols.ldap.LDAPResultCode.*;
 import static org.opends.server.util.ServerConstants.*;
 
+import java.io.IOException;
+
 
 /**
  * This class defines the structures and methods for an LDAP delete request
@@ -55,7 +52,7 @@
   private static final DebugTracer TRACER = getTracer();
 
   // The DN for this delete request.
-  private ASN1OctetString dn;
+  private ByteString dn;
 
 
 
@@ -64,7 +61,7 @@
    *
    * @param  dn  The DN for this delete request protocol op.
    */
-  public DeleteRequestProtocolOp(ASN1OctetString dn)
+  public DeleteRequestProtocolOp(ByteString dn)
   {
     this.dn = dn;
   }
@@ -76,21 +73,20 @@
    *
    * @return  The DN for this delete request.
    */
-  public ASN1OctetString getDN()
+  public ByteString getDN()
   {
     return dn;
   }
 
-
-
   /**
-   * Specifies the DN for this delete request.
+   * Writes this protocol op to an ASN.1 output stream.
    *
-   * @param  dn  The DN for this delete request.
+   * @param stream The ASN.1 output stream to write to.
+   * @throws IOException If a problem occurs while writing to the stream.
    */
-  public void setDN(ASN1OctetString dn)
+  public void write(ASN1Writer stream) throws IOException
   {
-    this.dn = dn;
+    stream.writeOctetString(OP_TYPE_DELETE_REQUEST, dn);
   }
 
 
@@ -118,53 +114,6 @@
   }
 
 
-
-  /**
-   * Encodes this protocol op to an ASN.1 element suitable for including in an
-   * LDAP message.
-   *
-   * @return  The ASN.1 element containing the encoded protocol op.
-   */
-  public ASN1Element encode()
-  {
-    dn.setType(OP_TYPE_DELETE_REQUEST);
-    return dn;
-  }
-
-
-
-  /**
-   * Decodes the provided ASN.1 element as an LDAP delete request protocol op.
-   *
-   * @param  element  The ASN.1 element to be decoded.
-   *
-   * @return  The decoded delete request protocol op.
-   *
-   * @throws  LDAPException  If a problem occurs while decoding the provided
-   *                         ASN.1 element as a delete request protocol op.
-   */
-  public static DeleteRequestProtocolOp decodeDeleteRequest(ASN1Element element)
-         throws LDAPException
-  {
-    try
-    {
-      return new DeleteRequestProtocolOp(element.decodeAsOctetString());
-    }
-    catch (Exception e)
-    {
-      if (debugEnabled())
-      {
-        TRACER.debugCaught(DebugLogLevel.ERROR, e);
-      }
-
-      Message message =
-          ERR_LDAP_DELETE_REQUEST_DECODE_DN.get(String.valueOf(e));
-      throw new LDAPException(PROTOCOL_ERROR, message, e);
-    }
-  }
-
-
-
   /**
    * Appends a string representation of this LDAP protocol op to the provided
    * buffer.
@@ -174,7 +123,7 @@
   public void toString(StringBuilder buffer)
   {
     buffer.append("DeleteRequest(dn=");
-    dn.toString(buffer);
+    buffer.append(dn.toString());
     buffer.append(")");
   }
 
@@ -202,7 +151,7 @@
 
     buffer.append(indentBuf);
     buffer.append("  Entry DN:  ");
-    dn.toString(buffer);
+    buffer.append(dn.toString());
     buffer.append(EOL);
   }
 }
diff --git a/opends/src/server/org/opends/server/protocols/ldap/DeleteResponseProtocolOp.java b/opends/src/server/org/opends/server/protocols/ldap/DeleteResponseProtocolOp.java
index 46fa95b..ada9276 100644
--- a/opends/src/server/org/opends/server/protocols/ldap/DeleteResponseProtocolOp.java
+++ b/opends/src/server/org/opends/server/protocols/ldap/DeleteResponseProtocolOp.java
@@ -28,24 +28,16 @@
 import org.opends.messages.Message;
 
 
-
-import java.util.ArrayList;
 import java.util.Iterator;
 import java.util.List;
+import java.io.IOException;
 
-import org.opends.server.protocols.asn1.ASN1Element;
-import org.opends.server.protocols.asn1.ASN1Enumerated;
-import org.opends.server.protocols.asn1.ASN1OctetString;
-import org.opends.server.protocols.asn1.ASN1Sequence;
-import org.opends.server.types.DebugLogLevel;
+import org.opends.server.protocols.asn1.*;
 import org.opends.server.types.DN;
-import org.opends.server.types.LDAPException;
 
 import static org.opends.server.loggers.debug.DebugLogger.*;
 import org.opends.server.loggers.debug.DebugTracer;
-import static org.opends.messages.ProtocolMessages.*;
 import static org.opends.server.protocols.ldap.LDAPConstants.*;
-import static org.opends.server.protocols.ldap.LDAPResultCode.*;
 import static org.opends.server.util.ServerConstants.*;
 
 
@@ -146,18 +138,6 @@
 
 
   /**
-   * Specifies the result code for this response.
-   *
-   * @param  resultCode  The result code for this response.
-   */
-  public void setResultCode(int resultCode)
-  {
-    this.resultCode = resultCode;
-  }
-
-
-
-  /**
    * Retrieves the error message for this response.
    *
    * @return  The error message for this response, or <CODE>null</CODE> if none
@@ -171,18 +151,6 @@
 
 
   /**
-   * Specifies the error message for this response.
-   *
-   * @param  errorMessage  The error message for this response.
-   */
-  public void setErrorMessage(Message errorMessage)
-  {
-    this.errorMessage = errorMessage;
-  }
-
-
-
-  /**
    * Retrieves the matched DN for this response.
    *
    * @return  The matched DN for this response, or <CODE>null</CODE> if none is
@@ -196,18 +164,6 @@
 
 
   /**
-   * Specifies the matched DN for this response.
-   *
-   * @param  matchedDN  The matched DN for this response.
-   */
-  public void setMatchedDN(DN matchedDN)
-  {
-    this.matchedDN = matchedDN;
-  }
-
-
-
-  /**
    * Retrieves the set of referral URLs for this response.
    *
    * @return  The set of referral URLs for this response, or <CODE>null</CODE>
@@ -221,18 +177,6 @@
 
 
   /**
-   * Specifies the set of referral URLs for this response.
-   *
-   * @param  referralURLs  The set of referral URLs for this response.
-   */
-  public void setReferralURLs(List<String> referralURLs)
-  {
-    this.referralURLs = referralURLs;
-  }
-
-
-
-  /**
    * Retrieves the BER type for this protocol op.
    *
    * @return  The BER type for this protocol op.
@@ -254,189 +198,46 @@
     return "Delete Response";
   }
 
-
-
   /**
-   * Encodes this protocol op to an ASN.1 element suitable for including in an
-   * LDAP message.
+   * Writes this protocol op to an ASN.1 output stream.
    *
-   * @return  The ASN.1 element containing the encoded protocol op.
+   * @param stream The ASN.1 output stream to write to.
+   * @throws IOException If a problem occurs while writing to the stream.
    */
-  public ASN1Element encode()
+  public void write(ASN1Writer stream) throws IOException
   {
-    ArrayList<ASN1Element> elements = new ArrayList<ASN1Element>(4);
-    elements.add(new ASN1Enumerated(resultCode));
+    stream.writeStartSequence(OP_TYPE_DELETE_RESPONSE);
+    stream.writeEnumerated(resultCode);
 
-    if (matchedDN == null)
+    if(matchedDN == null)
     {
-      elements.add(new ASN1OctetString());
+      stream.writeOctetString((String)null);
     }
     else
     {
-      elements.add(new ASN1OctetString(matchedDN.toString()));
+      stream.writeOctetString(matchedDN.toString());
     }
 
-    elements.add(new ASN1OctetString(errorMessage));
+    if(errorMessage == null)
+    {
+      stream.writeOctetString((String)null);
+    }
+    else
+    {
+      stream.writeOctetString(errorMessage.toString());
+    }
 
     if ((referralURLs != null) && (! referralURLs.isEmpty()))
     {
-      ArrayList<ASN1Element> referralElements =
-           new ArrayList<ASN1Element>(referralURLs.size());
-
+      stream.writeStartSequence(TYPE_REFERRAL_SEQUENCE);
       for (String s : referralURLs)
       {
-        referralElements.add(new ASN1OctetString(s));
+        stream.writeOctetString(s);
       }
-
-      elements.add(new ASN1Sequence(TYPE_REFERRAL_SEQUENCE, referralElements));
+      stream.writeEndSequence();
     }
 
-    return new ASN1Sequence(OP_TYPE_DELETE_RESPONSE, elements);
-  }
-
-
-
-  /**
-   * Decodes the provided ASN.1 element as a delete response protocol op.
-   *
-   * @param  element  The ASN.1 element to decode.
-   *
-   * @return  The decoded delete response protocol op.
-   *
-   * @throws  LDAPException  If a problem occurs while attempting to decode the
-   *                         ASN.1 element to a protocol op.
-   */
-  public static DeleteResponseProtocolOp decodeDeleteResponse(ASN1Element
-                                                                   element)
-         throws LDAPException
-  {
-    ArrayList<ASN1Element> elements;
-    try
-    {
-      elements = element.decodeAsSequence().elements();
-    }
-    catch (Exception e)
-    {
-      if (debugEnabled())
-      {
-        TRACER.debugCaught(DebugLogLevel.ERROR, e);
-      }
-
-      Message message = ERR_LDAP_RESULT_DECODE_SEQUENCE.get(String.valueOf(e));
-      throw new LDAPException(PROTOCOL_ERROR, message, e);
-    }
-
-
-    int numElements = elements.size();
-    if ((numElements < 3) || (numElements > 4))
-    {
-      Message message =
-          ERR_LDAP_RESULT_DECODE_INVALID_ELEMENT_COUNT.get(numElements);
-      throw new LDAPException(PROTOCOL_ERROR, message);
-    }
-
-
-    int resultCode;
-    try
-    {
-      resultCode = elements.get(0).decodeAsInteger().intValue();
-    }
-    catch (Exception e)
-    {
-      if (debugEnabled())
-      {
-        TRACER.debugCaught(DebugLogLevel.ERROR, e);
-      }
-
-      Message message =
-          ERR_LDAP_RESULT_DECODE_RESULT_CODE.get(String.valueOf(e));
-      throw new LDAPException(PROTOCOL_ERROR, message, e);
-    }
-
-
-    DN matchedDN;
-    try
-    {
-      String dnString = elements.get(1).decodeAsOctetString().stringValue();
-      if (dnString.length() == 0)
-      {
-        matchedDN = null;
-      }
-      else
-      {
-        matchedDN = DN.decode(dnString);
-      }
-    }
-    catch (Exception e)
-    {
-      if (debugEnabled())
-      {
-        TRACER.debugCaught(DebugLogLevel.ERROR, e);
-      }
-
-      Message message =
-          ERR_LDAP_RESULT_DECODE_MATCHED_DN.get(String.valueOf(e));
-      throw new LDAPException(PROTOCOL_ERROR, message, e);
-    }
-
-
-    Message errorMessage;
-    try
-    {
-      errorMessage = Message.raw(
-              elements.get(2).decodeAsOctetString().stringValue());
-      if (errorMessage.length() == 0)
-      {
-        errorMessage = null;
-      }
-    }
-    catch (Exception e)
-    {
-      if (debugEnabled())
-      {
-        TRACER.debugCaught(DebugLogLevel.ERROR, e);
-      }
-
-      Message message =
-          ERR_LDAP_RESULT_DECODE_ERROR_MESSAGE.get(String.valueOf(e));
-      throw new LDAPException(PROTOCOL_ERROR, message, e);
-    }
-
-
-    ArrayList<String> referralURLs;
-    if (numElements == 3)
-    {
-      referralURLs = null;
-    }
-    else
-    {
-      try
-      {
-        ArrayList<ASN1Element> referralElements =
-             elements.get(3).decodeAsSequence().elements();
-        referralURLs = new ArrayList<String>(referralElements.size());
-
-        for (ASN1Element e : referralElements)
-        {
-          referralURLs.add(e.decodeAsOctetString().stringValue());
-        }
-      }
-      catch (Exception e)
-      {
-        if (debugEnabled())
-        {
-          TRACER.debugCaught(DebugLogLevel.ERROR, e);
-        }
-
-        Message message =
-            ERR_LDAP_RESULT_DECODE_REFERRALS.get(String.valueOf(e));
-        throw new LDAPException(PROTOCOL_ERROR, message, e);
-      }
-    }
-
-
-    return new DeleteResponseProtocolOp(resultCode, errorMessage, matchedDN,
-                                        referralURLs);
+    stream.writeEndSequence();
   }
 
 
diff --git a/opends/src/server/org/opends/server/protocols/ldap/ExtendedRequestProtocolOp.java b/opends/src/server/org/opends/server/protocols/ldap/ExtendedRequestProtocolOp.java
index 28c668e..501a89e 100644
--- a/opends/src/server/org/opends/server/protocols/ldap/ExtendedRequestProtocolOp.java
+++ b/opends/src/server/org/opends/server/protocols/ldap/ExtendedRequestProtocolOp.java
@@ -25,23 +25,16 @@
  *      Copyright 2006-2008 Sun Microsystems, Inc.
  */
 package org.opends.server.protocols.ldap;
-import org.opends.messages.Message;
 
 
+import java.io.IOException;
 
-import java.util.ArrayList;
-
-import org.opends.server.protocols.asn1.ASN1Element;
-import org.opends.server.protocols.asn1.ASN1OctetString;
-import org.opends.server.protocols.asn1.ASN1Sequence;
-import org.opends.server.types.DebugLogLevel;
-import org.opends.server.types.LDAPException;
+import org.opends.server.protocols.asn1.*;
+import org.opends.server.types.ByteString;
 
 import static org.opends.server.loggers.debug.DebugLogger.*;
 import org.opends.server.loggers.debug.DebugTracer;
-import static org.opends.messages.ProtocolMessages.*;
 import static org.opends.server.protocols.ldap.LDAPConstants.*;
-import static org.opends.server.protocols.ldap.LDAPResultCode.*;
 import static org.opends.server.util.ServerConstants.*;
 
 
@@ -59,7 +52,7 @@
   private static final DebugTracer TRACER = getTracer();
 
   // The value for this extended request.
-  private ASN1OctetString value;
+  private ByteString value;
 
   // The OID for this extended request.
   private String oid;
@@ -87,7 +80,7 @@
    * @param  oid    The OID for this extended request.
    * @param  value  The value for this extended request.
    */
-  public ExtendedRequestProtocolOp(String oid, ASN1OctetString value)
+  public ExtendedRequestProtocolOp(String oid, ByteString value)
   {
     this.oid   = oid;
     this.value = value;
@@ -106,26 +99,13 @@
   }
 
 
-
-  /**
-   * Specifies the OID for this extended request.
-   *
-   * @param  oid  The OID for this extended request.
-   */
-  public void setOID(String oid)
-  {
-    this.oid = oid;
-  }
-
-
-
   /**
    * Retrieves the value for this extended request.
    *
    * @return  The value for this extended request, or <CODE>null</CODE> if there
    *          is no value.
    */
-  public ASN1OctetString getValue()
+  public ByteString getValue()
   {
     return value;
   }
@@ -133,18 +113,6 @@
 
 
   /**
-   * Specifies the value for this extended request.
-   *
-   * @param  value  The value for this extended request.
-   */
-  public void setValue(ASN1OctetString value)
-  {
-    this.value = value;
-  }
-
-
-
-  /**
    * Retrieves the BER type for this protocol op.
    *
    * @return  The BER type for this protocol op.
@@ -166,116 +134,23 @@
     return "Extended Request";
   }
 
-
-
   /**
-   * Encodes this protocol op to an ASN.1 element suitable for including in an
-   * LDAP message.
+   * Writes this protocol op to an ASN.1 output stream.
    *
-   * @return  The ASN.1 element containing the encoded protocol op.
+   * @param stream The ASN.1 output stream to write to.
+   * @throws IOException If a problem occurs while writing to the stream.
    */
-  public ASN1Element encode()
+  public void write(ASN1Writer stream) throws IOException
   {
-    ArrayList<ASN1Element> elements = new ArrayList<ASN1Element>(2);
-    elements.add(new ASN1OctetString(TYPE_EXTENDED_REQUEST_OID, oid));
+    stream.writeStartSequence(OP_TYPE_EXTENDED_REQUEST);
+    stream.writeOctetString(TYPE_EXTENDED_REQUEST_OID, oid);
 
-    if (value != null)
+    if(value != null)
     {
-      value.setType(TYPE_EXTENDED_REQUEST_VALUE);
-      elements.add(value);
+      stream.writeOctetString(TYPE_EXTENDED_REQUEST_VALUE, value);
     }
 
-    return new ASN1Sequence(OP_TYPE_EXTENDED_REQUEST, elements);
-  }
-
-
-
-  /**
-   * Decodes the provided ASN.1 element as an LDAP extended request protocol op.
-   *
-   * @param  element  The ASN.1 element to be decoded.
-   *
-   * @return  The decoded extended request protocol op.
-   *
-   * @throws  LDAPException  If a problem occurs while attempting to decode the
-   *                         provided ASN.1 element as an LDAP extended request
-   *                         protocol op.
-   */
-  public static ExtendedRequestProtocolOp decodeExtendedRequest(ASN1Element
-                                                                     element)
-         throws LDAPException
-  {
-    ArrayList<ASN1Element> elements;
-    try
-    {
-      elements = element.decodeAsSequence().elements();
-    }
-    catch (Exception e)
-    {
-      if (debugEnabled())
-      {
-        TRACER.debugCaught(DebugLogLevel.ERROR, e);
-      }
-
-      Message message =
-          ERR_LDAP_EXTENDED_REQUEST_DECODE_SEQUENCE.get(String.valueOf(e));
-      throw new LDAPException(PROTOCOL_ERROR, message, e);
-    }
-
-
-    int numElements = elements.size();
-    if ((numElements < 1) || (numElements > 2))
-    {
-      Message message = ERR_LDAP_EXTENDED_REQUEST_DECODE_INVALID_ELEMENT_COUNT.
-          get(numElements);
-      throw new LDAPException(PROTOCOL_ERROR, message);
-    }
-
-
-    String oid;
-    try
-    {
-      oid = elements.get(0).decodeAsOctetString().stringValue();
-    }
-    catch (Exception e)
-    {
-      if (debugEnabled())
-      {
-        TRACER.debugCaught(DebugLogLevel.ERROR, e);
-      }
-
-      Message message =
-          ERR_LDAP_EXTENDED_REQUEST_DECODE_OID.get(String.valueOf(e));
-      throw new LDAPException(PROTOCOL_ERROR, message, e);
-    }
-
-
-    ASN1OctetString value;
-    if (numElements == 2)
-    {
-      try
-      {
-        value = elements.get(1).decodeAsOctetString();
-      }
-      catch (Exception e)
-      {
-        if (debugEnabled())
-        {
-          TRACER.debugCaught(DebugLogLevel.ERROR, e);
-        }
-
-        Message message =
-            ERR_LDAP_EXTENDED_REQUEST_DECODE_VALUE.get(String.valueOf(e));
-        throw new LDAPException(PROTOCOL_ERROR, message, e);
-      }
-    }
-    else
-    {
-      value = null;
-    }
-
-
-    return new ExtendedRequestProtocolOp(oid, value);
+    stream.writeEndSequence();
   }
 
 
@@ -294,7 +169,7 @@
     if (value != null)
     {
       buffer.append(", value=");
-      value.toString(buffer);
+      buffer.append(value.toString());
     }
 
     buffer.append(")");
@@ -332,7 +207,7 @@
       buffer.append(indentBuf);
       buffer.append("  Value:");
       buffer.append(EOL);
-      value.toString(buffer, indent+4);
+      value.toHexPlusAscii(buffer, indent+4);
     }
   }
 }
diff --git a/opends/src/server/org/opends/server/protocols/ldap/ExtendedResponseProtocolOp.java b/opends/src/server/org/opends/server/protocols/ldap/ExtendedResponseProtocolOp.java
index a436c2f..b496211 100644
--- a/opends/src/server/org/opends/server/protocols/ldap/ExtendedResponseProtocolOp.java
+++ b/opends/src/server/org/opends/server/protocols/ldap/ExtendedResponseProtocolOp.java
@@ -28,24 +28,17 @@
 import org.opends.messages.Message;
 
 
-
-import java.util.ArrayList;
 import java.util.Iterator;
 import java.util.List;
+import java.io.IOException;
 
-import org.opends.server.protocols.asn1.ASN1Element;
-import org.opends.server.protocols.asn1.ASN1Enumerated;
-import org.opends.server.protocols.asn1.ASN1OctetString;
-import org.opends.server.protocols.asn1.ASN1Sequence;
-import org.opends.server.types.DebugLogLevel;
+import org.opends.server.protocols.asn1.*;
 import org.opends.server.types.DN;
-import org.opends.server.types.LDAPException;
+import org.opends.server.types.ByteString;
 
 import static org.opends.server.loggers.debug.DebugLogger.*;
 import org.opends.server.loggers.debug.DebugTracer;
-import static org.opends.messages.ProtocolMessages.*;
 import static org.opends.server.protocols.ldap.LDAPConstants.*;
-import static org.opends.server.protocols.ldap.LDAPResultCode.*;
 import static org.opends.server.util.ServerConstants.*;
 
 
@@ -64,7 +57,7 @@
   private static final DebugTracer TRACER = getTracer();
 
   // The value for this extended response.
-  private ASN1OctetString value;
+  private ByteString value;
 
   // The matched DN for this response.
   private DN matchedDN;
@@ -155,7 +148,7 @@
    */
   public ExtendedResponseProtocolOp(int resultCode, Message errorMessage,
                                     DN matchedDN, List<String> referralURLs,
-                                    String oid, ASN1OctetString value)
+                                    String oid, ByteString value)
   {
     this.resultCode   = resultCode;
     this.errorMessage = errorMessage;
@@ -180,18 +173,6 @@
 
 
   /**
-   * Specifies the result code for this response.
-   *
-   * @param  resultCode  The result code for this response.
-   */
-  public void setResultCode(int resultCode)
-  {
-    this.resultCode = resultCode;
-  }
-
-
-
-  /**
    * Retrieves the error message for this response.
    *
    * @return  The error message for this response, or <CODE>null</CODE> if none
@@ -203,19 +184,6 @@
   }
 
 
-
-  /**
-   * Specifies the error message for this response.
-   *
-   * @param  errorMessage  The error message for this response.
-   */
-  public void setErrorMessage(Message errorMessage)
-  {
-    this.errorMessage = errorMessage;
-  }
-
-
-
   /**
    * Retrieves the matched DN for this response.
    *
@@ -230,18 +198,6 @@
 
 
   /**
-   * Specifies the matched DN for this response.
-   *
-   * @param  matchedDN  The matched DN for this response.
-   */
-  public void setMatchedDN(DN matchedDN)
-  {
-    this.matchedDN = matchedDN;
-  }
-
-
-
-  /**
    * Retrieves the set of referral URLs for this response.
    *
    * @return  The set of referral URLs for this response, or <CODE>null</CODE>
@@ -255,18 +211,6 @@
 
 
   /**
-   * Specifies the set of referral URLs for this response.
-   *
-   * @param  referralURLs  The set of referral URLs for this response.
-   */
-  public void setReferralURLs(List<String> referralURLs)
-  {
-    this.referralURLs = referralURLs;
-  }
-
-
-
-  /**
    * Retrieves the OID for this extended response.
    *
    * @return  The OID for this extended response, or <CODE>null</CODE> if none
@@ -280,24 +224,12 @@
 
 
   /**
-   * Specifies the OID for this extended response.
-   *
-   * @param  oid  The OID for this extended response.
-   */
-  public void setOID(String oid)
-  {
-    this.oid = oid;
-  }
-
-
-
-  /**
    * Retrieves the value for this extended response.
    *
    * @return  The value for this extended response, or <CODE>null</CODE> if none
    *          was provided.
    */
-  public ASN1OctetString getValue()
+  public ByteString getValue()
   {
     return value;
   }
@@ -305,18 +237,6 @@
 
 
   /**
-   * Specifies the value for this extended response.
-   *
-   * @param  value  The value for this extended response.
-   */
-  public void setValue(ASN1OctetString value)
-  {
-    this.value = value;
-  }
-
-
-
-  /**
    * Retrieves the BER type for this protocol op.
    *
    * @return  The BER type for this protocol op.
@@ -338,245 +258,56 @@
     return "Extended Response";
   }
 
-
-
   /**
-   * Encodes this protocol op to an ASN.1 element suitable for including in an
-   * LDAP message.
+   * Writes this protocol op to an ASN.1 output stream.
    *
-   * @return  The ASN.1 element containing the encoded protocol op.
+   * @param stream The ASN.1 output stream to write to.
+   * @throws IOException If a problem occurs while writing to the stream.
    */
-  public ASN1Element encode()
+  public void write(ASN1Writer stream) throws IOException
   {
-    ArrayList<ASN1Element> elements = new ArrayList<ASN1Element>(6);
-    elements.add(new ASN1Enumerated(resultCode));
+    stream.writeStartSequence(OP_TYPE_EXTENDED_RESPONSE);
+    stream.writeEnumerated(resultCode);
 
-    if (matchedDN == null)
+    if(matchedDN == null)
     {
-      elements.add(new ASN1OctetString());
+      stream.writeOctetString((String)null);
     }
     else
     {
-      elements.add(new ASN1OctetString(matchedDN.toString()));
+      stream.writeOctetString(matchedDN.toString());
     }
 
-    elements.add(new ASN1OctetString(errorMessage));
+    if(errorMessage == null)
+    {
+      stream.writeOctetString((String)null);
+    }
+    else
+    {
+      stream.writeOctetString(errorMessage.toString());
+    }
 
     if ((referralURLs != null) && (! referralURLs.isEmpty()))
     {
-      ArrayList<ASN1Element> referralElements =
-           new ArrayList<ASN1Element>(referralURLs.size());
-
+      stream.writeStartSequence(TYPE_REFERRAL_SEQUENCE);
       for (String s : referralURLs)
       {
-        referralElements.add(new ASN1OctetString(s));
+        stream.writeOctetString(s);
       }
-
-      elements.add(new ASN1Sequence(TYPE_REFERRAL_SEQUENCE, referralElements));
+      stream.writeEndSequence();
     }
 
     if ((oid != null) && (oid.length() > 0))
     {
-      elements.add(new ASN1OctetString(TYPE_EXTENDED_RESPONSE_OID, oid));
+      stream.writeOctetString(TYPE_EXTENDED_RESPONSE_OID, oid);
     }
 
     if (value != null)
     {
-      value.setType(TYPE_EXTENDED_RESPONSE_VALUE);
-      elements.add(value);
+      stream.writeOctetString(TYPE_EXTENDED_RESPONSE_VALUE, value);
     }
 
-    return new ASN1Sequence(OP_TYPE_EXTENDED_RESPONSE, elements);
-  }
-
-
-
-  /**
-   * Decodes the provided ASN.1 element as a extended response protocol op.
-   *
-   * @param  element  The ASN.1 element to decode.
-   *
-   * @return  The decoded extended response protocol op.
-   *
-   * @throws  LDAPException  If a problem occurs while attempting to decode the
-   *                         ASN.1 element to a protocol op.
-   */
-  public static ExtendedResponseProtocolOp decodeExtendedResponse(ASN1Element
-                                                                       element)
-         throws LDAPException
-  {
-    ArrayList<ASN1Element> elements;
-    try
-    {
-      elements = element.decodeAsSequence().elements();
-    }
-    catch (Exception e)
-    {
-      if (debugEnabled())
-      {
-        TRACER.debugCaught(DebugLogLevel.ERROR, e);
-      }
-
-      Message message = ERR_LDAP_RESULT_DECODE_SEQUENCE.get(String.valueOf(e));
-      throw new LDAPException(PROTOCOL_ERROR, message, e);
-    }
-
-
-    int numElements = elements.size();
-    if ((numElements < 3) || (numElements > 6))
-    {
-      Message message = ERR_LDAP_EXTENDED_RESULT_DECODE_INVALID_ELEMENT_COUNT.
-          get(numElements);
-      throw new LDAPException(PROTOCOL_ERROR, message);
-    }
-
-
-    int resultCode;
-    try
-    {
-      resultCode = elements.get(0).decodeAsInteger().intValue();
-    }
-    catch (Exception e)
-    {
-      if (debugEnabled())
-      {
-        TRACER.debugCaught(DebugLogLevel.ERROR, e);
-      }
-
-      Message message =
-          ERR_LDAP_RESULT_DECODE_RESULT_CODE.get(String.valueOf(e));
-      throw new LDAPException(PROTOCOL_ERROR, message, e);
-    }
-
-
-    DN matchedDN;
-    try
-    {
-      String dnString = elements.get(1).decodeAsOctetString().stringValue();
-      if (dnString.length() == 0)
-      {
-        matchedDN = null;
-      }
-      else
-      {
-        matchedDN = DN.decode(dnString);
-      }
-    }
-    catch (Exception e)
-    {
-      if (debugEnabled())
-      {
-        TRACER.debugCaught(DebugLogLevel.ERROR, e);
-      }
-
-      Message message =
-          ERR_LDAP_RESULT_DECODE_MATCHED_DN.get(String.valueOf(e));
-      throw new LDAPException(PROTOCOL_ERROR, message, e);
-    }
-
-
-    Message errorMessage;
-    try
-    {
-      errorMessage = Message.raw(
-              elements.get(2).decodeAsOctetString().stringValue());
-      if (errorMessage.length() == 0)
-      {
-        errorMessage = null;
-      }
-    }
-    catch (Exception e)
-    {
-      if (debugEnabled())
-      {
-        TRACER.debugCaught(DebugLogLevel.ERROR, e);
-      }
-
-      Message message =
-          ERR_LDAP_RESULT_DECODE_ERROR_MESSAGE.get(String.valueOf(e));
-      throw new LDAPException(PROTOCOL_ERROR, message, e);
-    }
-
-
-    ArrayList<String> referralURLs = null;
-    String            oid          = null;
-    ASN1OctetString   value        = null;
-    for (int i=3; i < elements.size(); i++)
-    {
-      element = elements.get(i);
-      switch (element.getType())
-      {
-        case TYPE_REFERRAL_SEQUENCE:
-          try
-          {
-            ArrayList<ASN1Element> referralElements =
-                 element.decodeAsSequence().elements();
-            referralURLs = new ArrayList<String>(referralElements.size());
-
-            for (ASN1Element e : referralElements)
-            {
-              referralURLs.add(e.decodeAsOctetString().stringValue());
-            }
-          }
-          catch (Exception e)
-          {
-            if (debugEnabled())
-            {
-              TRACER.debugCaught(DebugLogLevel.ERROR, e);
-            }
-
-            Message message = ERR_LDAP_EXTENDED_RESULT_DECODE_REFERRALS.get(
-                String.valueOf(e));
-            throw new LDAPException(PROTOCOL_ERROR, message, e);
-          }
-
-          break;
-        case TYPE_EXTENDED_RESPONSE_OID:
-          try
-          {
-            oid = element.decodeAsOctetString().stringValue();
-          }
-          catch (Exception e)
-          {
-            if (debugEnabled())
-            {
-              TRACER.debugCaught(DebugLogLevel.ERROR, e);
-            }
-
-            Message message =
-                ERR_LDAP_EXTENDED_RESULT_DECODE_OID.get(String.valueOf(e));
-            throw new LDAPException(PROTOCOL_ERROR, message, e);
-          }
-
-          break;
-        case TYPE_EXTENDED_RESPONSE_VALUE:
-          try
-          {
-            value = element.decodeAsOctetString();
-          }
-          catch (Exception e)
-          {
-            if (debugEnabled())
-            {
-              TRACER.debugCaught(DebugLogLevel.ERROR, e);
-            }
-
-            Message message =
-                ERR_LDAP_EXTENDED_RESULT_DECODE_VALUE.get(String.valueOf(e));
-            throw new LDAPException(PROTOCOL_ERROR, message, e);
-          }
-
-          break;
-        default:
-          Message message = ERR_LDAP_EXTENDED_RESULT_DECODE_INVALID_TYPE.get(
-              element.getType());
-          throw new LDAPException(PROTOCOL_ERROR, message);
-      }
-    }
-
-
-    return new ExtendedResponseProtocolOp(resultCode, errorMessage, matchedDN,
-                                          referralURLs, oid, value);
+    stream.writeEndSequence();
   }
 
 
@@ -629,7 +360,7 @@
     if (value != null)
     {
       buffer.append(", value=");
-      value.toString(buffer);
+      buffer.append(value.toString());
     }
 
     buffer.append(")");
@@ -705,7 +436,7 @@
     {
       buffer.append(indentBuf);
       buffer.append("  Response Value:  ");
-      value.toString(buffer);
+      buffer.append(value.toString());
       buffer.append(EOL);
     }
   }
diff --git a/opends/src/server/org/opends/server/protocols/ldap/IntermediateResponseProtocolOp.java b/opends/src/server/org/opends/server/protocols/ldap/IntermediateResponseProtocolOp.java
index 639926b..b82a96b 100644
--- a/opends/src/server/org/opends/server/protocols/ldap/IntermediateResponseProtocolOp.java
+++ b/opends/src/server/org/opends/server/protocols/ldap/IntermediateResponseProtocolOp.java
@@ -25,27 +25,17 @@
  *      Copyright 2006-2008 Sun Microsystems, Inc.
  */
 package org.opends.server.protocols.ldap;
-import org.opends.messages.Message;
 
 
+import java.io.IOException;
 
-import java.util.ArrayList;
-
-import org.opends.server.protocols.asn1.ASN1Element;
-import org.opends.server.protocols.asn1.ASN1Exception;
-import org.opends.server.protocols.asn1.ASN1OctetString;
-import org.opends.server.protocols.asn1.ASN1Sequence;
-import org.opends.server.types.DebugLogLevel;
-import org.opends.server.types.LDAPException;
+import org.opends.server.protocols.asn1.*;
+import org.opends.server.types.ByteString;
 
 import static org.opends.server.loggers.debug.DebugLogger.*;
 import org.opends.server.loggers.debug.DebugTracer;
-import static org.opends.messages.ProtocolMessages.*;
 import static org.opends.server.protocols.ldap.LDAPConstants.*;
-import static org.opends.server.protocols.ldap.LDAPResultCode.*;
 import static org.opends.server.util.ServerConstants.*;
-import static org.opends.server.util.StaticUtils.*;
-
 
 
 /**
@@ -62,7 +52,7 @@
   private static final DebugTracer TRACER = getTracer();
 
   // The value for this intermediate response.
-  private ASN1OctetString value;
+  private ByteString value;
 
   // The OID for this intermediate response.
   private String oid;
@@ -90,7 +80,7 @@
    * @param  oid    The OID for this intermediate response.
    * @param  value  The value for this intermediate response.
    */
-  public IntermediateResponseProtocolOp(String oid, ASN1OctetString value)
+  public IntermediateResponseProtocolOp(String oid, ByteString value)
   {
     this.oid   = oid;
     this.value = value;
@@ -110,26 +100,13 @@
   }
 
 
-
-  /**
-   * Specifies the OID for this intermediate response.
-   *
-   * @param  oid  The OID for this intermediate response.
-   */
-  public void setOID(String oid)
-  {
-    this.oid = oid;
-  }
-
-
-
   /**
    * Retrieves the value for this intermediate response.
    *
    * @return  The value for this intermediate response, or <CODE>null</CODE> if
    *          there is no value.
    */
-  public ASN1OctetString getValue()
+  public ByteString getValue()
   {
     return value;
   }
@@ -137,18 +114,6 @@
 
 
   /**
-   * Specifies the value for this intermediate response.
-   *
-   * @param  value  The value for this intermediate response.
-   */
-  public void setValue(ASN1OctetString value)
-  {
-    this.value = value;
-  }
-
-
-
-  /**
    * Retrieves the BER type for this protocol op.
    *
    * @return  The BER type for this protocol op.
@@ -170,165 +135,27 @@
     return "Intermediate Response";
   }
 
-
-
   /**
-   * Encodes this protocol op to an ASN.1 element suitable for including in an
-   * LDAP message.
+   * Writes this protocol op to an ASN.1 output stream.
    *
-   * @return  The ASN.1 element containing the encoded protocol op.
+   * @param stream The ASN.1 output stream to write to.
+   * @throws IOException If a problem occurs while writing to the stream.
    */
-  public ASN1Element encode()
+  public void write(ASN1Writer stream) throws IOException
   {
-    ArrayList<ASN1Element> elements = new ArrayList<ASN1Element>(2);
+    stream.writeStartSequence(OP_TYPE_INTERMEDIATE_RESPONSE);
 
     if (oid != null)
     {
-      elements.add(new ASN1OctetString(TYPE_INTERMEDIATE_RESPONSE_OID, oid));
+      stream.writeOctetString(TYPE_INTERMEDIATE_RESPONSE_OID, oid);
     }
 
     if (value != null)
     {
-      value.setType(TYPE_INTERMEDIATE_RESPONSE_VALUE);
-      elements.add(value);
+      stream.writeOctetString(TYPE_INTERMEDIATE_RESPONSE_VALUE, value);
     }
 
-    return new ASN1Sequence(OP_TYPE_INTERMEDIATE_RESPONSE, elements);
-  }
-
-
-
-  /**
-   * Decodes the provided ASN.1 element as an LDAP intermediate response
-   * protocol op.
-   *
-   * @param  element  The ASN.1 element to be decoded.
-   *
-   * @return  The decoded intermediate response protocol op.
-   *
-   * @throws  LDAPException  If a problem occurs while attempting to decode the
-   *                         provided ASN.1 element as an LDAP intermediate
-   *                         response protocol op.
-   */
-  public static IntermediateResponseProtocolOp
-                     decodeIntermediateResponse(ASN1Element element)
-         throws LDAPException
-  {
-    ArrayList<ASN1Element> elements;
-    try
-    {
-      elements = element.decodeAsSequence().elements();
-    }
-    catch (Exception e)
-    {
-      if (debugEnabled())
-      {
-        TRACER.debugCaught(DebugLogLevel.ERROR, e);
-      }
-
-      Message message =
-          ERR_LDAP_INTERMEDIATE_RESPONSE_DECODE_SEQUENCE.get(String.valueOf(e));
-      throw new LDAPException(PROTOCOL_ERROR, message, e);
-    }
-
-
-    int numElements = elements.size();
-    if (numElements > 2)
-    {
-      Message message =
-          ERR_LDAP_INTERMEDIATE_RESPONSE_DECODE_INVALID_ELEMENT_COUNT.
-            get(numElements);
-      throw new LDAPException(PROTOCOL_ERROR, message);
-    }
-
-
-    String          oid   = null;
-    ASN1OctetString value = null;
-
-    if (elements.size() == 1)
-    {
-      ASN1Element e = elements.get(0);
-
-      switch (e.getType())
-      {
-        case TYPE_INTERMEDIATE_RESPONSE_OID:
-          try
-          {
-            oid = e.decodeAsOctetString().stringValue();
-          }
-          catch (ASN1Exception ae)
-          {
-            if (debugEnabled())
-            {
-              TRACER.debugCaught(DebugLogLevel.ERROR, ae);
-            }
-
-            Message message = ERR_LDAP_INTERMEDIATE_RESPONSE_CANNOT_DECODE_OID.
-                get(ae.getMessage());
-            throw new LDAPException(PROTOCOL_ERROR, message);
-          }
-          break;
-        case TYPE_INTERMEDIATE_RESPONSE_VALUE:
-          try
-          {
-            value = e.decodeAsOctetString();
-          }
-          catch (ASN1Exception ae)
-          {
-            if (debugEnabled())
-            {
-              TRACER.debugCaught(DebugLogLevel.ERROR, ae);
-            }
-
-            Message message =
-                ERR_LDAP_INTERMEDIATE_RESPONSE_CANNOT_DECODE_VALUE.
-                  get(ae.getMessage());
-            throw new LDAPException(PROTOCOL_ERROR, message);
-          }
-          break;
-        default:
-          Message message = ERR_LDAP_INTERMEDIATE_RESPONSE_INVALID_ELEMENT_TYPE.
-              get(byteToHex(e.getType()));
-          throw new LDAPException(PROTOCOL_ERROR, message);
-      }
-    }
-    else if (elements.size() == 2)
-    {
-      try
-      {
-        oid = elements.get(0).decodeAsOctetString().stringValue();
-      }
-      catch (ASN1Exception ae)
-      {
-        if (debugEnabled())
-        {
-          TRACER.debugCaught(DebugLogLevel.ERROR, ae);
-        }
-
-        Message message = ERR_LDAP_INTERMEDIATE_RESPONSE_CANNOT_DECODE_OID.get(
-            ae.getMessage());
-        throw new LDAPException(PROTOCOL_ERROR, message);
-      }
-
-      try
-      {
-        value = elements.get(1).decodeAsOctetString();
-      }
-      catch (ASN1Exception ae)
-      {
-        if (debugEnabled())
-        {
-          TRACER.debugCaught(DebugLogLevel.ERROR, ae);
-        }
-
-        Message message = ERR_LDAP_INTERMEDIATE_RESPONSE_CANNOT_DECODE_OID.get(
-            ae.getMessage());
-        throw new LDAPException(PROTOCOL_ERROR, message);
-      }
-    }
-
-
-    return new IntermediateResponseProtocolOp(oid, value);
+    stream.writeEndSequence();
   }
 
 
@@ -347,7 +174,7 @@
     if (value != null)
     {
       buffer.append(", value=");
-      value.toString(buffer);
+      buffer.append(value.toString());
     }
 
     buffer.append(")");
@@ -388,7 +215,7 @@
       buffer.append(indentBuf);
       buffer.append("  Value:");
       buffer.append(EOL);
-      value.toString(buffer, indent+4);
+      value.toHexPlusAscii(buffer, indent+4);
     }
   }
 }
diff --git a/opends/src/server/org/opends/server/protocols/ldap/LDAPAttribute.java b/opends/src/server/org/opends/server/protocols/ldap/LDAPAttribute.java
index 0548cf8..1ccf7c9 100644
--- a/opends/src/server/org/opends/server/protocols/ldap/LDAPAttribute.java
+++ b/opends/src/server/org/opends/server/protocols/ldap/LDAPAttribute.java
@@ -36,14 +36,7 @@
 import java.util.List;
 
 import org.opends.messages.Message;
-import org.opends.server.protocols.asn1.ASN1OctetString;
-import org.opends.server.types.Attribute;
-import org.opends.server.types.AttributeBuilder;
-import org.opends.server.types.AttributeType;
-import org.opends.server.types.AttributeValue;
-import org.opends.server.types.LDAPException;
-import org.opends.server.types.RawAttribute;
-
+import org.opends.server.types.*;
 
 
 /**
@@ -55,7 +48,7 @@
        extends RawAttribute
 {
   // The set of values for this attribute.
-  private ArrayList<ASN1OctetString> values;
+  private ArrayList<ByteString> values;
 
   // The attribute type for this attribute.
   private String attributeType;
@@ -71,7 +64,7 @@
   {
     this.attributeType = attributeType;
 
-    values = new ArrayList<ASN1OctetString>(0);
+    values = new ArrayList<ByteString>(0);
   }
 
 
@@ -86,8 +79,8 @@
   {
     this.attributeType = attributeType;
 
-    values = new ArrayList<ASN1OctetString>(1);
-    values.add(new ASN1OctetString(value));
+    values = new ArrayList<ByteString>(1);
+    values.add(ByteString.valueOf(value));
   }
 
 
@@ -98,11 +91,11 @@
    * @param  attributeType  The attribute type for this attribute.
    * @param  value          The value to use for this attribute.
    */
-  public LDAPAttribute(String attributeType, ASN1OctetString value)
+  public LDAPAttribute(String attributeType, ByteString value)
   {
     this.attributeType = attributeType;
 
-    values = new ArrayList<ASN1OctetString>(1);
+    values = new ArrayList<ByteString>(1);
     values.add(value);
   }
 
@@ -120,14 +113,14 @@
 
     if (values == null)
     {
-      this.values = new ArrayList<ASN1OctetString>(0);
+      this.values = new ArrayList<ByteString>(0);
     }
     else
     {
-      this.values = new ArrayList<ASN1OctetString>(values.size());
+      this.values = new ArrayList<ByteString>(values.size());
       for (String value : values)
       {
-        this.values.add(new ASN1OctetString(value));
+        this.values.add(ByteString.valueOf(value));
       }
     }
   }
@@ -140,13 +133,13 @@
    * @param  attributeType  The attribute type for this attribute.
    * @param  values         The set of values for this attribute.
    */
-  public LDAPAttribute(String attributeType, ArrayList<ASN1OctetString> values)
+  public LDAPAttribute(String attributeType, ArrayList<ByteString> values)
   {
     this.attributeType = attributeType;
 
     if (values == null)
     {
-      this.values = new ArrayList<ASN1OctetString>(0);
+      this.values = new ArrayList<ByteString>(0);
     }
     else
     {
@@ -181,14 +174,14 @@
 
     if (attribute.isEmpty())
     {
-      values = new ArrayList<ASN1OctetString>(0);
+      values = new ArrayList<ByteString>(0);
       return;
     }
 
-    values = new ArrayList<ASN1OctetString>(attribute.size());
+    values = new ArrayList<ByteString>(attribute.size());
     for (AttributeValue v : attribute)
     {
-      values.add(v.getValue().toASN1OctetString());
+      values.add(v.getValue());
     }
   }
 
@@ -224,7 +217,7 @@
    *
    * @return  The set of values for this attribute.
    */
-  public ArrayList<ASN1OctetString> getValues()
+  public ArrayList<ByteString> getValues()
   {
     return values;
   }
@@ -274,9 +267,10 @@
     }
 
     AttributeType attrType = builder.getAttributeType();
-    for (ASN1OctetString value : values)
+    for (ByteString value : values)
     {
-      if (!builder.add(new AttributeValue(attrType, value)))
+      if (!builder.add(
+          AttributeValues.create(attrType, value)))
       {
         Message message =
             ERR_LDAP_ATTRIBUTE_DUPLICATE_VALUES.get(attributeType);
@@ -317,12 +311,12 @@
 
     if (! values.isEmpty())
     {
-      Iterator<ASN1OctetString> iterator = values.iterator();
-      iterator.next().toString(buffer);
+      Iterator<ByteString> iterator = values.iterator();
+      buffer.append(iterator.next());
       while (iterator.hasNext())
       {
         buffer.append(", ");
-        iterator.next().toString(buffer);
+        buffer.append(iterator.next());
       }
     }
 
@@ -359,9 +353,9 @@
     buffer.append("  Attribute Values:");
     buffer.append(EOL);
 
-    for (ASN1OctetString value : values)
+    for (ByteString value : values)
     {
-      value.toString(buffer, indent+4);
+      value.toHexPlusAscii(buffer, indent+4);
     }
   }
 }
diff --git a/opends/src/server/org/opends/server/protocols/ldap/LDAPClientConnection.java b/opends/src/server/org/opends/server/protocols/ldap/LDAPClientConnection.java
index df57bde..fa7b7aa 100644
--- a/opends/src/server/org/opends/server/protocols/ldap/LDAPClientConnection.java
+++ b/opends/src/server/org/opends/server/protocols/ldap/LDAPClientConnection.java
@@ -22,17 +22,25 @@
  * CDDL HEADER END
  *
  *
- *      Copyright 2006-2008 Sun Microsystems, Inc.
+ *      Copyright 2006-2009 Sun Microsystems, Inc.
  */
 package org.opends.server.protocols.ldap;
 
 
 
+import static org.opends.messages.ProtocolMessages.*;
+import static org.opends.server.loggers.AccessLogger.*;
+import static org.opends.server.loggers.ErrorLogger.*;
+import static org.opends.server.loggers.debug.DebugLogger.*;
+import static org.opends.server.protocols.ldap.LDAPConstants.*;
+import static org.opends.server.types.OperationType.*;
+import static org.opends.server.util.StaticUtils.*;
+
 import java.net.InetAddress;
 import java.nio.ByteBuffer;
 import java.nio.channels.Selector;
 import java.nio.channels.SocketChannel;
-import java.util.ArrayList;
+import java.security.cert.Certificate;
 import java.util.Collection;
 import java.util.Iterator;
 import java.util.List;
@@ -44,7 +52,6 @@
 import org.opends.messages.MessageBuilder;
 import org.opends.server.api.ClientConnection;
 import org.opends.server.api.ConnectionHandler;
-import org.opends.server.api.ConnectionSecurityProvider;
 import org.opends.server.core.AbandonOperationBasis;
 import org.opends.server.core.AddOperationBasis;
 import org.opends.server.core.BindOperationBasis;
@@ -60,15 +67,18 @@
 import org.opends.server.core.SearchOperationBasis;
 import org.opends.server.core.UnbindOperationBasis;
 import org.opends.server.core.networkgroups.NetworkGroup;
-import org.opends.server.extensions.NullConnectionSecurityProvider;
+import org.opends.server.extensions.ConnectionSecurityProvider;
+import org.opends.server.extensions.RedirectingByteChannel;
+import org.opends.server.extensions.TLSByteChannel;
 import org.opends.server.extensions.TLSCapableConnection;
-import org.opends.server.extensions.TLSConnectionSecurityProvider;
 import org.opends.server.loggers.debug.DebugTracer;
 import org.opends.server.monitors.OperationMonitor;
-import org.opends.server.protocols.asn1.ASN1Element;
-import org.opends.server.protocols.asn1.ASN1OctetString;
-import org.opends.server.protocols.asn1.ASN1Sequence;
+import org.opends.server.protocols.asn1.ASN1;
+import org.opends.server.protocols.asn1.ASN1ByteChannelReader;
+import org.opends.server.protocols.asn1.ASN1Writer;
 import org.opends.server.types.AbstractOperation;
+import org.opends.server.types.ByteString;
+import org.opends.server.types.ByteStringBuilder;
 import org.opends.server.types.CancelRequest;
 import org.opends.server.types.CancelResult;
 import org.opends.server.types.Control;
@@ -83,151 +93,113 @@
 import org.opends.server.types.SearchResultReference;
 import org.opends.server.util.TimeThread;
 
-import static org.opends.messages.ProtocolMessages.*;
-import static org.opends.server.loggers.AccessLogger.logDisconnect;
-import static org.opends.server.loggers.ErrorLogger.logError;
-import static org.opends.server.loggers.debug.DebugLogger.debugEnabled;
-import static org.opends.server.loggers.debug.DebugLogger.getTracer;
-import static org.opends.server.protocols.ldap.LDAPConstants.*;
-import static org.opends.server.util.StaticUtils.getExceptionMessage;
-import static org.opends.server.util.StaticUtils.stackTraceToSingleLineString;
-import static org.opends.server.types.OperationType.*;
-
 
 
 /**
- * This class defines an LDAP client connection, which is a type of client
- * connection that will be accepted by an instance of the LDAP connection
- * handler and have its requests decoded by an LDAP request handler.
+ * This class defines an LDAP client connection, which is a type of
+ * client connection that will be accepted by an instance of the LDAP
+ * connection handler and have its requests decoded by an LDAP request
+ * handler.
  */
-public class LDAPClientConnection
-       extends ClientConnection
-       implements TLSCapableConnection
+
+public class LDAPClientConnection extends ClientConnection implements
+    TLSCapableConnection
 {
   /**
    * The tracer object for the debug logger.
    */
   private static final DebugTracer TRACER = getTracer();
 
-
-
   // The time that the last operation was completed.
-  private AtomicLong lastCompletionTime;
+  private final AtomicLong lastCompletionTime;
 
   // The next operation ID that should be used for this connection.
-  private AtomicLong nextOperationID;
+  private final AtomicLong nextOperationID;
 
   // The selector that may be used for write operations.
-  private AtomicReference<Selector> writeSelector;
+  private final AtomicReference<Selector> writeSelector;
 
-  // Indicates whether the Directory Server believes this connection to be
-  // valid and available for communication.
+  // Indicates whether the Directory Server believes this connection to
+  // be valid and available for communication.
   private boolean connectionValid;
 
-  // Indicates whether this connection is about to be closed.  This will be used
-  // to prevent accepting new requests while a disconnect is in progress.
+  // Indicates whether this connection is about to be closed. This will
+  // be used to prevent accepting new requests while a disconnect is in
+  // progress.
   private boolean disconnectRequested;
 
-  // Indicates whether the connection should keep statistics regarding the
-  // operations that it is performing.
-  private boolean keepStats;
-
-  // The BER type for the ASN.1 element that is in the process of being read.
-  private byte elementType;
-
-  // The encoded value for the ASN.1 element that is in the process of being
-  // read.
-  private byte[] elementValue;
+  // Indicates whether the connection should keep statistics regarding
+  // the operations that it is performing.
+  private final boolean keepStats;
 
   // The set of all operations currently in progress on this connection.
-  private ConcurrentHashMap<Integer,Operation> operationsInProgress;
+  private final ConcurrentHashMap<Integer, Operation> operationsInProgress;
 
   // The number of operations performed on this connection.
   // Used to compare with the resource limits of the network group.
   private long operationsPerformed;
 
   // Lock on the number of operations
-  private Object operationsPerformedLock;
-
-  // The connection security provider that was in use for the client connection
-  // before switching to a TLS-based provider.
-  private ConnectionSecurityProvider clearSecurityProvider;
-
-  // The connection security provider for this client connection.
-  private ConnectionSecurityProvider securityProvider;
+  private final Object operationsPerformedLock;
 
   // The port on the client from which this connection originated.
-  private int clientPort;
+  private final int clientPort;
 
-  // The number of bytes contained in the value for the ASN.1 element that is in
-  // the process of being read.
-  private int elementLength;
-
-  // The number of bytes in the multi-byte length that are still needed to fully
-  // decode the length of the ASN.1 element in process.
-  private int elementLengthBytesNeeded;
-
-  // The current state for the data read for the ASN.1 element in progress.
-  private int elementReadState;
-
-  // The number of bytes that have already been read for the ASN.1 element
-  // value in progress.
-  private int elementValueBytesRead;
-
-  // The number of bytes that are still needed to fully decode the value of the
-  // ASN.1 element in progress.
-  private int elementValueBytesNeeded;
-
-  // The LDAP version that the client is using to communicate with the server.
+  // The LDAP version that the client is using to communicate with the
+  // server.
   private int ldapVersion;
 
   // The port on the server to which this client has connected.
-  private int serverPort;
+  private final int serverPort;
 
-  // The reference to the connection handler that accepted this connection.
-  private LDAPConnectionHandler connectionHandler;
+  // The reference to the connection handler that accepted this
+  // connection.
+  private final LDAPConnectionHandler connectionHandler;
 
   // The reference to the request handler with which this connection is
   // associated.
-  private LDAPRequestHandler requestHandler;
+  private final LDAPRequestHandler requestHandler;
 
   // The statistics tracker associated with this client connection.
-  private LDAPStatistics statTracker;
+  private final LDAPStatistics statTracker;
 
   // The connectionHandler statistic tracker.
-  private LDAPStatistics parentTracker;
+  private final LDAPStatistics parentTracker;
 
   // The connection ID assigned to this connection.
-  private long connectionID;
+  private final long connectionID;
 
-  // The lock used to provide threadsafe access to the set of operations in
-  // progress.
-  private Object opsInProgressLock;
+  // The lock used to provide threadsafe access to the set of operations
+  // in progress.
+  private final Object opsInProgressLock;
 
-  // The lock used to provide threadsafe access when sending data to the client.
-  private Object transmitLock;
+  // The lock used to provide threadsafe access when sending data to the
+  // client.
+  private final Object transmitLock;
 
   // The socket channel with which this client connection is associated.
-  private SocketChannel clientChannel;
+  private final SocketChannel clientChannel;
 
   // The string representation of the address of the client.
-  private String clientAddress;
+  private final String clientAddress;
 
-  // The name of the protocol that the client is using to communicate with the
-  // server.
-  private String protocol;
+  // The name of the protocol that the client is using to communicate
+  // with the server.
+  private final String protocol;
 
-  // The string representation of the address of the server to which the client
-  // has connected.
-  private String serverAddress;
+  // The string representation of the address of the server to which the
+  // client has connected.
+  private final String serverAddress;
 
-  // The TLS connection security provider that may be used for this connection
-  // if StartTLS is requested.
-  private TLSConnectionSecurityProvider tlsSecurityProvider;
+  private final ThreadLocal<WriterBuffer> cachedBuffers;
 
-  //The SASL connection provider used if confidentiality/integrity is negotiated
-  //during a SASL bind (GSSAPI and DIGEST-MD5 only).
-  private ConnectionSecurityProvider saslSecurityProvider;
+  private ASN1ByteChannelReader asn1Reader;
+
+  private final RedirectingByteChannel saslChannel;
+  private final RedirectingByteChannel tlsChannel;
+  private ConnectionSecurityProvider activeProvider = null;
+  private ConnectionSecurityProvider tlsPendingProvider = null;
+  private ConnectionSecurityProvider saslPendingProvider = null;
 
   // Statistics for the processed operations
   private OperationMonitor addMonitor;
@@ -241,64 +213,67 @@
   private OperationMonitor moddnMonitor;
   private OperationMonitor unbindMonitor;
 
+
+
+  /**
+   * This class wraps the byte string buffer and ASN1 writer.
+   */
+  private static class WriterBuffer
+  {
+    ASN1Writer writer;
+    ByteStringBuilder buffer;
+  }
+
+
+
   /**
    * Creates a new LDAP client connection with the provided information.
    *
-   * @param  connectionHandler  The connection handler that accepted this
-   *                            connection.
-   * @param  clientChannel      The socket channel that may be used to
-   *                            communicate with the client.
+   * @param connectionHandler
+   *          The connection handler that accepted this connection.
+   * @param clientChannel
+   *          The socket channel that may be used to communicate with
+   *          the client.
    */
   public LDAPClientConnection(LDAPConnectionHandler connectionHandler,
-                              SocketChannel clientChannel)
+      SocketChannel clientChannel)
   {
     super();
 
-
-    this.connectionHandler     = connectionHandler;
-    if (connectionHandler.isAdminConnectionHandler()) {
+    this.connectionHandler = connectionHandler;
+    if (connectionHandler.isAdminConnectionHandler())
+    {
       setNetworkGroup(NetworkGroup.getAdminNetworkGroup());
     }
 
-    this.clientChannel         = clientChannel;
-    this.securityProvider      = null;
-    this.clearSecurityProvider = null;
-
+    this.clientChannel = clientChannel;
     opsInProgressLock = new Object();
-    transmitLock      = new Object();
-
-    elementReadState         = ELEMENT_READ_STATE_NEED_TYPE;
-    elementType              = 0x00;
-    elementLength            = 0;
-    elementLengthBytesNeeded = 0;
-    elementValue             = null;
-    elementValueBytesRead    = 0;
-    elementValueBytesNeeded  = 0;
-
-    ldapVersion          = 3;
-    requestHandler       = null;
-    lastCompletionTime   = new AtomicLong(TimeThread.getTime());
-    nextOperationID      = new AtomicLong(0);
-    connectionValid      = true;
-    disconnectRequested  = false;
-    operationsInProgress = new ConcurrentHashMap<Integer,Operation>();
+    transmitLock = new Object();
+    ldapVersion = 3;
+    requestHandler = null;
+    lastCompletionTime = new AtomicLong(TimeThread.getTime());
+    nextOperationID = new AtomicLong(0);
+    connectionValid = true;
+    disconnectRequested = false;
+    operationsInProgress = new ConcurrentHashMap<Integer, Operation>();
     operationsPerformed = 0;
     operationsPerformedLock = new Object();
-    keepStats            = connectionHandler.keepStats();
-    protocol             = "LDAP";
-    writeSelector        = new AtomicReference<Selector>();
-
-    clientAddress = clientChannel.socket().getInetAddress().getHostAddress();
-    clientPort    = clientChannel.socket().getPort();
-    serverAddress = clientChannel.socket().getLocalAddress().getHostAddress();
-    serverPort    = clientChannel.socket().getLocalPort();
-
+    keepStats = connectionHandler.keepStats();
+    protocol = "LDAP";
+    writeSelector = new AtomicReference<Selector>();
+    clientAddress =
+        clientChannel.socket().getInetAddress().getHostAddress();
+    clientPort = clientChannel.socket().getPort();
+    serverAddress =
+        clientChannel.socket().getLocalAddress().getHostAddress();
+    serverPort = clientChannel.socket().getLocalPort();
     parentTracker = connectionHandler.getStatTracker();
-    String         instanceName  = parentTracker.getMonitorInstanceName() +
-                                   " for " + toString();
+    String instanceName =
+        parentTracker.getMonitorInstanceName() + " for " + toString();
     this.initializeOperationMonitors();
-    statTracker = new LDAPStatistics(connectionHandler,
-            instanceName, parentTracker);
+    statTracker =
+        new LDAPStatistics(connectionHandler, instanceName,
+            parentTracker);
 
     if (keepStats)
     {
@@ -309,8 +284,16 @@
     if (connectionID < 0)
     {
       disconnect(DisconnectReason.ADMIN_LIMIT_EXCEEDED, true,
-                 ERR_LDAP_CONNHANDLER_REJECTED_BY_SERVER.get());
+          ERR_LDAP_CONNHANDLER_REJECTED_BY_SERVER.get());
     }
+    cachedBuffers = new ThreadLocal<WriterBuffer>();
+    tlsChannel =
+        RedirectingByteChannel.getRedirectingByteChannel(clientChannel);
+    saslChannel =
+        RedirectingByteChannel.getRedirectingByteChannel(tlsChannel);
+    this.asn1Reader =
+        ASN1.getReader(saslChannel, 4096, connectionHandler
+            .getMaxRequestSize());
   }
 
 
@@ -318,8 +301,9 @@
   /**
    * Retrieves the connection ID assigned to this connection.
    *
-   * @return  The connection ID assigned to this connection.
+   * @return The connection ID assigned to this connection.
    */
+  @Override
   public long getConnectionID()
   {
     return connectionID;
@@ -328,10 +312,13 @@
 
 
   /**
-   * Retrieves the connection handler that accepted this client connection.
+   * Retrieves the connection handler that accepted this client
+   * connection.
    *
-   * @return  The connection handler that accepted this client connection.
+   * @return The connection handler that accepted this client
+   *         connection.
    */
+  @Override
   public ConnectionHandler<?> getConnectionHandler()
   {
     return connectionHandler;
@@ -340,11 +327,12 @@
 
 
   /**
-   * Retrieves the request handler that will read requests for this client
-   * connection.
+   * Retrieves the request handler that will read requests for this
+   * client connection.
    *
-   * @return  The request handler that will read requests for this client
-   *          connection, or <CODE>null</CODE> if none has been assigned yet.
+   * @return The request handler that will read requests for this client
+   *         connection, or <CODE>null</CODE> if none has been assigned
+   *         yet.
    */
   public LDAPRequestHandler getRequestHandler()
   {
@@ -354,25 +342,11 @@
 
 
   /**
-   * Specifies the request handler that will read requests for this client
-   * connection.
+   * Retrieves the socket channel that can be used to communicate with
+   * the client.
    *
-   * @param  requestHandler  The request handler that will read requests for
-   *                         this client connection.
-   */
-  public void setRequestHandler(LDAPRequestHandler requestHandler)
-  {
-    this.requestHandler = requestHandler;
-  }
-
-
-
-  /**
-   * Retrieves the socket channel that can be used to communicate with the
-   * client.
-   *
-   * @return  The socket channel that can be used to communicate with the
-   *          client.
+   * @return The socket channel that can be used to communicate with the
+   *         client.
    */
   public SocketChannel getSocketChannel()
   {
@@ -382,12 +356,13 @@
 
 
   /**
-   * Retrieves the protocol that the client is using to communicate with the
-   * Directory Server.
+   * Retrieves the protocol that the client is using to communicate with
+   * the Directory Server.
    *
-   * @return  The protocol that the client is using to communicate with the
-   *          Directory Server.
+   * @return The protocol that the client is using to communicate with
+   *         the Directory Server.
    */
+  @Override
   public String getProtocol()
   {
     return protocol;
@@ -398,8 +373,9 @@
   /**
    * Retrieves a string representation of the address of the client.
    *
-   * @return  A string representation of the address of the client.
+   * @return A string representation of the address of the client.
    */
+  @Override
   public String getClientAddress()
   {
     return clientAddress;
@@ -410,8 +386,9 @@
   /**
    * Retrieves the port number for this connection on the client system.
    *
-   * @return  The port number for this connection on the client system.
+   * @return The port number for this connection on the client system.
    */
+  @Override
   public int getClientPort()
   {
     return clientPort;
@@ -420,12 +397,13 @@
 
 
   /**
-   * Retrieves a string representation of the address on the server to which the
-   * client connected.
+   * Retrieves a string representation of the address on the server to
+   * which the client connected.
    *
-   * @return  A string representation of the address on the server to which the
-   *          client connected.
+   * @return A string representation of the address on the server to
+   *         which the client connected.
    */
+  @Override
   public String getServerAddress()
   {
     return serverAddress;
@@ -436,8 +414,9 @@
   /**
    * Retrieves the port number for this connection on the server system.
    *
-   * @return  The port number for this connection on the server system.
+   * @return The port number for this connection on the server system.
    */
+  @Override
   public int getServerPort()
   {
     return serverPort;
@@ -446,13 +425,14 @@
 
 
   /**
-   * Retrieves the <CODE>java.net.InetAddress</CODE> associated with the remote
-   * client system.
+   * Retrieves the <CODE>java.net.InetAddress</CODE> associated with the
+   * remote client system.
    *
-   * @return  The <CODE>java.net.InetAddress</CODE> associated with the remote
-   *          client system.  It may be <CODE>null</CODE> if the client is not
-   *          connected over an IP-based connection.
+   * @return The <CODE>java.net.InetAddress</CODE> associated with the
+   *         remote client system. It may be <CODE>null</CODE> if the
+   *         client is not connected over an IP-based connection.
    */
+  @Override
   public InetAddress getRemoteAddress()
   {
     return clientChannel.socket().getInetAddress();
@@ -461,14 +441,15 @@
 
 
   /**
-   * Retrieves the <CODE>java.net.InetAddress</CODE> for the Directory Server
-   * system to which the client has established the connection.
+   * Retrieves the <CODE>java.net.InetAddress</CODE> for the Directory
+   * Server system to which the client has established the connection.
    *
-   * @return  The <CODE>java.net.InetAddress</CODE> for the Directory Server
-   *          system to which the client has established the connection.  It may
-   *          be <CODE>null</CODE> if the client is not connected over an
-   *          IP-based connection.
+   * @return The <CODE>java.net.InetAddress</CODE> for the Directory
+   *         Server system to which the client has established the
+   *         connection. It may be <CODE>null</CODE> if the client is
+   *         not connected over an IP-based connection.
    */
+  @Override
   public InetAddress getLocalAddress()
   {
     return clientChannel.socket().getLocalAddress();
@@ -477,92 +458,34 @@
 
 
   /**
-   * Indicates whether this client connection is currently using a secure
-   * mechanism to communicate with the server.  Note that this may change over
-   * time based on operations performed by the client or server (e.g., it may go
-   * from <CODE>false</CODE> to <CODE>true</CODE> if the client uses the
-   * StartTLS extended operation).
+   * Indicates whether this client connection is currently using a
+   * secure mechanism to communicate with the server. Note that this may
+   * change over time based on operations performed by the client or
+   * server (e.g., it may go from <CODE>false</CODE> to
+   * <CODE>true</CODE> if the client uses the StartTLS extended
+   * operation).
    *
-   * @return  <CODE>true</CODE> if the client connection is currently using a
-   *          secure mechanism to communicate with the server, or
-   *          <CODE>false</CODE> if not.
+   * @return <CODE>true</CODE> if the client connection is currently
+   *         using a secure mechanism to communicate with the server, or
+   *         <CODE>false</CODE> if not.
    */
+  @Override
   public boolean isSecure()
   {
-    return securityProvider.isSecure();
-  }
-
-
-
-  /**
-   * Retrieves the connection security provider for this client connection.
-   *
-   * @return  The connection security provider for this client connection.
-   */
-  public ConnectionSecurityProvider getConnectionSecurityProvider()
-  {
-      if(saslSecurityProvider != null && saslSecurityProvider.isActive())
-          securityProvider =  saslSecurityProvider;
-      return securityProvider;
-  }
-
-
-
-  /**
-   * Set the security provider to be used to process SASL (DIGEST-MD5, GSSAPI)
-   * confidentiality/integrity messages.
-   *
-   * @param secProvider The security provider to use.
-   */
-    public void
-    setSASLConnectionSecurityProvider(ConnectionSecurityProvider secProvider) {
-        saslSecurityProvider = secProvider;
-    }
-
-
-
-  /**
-   * Specifies the connection security provider for this client connection.
-   *
-   * @param  securityProvider  The connection security provider to use for
-   *                           communication on this client connection.
-   */
-  public void setConnectionSecurityProvider(ConnectionSecurityProvider
-                                                 securityProvider)
-  {
-    this.securityProvider = securityProvider;
-
-    if (securityProvider.isSecure())
-    {
-      protocol = "LDAP+" + securityProvider.getSecurityMechanismName();
-    }
+    if (activeProvider != null)
+      return activeProvider.isSecure();
     else
-    {
-      protocol = "LDAP";
-    }
+      return false;
   }
 
 
 
   /**
-   * Retrieves the human-readable name of the security mechanism that is used to
-   * protect communication with this client.
+   * Retrieves the next operation ID that should be used for this
+   * connection.
    *
-   * @return  The human-readable name of the security mechanism that is used to
-   *          protect communication with this client, or <CODE>null</CODE> if no
-   *          security is in place.
-   */
-  public String getSecurityMechanism()
-  {
-    return securityProvider.getSecurityMechanismName();
-  }
-
-
-
-  /**
-   * Retrieves the next operation ID that should be used for this connection.
-   *
-   * @return  The next operation ID that should be used for this connection.
+   * @return The next operation ID that should be used for this
+   *         connection.
    */
   public long nextOperationID()
   {
@@ -572,57 +495,56 @@
 
 
   /**
-   * Sends a response to the client based on the information in the provided
-   * operation.
+   * Sends a response to the client based on the information in the
+   * provided operation.
    *
-   * @param  operation  The operation for which to send the response.
+   * @param operation
+   *          The operation for which to send the response.
    */
+  @Override
   public void sendResponse(Operation operation)
   {
-    // Since this is the final response for this operation, we can go ahead and
-    // remove it from the "operations in progress" list.  It can't be canceled
-    // after this point, and this will avoid potential race conditions in which
-    // the client immediately sends another request with the same message ID as
-    // was used for this operation.
+    // Since this is the final response for this operation, we can go
+    // ahead and remove it from the "operations in progress" list. It
+    // can't be canceled after this point, and this will avoid potential
+    // race conditions in which the client immediately sends another
+    // request with the same message ID as was used for this operation.
     removeOperationInProgress(operation.getMessageID());
 
     LDAPMessage message = operationToResponseLDAPMessage(operation);
     if (message != null)
     {
-      sendLDAPMessage(securityProvider, message);
+      sendLDAPMessage(message);
     }
   }
 
 
 
   /**
-   * Retrieves an LDAPMessage containing a response generated from the provided
-   * operation.
+   * Retrieves an LDAPMessage containing a response generated from the
+   * provided operation.
    *
-   * @param  operation  The operation to use to generate the response
-   *                    LDAPMessage.
-   *
-   * @return  An LDAPMessage containing a response generated from the provided
-   *          operation.
+   * @param operation
+   *          The operation to use to generate the response LDAPMessage.
+   * @return An LDAPMessage containing a response generated from the
+   *         provided operation.
    */
   private LDAPMessage operationToResponseLDAPMessage(Operation operation)
   {
     ResultCode resultCode = operation.getResultCode();
     if (resultCode == null)
     {
-      // This must mean that the operation has either not yet completed or that
-      // it completed without a result for some reason.  In any case, log a
-      // message and set the response to "operations error".
-      logError(ERR_LDAP_CLIENT_SEND_RESPONSE_NO_RESULT_CODE.
-          get(operation.getOperationType().toString(),
-              operation.getConnectionID(), operation.getOperationID()));
+      // This must mean that the operation has either not yet completed
+      // or that it completed without a result for some reason. In any
+      // case, log a message and set the response to "operations error".
+      logError(ERR_LDAP_CLIENT_SEND_RESPONSE_NO_RESULT_CODE.get(
+          operation.getOperationType().toString(), operation
+              .getConnectionID(), operation.getOperationID()));
       resultCode = DirectoryServer.getServerErrorResultCode();
     }
 
-
     MessageBuilder errorMessage = operation.getErrorMessage();
-    DN             matchedDN    = operation.getMatchedDN();
-
+    DN matchedDN = operation.getMatchedDN();
 
     // Referrals are not allowed for LDAPv2 clients.
     List<String> referralURLs;
@@ -637,7 +559,7 @@
       }
 
       List<String> opReferrals = operation.getReferralURLs();
-      if ((opReferrals != null) && (! opReferrals.isEmpty()))
+      if ((opReferrals != null) && (!opReferrals.isEmpty()))
       {
         StringBuilder referralsStr = new StringBuilder();
         Iterator<String> iterator = opReferrals.iterator();
@@ -649,8 +571,8 @@
           referralsStr.append(iterator.next());
         }
 
-        errorMessage.append(ERR_LDAPV2_REFERRALS_OMITTED.get(
-                String.valueOf(referralsStr)));
+        errorMessage.append(ERR_LDAPV2_REFERRALS_OMITTED.get(String
+            .valueOf(referralsStr)));
       }
     }
     else
@@ -661,94 +583,82 @@
     ProtocolOp protocolOp;
     switch (operation.getOperationType())
     {
-      case ADD:
-        protocolOp = new AddResponseProtocolOp(resultCode.getIntValue(),
-                                               errorMessage.toMessage(),
-                                               matchedDN, referralURLs);
-        break;
-      case BIND:
-        ASN1OctetString serverSASLCredentials =
-             ((BindOperationBasis) operation).getServerSASLCredentials();
-        protocolOp = new BindResponseProtocolOp(resultCode.getIntValue(),
-                              errorMessage.toMessage(), matchedDN,
-                              referralURLs, serverSASLCredentials);
-        break;
-      case COMPARE:
-        protocolOp = new CompareResponseProtocolOp(resultCode.getIntValue(),
-                                                   errorMessage.toMessage(),
-                                                   matchedDN, referralURLs);
-        break;
-      case DELETE:
-        protocolOp = new DeleteResponseProtocolOp(resultCode.getIntValue(),
-                                                  errorMessage.toMessage(),
-                                                  matchedDN, referralURLs);
-        break;
-      case EXTENDED:
-        // If this an LDAPv2 client, then we can't send this.
-        if (ldapVersion == 2)
-        {
-          logError(ERR_LDAPV2_SKIPPING_EXTENDED_RESPONSE.get(
-              getConnectionID(), operation.getOperationID(),
-                  String.valueOf(operation)));
-          return null;
-        }
-
-        ExtendedOperationBasis extOp = (ExtendedOperationBasis) operation;
-        protocolOp = new ExtendedResponseProtocolOp(resultCode.getIntValue(),
-                              errorMessage.toMessage(), matchedDN, referralURLs,
-                              extOp.getResponseOID(), extOp.getResponseValue());
-        break;
-      case MODIFY:
-        protocolOp = new ModifyResponseProtocolOp(resultCode.getIntValue(),
-                                                  errorMessage.toMessage(),
-                                                  matchedDN, referralURLs);
-        break;
-      case MODIFY_DN:
-        protocolOp = new ModifyDNResponseProtocolOp(resultCode.getIntValue(),
-                                                    errorMessage.toMessage(),
-                                                    matchedDN, referralURLs);
-        break;
-      case SEARCH:
-        protocolOp = new SearchResultDoneProtocolOp(resultCode.getIntValue(),
-                                                    errorMessage.toMessage(),
-                                                    matchedDN, referralURLs);
-        break;
-      default:
-        // This must be a type of operation that doesn't have a response.  This
-        // shouldn't happen, so log a message and return.
-        logError(ERR_LDAP_CLIENT_SEND_RESPONSE_INVALID_OP.get(
-                String.valueOf(operation.getOperationType()),
-                getConnectionID(),
-                operation.getOperationID(),
-                String.valueOf(operation)));
+    case ADD:
+      protocolOp =
+          new AddResponseProtocolOp(resultCode.getIntValue(),
+              errorMessage.toMessage(), matchedDN, referralURLs);
+      break;
+    case BIND:
+      ByteString serverSASLCredentials =
+          ((BindOperationBasis) operation).getServerSASLCredentials();
+      protocolOp =
+          new BindResponseProtocolOp(resultCode.getIntValue(),
+              errorMessage.toMessage(), matchedDN, referralURLs,
+              serverSASLCredentials);
+      break;
+    case COMPARE:
+      protocolOp =
+          new CompareResponseProtocolOp(resultCode.getIntValue(),
+              errorMessage.toMessage(), matchedDN, referralURLs);
+      break;
+    case DELETE:
+      protocolOp =
+          new DeleteResponseProtocolOp(resultCode.getIntValue(),
+              errorMessage.toMessage(), matchedDN, referralURLs);
+      break;
+    case EXTENDED:
+      // If this an LDAPv2 client, then we can't send this.
+      if (ldapVersion == 2)
+      {
+        logError(ERR_LDAPV2_SKIPPING_EXTENDED_RESPONSE.get(
+            getConnectionID(), operation.getOperationID(), String
+                .valueOf(operation)));
         return null;
+      }
+
+      ExtendedOperationBasis extOp = (ExtendedOperationBasis) operation;
+      protocolOp =
+          new ExtendedResponseProtocolOp(resultCode.getIntValue(),
+              errorMessage.toMessage(), matchedDN, referralURLs, extOp
+                  .getResponseOID(), extOp.getResponseValue());
+      break;
+    case MODIFY:
+      protocolOp =
+          new ModifyResponseProtocolOp(resultCode.getIntValue(),
+              errorMessage.toMessage(), matchedDN, referralURLs);
+      break;
+    case MODIFY_DN:
+      protocolOp =
+          new ModifyDNResponseProtocolOp(resultCode.getIntValue(),
+              errorMessage.toMessage(), matchedDN, referralURLs);
+      break;
+    case SEARCH:
+      protocolOp =
+          new SearchResultDoneProtocolOp(resultCode.getIntValue(),
+              errorMessage.toMessage(), matchedDN, referralURLs);
+      break;
+    default:
+      // This must be a type of operation that doesn't have a response.
+      // This shouldn't happen, so log a message and return.
+      logError(ERR_LDAP_CLIENT_SEND_RESPONSE_INVALID_OP.get(String
+          .valueOf(operation.getOperationType()), getConnectionID(),
+          operation.getOperationID(), String.valueOf(operation)));
+      return null;
     }
 
-
     // Controls are not allowed for LDAPv2 clients.
-    ArrayList<LDAPControl> controls;
+    List<Control> controls;
     if (ldapVersion == 2)
     {
       controls = null;
     }
     else
     {
-      List<Control> responseControls = operation.getResponseControls();
-      if ((responseControls == null) || responseControls.isEmpty())
-      {
-        controls = null;
-      }
-      else
-      {
-        controls = new ArrayList<LDAPControl>(responseControls.size());
-        for (Control c : responseControls)
-        {
-          controls.add(new LDAPControl(c));
-        }
-      }
+      controls = operation.getResponseControls();
     }
 
-    return new LDAPMessage(operation.getMessageID(), protocolOp, controls);
+    return new LDAPMessage(operation.getMessageID(), protocolOp,
+        controls);
   }
 
 
@@ -756,34 +666,20 @@
   /**
    * Sends the provided search result entry to the client.
    *
-   * @param  searchOperation  The search operation with which the entry is
-   *                          associated.
-   * @param  searchEntry      The search result entry to be sent to the client.
+   * @param searchOperation
+   *          The search operation with which the entry is associated.
+   * @param searchEntry
+   *          The search result entry to be sent to the client.
    */
+  @Override
   public void sendSearchEntry(SearchOperation searchOperation,
-                              SearchResultEntry searchEntry)
+      SearchResultEntry searchEntry)
   {
     SearchResultEntryProtocolOp protocolOp =
-         new SearchResultEntryProtocolOp(searchEntry,ldapVersion);
+        new SearchResultEntryProtocolOp(searchEntry, ldapVersion);
 
-    List<Control> entryControls = searchEntry.getControls();
-    ArrayList<LDAPControl> controls;
-    if ((entryControls == null) || entryControls.isEmpty())
-    {
-      controls = null;
-    }
-    else
-    {
-      controls = new ArrayList<LDAPControl>(entryControls.size());
-      for (Control c : entryControls)
-      {
-        controls.add(new LDAPControl(c));
-      }
-    }
-
-    sendLDAPMessage(securityProvider,
-                    new LDAPMessage(searchOperation.getMessageID(), protocolOp,
-                                    controls));
+    sendLDAPMessage(new LDAPMessage(searchOperation.getMessageID(),
+        protocolOp, searchEntry.getControls()));
   }
 
 
@@ -791,92 +687,69 @@
   /**
    * Sends the provided search result reference to the client.
    *
-   * @param  searchOperation  The search operation with which the reference is
-   *                          associated.
-   * @param  searchReference  The search result reference to be sent to the
-   *                          client.
-   *
-   * @return  <CODE>true</CODE> if the client is able to accept referrals, or
-   *          <CODE>false</CODE> if the client cannot handle referrals and no
-   *          more attempts should be made to send them for the associated
-   *          search operation.
+   * @param searchOperation
+   *          The search operation with which the reference is
+   *          associated.
+   * @param searchReference
+   *          The search result reference to be sent to the client.
+   * @return <CODE>true</CODE> if the client is able to accept
+   *         referrals, or <CODE>false</CODE> if the client cannot
+   *         handle referrals and no more attempts should be made to
+   *         send them for the associated search operation.
    */
+  @Override
   public boolean sendSearchReference(SearchOperation searchOperation,
-                                     SearchResultReference searchReference)
+      SearchResultReference searchReference)
   {
-    // Make sure this is not an LDAPv2 client.  If it is, then they can't see
-    // referrals so we'll not send anything.  Also, throw an exception so that
-    // the core server will know not to try sending any more referrals to this
-    // client for the rest of the operation.
+    // Make sure this is not an LDAPv2 client. If it is, then they can't
+    // see referrals so we'll not send anything. Also, throw an
+    // exception so that the core server will know not to try sending
+    // any more referrals to this client for the rest of the operation.
     if (ldapVersion == 2)
     {
-      Message message = ERR_LDAPV2_SKIPPING_SEARCH_REFERENCE.
-          get(getConnectionID(), searchOperation.getOperationID(),
-              String.valueOf(searchReference));
+      Message message =
+          ERR_LDAPV2_SKIPPING_SEARCH_REFERENCE.get(getConnectionID(),
+              searchOperation.getOperationID(), String
+                  .valueOf(searchReference));
       logError(message);
       return false;
     }
 
     SearchResultReferenceProtocolOp protocolOp =
-         new SearchResultReferenceProtocolOp(searchReference);
+        new SearchResultReferenceProtocolOp(searchReference);
 
-    List<Control> referenceControls = searchReference.getControls();
-    ArrayList<LDAPControl> controls;
-    if ((referenceControls == null) || referenceControls.isEmpty())
-    {
-      controls = null;
-    }
-    else
-    {
-      controls = new ArrayList<LDAPControl>(referenceControls.size());
-      for (Control c : referenceControls)
-      {
-        controls.add(new LDAPControl(c));
-      }
-    }
-
-    sendLDAPMessage(securityProvider,
-                    new LDAPMessage(searchOperation.getMessageID(), protocolOp,
-                                    controls));
+    sendLDAPMessage(new LDAPMessage(searchOperation.getMessageID(),
+        protocolOp, searchReference.getControls()));
     return true;
   }
 
 
 
-
   /**
    * Sends the provided intermediate response message to the client.
    *
-   * @param  intermediateResponse  The intermediate response message to be sent.
-   *
-   * @return  <CODE>true</CODE> if processing on the associated operation should
-   *          continue, or <CODE>false</CODE> if not.
+   * @param intermediateResponse
+   *          The intermediate response message to be sent.
+   * @return <CODE>true</CODE> if processing on the associated operation
+   *         should continue, or <CODE>false</CODE> if not.
    */
+  @Override
   protected boolean sendIntermediateResponseMessage(
-                         IntermediateResponse intermediateResponse)
+      IntermediateResponse intermediateResponse)
   {
     IntermediateResponseProtocolOp protocolOp =
-         new IntermediateResponseProtocolOp(intermediateResponse.getOID(),
-                                            intermediateResponse.getValue());
+        new IntermediateResponseProtocolOp(intermediateResponse
+            .getOID(), intermediateResponse.getValue());
 
     Operation operation = intermediateResponse.getOperation();
 
-    List<Control> controls = intermediateResponse.getControls();
-    ArrayList<LDAPControl> ldapControls =
-         new ArrayList<LDAPControl>(controls.size());
-    for (Control c : controls)
-    {
-      ldapControls.add(new LDAPControl(c));
-    }
+    LDAPMessage message =
+        new LDAPMessage(operation.getMessageID(), protocolOp,
+            intermediateResponse.getControls());
+    sendLDAPMessage(message);
 
-
-    LDAPMessage message = new LDAPMessage(operation.getMessageID(), protocolOp,
-                                          ldapControls);
-    sendLDAPMessage(securityProvider, message);
-
-
-    // The only reason we shouldn't continue processing is if the connection is
-    // closed.
+    // The only reason we shouldn't continue processing is if the
+    // connection is closed.
     return connectionValid;
   }
 
@@ -885,95 +758,92 @@
   /**
    * Sends the provided LDAP message to the client.
    *
-   * @param  secProvider  The connection security provider to use to handle any
-   *                      necessary security translation.
-   * @param  message      The LDAP message to send to the client.
+   * @param message
+   *          The LDAP message to send to the client.
    */
-  public void sendLDAPMessage(ConnectionSecurityProvider secProvider,
-                              LDAPMessage message)
+  public void sendLDAPMessage(LDAPMessage message)
   {
-    ASN1Element messageElement = message.encode();
-
-    ByteBuffer messageBuffer = ByteBuffer.wrap(messageElement.encode());
-
-
-    // Make sure that we can only send one message at a time.  This locking will
-    // not have any impact on the ability to read requests from the client.
-    synchronized (transmitLock)
+    // Get the buffer used by this thread.
+    WriterBuffer writerBuffer = cachedBuffers.get();
+    if (writerBuffer == null)
     {
-      try
+      writerBuffer = new WriterBuffer();
+      // TODO SASLPhase2 maybe don't want to cache these
+      if (isSecure())
       {
-        try
+        int appBufSize = activeProvider.getAppBufSize();
+        writerBuffer.writer = ASN1.getWriter(saslChannel, appBufSize);
+      }
+      else
+        writerBuffer.writer = ASN1.getWriter(saslChannel, 4096);
+      cachedBuffers.set(writerBuffer);
+    }
+    try
+    {
+      // Make sure that we can only send one message at a time. This
+      // locking will not have any impact on the ability to read
+      // requests from the client.
+      synchronized (transmitLock)
+      {
+        message.write(writerBuffer.writer);
+        writerBuffer.writer.flush();
+        if(debugEnabled())
         {
-          int bytesWritten = messageBuffer.limit() - messageBuffer.position();
-          if (! secProvider.writeData(messageBuffer))
-          {
-            return;
-          }
+          TRACER.debugProtocolElement(DebugLogLevel.VERBOSE,
+              message.toString());
 
-          TRACER.debugProtocolElement(DebugLogLevel.VERBOSE, message);
-          TRACER.debugProtocolElement(DebugLogLevel.VERBOSE, messageElement);
-
-          messageBuffer.rewind();
-          if (debugEnabled())
-          {
-            TRACER.debugData(DebugLogLevel.VERBOSE, messageBuffer);
-          }
-
-          if (keepStats)
-          {
-            statTracker.updateMessageWritten(message, bytesWritten);
-          }
+          // TODO SASLPhase2 message buffer?
+          // TRACER.debugData(DebugLogLevel.VERBOSE, messageBuffer);
         }
-        catch (@Deprecated Exception e)
-        {
-          if (debugEnabled())
-          {
-            TRACER.debugCaught(DebugLogLevel.ERROR, e);
-          }
 
-          // We were unable to send the message due to some other internal
-          // problem.  Disconnect from the client and return.
-          disconnect(DisconnectReason.SERVER_ERROR, true, null);
-          return;
+        if (keepStats)
+        {
+          // TODO SASLPhase2 hard-coded for now, flush probably needs to
+          // return how many bytes were flushed.
+          statTracker.updateMessageWritten(message, 4096);
         }
       }
-      catch (Exception e)
+      // writerBuffer.buffer.clear();
+    }
+    catch (Exception e)
+    {
+      if (debugEnabled())
       {
-        if (debugEnabled())
-        {
-          TRACER.debugCaught(DebugLogLevel.ERROR, e);
-        }
-
-        // FIXME -- Log a message or something
-        disconnect(DisconnectReason.SERVER_ERROR, true, null);
-        return;
+        TRACER.debugCaught(DebugLogLevel.ERROR, e);
       }
+
+      // FIXME -- Log a message or something
+      disconnect(DisconnectReason.SERVER_ERROR, true, null);
+      return;
     }
   }
 
 
 
   /**
-   * Closes the connection to the client, optionally sending it a message
-   * indicating the reason for the closure.  Note that the ability to send a
-   * notice of disconnection may not be available for all protocols or under all
-   * circumstances.
+   * Closes the connection to the client, optionally sending it a
+   * message indicating the reason for the closure. Note that the
+   * ability to send a notice of disconnection may not be available for
+   * all protocols or under all circumstances.
    *
-   * @param  disconnectReason  The disconnect reason that provides the generic
-   *                           cause for the disconnect.
-   * @param  sendNotification  Indicates whether to try to provide notification
-   *                           to the client that the connection will be closed.
-   * @param  message           The message to include in the disconnect
-   *                           notification response.  It may be
-   *                           <CODE>null</CODE> if no message is to be sent.
+   * @param disconnectReason
+   *          The disconnect reason that provides the generic cause for
+   *          the disconnect.
+   * @param sendNotification
+   *          Indicates whether to try to provide notification to the
+   *          client that the connection will be closed.
+   * @param message
+   *          The message to include in the disconnect notification
+   *          response. It may be <CODE>null</CODE> if no message is to
+   *          be sent.
    */
+  @Override
   public void disconnect(DisconnectReason disconnectReason,
-                         boolean sendNotification,
-                         Message message)
+      boolean sendNotification, Message message)
   {
-    // Set a flag indicating that the connection is being terminated so that no
-    // new requests will be accepted.  Also cancel all operations in progress.
+    // Set a flag indicating that the connection is being terminated so
+    // that no new requests will be accepted. Also cancel all operations
+    // in progress.
     synchronized (opsInProgressLock)
     {
       // If we are already in the middle of a disconnect, then don't
@@ -986,7 +856,6 @@
       disconnectRequested = true;
     }
 
-
     if (keepStats)
     {
       statTracker.updateDisconnect();
@@ -997,26 +866,25 @@
       DirectoryServer.connectionClosed(this);
     }
 
-
     // Indicate that this connection is no longer valid.
     connectionValid = false;
 
-    if(message != null)
+    if (message != null)
     {
       MessageBuilder msgBuilder = new MessageBuilder();
       msgBuilder.append(disconnectReason.getClosureMessage());
       msgBuilder.append(": ");
       msgBuilder.append(message);
-      cancelAllOperations(new CancelRequest(true, msgBuilder.toMessage()));
+      cancelAllOperations(new CancelRequest(true, msgBuilder
+          .toMessage()));
     }
     else
     {
-      cancelAllOperations(new CancelRequest(true,
-          disconnectReason.getClosureMessage()));
+      cancelAllOperations(new CancelRequest(true, disconnectReason
+          .getClosureMessage()));
     }
     finalizeConnectionInternal();
 
-
     // If there is a write selector for this connection, then close it.
     Selector selector = writeSelector.get();
     if (selector != null)
@@ -1024,13 +892,16 @@
       try
       {
         selector.close();
-      } catch (Exception e) {}
+      }
+      catch (Exception e)
+      {
+      }
     }
 
-
-    // See if we should send a notification to the client.  If so, then
-    // construct and send a notice of disconnection unsolicited response.
-    // Note that we cannot send this notification to an LDAPv2 client.
+    // See if we should send a notification to the client. If so, then
+    // construct and send a notice of disconnection unsolicited
+    // response. Note that we cannot send this notification to an LDAPv2
+    // client.
     if (sendNotification && (ldapVersion != 2))
     {
       try
@@ -1038,70 +909,63 @@
         int resultCode;
         switch (disconnectReason)
         {
-          case PROTOCOL_ERROR:
-            resultCode = LDAPResultCode.PROTOCOL_ERROR;
-            break;
-          case SERVER_SHUTDOWN:
-            resultCode = LDAPResultCode.UNAVAILABLE;
-            break;
-          case SERVER_ERROR:
-            resultCode =
-                 DirectoryServer.getServerErrorResultCode().getIntValue();
-            break;
-          case ADMIN_LIMIT_EXCEEDED:
-          case IDLE_TIME_LIMIT_EXCEEDED:
-          case MAX_REQUEST_SIZE_EXCEEDED:
-          case IO_TIMEOUT:
-            resultCode = LDAPResultCode.ADMIN_LIMIT_EXCEEDED;
-            break;
-          case CONNECTION_REJECTED:
-            resultCode = LDAPResultCode.CONSTRAINT_VIOLATION;
-            break;
-          default:
-            resultCode = LDAPResultCode.OTHER;
-            break;
+        case PROTOCOL_ERROR:
+          resultCode = LDAPResultCode.PROTOCOL_ERROR;
+          break;
+        case SERVER_SHUTDOWN:
+          resultCode = LDAPResultCode.UNAVAILABLE;
+          break;
+        case SERVER_ERROR:
+          resultCode =
+              DirectoryServer.getServerErrorResultCode().getIntValue();
+          break;
+        case ADMIN_LIMIT_EXCEEDED:
+        case IDLE_TIME_LIMIT_EXCEEDED:
+        case MAX_REQUEST_SIZE_EXCEEDED:
+        case IO_TIMEOUT:
+          resultCode = LDAPResultCode.ADMIN_LIMIT_EXCEEDED;
+          break;
+        case CONNECTION_REJECTED:
+          resultCode = LDAPResultCode.CONSTRAINT_VIOLATION;
+          break;
+        default:
+          resultCode = LDAPResultCode.OTHER;
+          break;
         }
 
-
         Message errMsg;
         if (message == null)
         {
-          errMsg = INFO_LDAP_CLIENT_GENERIC_NOTICE_OF_DISCONNECTION.get();
+          errMsg =
+              INFO_LDAP_CLIENT_GENERIC_NOTICE_OF_DISCONNECTION.get();
         }
         else
         {
           errMsg = message;
         }
 
-
         ExtendedResponseProtocolOp notificationOp =
-             new ExtendedResponseProtocolOp(resultCode, errMsg, null, null,
-                                            OID_NOTICE_OF_DISCONNECTION, null);
-        byte[] messageBytes =
-                    new LDAPMessage(0, notificationOp, null).encode().encode();
-        ByteBuffer buffer = ByteBuffer.wrap(messageBytes);
-        try
-        {
-          securityProvider.writeData(buffer);
-        } catch (Exception e) {}
+            new ExtendedResponseProtocolOp(resultCode, errMsg, null,
+                null, OID_NOTICE_OF_DISCONNECTION, null);
+
+        sendLDAPMessage(new LDAPMessage(0, notificationOp, null));
       }
       catch (Exception e)
       {
-        // NYI -- Log a message indicating that we couldn't send the notice of
-        // disconnection.
+        // NYI -- Log a message indicating that we couldn't send the
+        // notice of disconnection.
       }
     }
 
-
     // Close the connection to the client.
     try
     {
-      securityProvider.disconnect(sendNotification);
+      asn1Reader.close();
     }
     catch (Exception e)
     {
-      // In general, we don't care about any exception that might be thrown
-      // here.
+      // In general, we don't care about any exception that might be
+      // thrown here.
       if (debugEnabled())
       {
         TRACER.debugCaught(DebugLogLevel.ERROR, e);
@@ -1114,29 +978,29 @@
     }
     catch (Exception e)
     {
-      // In general, we don't care about any exception that might be thrown
-      // here.
+      // In general, we don't care about any exception that might be
+      // thrown here.
       if (debugEnabled())
       {
         TRACER.debugCaught(DebugLogLevel.ERROR, e);
       }
     }
 
+    // Remove the thread local buffers.
+    cachedBuffers.remove();
 
     // NYI -- Deregister the client connection from any server components that
     // might know about it.
 
-
     // Log a disconnect message.
     logDisconnect(this, disconnectReason, message);
 
-
     try
     {
       PluginConfigManager pluginManager =
-           DirectoryServer.getPluginConfigManager();
+          DirectoryServer.getPluginConfigManager();
       pluginManager.invokePostDisconnectPlugins(this, disconnectReason,
-              message);
+          message);
     }
     catch (Exception e)
     {
@@ -1150,11 +1014,13 @@
 
 
   /**
-   * Retrieves the set of operations in progress for this client connection.
-   * This list must not be altered by any caller.
+   * Retrieves the set of operations in progress for this client
+   * connection. This list must not be altered by any caller.
    *
-   * @return  The set of operations in progress for this client connection.
+   * @return The set of operations in progress for this client
+   *         connection.
    */
+  @Override
   public Collection<Operation> getOperationsInProgress()
   {
     return operationsInProgress.values();
@@ -1165,11 +1031,12 @@
   /**
    * Retrieves the operation in progress with the specified message ID.
    *
-   * @param  messageID  The message ID for the operation to retrieve.
-   *
-   * @return  The operation in progress with the specified message ID, or
-   *          <CODE>null</CODE> if no such operation could be found.
+   * @param messageID
+   *          The message ID for the operation to retrieve.
+   * @return The operation in progress with the specified message ID, or
+   *         <CODE>null</CODE> if no such operation could be found.
    */
+  @Override
   public Operation getOperationInProgress(int messageID)
   {
     return operationsInProgress.get(messageID);
@@ -1178,56 +1045,59 @@
 
 
   /**
-   * Adds the provided operation to the set of operations in progress for this
-   * client connection.
+   * Adds the provided operation to the set of operations in progress
+   * for this client connection.
    *
-   * @param  operation  The operation to add to the set of operations in
-   *                    progress for this client connection.
-   *
-   * @throws  DirectoryException  If the operation is not added for some reason
-   *                              (e.g., the client already has reached the
-   *                              maximum allowed concurrent requests).
+   * @param operation
+   *          The operation to add to the set of operations in progress
+   *          for this client connection.
+   * @throws DirectoryException
+   *           If the operation is not added for some reason (e.g., the
+   *           client already has reached the maximum allowed concurrent
+   *           requests).
    */
   public void addOperationInProgress(AbstractOperation operation)
-         throws DirectoryException
+      throws DirectoryException
   {
     int messageID = operation.getMessageID();
 
-    // We need to grab a lock to ensure that no one else can add operations to
-    // the queue while we are performing some preliminary checks.
+    // We need to grab a lock to ensure that no one else can add
+    // operations to the queue while we are performing some preliminary
+    // checks.
     synchronized (opsInProgressLock)
     {
       try
       {
-        // If we're already in the process of disconnecting the client, then
-        // reject the operation.
+        // If we're already in the process of disconnecting the client,
+        // then reject the operation.
         if (disconnectRequested)
         {
-          Message message = WARN_LDAP_CLIENT_DISCONNECT_IN_PROGRESS.get();
+          Message message =
+              WARN_LDAP_CLIENT_DISCONNECT_IN_PROGRESS.get();
           throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM,
-                                       message);
+              message);
         }
 
-
-        // See if there is already an operation in progress with the same
-        // message ID.  If so, then we can't allow it.
+        // See if there is already an operation in progress with the
+        // same message ID. If so, then we can't allow it.
         Operation op = operationsInProgress.get(messageID);
         if (op != null)
         {
           Message message =
-               WARN_LDAP_CLIENT_DUPLICATE_MESSAGE_ID.get(messageID);
-          throw new DirectoryException(ResultCode.PROTOCOL_ERROR, message);
+              WARN_LDAP_CLIENT_DUPLICATE_MESSAGE_ID.get(messageID);
+          throw new DirectoryException(ResultCode.PROTOCOL_ERROR,
+              message);
         }
 
-
-        // Add the operation to the list of operations in progress for this
-        // connection.
+        // Add the operation to the list of operations in progress for
+        // this connection.
         operationsInProgress.put(messageID, operation);
 
-
         // Try to add the operation to the work queue,
-        // or run it synchronously (typically for the administration connector)
-        connectionHandler.getQueueingStrategy().enqueueRequest(operation);
+        // or run it synchronously (typically for the administration
+        // connector)
+        connectionHandler.getQueueingStrategy().enqueueRequest(
+            operation);
       }
       catch (DirectoryException de)
       {
@@ -1250,8 +1120,8 @@
 
         Message message =
             WARN_LDAP_CLIENT_CANNOT_ENQUEUE.get(getExceptionMessage(e));
-        throw new DirectoryException(DirectoryServer.getServerErrorResultCode(),
-                                     message, e);
+        throw new DirectoryException(DirectoryServer
+            .getServerErrorResultCode(), message, e);
       }
     }
   }
@@ -1259,16 +1129,19 @@
 
 
   /**
-   * Removes the provided operation from the set of operations in progress for
-   * this client connection.  Note that this does not make any attempt to
-   * cancel any processing that may already be in progress for the operation.
+   * Removes the provided operation from the set of operations in
+   * progress for this client connection. Note that this does not make
+   * any attempt to cancel any processing that may already be in
+   * progress for the operation.
    *
-   * @param  messageID  The message ID of the operation to remove from the set
-   *                    of operations in progress.
-   *
-   * @return  <CODE>true</CODE> if the operation was found and removed from the
-   *          set of operations in progress, or <CODE>false</CODE> if not.
+   * @param messageID
+   *          The message ID of the operation to remove from the set of
+   *          operations in progress.
+   * @return <CODE>true</CODE> if the operation was found and removed
+   *         from the set of operations in progress, or
+   *         <CODE>false</CODE> if not.
    */
+  @Override
   public boolean removeOperationInProgress(int messageID)
   {
     Operation operation = operationsInProgress.remove(messageID);
@@ -1288,15 +1161,17 @@
   /**
    * Attempts to cancel the specified operation.
    *
-   * @param  messageID      The message ID of the operation to cancel.
-   * @param  cancelRequest  An object providing additional information about how
-   *                        the cancel should be processed.
-   *
-   * @return  A cancel result that either indicates that the cancel was
-   *          successful or provides a reason that it was not.
+   * @param messageID
+   *          The message ID of the operation to cancel.
+   * @param cancelRequest
+   *          An object providing additional information about how the
+   *          cancel should be processed.
+   * @return A cancel result that either indicates that the cancel was
+   *         successful or provides a reason that it was not.
    */
+  @Override
   public CancelResult cancelOperation(int messageID,
-                                      CancelRequest cancelRequest)
+      CancelRequest cancelRequest)
   {
     Operation op = operationsInProgress.get(messageID);
     if (op == null)
@@ -1331,9 +1206,11 @@
   /**
    * Attempts to cancel all operations in progress on this connection.
    *
-   * @param  cancelRequest  An object providing additional information about how
-   *                        the cancel should be processed.
+   * @param cancelRequest
+   *          An object providing additional information about how the
+   *          cancel should be processed.
    */
+  @Override
   public void cancelAllOperations(CancelRequest cancelRequest)
   {
     // Make sure that no one can add any new operations.
@@ -1362,15 +1239,14 @@
           }
         }
 
-        if (! (operationsInProgress.isEmpty() &&
-               getPersistentSearches().isEmpty()))
+        if (!(operationsInProgress.isEmpty() && getPersistentSearches()
+            .isEmpty()))
         {
           lastCompletionTime.set(TimeThread.getTime());
         }
 
         operationsInProgress.clear();
 
-
         for (PersistentSearch persistentSearch : getPersistentSearches())
         {
           persistentSearch.cancel();
@@ -1389,16 +1265,19 @@
 
 
   /**
-   * Attempts to cancel all operations in progress on this connection except the
-   * operation with the specified message ID.
+   * Attempts to cancel all operations in progress on this connection
+   * except the operation with the specified message ID.
    *
-   * @param  cancelRequest  An object providing additional information about how
-   *                        the cancel should be processed.
-   * @param  messageID      The message ID of the operation that should not be
-   *                        canceled.
+   * @param cancelRequest
+   *          An object providing additional information about how the
+   *          cancel should be processed.
+   * @param messageID
+   *          The message ID of the operation that should not be
+   *          canceled.
    */
+  @Override
   public void cancelAllOperationsExcept(CancelRequest cancelRequest,
-                                        int messageID)
+      int messageID)
   {
     // Make sure that no one can add any new operations.
     synchronized (opsInProgressLock)
@@ -1438,7 +1317,6 @@
           lastCompletionTime.set(TimeThread.getTime());
         }
 
-
         for (PersistentSearch persistentSearch : getPersistentSearches())
         {
           if (persistentSearch.getMessageID() == messageID)
@@ -1474,7 +1352,7 @@
       try
       {
         selector = Selector.open();
-        if (! writeSelector.compareAndSet(null, selector))
+        if (!writeSelector.compareAndSet(null, selector))
         {
           selector.close();
           selector = writeSelector.get();
@@ -1506,308 +1384,109 @@
 
 
   /**
-   * Returns the total number of operations initiated on this connection.
+   * Returns the total number of operations initiated on this
+   * connection.
    *
    * @return the total number of operations on this connection
    */
-  public long getNumberOfOperations() {
+  @Override
+  public long getNumberOfOperations()
+  {
     long tmpNumberOfOperations;
-    synchronized (operationsPerformedLock) {
+    synchronized (operationsPerformedLock)
+    {
       tmpNumberOfOperations = operationsPerformed;
     }
     return tmpNumberOfOperations;
   }
 
 
+
   /**
-   * Process the information contained in the provided byte buffer as an ASN.1
-   * element.  It may take several calls to this method in order to get all the
-   * information necessary to decode a single ASN.1 element, but it may also be
-   * possible that there are multiple elements (or at least fragments of
-   * multiple elements) in a single buffer.  This will fully process whatever
-   * the client provided and set up the appropriate state information to make it
-   * possible to pick up in the right place the next time around.
+   * Process data read.
    *
-   * @param  buffer  The buffer containing the data to be processed.  It must be
-   *                 ready for reading (i.e., it should have been flipped by the
-   *                 caller), and the data provided must be unencrypted (e.g.,
-   *                 if the client is communicating over SSL, then the
-   *                 decryption should happen before calling this method).
-   *
-   * @return  <CODE>true</CODE> if all the data in the provided buffer was
-   *          processed and the client connection can remain established, or
-   *          <CODE>false</CODE> if a decoding error occurred and requests from
-   *          this client should no longer be processed.  Note that if this
-   *          method does return <CODE>false</CODE>, then it must have already
-   *          disconnected the client, and upon returning the request handler
-   *          should remove it from the associated selector.
+   * @return {@code true} if this connection is still valid.
    */
-  public boolean processDataRead(ByteBuffer buffer)
+  public boolean processDataRead()
   {
-    if (debugEnabled())
+    if (this.saslPendingProvider != null)
     {
-      TRACER.debugData(DebugLogLevel.VERBOSE, buffer);
+      enableSASL();
     }
-
-
-    int bytesAvailable = buffer.limit() - buffer.position();
-
-    if (keepStats)
+    while (true)
     {
-      statTracker.updateBytesRead(bytesAvailable);
-    }
-
-    while (bytesAvailable > 0)
-    {
-      switch (elementReadState)
+      try
       {
-        case ELEMENT_READ_STATE_NEED_TYPE:
-          // Read just the type and then loop again to see if there is more.
-          elementType = buffer.get();
-          bytesAvailable--;
-          elementReadState = ELEMENT_READ_STATE_NEED_FIRST_LENGTH_BYTE;
-          continue;
-
-
-        case ELEMENT_READ_STATE_NEED_FIRST_LENGTH_BYTE:
-          // Get the first length byte and see if it is a single-byte or
-          // multi-byte length.
-          byte firstLengthByte = buffer.get();
-          bytesAvailable--;
-          elementLengthBytesNeeded = (firstLengthByte & 0x7F);
-          if (elementLengthBytesNeeded == firstLengthByte)
-          {
-            elementLength = firstLengthByte;
-
-            // If the length is zero, then it cannot be a valid LDAP message.
-            if (elementLength == 0)
-            {
-              disconnect(DisconnectReason.PROTOCOL_ERROR, true,
-                         ERR_LDAP_CLIENT_DECODE_ZERO_BYTE_VALUE.get());
-              return false;
-            }
-
-            // Make sure that the element is not larger than the maximum allowed
-            // message size.
-            if ((connectionHandler.getMaxRequestSize() > 0) &&
-                (elementLength > connectionHandler.getMaxRequestSize()))
-            {
-              Message m = ERR_LDAP_CLIENT_DECODE_MAX_REQUEST_SIZE_EXCEEDED.get(
-                elementLength, connectionHandler.getMaxRequestSize());
-              disconnect(DisconnectReason.MAX_REQUEST_SIZE_EXCEEDED, true, m);
-              return false;
-            }
-
-            elementValue            = new byte[elementLength];
-            elementValueBytesRead   = 0;
-            elementValueBytesNeeded = elementLength;
-            elementReadState        = ELEMENT_READ_STATE_NEED_VALUE_BYTES;
-            continue;
-          }
-          else
-          {
-            if (elementLengthBytesNeeded > 4)
-            {
-              // We cannot handle multi-byte lengths in which more than four
-              // bytes are used to encode the length.
-              Message m = ERR_LDAP_CLIENT_DECODE_INVALID_MULTIBYTE_LENGTH.get(
-                elementLengthBytesNeeded);
-              disconnect(DisconnectReason.PROTOCOL_ERROR, true, m);
-              return false;
-            }
-
-            elementLength = 0x00;
-            if (elementLengthBytesNeeded <= bytesAvailable)
-            {
-              // We can read the entire length, so do it.
-              while (elementLengthBytesNeeded > 0)
-              {
-                elementLength = (elementLength << 8) | (buffer.get() & 0xFF);
-                bytesAvailable--;
-                elementLengthBytesNeeded--;
-              }
-
-              // If the length is zero, then it cannot be a valid LDAP message.
-              if (elementLength == 0)
-              {
-                disconnect(DisconnectReason.PROTOCOL_ERROR, true,
-                           ERR_LDAP_CLIENT_DECODE_ZERO_BYTE_VALUE.get());
-                return false;
-              }
-
-              // Make sure that the element is not larger than the maximum
-              // allowed message size.
-              if ((connectionHandler.getMaxRequestSize() > 0) &&
-                  (elementLength > connectionHandler.getMaxRequestSize()))
-              {
-                disconnect(DisconnectReason.MAX_REQUEST_SIZE_EXCEEDED, true,
-                           ERR_LDAP_CLIENT_DECODE_MAX_REQUEST_SIZE_EXCEEDED.get(
-                                   elementLength,
-                                   connectionHandler.getMaxRequestSize()));
-                return false;
-              }
-
-              elementValue            = new byte[elementLength];
-              elementValueBytesRead   = 0;
-              elementValueBytesNeeded = elementLength;
-              elementReadState        = ELEMENT_READ_STATE_NEED_VALUE_BYTES;
-              continue;
-            }
-            else
-            {
-              // We can't read the entire length, so just read what is
-              // available.
-              while (bytesAvailable > 0)
-              {
-                elementLength = (elementLength << 8) | (buffer.get() & 0xFF);
-                bytesAvailable--;
-                elementLengthBytesNeeded--;
-              }
-
-              return true;
-            }
-          }
-
-
-        case ELEMENT_READ_STATE_NEED_ADDITIONAL_LENGTH_BYTES:
-          if (bytesAvailable >= elementLengthBytesNeeded)
-          {
-            // We have enough data available to be able to read the entire
-            // length.  Do so.
-            while (elementLengthBytesNeeded > 0)
-            {
-              elementLength = (elementLength << 8) | (buffer.get() & 0xFF);
-              bytesAvailable--;
-              elementLengthBytesNeeded--;
-            }
-
-            // If the length is zero, then it cannot be a valid LDAP message.
-            if (elementLength == 0)
-            {
-              disconnect(DisconnectReason.PROTOCOL_ERROR, true,
-                         ERR_LDAP_CLIENT_DECODE_ZERO_BYTE_VALUE.get());
-              return false;
-            }
-
-            // Make sure that the element is not larger than the maximum allowed
-            // message size.
-            if ((connectionHandler.getMaxRequestSize() > 0) &&
-                (elementLength > connectionHandler.getMaxRequestSize()))
-            {
-              disconnect(DisconnectReason.MAX_REQUEST_SIZE_EXCEEDED, true,
-                         ERR_LDAP_CLIENT_DECODE_MAX_REQUEST_SIZE_EXCEEDED.get(
-                                 elementLength,
-                                 connectionHandler.getMaxRequestSize()));
-              return false;
-            }
-
-            elementValue            = new byte[elementLength];
-            elementValueBytesRead   = 0;
-            elementValueBytesNeeded = elementLength;
-            elementReadState        = ELEMENT_READ_STATE_NEED_VALUE_BYTES;
-            continue;
-          }
-          else
-          {
-            // We still don't have enough data to complete the length, so just
-            // read as much as possible.
-            while (bytesAvailable > 0)
-            {
-              elementLength = (elementLength << 8) | (buffer.get() & 0xFF);
-              bytesAvailable--;
-              elementLengthBytesNeeded--;
-            }
-
-            return true;
-          }
-
-
-        case ELEMENT_READ_STATE_NEED_VALUE_BYTES:
-          if (bytesAvailable >= elementValueBytesNeeded)
-          {
-            // We have enough data available to fully read the value.  Finish
-            // reading the information and convert it to an ASN.1 element.  Then
-            // decode that as an LDAP message.
-            buffer.get(elementValue, elementValueBytesRead,
-                       elementValueBytesNeeded);
-            elementValueBytesRead += elementValueBytesNeeded;
-            bytesAvailable -= elementValueBytesNeeded;
-            elementReadState = ELEMENT_READ_STATE_NEED_TYPE;
-
-            ASN1Sequence requestSequence;
-            try
-            {
-              requestSequence = ASN1Sequence.decodeAsSequence(elementType,
-                                                              elementValue);
-              TRACER.debugProtocolElement(DebugLogLevel.VERBOSE,
-                                          requestSequence);
-            }
-            catch (Exception e)
-            {
-              if (debugEnabled())
-              {
-                TRACER.debugCaught(DebugLogLevel.ERROR, e);
-              }
-              Message m = ERR_LDAP_CLIENT_DECODE_ASN1_FAILED.get(
-                String.valueOf(e));
-              disconnect(DisconnectReason.PROTOCOL_ERROR, true, m);
-              return false;
-            }
-
-            LDAPMessage requestMessage;
-            try
-            {
-              requestMessage = LDAPMessage.decode(requestSequence);
-              TRACER.debugProtocolElement(DebugLogLevel.VERBOSE,
-                                          requestMessage);
-            }
-            catch (Exception e)
-            {
-              if (debugEnabled())
-              {
-                TRACER.debugCaught(DebugLogLevel.ERROR, e);
-              }
-              Message m = ERR_LDAP_CLIENT_DECODE_LDAP_MESSAGE_FAILED.get(
-                String.valueOf(e));
-              disconnect(DisconnectReason.PROTOCOL_ERROR, true, m);
-              return false;
-            }
-
-            if (processLDAPMessage(requestMessage))
-            {
-              continue;
-            }
-            else
-            {
-              return false;
-            }
-          }
-          else
-          {
-            // We can't read all the value, so just read as much as we have
-            // available and pick it up again the next time around.
-            buffer.get(elementValue, elementValueBytesRead, bytesAvailable);
-            elementValueBytesRead   += bytesAvailable;
-            elementValueBytesNeeded -= bytesAvailable;
-            return true;
-          }
-
-
-        default:
-          // This should never happen.  There is an invalid internal read state.
-          // The only recourse that we have is to log a message and disconnect
-          // the client.
-          Message message =
-              ERR_LDAP_CLIENT_INVALID_DECODE_STATE.get(elementReadState);
-          logError(message);
-          disconnect(DisconnectReason.SERVER_ERROR, true, message);
+        int result = asn1Reader.processChannelData();
+        if (result < 0)
+        {
+          // The connection has been closed by the client. Disconnect
+          // and return.
+          disconnect(DisconnectReason.CLIENT_DISCONNECT, false, null);
           return false;
+        }
+        if (result == 0)
+        {
+          // We have read all the data that there is to read right now
+          // (or there wasn't any in the first place). Just return and
+          // wait for future notification.
+          return true;
+        }
+        else
+        {
+          // Decode all complete elements from the last read
+          while (asn1Reader.elementAvailable())
+          {
+            processLDAPMessage(LDAPReader.readMessage(asn1Reader));
+          }
+        }
+      }
+      catch (Exception e)
+      {
+        if (debugEnabled())
+        {
+          TRACER.debugCaught(DebugLogLevel.ERROR, e);
+        }
+        Message m =
+            ERR_LDAP_CLIENT_DECODE_LDAP_MESSAGE_FAILED.get(String
+                .valueOf(e));
+        disconnect(DisconnectReason.PROTOCOL_ERROR, true, m);
+        return false;
       }
     }
+  }
 
 
-    // If we've gotten here, then all of the data must have been processed
-    // properly so we can return true.
+
+  /**
+   * Process the information contained in the provided byte buffer as an
+   * ASN.1 element. It may take several calls to this method in order to
+   * get all the information necessary to decode a single ASN.1 element,
+   * but it may also be possible that there are multiple elements (or at
+   * least fragments of multiple elements) in a single buffer. This will
+   * fully process whatever the client provided and set up the
+   * appropriate state information to make it possible to pick up in the
+   * right place the next time around.
+   *
+   * @param buffer
+   *          The buffer containing the data to be processed. It must be
+   *          ready for reading (i.e., it should have been flipped by
+   *          the caller), and the data provided must be unencrypted
+   *          (e.g., if the client is communicating over SSL, then the
+   *          decryption should happen before calling this method).
+   * @return <CODE>true</CODE> if all the data in the provided buffer
+   *         was processed and the client connection can remain
+   *         established, or <CODE>false</CODE> if a decoding error
+   *         occurred and requests from this client should no longer be
+   *         processed. Note that if this method does return
+   *         <CODE>false</CODE>, then it must have already disconnected
+   *         the client, and upon returning the request handler should
+   *         remove it from the associated selector.
+   */
+  @Override
+  public boolean processDataRead(ByteBuffer buffer)
+  {
+    // this is no longer used.
     return true;
   }
 
@@ -1815,16 +1494,16 @@
 
   /**
    * Processes the provided LDAP message read from the client and takes
-   * whatever action is appropriate.  For most requests, this will include
-   * placing the operation in the work queue.  Certain requests (in particular,
-   * abandons and unbinds) will be processed directly.
+   * whatever action is appropriate. For most requests, this will
+   * include placing the operation in the work queue. Certain requests
+   * (in particular, abandons and unbinds) will be processed directly.
    *
-   * @param  message  The LDAP message to process.
-   *
-   * @return  <CODE>true</CODE> if the appropriate action was taken for the
-   *          request, or <CODE>false</CODE> if there was a fatal error and
-   *          the client has been disconnected as a result, or if the client
-   *          unbound from the server.
+   * @param message
+   *          The LDAP message to process.
+   * @return <CODE>true</CODE> if the appropriate action was taken for
+   *         the request, or <CODE>false</CODE> if there was a fatal
+   *         error and the client has been disconnected as a result, or
+   *         if the client unbound from the server.
    */
   private boolean processLDAPMessage(LDAPMessage message)
   {
@@ -1833,126 +1512,124 @@
       statTracker.updateMessageRead(message);
       this.getNetworkGroup().updateMessageRead(message);
     }
-    synchronized (operationsPerformedLock) {
+    synchronized (operationsPerformedLock)
+    {
       operationsPerformed++;
     }
 
-    ArrayList<Control> opControls;
-    ArrayList<LDAPControl> ldapControls = message.getControls();
-    if ((ldapControls == null) || ldapControls.isEmpty())
-    {
-      opControls = null;
-    }
-    else
-    {
-      opControls = new ArrayList<Control>(ldapControls.size());
-      for (LDAPControl c : ldapControls)
-      {
-        opControls.add(c.getControl());
-      }
-    }
+    List<Control> opControls = message.getControls();
 
+    // FIXME -- See if there is a bind in progress. If so, then deny
+    // most kinds of operations.
 
-    // FIXME -- See if there is a bind in progress.  If so, then deny most
-    // kinds of operations.
-
-
-    // Figure out what type of operation we're dealing with based on the LDAP
-    // message.  Abandon and unbind requests will be processed here.  All other
-    // types of requests will be encapsulated into operations and put into the
-    // work queue to be picked up by a worker thread.  Any other kinds of
-    // LDAP messages (e.g., response messages) are illegal and will result in
-    // the connection being terminated.
+    // Figure out what type of operation we're dealing with based on the
+    // LDAP message. Abandon and unbind requests will be processed here.
+    // All other types of requests will be encapsulated into operations
+    // and append into the work queue to be picked up by a worker
+    // thread. Any other kinds of LDAP messages (e.g., response
+    // messages) are illegal and will result in the connection being
+    // terminated.
     try
     {
       boolean result;
       switch (message.getProtocolOpType())
       {
-        case OP_TYPE_ABANDON_REQUEST:
-          if (keepStats) this.abandonMonitor.start();
-          result=processAbandonRequest(message, opControls);
-          if (keepStats) {
-              this.abandonMonitor.stop();
-              this.abandonMonitor.updateMonitorProvider(statTracker);
-          }
-          return result;
-        case OP_TYPE_ADD_REQUEST:
-          if (keepStats) this.addMonitor.start();
-          result=processAddRequest(message, opControls);
-          if (keepStats) {
-              this.addMonitor.stop();
-              this.addMonitor.updateMonitorProvider(statTracker);
-          }
-          return result;
-        case OP_TYPE_BIND_REQUEST:
-          if (keepStats) this.bindMonitor.start();
-          result=processBindRequest(message, opControls);
-          if (keepStats) {
-              this.bindMonitor.stop();
-              this.bindMonitor.updateMonitorProvider(statTracker);
-          }
-          return result;
-        case OP_TYPE_COMPARE_REQUEST:
-          if (keepStats) this.compareMonitor.start();
-          result=processCompareRequest(message, opControls);
-          if (keepStats) {
-              this.compareMonitor.stop();
-              this.compareMonitor.updateMonitorProvider(statTracker);
-          }
-          return result;
-        case OP_TYPE_DELETE_REQUEST:
-          if (keepStats) this.delMonitor.start();
-          result=processDeleteRequest(message, opControls);
-          if (keepStats) {
-              this.delMonitor.stop();
-              this.delMonitor.updateMonitorProvider(statTracker);
-          }
-          return result;
-        case OP_TYPE_EXTENDED_REQUEST:
-          if (keepStats) this.extendedMonitor.start();
-          result=processExtendedRequest(message, opControls);
-          if (keepStats) {
-              this.extendedMonitor.stop();
-              this.extendedMonitor.updateMonitorProvider(statTracker);
-          }
-          return result;
-        case OP_TYPE_MODIFY_REQUEST:
-          if (keepStats) this.modMonitor.start();
-          result=processModifyRequest(message, opControls);
-          if (keepStats) {
-              this.modMonitor.stop();
-              this.modMonitor.updateMonitorProvider(statTracker);
-          }
-          return result;
-        case OP_TYPE_MODIFY_DN_REQUEST:
-          if (keepStats) this.moddnMonitor.start();
-          result=processModifyDNRequest(message, opControls);
-          if (keepStats) {
-              this.moddnMonitor.stop();
-              this.moddnMonitor.updateMonitorProvider(statTracker);
-          }
-          return result;
-        case OP_TYPE_SEARCH_REQUEST:
-          if (keepStats) this.searchMonitor.start();
-          result=processSearchRequest(message, opControls);
-          if (keepStats) {
-              this.searchMonitor.stop();
-              this.searchMonitor.updateMonitorProvider(statTracker);
-          }
-          return result;
-        case OP_TYPE_UNBIND_REQUEST:
-          if (keepStats) this.unbindMonitor.start();
-          result=processUnbindRequest(message, opControls);
-          if (keepStats) {
-              this.unbindMonitor.stop();
-              this.unbindMonitor.updateMonitorProvider(statTracker);
-          }
-          return result;
-        default:
-          Message msg = ERR_LDAP_DISCONNECT_DUE_TO_INVALID_REQUEST_TYPE.get(
-                  message.getProtocolOpName(), message.getMessageID());
-          disconnect(DisconnectReason.PROTOCOL_ERROR, true, msg);
-          return false;
+      case OP_TYPE_ABANDON_REQUEST:
+        if (keepStats) this.abandonMonitor.start();
+        result = processAbandonRequest(message, opControls);
+        if (keepStats)
+        {
+          this.abandonMonitor.stop();
+          this.abandonMonitor.updateMonitorProvider(statTracker);
+        }
+        return result;
+      case OP_TYPE_ADD_REQUEST:
+        if (keepStats) this.addMonitor.start();
+        result = processAddRequest(message, opControls);
+        if (keepStats)
+        {
+          this.addMonitor.stop();
+          this.addMonitor.updateMonitorProvider(statTracker);
+        }
+        return result;
+      case OP_TYPE_BIND_REQUEST:
+        if (keepStats) this.bindMonitor.start();
+        result = processBindRequest(message, opControls);
+        if (keepStats)
+        {
+          this.bindMonitor.stop();
+          this.bindMonitor.updateMonitorProvider(statTracker);
+        }
+        return result;
+      case OP_TYPE_COMPARE_REQUEST:
+        if (keepStats) this.compareMonitor.start();
+        result = processCompareRequest(message, opControls);
+        if (keepStats)
+        {
+          this.compareMonitor.stop();
+          this.compareMonitor.updateMonitorProvider(statTracker);
+        }
+        return result;
+      case OP_TYPE_DELETE_REQUEST:
+        if (keepStats) this.delMonitor.start();
+        result = processDeleteRequest(message, opControls);
+        if (keepStats)
+        {
+          this.delMonitor.stop();
+          this.delMonitor.updateMonitorProvider(statTracker);
+        }
+        return result;
+      case OP_TYPE_EXTENDED_REQUEST:
+        if (keepStats) this.extendedMonitor.start();
+        result = processExtendedRequest(message, opControls);
+        if (keepStats)
+        {
+          this.extendedMonitor.stop();
+          this.extendedMonitor.updateMonitorProvider(statTracker);
+        }
+        return result;
+      case OP_TYPE_MODIFY_REQUEST:
+        if (keepStats) this.modMonitor.start();
+        result = processModifyRequest(message, opControls);
+        if (keepStats)
+        {
+          this.modMonitor.stop();
+          this.modMonitor.updateMonitorProvider(statTracker);
+        }
+        return result;
+      case OP_TYPE_MODIFY_DN_REQUEST:
+        if (keepStats) this.moddnMonitor.start();
+        result = processModifyDNRequest(message, opControls);
+        if (keepStats)
+        {
+          this.moddnMonitor.stop();
+          this.moddnMonitor.updateMonitorProvider(statTracker);
+        }
+        return result;
+      case OP_TYPE_SEARCH_REQUEST:
+        if (keepStats) this.searchMonitor.start();
+        result = processSearchRequest(message, opControls);
+        if (keepStats)
+        {
+          this.searchMonitor.stop();
+          this.searchMonitor.updateMonitorProvider(statTracker);
+        }
+        return result;
+      case OP_TYPE_UNBIND_REQUEST:
+        if (keepStats) this.unbindMonitor.start();
+        result = processUnbindRequest(message, opControls);
+        if (keepStats)
+        {
+          this.unbindMonitor.stop();
+          this.unbindMonitor.updateMonitorProvider(statTracker);
+        }
+        return result;
+      default:
+        Message msg =
+            ERR_LDAP_DISCONNECT_DUE_TO_INVALID_REQUEST_TYPE.get(message
+                .getProtocolOpName(), message.getMessageID());
+        disconnect(DisconnectReason.PROTOCOL_ERROR, true, msg);
+        return false;
       }
     }
     catch (Exception e)
@@ -1962,9 +1639,10 @@
         TRACER.debugCaught(DebugLogLevel.ERROR, e);
       }
 
-      Message msg = ERR_LDAP_DISCONNECT_DUE_TO_PROCESSING_FAILURE.get(
-              message.getProtocolOpName(),
-              message.getMessageID(), String.valueOf(e));
+      Message msg =
+          ERR_LDAP_DISCONNECT_DUE_TO_PROCESSING_FAILURE.get(message
+              .getProtocolOpName(), message.getMessageID(), String
+              .valueOf(e));
       disconnect(DisconnectReason.SERVER_ERROR, true, msg);
       return false;
     }
@@ -1975,24 +1653,26 @@
   /**
    * Processes the provided LDAP message as an abandon request.
    *
-   * @param  message   The LDAP message containing the abandon request to
-   *                   process.
-   * @param  controls  The set of pre-decoded request controls contained in the
-   *                   message.
-   *
-   * @return  <CODE>true</CODE> if the request was processed successfully, or
-   *          <CODE>false</CODE> if not and the connection has been closed as a
-   *          result (it is the responsibility of this method to close the
-   *          connection).
+   * @param message
+   *          The LDAP message containing the abandon request to
+   *          process.
+   * @param controls
+   *          The set of pre-decoded request controls contained in the
+   *          message.
+   * @return <CODE>true</CODE> if the request was processed
+   *         successfully, or <CODE>false</CODE> if not and the
+   *         connection has been closed as a result (it is the
+   *         responsibility of this method to close the connection).
    */
   private boolean processAbandonRequest(LDAPMessage message,
-                                        ArrayList<Control> controls)
+      List<Control> controls)
   {
-    AbandonRequestProtocolOp protocolOp = message.getAbandonRequestProtocolOp();
+    AbandonRequestProtocolOp protocolOp =
+        message.getAbandonRequestProtocolOp();
     AbandonOperationBasis abandonOp =
-         new AbandonOperationBasis(this, nextOperationID.getAndIncrement(),
-                              message.getMessageID(), controls,
-                              protocolOp.getIDToAbandon());
+        new AbandonOperationBasis(this, nextOperationID
+            .getAndIncrement(), message.getMessageID(), controls,
+            protocolOp.getIDToAbandon());
 
     abandonOp.run();
     if (keepStats && (abandonOp.getResultCode() == ResultCode.CANCELED))
@@ -2008,37 +1688,39 @@
   /**
    * Processes the provided LDAP message as an add request.
    *
-   * @param  message   The LDAP message containing the add request to process.
-   * @param  controls  The set of pre-decoded request controls contained in the
-   *                   message.
-   *
-   * @return  <CODE>true</CODE> if the request was processed successfully, or
-   *          <CODE>false</CODE> if not and the connection has been closed as a
-   *          result (it is the responsibility of this method to close the
-   *          connection).
+   * @param message
+   *          The LDAP message containing the add request to process.
+   * @param controls
+   *          The set of pre-decoded request controls contained in the
+   *          message.
+   * @return <CODE>true</CODE> if the request was processed
+   *         successfully, or <CODE>false</CODE> if not and the
+   *         connection has been closed as a result (it is the
+   *         responsibility of this method to close the connection).
    */
   private boolean processAddRequest(LDAPMessage message,
-                                    ArrayList<Control> controls)
+      List<Control> controls)
   {
-    if ((ldapVersion == 2) && (controls != null) && (! controls.isEmpty()))
+    if ((ldapVersion == 2) && (controls != null)
+        && (!controls.isEmpty()))
     {
       // LDAPv2 clients aren't allowed to send controls.
       AddResponseProtocolOp responseOp =
-           new AddResponseProtocolOp(LDAPResultCode.PROTOCOL_ERROR,
-                    ERR_LDAPV2_CONTROLS_NOT_ALLOWED.get());
-      sendLDAPMessage(securityProvider,
-                      new LDAPMessage(message.getMessageID(), responseOp));
+          new AddResponseProtocolOp(LDAPResultCode.PROTOCOL_ERROR,
+              ERR_LDAPV2_CONTROLS_NOT_ALLOWED.get());
+      sendLDAPMessage(new LDAPMessage(message.getMessageID(),
+          responseOp));
       disconnect(DisconnectReason.PROTOCOL_ERROR, false,
-                 ERR_LDAPV2_CONTROLS_NOT_ALLOWED.get());
+          ERR_LDAPV2_CONTROLS_NOT_ALLOWED.get());
       return false;
     }
 
     // Create the add operation and add it into the work queue.
     AddRequestProtocolOp protocolOp = message.getAddRequestProtocolOp();
     AddOperationBasis addOp =
-         new AddOperationBasis(this, nextOperationID.getAndIncrement(),
-                          message.getMessageID(), controls, protocolOp.getDN(),
-                          protocolOp.getAttributes());
+        new AddOperationBasis(this, nextOperationID.getAndIncrement(),
+            message.getMessageID(), controls, protocolOp.getDN(),
+            protocolOp.getAttributes());
 
     try
     {
@@ -2052,24 +1734,14 @@
       }
 
       AddResponseProtocolOp responseOp =
-           new AddResponseProtocolOp(de.getResultCode().getIntValue(),
-                                     de.getMessageObject(), de.getMatchedDN(),
-                                     de.getReferralURLs());
+          new AddResponseProtocolOp(de.getResultCode().getIntValue(),
+              de.getMessageObject(), de.getMatchedDN(), de
+                  .getReferralURLs());
 
-      List<Control> responseControls = addOp.getResponseControls();
-      ArrayList<LDAPControl> responseLDAPControls =
-           new ArrayList<LDAPControl>(responseControls.size());
-      for (Control c : responseControls)
-      {
-        responseLDAPControls.add(new LDAPControl(c));
-      }
-
-      sendLDAPMessage(securityProvider,
-                      new LDAPMessage(message.getMessageID(), responseOp,
-                                      responseLDAPControls));
+      sendLDAPMessage(new LDAPMessage(message.getMessageID(),
+          responseOp, addOp.getResponseControls()));
     }
 
-
     return connectionValid;
   }
 
@@ -2078,91 +1750,92 @@
   /**
    * Processes the provided LDAP message as a bind request.
    *
-   * @param  message   The LDAP message containing the bind request to process.
-   * @param  controls  The set of pre-decoded request controls contained in the
-   *                   message.
-   *
-   * @return  <CODE>true</CODE> if the request was processed successfully, or
-   *          <CODE>false</CODE> if not and the connection has been closed as a
-   *          result (it is the responsibility of this method to close the
-   *          connection).
+   * @param message
+   *          The LDAP message containing the bind request to process.
+   * @param controls
+   *          The set of pre-decoded request controls contained in the
+   *          message.
+   * @return <CODE>true</CODE> if the request was processed
+   *         successfully, or <CODE>false</CODE> if not and the
+   *         connection has been closed as a result (it is the
+   *         responsibility of this method to close the connection).
    */
   private boolean processBindRequest(LDAPMessage message,
-                                     ArrayList<Control> controls)
+      List<Control> controls)
   {
-    BindRequestProtocolOp protocolOp = message.getBindRequestProtocolOp();
+    BindRequestProtocolOp protocolOp =
+        message.getBindRequestProtocolOp();
 
-    // See if this is an LDAPv2 bind request, and if so whether that should be
-    // allowed.
+    // See if this is an LDAPv2 bind request, and if so whether that
+    // should be allowed.
     String versionString;
     switch (ldapVersion = protocolOp.getProtocolVersion())
     {
-      case 2:
-        versionString = "2";
+    case 2:
+      versionString = "2";
 
-        if (! connectionHandler.allowLDAPv2())
-        {
-          BindResponseProtocolOp responseOp =
-               new BindResponseProtocolOp(
-                        LDAPResultCode.INAPPROPRIATE_AUTHENTICATION,
-                        ERR_LDAPV2_CLIENTS_NOT_ALLOWED.get());
-          sendLDAPMessage(securityProvider,
-                          new LDAPMessage(message.getMessageID(), responseOp));
-          disconnect(DisconnectReason.PROTOCOL_ERROR, false,
-                     ERR_LDAPV2_CLIENTS_NOT_ALLOWED.get());
-          return false;
-        }
+      if (!connectionHandler.allowLDAPv2())
+      {
+        BindResponseProtocolOp responseOp =
+            new BindResponseProtocolOp(
+                LDAPResultCode.INAPPROPRIATE_AUTHENTICATION,
+                ERR_LDAPV2_CLIENTS_NOT_ALLOWED.get());
+        sendLDAPMessage(new LDAPMessage(message.getMessageID(),
+            responseOp));
+        disconnect(DisconnectReason.PROTOCOL_ERROR, false,
+            ERR_LDAPV2_CLIENTS_NOT_ALLOWED.get());
+        return false;
+      }
 
-        if ((controls != null) && (! controls.isEmpty()))
-        {
-          // LDAPv2 clients aren't allowed to send controls.
-          BindResponseProtocolOp responseOp =
-               new BindResponseProtocolOp(LDAPResultCode.PROTOCOL_ERROR,
-                        ERR_LDAPV2_CONTROLS_NOT_ALLOWED.get());
-          sendLDAPMessage(securityProvider,
-                          new LDAPMessage(message.getMessageID(), responseOp));
-          disconnect(DisconnectReason.PROTOCOL_ERROR, false,
-                     ERR_LDAPV2_CONTROLS_NOT_ALLOWED.get());
-          return false;
-        }
+      if ((controls != null) && (!controls.isEmpty()))
+      {
+        // LDAPv2 clients aren't allowed to send controls.
+        BindResponseProtocolOp responseOp =
+            new BindResponseProtocolOp(LDAPResultCode.PROTOCOL_ERROR,
+                ERR_LDAPV2_CONTROLS_NOT_ALLOWED.get());
+        sendLDAPMessage(new LDAPMessage(message.getMessageID(),
+            responseOp));
+        disconnect(DisconnectReason.PROTOCOL_ERROR, false,
+            ERR_LDAPV2_CONTROLS_NOT_ALLOWED.get());
+        return false;
+      }
 
-        break;
-      case 3:
-        versionString = "3";
-        break;
-      default:
-        versionString = String.valueOf(ldapVersion);
-        break;
+      break;
+    case 3:
+      versionString = "3";
+      break;
+    default:
+      versionString = String.valueOf(ldapVersion);
+      break;
     }
 
-
-    ASN1OctetString bindDN = protocolOp.getDN();
+    ByteString bindDN = protocolOp.getDN();
 
     BindOperationBasis bindOp;
     switch (protocolOp.getAuthenticationType())
     {
-      case SIMPLE:
-        bindOp = new BindOperationBasis(this, nextOperationID.getAndIncrement(),
-                                   message.getMessageID(), controls,
-                                   versionString, bindDN,
-                                   protocolOp.getSimplePassword());
-        break;
-      case SASL:
-        bindOp = new BindOperationBasis(this, nextOperationID.getAndIncrement(),
-                                   message.getMessageID(), controls,
-                                   versionString, bindDN,
-                                   protocolOp.getSASLMechanism(),
-                                   protocolOp.getSASLCredentials());
-        break;
-      default:
-        // This is an invalid authentication type, and therefore a protocol
-        // error.  As per RFC 2251, a protocol error in a bind request must
-        // result in terminating the connection.
-        Message msg =
-                ERR_LDAP_INVALID_BIND_AUTH_TYPE.get(message.getMessageID(),
-                          String.valueOf(protocolOp.getAuthenticationType()));
-        disconnect(DisconnectReason.PROTOCOL_ERROR, true, msg);
-        return false;
+    case SIMPLE:
+      bindOp =
+          new BindOperationBasis(this, nextOperationID
+              .getAndIncrement(), message.getMessageID(), controls,
+              versionString, bindDN, protocolOp.getSimplePassword());
+      break;
+    case SASL:
+      bindOp =
+          new BindOperationBasis(this, nextOperationID
+              .getAndIncrement(), message.getMessageID(), controls,
+              versionString, bindDN, protocolOp.getSASLMechanism(),
+              protocolOp.getSASLCredentials());
+      break;
+    default:
+      // This is an invalid authentication type, and therefore a
+      // protocol error. As per RFC 2251, a protocol error in a bind
+      // request must result in terminating the connection.
+      Message msg =
+          ERR_LDAP_INVALID_BIND_AUTH_TYPE.get(message.getMessageID(),
+              String.valueOf(protocolOp.getAuthenticationType()));
+      disconnect(DisconnectReason.PROTOCOL_ERROR, true, msg);
+      return false;
     }
 
     // Add the operation into the work queue.
@@ -2178,32 +1851,23 @@
       }
 
       BindResponseProtocolOp responseOp =
-           new BindResponseProtocolOp(de.getResultCode().getIntValue(),
-                                      de.getMessageObject(), de.getMatchedDN(),
-                                      de.getReferralURLs());
+          new BindResponseProtocolOp(de.getResultCode().getIntValue(),
+              de.getMessageObject(), de.getMatchedDN(), de
+                  .getReferralURLs());
 
-      List<Control> responseControls = bindOp.getResponseControls();
-      ArrayList<LDAPControl> responseLDAPControls =
-           new ArrayList<LDAPControl>(responseControls.size());
-      for (Control c : responseControls)
-      {
-        responseLDAPControls.add(new LDAPControl(c));
-      }
-
-      sendLDAPMessage(securityProvider,
-                      new LDAPMessage(message.getMessageID(), responseOp,
-                                      responseLDAPControls));
+      sendLDAPMessage(new LDAPMessage(message.getMessageID(),
+          responseOp, bindOp.getResponseControls()));
 
       // If it was a protocol error, then terminate the connection.
       if (de.getResultCode() == ResultCode.PROTOCOL_ERROR)
       {
-        Message msg = ERR_LDAP_DISCONNECT_DUE_TO_BIND_PROTOCOL_ERROR.get(
-                message.getMessageID(), de.getMessageObject());
+        Message msg =
+            ERR_LDAP_DISCONNECT_DUE_TO_BIND_PROTOCOL_ERROR.get(message
+                .getMessageID(), de.getMessageObject());
         disconnect(DisconnectReason.PROTOCOL_ERROR, true, msg);
       }
     }
 
-
     return connectionValid;
   }
 
@@ -2212,38 +1876,41 @@
   /**
    * Processes the provided LDAP message as a compare request.
    *
-   * @param  message   The LDAP message containing the compare request to
-   *                   process.
-   * @param  controls  The set of pre-decoded request controls contained in the
-   *                   message.
-   *
-   * @return  <CODE>true</CODE> if the request was processed successfully, or
-   *          <CODE>false</CODE> if not and the connection has been closed as a
-   *          result (it is the responsibility of this method to close the
-   *          connection).
+   * @param message
+   *          The LDAP message containing the compare request to
+   *          process.
+   * @param controls
+   *          The set of pre-decoded request controls contained in the
+   *          message.
+   * @return <CODE>true</CODE> if the request was processed
+   *         successfully, or <CODE>false</CODE> if not and the
+   *         connection has been closed as a result (it is the
+   *         responsibility of this method to close the connection).
    */
   private boolean processCompareRequest(LDAPMessage message,
-                                        ArrayList<Control> controls)
+      List<Control> controls)
   {
-    if ((ldapVersion == 2) && (controls != null) && (! controls.isEmpty()))
+    if ((ldapVersion == 2) && (controls != null)
+        && (!controls.isEmpty()))
     {
       // LDAPv2 clients aren't allowed to send controls.
       CompareResponseProtocolOp responseOp =
-           new CompareResponseProtocolOp(LDAPResultCode.PROTOCOL_ERROR,
-                    ERR_LDAPV2_CONTROLS_NOT_ALLOWED.get());
-      sendLDAPMessage(securityProvider,
-                      new LDAPMessage(message.getMessageID(), responseOp));
+          new CompareResponseProtocolOp(LDAPResultCode.PROTOCOL_ERROR,
+              ERR_LDAPV2_CONTROLS_NOT_ALLOWED.get());
+      sendLDAPMessage(new LDAPMessage(message.getMessageID(),
+          responseOp));
       disconnect(DisconnectReason.PROTOCOL_ERROR, false,
-                 ERR_LDAPV2_CONTROLS_NOT_ALLOWED.get());
+          ERR_LDAPV2_CONTROLS_NOT_ALLOWED.get());
       return false;
     }
 
-    CompareRequestProtocolOp protocolOp = message.getCompareRequestProtocolOp();
+    CompareRequestProtocolOp protocolOp =
+        message.getCompareRequestProtocolOp();
     CompareOperationBasis compareOp =
-         new CompareOperationBasis(this, nextOperationID.getAndIncrement(),
-                              message.getMessageID(), controls,
-                              protocolOp.getDN(), protocolOp.getAttributeType(),
-                              protocolOp.getAssertionValue());
+        new CompareOperationBasis(this, nextOperationID
+            .getAndIncrement(), message.getMessageID(), controls,
+            protocolOp.getDN(), protocolOp.getAttributeType(),
+            protocolOp.getAssertionValue());
 
     // Add the operation into the work queue.
     try
@@ -2258,25 +1925,14 @@
       }
 
       CompareResponseProtocolOp responseOp =
-           new CompareResponseProtocolOp(de.getResultCode().getIntValue(),
-                                         de.getMessageObject(),
-                                         de.getMatchedDN(),
-                                         de.getReferralURLs());
+          new CompareResponseProtocolOp(de.getResultCode()
+              .getIntValue(), de.getMessageObject(), de.getMatchedDN(),
+              de.getReferralURLs());
 
-      List<Control> responseControls = compareOp.getResponseControls();
-      ArrayList<LDAPControl> responseLDAPControls =
-           new ArrayList<LDAPControl>(responseControls.size());
-      for (Control c : responseControls)
-      {
-        responseLDAPControls.add(new LDAPControl(c));
-      }
-
-      sendLDAPMessage(securityProvider,
-                      new LDAPMessage(message.getMessageID(), responseOp,
-                                      responseLDAPControls));
+      sendLDAPMessage(new LDAPMessage(message.getMessageID(),
+          responseOp, compareOp.getResponseControls()));
     }
 
-
     return connectionValid;
   }
 
@@ -2285,37 +1941,39 @@
   /**
    * Processes the provided LDAP message as a delete request.
    *
-   * @param  message   The LDAP message containing the delete request to
-   *                   process.
-   * @param  controls  The set of pre-decoded request controls contained in the
-   *                   message.
-   *
-   * @return  <CODE>true</CODE> if the request was processed successfully, or
-   *          <CODE>false</CODE> if not and the connection has been closed as a
-   *          result (it is the responsibility of this method to close the
-   *          connection).
+   * @param message
+   *          The LDAP message containing the delete request to process.
+   * @param controls
+   *          The set of pre-decoded request controls contained in the
+   *          message.
+   * @return <CODE>true</CODE> if the request was processed
+   *         successfully, or <CODE>false</CODE> if not and the
+   *         connection has been closed as a result (it is the
+   *         responsibility of this method to close the connection).
    */
   private boolean processDeleteRequest(LDAPMessage message,
-                                       ArrayList<Control> controls)
+      List<Control> controls)
   {
-    if ((ldapVersion == 2) && (controls != null) && (! controls.isEmpty()))
+    if ((ldapVersion == 2) && (controls != null)
+        && (!controls.isEmpty()))
     {
       // LDAPv2 clients aren't allowed to send controls.
       DeleteResponseProtocolOp responseOp =
-           new DeleteResponseProtocolOp(LDAPResultCode.PROTOCOL_ERROR,
-                    ERR_LDAPV2_CONTROLS_NOT_ALLOWED.get());
-      sendLDAPMessage(securityProvider,
-                      new LDAPMessage(message.getMessageID(), responseOp));
+          new DeleteResponseProtocolOp(LDAPResultCode.PROTOCOL_ERROR,
+              ERR_LDAPV2_CONTROLS_NOT_ALLOWED.get());
+      sendLDAPMessage(new LDAPMessage(message.getMessageID(),
+          responseOp));
       disconnect(DisconnectReason.PROTOCOL_ERROR, false,
-                 ERR_LDAPV2_CONTROLS_NOT_ALLOWED.get());
+          ERR_LDAPV2_CONTROLS_NOT_ALLOWED.get());
       return false;
     }
 
-    DeleteRequestProtocolOp protocolOp = message.getDeleteRequestProtocolOp();
+    DeleteRequestProtocolOp protocolOp =
+        message.getDeleteRequestProtocolOp();
     DeleteOperationBasis deleteOp =
-         new DeleteOperationBasis(this, nextOperationID.getAndIncrement(),
-                             message.getMessageID(), controls,
-                             protocolOp.getDN());
+        new DeleteOperationBasis(this, nextOperationID
+            .getAndIncrement(), message.getMessageID(), controls,
+            protocolOp.getDN());
 
     // Add the operation into the work queue.
     try
@@ -2330,25 +1988,14 @@
       }
 
       DeleteResponseProtocolOp responseOp =
-           new DeleteResponseProtocolOp(de.getResultCode().getIntValue(),
-                                        de.getMessageObject(),
-                                        de.getMatchedDN(),
-                                        de.getReferralURLs());
+          new DeleteResponseProtocolOp(
+              de.getResultCode().getIntValue(), de.getMessageObject(),
+              de.getMatchedDN(), de.getReferralURLs());
 
-      List<Control> responseControls = deleteOp.getResponseControls();
-      ArrayList<LDAPControl> responseLDAPControls =
-           new ArrayList<LDAPControl>(responseControls.size());
-      for (Control c : responseControls)
-      {
-        responseLDAPControls.add(new LDAPControl(c));
-      }
-
-      sendLDAPMessage(securityProvider,
-                      new LDAPMessage(message.getMessageID(), responseOp,
-                                      responseLDAPControls));
+      sendLDAPMessage(new LDAPMessage(message.getMessageID(),
+          responseOp, deleteOp.getResponseControls()));
     }
 
-
     return connectionValid;
   }
 
@@ -2357,43 +2004,44 @@
   /**
    * Processes the provided LDAP message as an extended request.
    *
-   * @param  message   The LDAP message containing the extended request to
-   *                   process.
-   * @param  controls  The set of pre-decoded request controls contained in the
-   *                   message.
-   *
-   * @return  <CODE>true</CODE> if the request was processed successfully, or
-   *          <CODE>false</CODE> if not and the connection has been closed as a
-   *          result (it is the responsibility of this method to close the
-   *          connection).
+   * @param message
+   *          The LDAP message containing the extended request to
+   *          process.
+   * @param controls
+   *          The set of pre-decoded request controls contained in the
+   *          message.
+   * @return <CODE>true</CODE> if the request was processed
+   *         successfully, or <CODE>false</CODE> if not and the
+   *         connection has been closed as a result (it is the
+   *         responsibility of this method to close the connection).
    */
   private boolean processExtendedRequest(LDAPMessage message,
-                                         ArrayList<Control> controls)
+      List<Control> controls)
   {
-    // See if this is an LDAPv2 client.  If it is, then they should not be
-    // issuing extended requests.  We can't send a response that we can be sure
-    // they can understand, so we have no choice but to close the connection.
+    // See if this is an LDAPv2 client. If it is, then they should not
+    // be issuing extended requests. We can't send a response that we
+    // can be sure they can understand, so we have no choice but to
+    // close the connection.
     if (ldapVersion == 2)
     {
-      Message msg = ERR_LDAPV2_EXTENDED_REQUEST_NOT_ALLOWED.get(
-          getConnectionID(), message.getMessageID());
+      Message msg =
+          ERR_LDAPV2_EXTENDED_REQUEST_NOT_ALLOWED.get(
+              getConnectionID(), message.getMessageID());
       logError(msg);
       disconnect(DisconnectReason.PROTOCOL_ERROR, false, msg);
       return false;
     }
 
-
     // FIXME -- Do we need to handle certain types of request here?
     // -- StartTLS requests
     // -- Cancel requests
 
-
     ExtendedRequestProtocolOp protocolOp =
-         message.getExtendedRequestProtocolOp();
+        message.getExtendedRequestProtocolOp();
     ExtendedOperationBasis extendedOp =
-         new ExtendedOperationBasis(this, nextOperationID.getAndIncrement(),
-                               message.getMessageID(), controls,
-                               protocolOp.getOID(), protocolOp.getValue());
+        new ExtendedOperationBasis(this, nextOperationID
+            .getAndIncrement(), message.getMessageID(), controls,
+            protocolOp.getOID(), protocolOp.getValue());
 
     // Add the operation into the work queue.
     try
@@ -2408,25 +2056,14 @@
       }
 
       ExtendedResponseProtocolOp responseOp =
-           new ExtendedResponseProtocolOp(de.getResultCode().getIntValue(),
-                                          de.getMessageObject(),
-                                          de.getMatchedDN(),
-                                          de.getReferralURLs());
+          new ExtendedResponseProtocolOp(de.getResultCode()
+              .getIntValue(), de.getMessageObject(), de.getMatchedDN(),
+              de.getReferralURLs());
 
-      List<Control> responseControls = extendedOp.getResponseControls();
-      ArrayList<LDAPControl> responseLDAPControls =
-           new ArrayList<LDAPControl>(responseControls.size());
-      for (Control c : responseControls)
-      {
-        responseLDAPControls.add(new LDAPControl(c));
-      }
-
-      sendLDAPMessage(securityProvider,
-                      new LDAPMessage(message.getMessageID(), responseOp,
-                                      responseLDAPControls));
+      sendLDAPMessage(new LDAPMessage(message.getMessageID(),
+          responseOp, extendedOp.getResponseControls()));
     }
 
-
     return connectionValid;
   }
 
@@ -2435,37 +2072,39 @@
   /**
    * Processes the provided LDAP message as a modify request.
    *
-   * @param  message   The LDAP message containing the modify request to
-   *                   process.
-   * @param  controls  The set of pre-decoded request controls contained in the
-   *                   message.
-   *
-   * @return  <CODE>true</CODE> if the request was processed successfully, or
-   *          <CODE>false</CODE> if not and the connection has been closed as a
-   *          result (it is the responsibility of this method to close the
-   *          connection).
+   * @param message
+   *          The LDAP message containing the modify request to process.
+   * @param controls
+   *          The set of pre-decoded request controls contained in the
+   *          message.
+   * @return <CODE>true</CODE> if the request was processed
+   *         successfully, or <CODE>false</CODE> if not and the
+   *         connection has been closed as a result (it is the
+   *         responsibility of this method to close the connection).
    */
   private boolean processModifyRequest(LDAPMessage message,
-                                       ArrayList<Control> controls)
+      List<Control> controls)
   {
-    if ((ldapVersion == 2) && (controls != null) && (! controls.isEmpty()))
+    if ((ldapVersion == 2) && (controls != null)
+        && (!controls.isEmpty()))
     {
       // LDAPv2 clients aren't allowed to send controls.
       ModifyResponseProtocolOp responseOp =
-           new ModifyResponseProtocolOp(LDAPResultCode.PROTOCOL_ERROR,
-                    ERR_LDAPV2_CONTROLS_NOT_ALLOWED.get());
-      sendLDAPMessage(securityProvider,
-                      new LDAPMessage(message.getMessageID(), responseOp));
+          new ModifyResponseProtocolOp(LDAPResultCode.PROTOCOL_ERROR,
+              ERR_LDAPV2_CONTROLS_NOT_ALLOWED.get());
+      sendLDAPMessage(new LDAPMessage(message.getMessageID(),
+          responseOp));
       disconnect(DisconnectReason.PROTOCOL_ERROR, false,
-                 ERR_LDAPV2_CONTROLS_NOT_ALLOWED.get());
+          ERR_LDAPV2_CONTROLS_NOT_ALLOWED.get());
       return false;
     }
 
-    ModifyRequestProtocolOp protocolOp = message.getModifyRequestProtocolOp();
+    ModifyRequestProtocolOp protocolOp =
+        message.getModifyRequestProtocolOp();
     ModifyOperationBasis modifyOp =
-         new ModifyOperationBasis(this, nextOperationID.getAndIncrement(),
-                             message.getMessageID(), controls,
-                             protocolOp.getDN(), protocolOp.getModifications());
+        new ModifyOperationBasis(this, nextOperationID
+            .getAndIncrement(), message.getMessageID(), controls,
+            protocolOp.getDN(), protocolOp.getModifications());
 
     // Add the operation into the work queue.
     try
@@ -2480,25 +2119,14 @@
       }
 
       ModifyResponseProtocolOp responseOp =
-           new ModifyResponseProtocolOp(de.getResultCode().getIntValue(),
-                                        de.getMessageObject(),
-                                        de.getMatchedDN(),
-                                        de.getReferralURLs());
+          new ModifyResponseProtocolOp(
+              de.getResultCode().getIntValue(), de.getMessageObject(),
+              de.getMatchedDN(), de.getReferralURLs());
 
-      List<Control> responseControls = modifyOp.getResponseControls();
-      ArrayList<LDAPControl> responseLDAPControls =
-           new ArrayList<LDAPControl>(responseControls.size());
-      for (Control c : responseControls)
-      {
-        responseLDAPControls.add(new LDAPControl(c));
-      }
-
-      sendLDAPMessage(securityProvider,
-                      new LDAPMessage(message.getMessageID(), responseOp,
-                                      responseLDAPControls));
+      sendLDAPMessage(new LDAPMessage(message.getMessageID(),
+          responseOp, modifyOp.getResponseControls()));
     }
 
-
     return connectionValid;
   }
 
@@ -2507,40 +2135,41 @@
   /**
    * Processes the provided LDAP message as a modify DN request.
    *
-   * @param  message   The LDAP message containing the modify DN request to
-   *                   process.
-   * @param  controls  The set of pre-decoded request controls contained in the
-   *                   message.
-   *
-   * @return  <CODE>true</CODE> if the request was processed successfully, or
-   *          <CODE>false</CODE> if not and the connection has been closed as a
-   *          result (it is the responsibility of this method to close the
-   *          connection).
+   * @param message
+   *          The LDAP message containing the modify DN request to
+   *          process.
+   * @param controls
+   *          The set of pre-decoded request controls contained in the
+   *          message.
+   * @return <CODE>true</CODE> if the request was processed
+   *         successfully, or <CODE>false</CODE> if not and the
+   *         connection has been closed as a result (it is the
+   *         responsibility of this method to close the connection).
    */
   private boolean processModifyDNRequest(LDAPMessage message,
-                                         ArrayList<Control> controls)
+      List<Control> controls)
   {
-    if ((ldapVersion == 2) && (controls != null) && (! controls.isEmpty()))
+    if ((ldapVersion == 2) && (controls != null)
+        && (!controls.isEmpty()))
     {
       // LDAPv2 clients aren't allowed to send controls.
       ModifyDNResponseProtocolOp responseOp =
-           new ModifyDNResponseProtocolOp(LDAPResultCode.PROTOCOL_ERROR,
-                    ERR_LDAPV2_CONTROLS_NOT_ALLOWED.get());
-      sendLDAPMessage(securityProvider,
-                      new LDAPMessage(message.getMessageID(), responseOp));
+          new ModifyDNResponseProtocolOp(LDAPResultCode.PROTOCOL_ERROR,
+              ERR_LDAPV2_CONTROLS_NOT_ALLOWED.get());
+      sendLDAPMessage(new LDAPMessage(message.getMessageID(),
+          responseOp));
       disconnect(DisconnectReason.PROTOCOL_ERROR, false,
-                 ERR_LDAPV2_CONTROLS_NOT_ALLOWED.get());
+          ERR_LDAPV2_CONTROLS_NOT_ALLOWED.get());
       return false;
     }
 
     ModifyDNRequestProtocolOp protocolOp =
-         message.getModifyDNRequestProtocolOp();
+        message.getModifyDNRequestProtocolOp();
     ModifyDNOperationBasis modifyDNOp =
-         new ModifyDNOperationBasis(this, nextOperationID.getAndIncrement(),
-                               message.getMessageID(), controls,
-                               protocolOp.getEntryDN(), protocolOp.getNewRDN(),
-                               protocolOp.deleteOldRDN(),
-                               protocolOp.getNewSuperior());
+        new ModifyDNOperationBasis(this, nextOperationID
+            .getAndIncrement(), message.getMessageID(), controls,
+            protocolOp.getEntryDN(), protocolOp.getNewRDN(), protocolOp
+                .deleteOldRDN(), protocolOp.getNewSuperior());
 
     // Add the operation into the work queue.
     try
@@ -2555,25 +2184,14 @@
       }
 
       ModifyDNResponseProtocolOp responseOp =
-           new ModifyDNResponseProtocolOp(de.getResultCode().getIntValue(),
-                                          de.getMessageObject(),
-                                          de.getMatchedDN(),
-                                          de.getReferralURLs());
+          new ModifyDNResponseProtocolOp(de.getResultCode()
+              .getIntValue(), de.getMessageObject(), de.getMatchedDN(),
+              de.getReferralURLs());
 
-      List<Control> responseControls = modifyDNOp.getResponseControls();
-      ArrayList<LDAPControl> responseLDAPControls =
-           new ArrayList<LDAPControl>(responseControls.size());
-      for (Control c : responseControls)
-      {
-        responseLDAPControls.add(new LDAPControl(c));
-      }
-
-      sendLDAPMessage(securityProvider,
-                      new LDAPMessage(message.getMessageID(), responseOp,
-                                      responseLDAPControls));
+      sendLDAPMessage(new LDAPMessage(message.getMessageID(),
+          responseOp, modifyDNOp.getResponseControls()));
     }
 
-
     return connectionValid;
   }
 
@@ -2582,42 +2200,42 @@
   /**
    * Processes the provided LDAP message as a search request.
    *
-   * @param  message   The LDAP message containing the search request to
-   *                   process.
-   * @param  controls  The set of pre-decoded request controls contained in the
-   *                   message.
-   *
-   * @return  <CODE>true</CODE> if the request was processed successfully, or
-   *          <CODE>false</CODE> if not and the connection has been closed as a
-   *          result (it is the responsibility of this method to close the
-   *          connection).
+   * @param message
+   *          The LDAP message containing the search request to process.
+   * @param controls
+   *          The set of pre-decoded request controls contained in the
+   *          message.
+   * @return <CODE>true</CODE> if the request was processed
+   *         successfully, or <CODE>false</CODE> if not and the
+   *         connection has been closed as a result (it is the
+   *         responsibility of this method to close the connection).
    */
   private boolean processSearchRequest(LDAPMessage message,
-                                       ArrayList<Control> controls)
+      List<Control> controls)
   {
-    if ((ldapVersion == 2) && (controls != null) && (! controls.isEmpty()))
+    if ((ldapVersion == 2) && (controls != null)
+        && (!controls.isEmpty()))
     {
       // LDAPv2 clients aren't allowed to send controls.
       SearchResultDoneProtocolOp responseOp =
-           new SearchResultDoneProtocolOp(LDAPResultCode.PROTOCOL_ERROR,
-                    ERR_LDAPV2_CONTROLS_NOT_ALLOWED.get());
-      sendLDAPMessage(securityProvider,
-                      new LDAPMessage(message.getMessageID(), responseOp));
+          new SearchResultDoneProtocolOp(LDAPResultCode.PROTOCOL_ERROR,
+              ERR_LDAPV2_CONTROLS_NOT_ALLOWED.get());
+      sendLDAPMessage(new LDAPMessage(message.getMessageID(),
+          responseOp));
       disconnect(DisconnectReason.PROTOCOL_ERROR, false,
-                 ERR_LDAPV2_CONTROLS_NOT_ALLOWED.get());
+          ERR_LDAPV2_CONTROLS_NOT_ALLOWED.get());
       return false;
     }
 
-    SearchRequestProtocolOp protocolOp = message.getSearchRequestProtocolOp();
+    SearchRequestProtocolOp protocolOp =
+        message.getSearchRequestProtocolOp();
     SearchOperationBasis searchOp =
-         new SearchOperationBasis(this, nextOperationID.getAndIncrement(),
-                             message.getMessageID(), controls,
-                             protocolOp.getBaseDN(), protocolOp.getScope(),
-                             protocolOp.getDereferencePolicy(),
-                             protocolOp.getSizeLimit(),
-                             protocolOp.getTimeLimit(),
-                             protocolOp.getTypesOnly(), protocolOp.getFilter(),
-                             protocolOp.getAttributes());
+        new SearchOperationBasis(this, nextOperationID
+            .getAndIncrement(), message.getMessageID(), controls,
+            protocolOp.getBaseDN(), protocolOp.getScope(), protocolOp
+                .getDereferencePolicy(), protocolOp.getSizeLimit(),
+            protocolOp.getTimeLimit(), protocolOp.getTypesOnly(),
+            protocolOp.getFilter(), protocolOp.getAttributes());
 
     // Add the operation into the work queue.
     try
@@ -2632,25 +2250,14 @@
       }
 
       SearchResultDoneProtocolOp responseOp =
-           new SearchResultDoneProtocolOp(de.getResultCode().getIntValue(),
-                                          de.getMessageObject(),
-                                          de.getMatchedDN(),
-                                          de.getReferralURLs());
+          new SearchResultDoneProtocolOp(de.getResultCode()
+              .getIntValue(), de.getMessageObject(), de.getMatchedDN(),
+              de.getReferralURLs());
 
-      List<Control> responseControls = searchOp.getResponseControls();
-      ArrayList<LDAPControl> responseLDAPControls =
-           new ArrayList<LDAPControl>(responseControls.size());
-      for (Control c : responseControls)
-      {
-        responseLDAPControls.add(new LDAPControl(c));
-      }
-
-      sendLDAPMessage(securityProvider,
-                      new LDAPMessage(message.getMessageID(), responseOp,
-                                      responseLDAPControls));
+      sendLDAPMessage(new LDAPMessage(message.getMessageID(),
+          responseOp, searchOp.getResponseControls()));
     }
 
-
     return connectionValid;
   }
 
@@ -2659,22 +2266,22 @@
   /**
    * Processes the provided LDAP message as an unbind request.
    *
-   * @param  message   The LDAP message containing the unbind request to
-   *                   process.
-   * @param  controls  The set of pre-decoded request controls contained in the
-   *                   message.
-   *
-   * @return  <CODE>true</CODE> if the request was processed successfully, or
-   *          <CODE>false</CODE> if not and the connection has been closed as a
-   *          result (it is the responsibility of this method to close the
-   *          connection).
+   * @param message
+   *          The LDAP message containing the unbind request to process.
+   * @param controls
+   *          The set of pre-decoded request controls contained in the
+   *          message.
+   * @return <CODE>true</CODE> if the request was processed
+   *         successfully, or <CODE>false</CODE> if not and the
+   *         connection has been closed as a result (it is the
+   *         responsibility of this method to close the connection).
    */
   private boolean processUnbindRequest(LDAPMessage message,
-                                       ArrayList<Control> controls)
+      List<Control> controls)
   {
     UnbindOperationBasis unbindOp =
-         new UnbindOperationBasis(this, nextOperationID.getAndIncrement(),
-                              message.getMessageID(), controls);
+        new UnbindOperationBasis(this, nextOperationID
+            .getAndIncrement(), message.getMessageID(), controls);
 
     unbindOp.run();
 
@@ -2687,6 +2294,7 @@
   /**
    * {@inheritDoc}
    */
+  @Override
   public String getMonitorSummary()
   {
     StringBuilder buffer = new StringBuilder();
@@ -2713,9 +2321,9 @@
     }
 
     buffer.append("\" security=\"");
-    if (securityProvider.isSecure())
+    if (isSecure())
     {
-      buffer.append(securityProvider.getSecurityMechanismName());
+      buffer.append(activeProvider.getName());
     }
     else
     {
@@ -2732,11 +2340,13 @@
 
 
   /**
-   * Appends a string representation of this client connection to the provided
-   * buffer.
+   * Appends a string representation of this client connection to the
+   * provided buffer.
    *
-   * @param  buffer  The buffer to which the information should be appended.
+   * @param buffer
+   *          The buffer to which the information should be appended.
    */
+  @Override
   public void toString(StringBuilder buffer)
   {
     buffer.append("LDAP client connection from ");
@@ -2752,218 +2362,90 @@
 
 
   /**
-   * Indicates whether TLS protection is actually available for the underlying
-   * client connection.  If there is any reason that TLS protection cannot be
-   * enabled on this client connection, then it should be appended to the
-   * provided buffer.
+   * Indicates whether TLS protection is actually available for the
+   * underlying client connection. If there is any reason that TLS
+   * protection cannot be enabled on this client connection, then it
+   * should be appended to the provided buffer.
    *
-   * @param  unavailableReason  The buffer used to hold the reason that TLS is
-   *                            not available on the underlying client
-   *                            connection.
-   *
-   * @return  <CODE>true</CODE> if TLS is available on the underlying client
-   *          connection, or <CODE>false</CODE> if it is not.
+   * @param unavailableReason
+   *          The buffer used to hold the reason that TLS is not
+   *          available on the underlying client connection.
+   * @return <CODE>true</CODE> if TLS is available on the underlying
+   *         client connection, or <CODE>false</CODE> if it is not.
    */
-  public boolean tlsProtectionAvailable(MessageBuilder unavailableReason)
+  public boolean isTLSAvailable(MessageBuilder unavailableReason)
   {
-    // Make sure that this client connection does not already have some other
-    // security provider enabled.
-    if (! (securityProvider instanceof NullConnectionSecurityProvider))
+    if (isSecure() && activeProvider.getName().equals("TLS"))
     {
-
-      unavailableReason.append(ERR_LDAP_TLS_EXISTING_SECURITY_PROVIDER.get(
-              securityProvider.getSecurityMechanismName()));
+      // TODO SASLPhase2 more general message
+      unavailableReason.append(ERR_LDAP_TLS_EXISTING_SECURITY_PROVIDER
+          .get(activeProvider.getName()));
       return false;
     }
-
-
-    // Make sure that the connection handler allows the use of the StartTLS
-    // operation.
-    if (! connectionHandler.allowStartTLS())
+    // Make sure that the connection handler allows the use of the
+    // StartTLS operation.
+    if (!connectionHandler.allowStartTLS())
     {
-
       unavailableReason.append(ERR_LDAP_TLS_STARTTLS_NOT_ALLOWED.get());
       return false;
     }
-
-
-    // Make sure that the TLS security provider is available.
-    if (tlsSecurityProvider == null)
+    try
     {
-      try
-      {
-        TLSConnectionSecurityProvider tlsProvider =
-             new TLSConnectionSecurityProvider();
-        tlsProvider.initializeConnectionSecurityProvider(null);
-        tlsProvider.setSSLClientAuthPolicy(
-             connectionHandler.getSSLClientAuthPolicy());
-        tlsProvider.setEnabledProtocols(
-             connectionHandler.getEnabledSSLProtocols());
-        tlsProvider.setEnabledCipherSuites(
-             connectionHandler.getEnabledSSLCipherSuites());
-
-        tlsSecurityProvider = (TLSConnectionSecurityProvider)
-                              tlsProvider.newInstance(this, clientChannel);
-      }
-      catch (Exception e)
-      {
-        if (debugEnabled())
-        {
-          TRACER.debugCaught(DebugLogLevel.ERROR, e);
-        }
-
-        tlsSecurityProvider = null;
-
-
-        unavailableReason.append(ERR_LDAP_TLS_CANNOT_CREATE_TLS_PROVIDER.get(
-                stackTraceToSingleLineString(e)));
-        return false;
-      }
+      TLSByteChannel tlsByteChannel =
+          connectionHandler.getTLSByteChannel(this, clientChannel);
+      setTLSPendingProvider(tlsByteChannel);
     }
-
-
-    // If we've gotten here, then everything looks OK.
+    catch (DirectoryException de)
+    {
+      if (debugEnabled())
+      {
+        TRACER.debugCaught(DebugLogLevel.ERROR, de);
+      }
+      unavailableReason.append(ERR_LDAP_TLS_CANNOT_CREATE_TLS_PROVIDER
+          .get(stackTraceToSingleLineString(de)));
+      return false;
+    }
     return true;
   }
 
 
 
   /**
-   * Installs the TLS connection security provider on this client connection.
-   * If an error occurs in the process, then the underlying client connection
-   * must be terminated and an exception must be thrown to indicate the
-   * underlying cause.
-   *
-   * @throws  DirectoryException  If the TLS connection security provider could
-   *                              not be enabled and the underlying connection
-   *                              has been closed.
-   */
-  public void enableTLSConnectionSecurityProvider()
-         throws DirectoryException
-  {
-    if (tlsSecurityProvider == null)
-    {
-      Message message = ERR_LDAP_TLS_NO_PROVIDER.get();
-
-      disconnect(DisconnectReason.OTHER, false, message);
-      throw new DirectoryException(DirectoryServer.getServerErrorResultCode(),
-                                   message);
-    }
-
-    clearSecurityProvider = securityProvider;
-    setConnectionSecurityProvider(tlsSecurityProvider);
-  }
-
-
-
-  /**
-   * Disables the TLS connection security provider on this client connection.
-   * This must also eliminate any authentication that had been performed on the
-   * client connection so that it is in an anonymous state.  If a problem occurs
-   * while attempting to revert the connection to a non-TLS-protected state,
-   * then an exception must be thrown and the client connection must be
-   * terminated.
-   *
-   * @throws  DirectoryException  If TLS protection cannot be reverted and the
-   *                              underlying client connection has been closed.
-   */
-  public void disableTLSConnectionSecurityProvider()
-         throws DirectoryException
-  {
-    Message message = ERR_LDAP_TLS_CLOSURE_NOT_ALLOWED.get();
-
-    disconnect(DisconnectReason.OTHER, false, message);
-    throw new DirectoryException(DirectoryServer.getServerErrorResultCode(),
-                                 message);
-  }
-
-
-
-  /**
    * Sends a response to the client in the clear rather than through the
-   * encrypted channel.  This should only be used when processing the StartTLS
-   * extended operation to send the response in the clear after the TLS
-   * negotiation has already been initiated.
+   * encrypted channel. This should only be used when processing the
+   * StartTLS extended operation to send the response in the clear after
+   * the TLS negotiation has already been initiated.
    *
-   * @param  operation  The operation for which to send the response in the
-   *                    clear.
-   *
-   *
-   * @throws  DirectoryException  If a problem occurs while sending the response
-   *                              in the clear.
+   * @param operation
+   *          The operation for which to send the response in the clear.
+   * @throws DirectoryException
+   *           If a problem occurs while sending the response in the
+   *           clear.
    */
   public void sendClearResponse(Operation operation)
-         throws DirectoryException
+      throws DirectoryException
   {
-    if (clearSecurityProvider == null)
-    {
-      Message message = ERR_LDAP_NO_CLEAR_SECURITY_PROVIDER.get(toString());
-      throw new DirectoryException(DirectoryServer.getServerErrorResultCode(),
-                                   message);
-    }
-
-    sendLDAPMessage(clearSecurityProvider,
-                    operationToResponseLDAPMessage(operation));
-  }
-
-
-
-  /**
-   * {@inheritDoc}
-   */
-  @Override
-  public DN getKeyManagerProviderDN()
-  {
-    return connectionHandler.getKeyManagerProviderDN();
-  }
-
-
-
-  /**
-   * {@inheritDoc}
-   */
-  @Override
-  public DN getTrustManagerProviderDN()
-  {
-    return connectionHandler.getTrustManagerProviderDN();
-  }
-
-
-
-  /**
-   * Retrieves the alias of the server certificate that should be used
-   * for operations requiring a server certificate.  The default
-   * implementation returns {@code null} to indicate that any alias is
-   * acceptable.
-   *
-   * @return  The alias of the server certificate that should be used
-   *          for operations requring a server certificate, or
-   *          {@code null} if any alias is acceptable.
-   */
-  @Override
-  public String getCertificateAlias()
-  {
-    return connectionHandler.getSSLServerCertNickname();
+    sendLDAPMessage(operationToResponseLDAPMessage(operation));
   }
 
 
 
   /**
    * Retrieves the length of time in milliseconds that this client
-   * connection has been idle.
-   * <BR><BR>
+   * connection has been idle. <BR>
+   * <BR>
    * Note that the default implementation will always return zero.
-   * Subclasses associated with connection handlers should override
-   * this method if they wish to provided idle time limit
-   * functionality.
+   * Subclasses associated with connection handlers should override this
+   * method if they wish to provided idle time limit functionality.
    *
-   * @return  The length of time in milliseconds that this client
-   *          connection has been idle.
+   * @return The length of time in milliseconds that this client
+   *         connection has been idle.
    */
   @Override
   public long getIdleTime()
   {
-    if (operationsInProgress.isEmpty() && getPersistentSearches().isEmpty())
+    if (operationsInProgress.isEmpty()
+        && getPersistentSearches().isEmpty())
     {
       return (TimeThread.getTime() - lastCompletionTime.get());
     }
@@ -2974,27 +2456,131 @@
     }
   }
 
-  private void initializeOperationMonitors() {
-    this.addMonitor = OperationMonitor.getOperationMonitor(
-            ADD);
-    this.searchMonitor = OperationMonitor.getOperationMonitor(
-            SEARCH);
-    this.abandonMonitor = OperationMonitor.getOperationMonitor(
-            ABANDON);
-    this.bindMonitor = OperationMonitor.getOperationMonitor(
-            BIND);
-    this.compareMonitor = OperationMonitor.getOperationMonitor(
-            COMPARE);
-    this.delMonitor = OperationMonitor.getOperationMonitor(
-            DELETE);
-    this.extendedMonitor = OperationMonitor.getOperationMonitor(
-            EXTENDED);
-    this.modMonitor = OperationMonitor.getOperationMonitor(
-            MODIFY);
-    this.moddnMonitor = OperationMonitor.getOperationMonitor(
-            MODIFY_DN);
-    this.unbindMonitor = OperationMonitor.getOperationMonitor(
-            UNBIND);
+
+
+  /**
+   * Set the connection provider that is not in use yet. Used in TLS
+   * negotiation when a clear response is needed before the connection
+   * provider is active.
+   *
+   * @param provider
+   *          The provider that needs to be activated.
+   */
+  public void setTLSPendingProvider(ConnectionSecurityProvider provider)
+  {
+    tlsPendingProvider = provider;
+
+  }
+
+
+
+  /**
+   * Set the connection provider that is not in use. Used in SASL
+   * negotiation when a clear response is needed before the connection
+   * provider is active.
+   *
+   * @param provider
+   *          The provider that needs to be activated.
+   */
+  public void setSASLPendingProvider(ConnectionSecurityProvider provider)
+  {
+    saslPendingProvider = provider;
+
+  }
+
+
+
+  /**
+   * Enable the provider that is inactive.
+   */
+  public void enableTLS()
+  {
+    this.asn1Reader =
+        ASN1.getReader(saslChannel, tlsPendingProvider.getAppBufSize(),
+            connectionHandler.getMaxRequestSize());
+    activeProvider = tlsPendingProvider;
+    tlsChannel.redirect(tlsPendingProvider);
+    tlsPendingProvider = null;
+  }
+
+
+
+  /**
+   * Set the security provider to the specified provider.
+   *
+   * @param sslProvider
+   *          The provider to set the security provider to.
+   */
+  public void enableSSL(ConnectionSecurityProvider sslProvider)
+  {
+    this.asn1Reader =
+        ASN1.getReader(saslChannel, sslProvider.getAppBufSize(),
+            connectionHandler.getMaxRequestSize());
+    activeProvider = sslProvider;
+    tlsChannel.redirect(sslProvider);
+  }
+
+
+
+  /**
+   * Enable the SASL provider that is currently inactive or pending.
+   */
+  public void enableSASL()
+  {
+    activeProvider = saslPendingProvider;
+    saslChannel.redirect(saslPendingProvider);
+    asn1Reader =
+        ASN1.getReader(saslChannel,
+            saslPendingProvider.getAppBufSize(), connectionHandler
+                .getMaxRequestSize());
+    saslPendingProvider = null;
+  }
+
+
+
+  /**
+   * Return the certificate chain array associated with a connection.
+   *
+   * @return The array of certificates associated with a connection.
+   */
+  public Certificate[] getClientCertificateChain()
+  {
+    if (activeProvider != null)
+    {
+      return activeProvider.getClientCertificateChain();
+    }
+    else
+      return new Certificate[0];
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public int getSSF()
+  {
+    if (activeProvider != null)
+      return activeProvider.getSSF();
+    else
+      return 0;
+  }
+
+
+
+  private void initializeOperationMonitors()
+  {
+    this.addMonitor = OperationMonitor.getOperationMonitor(ADD);
+    this.searchMonitor = OperationMonitor.getOperationMonitor(SEARCH);
+    this.abandonMonitor = OperationMonitor.getOperationMonitor(ABANDON);
+    this.bindMonitor = OperationMonitor.getOperationMonitor(BIND);
+    this.compareMonitor = OperationMonitor.getOperationMonitor(COMPARE);
+    this.delMonitor = OperationMonitor.getOperationMonitor(DELETE);
+    this.extendedMonitor =
+        OperationMonitor.getOperationMonitor(EXTENDED);
+    this.modMonitor = OperationMonitor.getOperationMonitor(MODIFY);
+    this.moddnMonitor = OperationMonitor.getOperationMonitor(MODIFY_DN);
+    this.unbindMonitor = OperationMonitor.getOperationMonitor(UNBIND);
   }
 }
-
diff --git a/opends/src/server/org/opends/server/protocols/ldap/LDAPConnectionHandler.java b/opends/src/server/org/opends/server/protocols/ldap/LDAPConnectionHandler.java
index 8b5da30..7499f45 100644
--- a/opends/src/server/org/opends/server/protocols/ldap/LDAPConnectionHandler.java
+++ b/opends/src/server/org/opends/server/protocols/ldap/LDAPConnectionHandler.java
@@ -22,7 +22,7 @@
  * CDDL HEADER END
  *
  *
- *      Copyright 2006-2008 Sun Microsystems, Inc.
+ *      Copyright 2006-2009 Sun Microsystems, Inc.
  */
 package org.opends.server.protocols.ldap;
 import org.opends.messages.Message;
@@ -45,6 +45,8 @@
 import java.nio.channels.Selector;
 import java.nio.channels.ServerSocketChannel;
 import java.nio.channels.SocketChannel;
+import java.security.KeyManagementException;
+import java.security.NoSuchAlgorithmException;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Iterator;
@@ -53,26 +55,31 @@
 import java.util.List;
 import java.util.Set;
 
+import javax.net.ssl.SSLContext;
+
 import org.opends.server.admin.server.ConfigurationChangeListener;
 import org.opends.server.admin.std.server.ConnectionHandlerCfg;
 import org.opends.server.admin.std.server.LDAPConnectionHandlerCfg;
 import org.opends.server.api.AlertGenerator;
 import org.opends.server.api.ClientConnection;
 import org.opends.server.api.ConnectionHandler;
-import org.opends.server.api.ConnectionSecurityProvider;
+import org.opends.server.api.KeyManagerProvider;
 import org.opends.server.api.ServerShutdownListener;
+import org.opends.server.api.TrustManagerProvider;
 import org.opends.server.api.plugin.PluginResult;
 import org.opends.server.config.ConfigException;
 import org.opends.server.core.DirectoryServer;
 import org.opends.server.core.PluginConfigManager;
 import org.opends.server.core.QueueingStrategy;
 import org.opends.server.core.WorkQueueStrategy;
-import org.opends.server.extensions.NullConnectionSecurityProvider;
-import org.opends.server.extensions.TLSConnectionSecurityProvider;
+import org.opends.server.extensions.NullKeyManagerProvider;
+import org.opends.server.extensions.NullTrustManagerProvider;
+import org.opends.server.extensions.TLSByteChannel;
 import org.opends.server.types.AddressMask;
 import org.opends.server.types.ConfigChangeResult;
 import org.opends.server.types.DN;
 import org.opends.server.types.DebugLogLevel;
+import org.opends.server.types.DirectoryException;
 import org.opends.server.types.DisconnectReason;
 
 
@@ -80,6 +87,7 @@
 import org.opends.server.types.InitializationException;
 import org.opends.server.types.ResultCode;
 import org.opends.server.types.SSLClientAuthPolicy;
+import org.opends.server.util.SelectableCertificateKeyManager;
 import org.opends.server.util.StaticUtils;
 
 
@@ -188,10 +196,6 @@
   // The protocol used by this connection handler.
   private String protocol;
 
-  // The connection security provider that will be used by default for
-  // new client connections.
-  private ConnectionSecurityProvider securityProvider;
-
 // Queueing strategy
   private final QueueingStrategy queueingStrategy;
 
@@ -203,6 +207,13 @@
   // The friendly name of this connection handler.
   private String friendlyName;
 
+  //SSL instance name used in context creation.
+  private static final String SSL_CONTEXT_INSTANCE_NAME = "TLS";
+
+  //SSL context.
+  private SSLContext sslContext;
+  private boolean sslConfig = false;
+
   /**
    * Creates a new instance of this LDAP connection handler. It must
    * be initialized before it may be used.
@@ -308,20 +319,10 @@
         new AddressMask[0]);
     deniedClients = config.getDeniedClient().toArray(
         new AddressMask[0]);
+    //Reconfigure SSL context if needed.
+    if (config.isUseSSL() || config.isAllowStartTLS()) {
+            sslConfig = true;
 
-    // Get the supported SSL ciphers and protocols.
-    Set<String> ciphers = config.getSSLCipherSuite();
-    if (ciphers.isEmpty()) {
-      enabledSSLCipherSuites = null;
-    } else {
-      enabledSSLCipherSuites = ciphers.toArray(new String[0]);
-    }
-
-    Set<String> protocols = config.getSSLProtocol();
-    if (protocols.isEmpty()) {
-      enabledSSLProtocols = null;
-    } else {
-      enabledSSLProtocols = protocols.toArray(new String[0]);
     }
 
     if (config.isAllowLDAPV2())
@@ -491,21 +492,6 @@
 
 
 
-  /**
-   * Retrieves the DN of the key manager provider that should be used
-   * for operations associated with this connection handler which need
-   * access to a key manager.
-   *
-   * @return The DN of the key manager provider that should be used
-   *         for operations associated with this connection handler
-   *         which need access to a key manager, or {@code null} if no
-   *         key manager provider has been configured for this
-   *         connection handler.
-   */
-  public DN getKeyManagerProviderDN() {
-    return currentConfig.getKeyManagerProviderDN();
-  }
-
 
 
   /**
@@ -575,16 +561,6 @@
 
 
 
-  /**
-   * Retrieves the nickname of the server certificate that should be
-   * used in conjunction with this LDAP connection handler.
-   *
-   * @return The nickname of the server certificate that should be
-   *         used in conjunction with this LDAP connection handler.
-   */
-  public String getSSLServerCertNickname() {
-    return currentConfig.getSSLCertNickname();
-  }
 
 
 
@@ -614,22 +590,6 @@
 
 
 
-  /**
-   * Retrieves the DN of the trust manager provider that should be
-   * used for operations associated with this connection handler which
-   * need access to a trust manager.
-   *
-   * @return The DN of the trust manager provider that should be used
-   *         for operations associated with this connection handler
-   *         which need access to a trust manager, or {@code null} if
-   *         no trust manager provider has been configured for this
-   *         connection handler.
-   */
-  public DN getTrustManagerProviderDN() {
-    return currentConfig.getTrustManagerProviderDN();
-  }
-
-
 
   /**
    * {@inheritDoc}
@@ -651,51 +611,7 @@
       throw new InitializationException(message, e);
     }
 
-    // Get the SSL auth policy.
-    switch (config.getSSLClientAuthPolicy()) {
-    case DISABLED:
-      sslClientAuthPolicy = SSLClientAuthPolicy.DISABLED;
-      break;
-    case REQUIRED:
-      sslClientAuthPolicy = SSLClientAuthPolicy.REQUIRED;
-      break;
-    default:
-      sslClientAuthPolicy = SSLClientAuthPolicy.OPTIONAL;
-      break;
-    }
-
-    // Get the supported SSL ciphers and protocols.
-    Set<String> ciphers = config.getSSLCipherSuite();
-    if (ciphers.isEmpty()) {
-      enabledSSLCipherSuites = null;
-    } else {
-      enabledSSLCipherSuites = ciphers.toArray(new String[0]);
-    }
-
-    Set<String> protocols = config.getSSLProtocol();
-    if (protocols.isEmpty()) {
-      enabledSSLProtocols = null;
-    } else {
-      enabledSSLProtocols = protocols.toArray(new String[0]);
-    }
-
-    // Initialize the security provider.
-    if (config.isUseSSL()) {
-      TLSConnectionSecurityProvider tlsProvider =
-        new TLSConnectionSecurityProvider();
-      tlsProvider.initializeConnectionSecurityProvider(null);
-      tlsProvider.setSSLClientAuthPolicy(sslClientAuthPolicy);
-      tlsProvider.setEnabledProtocols(enabledSSLProtocols);
-      tlsProvider.setEnabledCipherSuites(enabledSSLCipherSuites);
-
-      // FIXME -- Need to do something with the requested cert
-      // nickname.
-
-      securityProvider = tlsProvider;
-    } else {
-      securityProvider = new NullConnectionSecurityProvider();
-      securityProvider.initializeConnectionSecurityProvider(null);
-    }
+     protocol = "LDAP";
 
     // Save this configuration for future reference.
     currentConfig = config;
@@ -705,6 +621,9 @@
         new AddressMask[0]);
     deniedClients = config.getDeniedClient().toArray(
         new AddressMask[0]);
+    //Setup SSL context if needed.
+    if (config.isUseSSL() || config.isAllowStartTLS())
+        sslConfig=true;
 
     // Save properties that cannot be dynamically modified.
     allowReuseAddress = config.isAllowTCPReuseAddress();
@@ -728,13 +647,6 @@
     nameBuffer.append(listenPort);
     handlerName = nameBuffer.toString();
 
-    // Set the protocol for this connection handler.
-    if (config.isUseSSL()) {
-      protocol = "LDAP+SSL";
-    } else {
-      protocol = "LDAP";
-    }
-
     // Perform any additional initialization that might be required.
     statTracker = new LDAPStatistics(this, handlerName + " Statistics");
 
@@ -819,7 +731,6 @@
         }
       }
     }
-
     return isConfigurationChangeAcceptable(config, unacceptableReasons);
   }
 
@@ -992,9 +903,8 @@
                       .channel();
                   SocketChannel clientChannel = serverChannel
                       .accept();
-                  LDAPClientConnection clientConnection =
-                    new LDAPClientConnection(this, clientChannel);
-
+                  LDAPClientConnection clientConnection  =
+                                          createClientConnection(clientChannel);
                   // Check to see if the core server rejected the
                   // connection (e.g., already too many connections
                   // established).
@@ -1043,29 +953,6 @@
                   clientChannel.socket().setTcpNoDelay(
                       currentConfig.isUseTCPNoDelay());
 
-                  try
-                  {
-                    ConnectionSecurityProvider connectionSecurityProvider =
-                         securityProvider.newInstance(clientConnection,
-                                                      clientChannel);
-                    clientConnection.setConnectionSecurityProvider(
-                         connectionSecurityProvider);
-                  }
-                  catch (Exception e)
-                  {
-                    if (debugEnabled())
-                    {
-                      TRACER.debugCaught(DebugLogLevel.ERROR, e);
-                    }
-
-                    clientConnection.disconnect(
-                         DisconnectReason.SECURITY_PROBLEM, false,
-                         ERR_LDAP_CONNHANDLER_CANNOT_SET_SECURITY_PROVIDER.get(
-                          String.valueOf(e)));
-                    iterator.remove();
-                    continue;
-                  }
-
                   // If we've gotten here, then we'll take the
                   // connection so invoke the post-connect plugins and
                   // register the client connection with a request
@@ -1276,4 +1163,83 @@
     return queueingStrategy;
   }
 
+  private LDAPClientConnection
+  createClientConnection(SocketChannel socketChannel)
+  throws DirectoryException {
+      if(sslConfig) {
+          configSSL(currentConfig);
+          sslConfig=false;
+      }
+      LDAPClientConnection c =
+                                 new LDAPClientConnection(this, socketChannel);
+      if(currentConfig.isUseSSL()) {
+          TLSByteChannel tlsByteChannel =  getTLSByteChannel(c, socketChannel);
+          c.enableSSL(tlsByteChannel);
+      }
+      return c;
+  }
+
+  /**
+   * Creates a TLS Byte Channel instance using the specified LDAP
+   * client connection and socket channel.
+   *
+   * @param c The client connection to use in the creation.
+   * @param socketChannel The socket channel to use in the creation.
+   * @return A TLS Byte Channel instance.
+   * @throws DirectoryException If the channel cannot be created.
+   */
+  public TLSByteChannel
+  getTLSByteChannel(LDAPClientConnection c, SocketChannel socketChannel)
+                  throws DirectoryException {
+         return(TLSByteChannel.getTLSByteChannel(currentConfig, c,
+                                                    sslContext,
+                                                    socketChannel));
+  }
+
+  private void configSSL(LDAPConnectionHandlerCfg config)
+  throws DirectoryException {
+      ResultCode resCode = DirectoryServer.getServerErrorResultCode();
+      try {
+          String alias = config.getSSLCertNickname();
+          protocol += "+SSL";
+          DN keyMgrDN = config.getKeyManagerProviderDN();
+          DN trustMgrDN = config.getTrustManagerProviderDN();
+          KeyManagerProvider<?> keyManagerProvider =
+              DirectoryServer.getKeyManagerProvider(keyMgrDN);
+          if (keyManagerProvider == null)
+              keyManagerProvider = new NullKeyManagerProvider();
+          TrustManagerProvider<?> trustManagerProvider =
+              DirectoryServer.getTrustManagerProvider(trustMgrDN);
+          if (trustManagerProvider == null)
+              trustManagerProvider = new NullTrustManagerProvider();
+          sslContext = SSLContext.getInstance(SSL_CONTEXT_INSTANCE_NAME);
+          if (alias == null) {
+              sslContext.init(keyManagerProvider.getKeyManagers(),
+                      trustManagerProvider.getTrustManagers(), null);
+          } else {
+              sslContext.init(SelectableCertificateKeyManager.wrap(
+                      keyManagerProvider.getKeyManagers(), alias),
+                      trustManagerProvider.getTrustManagers(), null);
+          }
+      } catch (NoSuchAlgorithmException nsae) {
+          if (debugEnabled())
+              TRACER.debugCaught(DebugLogLevel.ERROR, nsae);
+          Message message =  ERR_CONNHANDLER_SSL_CANNOT_INITIALIZE.
+                                                get(getExceptionMessage(nsae));
+          throw new DirectoryException(resCode, message, nsae);
+      } catch (KeyManagementException kme) {
+          if (debugEnabled())
+              TRACER.debugCaught(DebugLogLevel.ERROR, kme);
+          Message message = ERR_CONNHANDLER_SSL_CANNOT_INITIALIZE
+                                                 .get(getExceptionMessage(kme));
+          throw new DirectoryException(resCode, message, kme);
+      } catch (DirectoryException de) {
+          if (debugEnabled())
+              TRACER.debugCaught(DebugLogLevel.ERROR, de);
+          Message message = ERR_CONNHANDLER_SSL_CANNOT_INITIALIZE
+                                                 .get(getExceptionMessage(de));
+          throw new DirectoryException(resCode, message, de);
+      }
+  }
+
 }
diff --git a/opends/src/server/org/opends/server/protocols/ldap/LDAPControl.java b/opends/src/server/org/opends/server/protocols/ldap/LDAPControl.java
index e3aaace..b3fb484 100644
--- a/opends/src/server/org/opends/server/protocols/ldap/LDAPControl.java
+++ b/opends/src/server/org/opends/server/protocols/ldap/LDAPControl.java
@@ -25,55 +25,25 @@
  *      Copyright 2006-2008 Sun Microsystems, Inc.
  */
 package org.opends.server.protocols.ldap;
-import org.opends.messages.Message;
 
 
+import java.io.IOException;
 
-import java.util.ArrayList;
-
-import org.opends.server.protocols.asn1.ASN1Boolean;
-import org.opends.server.protocols.asn1.ASN1Element;
-import org.opends.server.protocols.asn1.ASN1OctetString;
-import org.opends.server.protocols.asn1.ASN1Sequence;
+import org.opends.server.protocols.asn1.*;
 import org.opends.server.types.Control;
-import org.opends.server.types.DebugLogLevel;
-import org.opends.server.types.LDAPException;
+import org.opends.server.types.ByteString;
 
-import static org.opends.server.loggers.debug.DebugLogger.*;
-import org.opends.server.loggers.debug.DebugTracer;
-import static org.opends.messages.ProtocolMessages.*;
-import static org.opends.server.protocols.asn1.ASN1Constants.*;
-import static org.opends.server.protocols.ldap.LDAPConstants.*;
-import static org.opends.server.protocols.ldap.LDAPResultCode.*;
 import static org.opends.server.util.ServerConstants.*;
 
 
-
 /**
  * This class defines the data structures and methods to use when interacting
- * with a generic LDAP control or set of controls.
+ * with a generic LDAP control.
  */
-public class LDAPControl
+public class LDAPControl extends Control
 {
-  /**
-   * The tracer object for the debug logger.
-   */
-  private static final DebugTracer TRACER = getTracer();
-
-  // The control wrapped by this LDAP control.
-  private Control control;
-
-
-
-  /**
-   * Creates a new LDAP control with the information in the provided control.
-   *
-   * @param  control  The control to use to create this LDAP control.
-   */
-  public LDAPControl(Control control)
-  {
-    this.control = control;
-  }
+  // The control value.
+  private ByteString value;
 
 
 
@@ -85,7 +55,7 @@
    */
   public LDAPControl(String oid)
   {
-    control = new Control(oid, false);
+    super(oid, false);
   }
 
 
@@ -100,7 +70,7 @@
    */
   public LDAPControl(String oid, boolean isCritical)
   {
-    control = new Control(oid, isCritical);
+    super(oid, isCritical);
   }
 
 
@@ -113,326 +83,46 @@
    *                     critical.
    * @param  value       The value for this LDAP control.
    */
-  public LDAPControl(String oid, boolean isCritical, ASN1OctetString value)
+  public LDAPControl(String oid, boolean isCritical, ByteString value)
   {
-    control = new Control(oid, isCritical, value);
+    super(oid, isCritical);
+    this.value = value;
   }
 
 
-
-  /**
-   * Retrieves the control wrapped by this LDAP control.
-   *
-   * @return  The control wrapped by this LDAP control.
-   */
-  public Control getControl()
-  {
-    return control;
-  }
-
-
-
-  /**
-   * Encodes this control to an ASN.1 element.
-   *
-   * @return  The ASN.1 element containing the encoded control.
-   */
-  public ASN1Element encode()
-  {
-    ArrayList<ASN1Element> elements = new ArrayList<ASN1Element>(3);
-    elements.add(new ASN1OctetString(control.getOID()));
-
-    if (control.isCritical())
-    {
-      elements.add(new ASN1Boolean(control.isCritical()));
-    }
-
-    ASN1OctetString value = control.getValue();
-    if (value != null)
-    {
-      elements.add(value);
-    }
-
-    return new ASN1Sequence(elements);
-  }
-
-
-
-  /**
-   * Encodes the provided set of controls into an ASN.1 sequence.
-   *
-   * @param  controls  The set of controls to encode.
-   *
-   * @return  The ASN.1 element containing the encoded set of controls.
-   */
-  public static ASN1Element encodeControls(ArrayList<LDAPControl> controls)
-  {
-    ArrayList<ASN1Element> elements =
-         new ArrayList<ASN1Element>(controls.size());
-    for (LDAPControl c : controls)
-    {
-      elements.add(c.encode());
-    }
-
-    return new ASN1Sequence(TYPE_CONTROL_SEQUENCE, elements);
-  }
-
-
-
-  /**
-   * Decodes the provided ASN.1 element as an LDAP control.
-   *
-   * @param  element  The ASN.1 element to decode.
-   *
-   * @return  The decoded LDAP control.
-   *
-   * @throws  LDAPException  If a problem occurs while attempting to decode the
-   *                         provided ASN.1 element as an LDAP control.
-   */
-  public static LDAPControl decode(ASN1Element element)
-         throws LDAPException
-  {
-    if (element == null)
-    {
-      Message message = ERR_LDAP_CONTROL_DECODE_NULL.get();
-      throw new LDAPException(PROTOCOL_ERROR, message);
-    }
-
-
-    ArrayList<ASN1Element> elements;
-    try
-    {
-      elements = element.decodeAsSequence().elements();
-    }
-    catch (Exception e)
-    {
-      if (debugEnabled())
-      {
-        TRACER.debugCaught(DebugLogLevel.ERROR, e);
-      }
-
-      Message message = ERR_LDAP_CONTROL_DECODE_SEQUENCE.get(String.valueOf(e));
-      throw new LDAPException(PROTOCOL_ERROR, message, e);
-    }
-
-
-    int numElements = elements.size();
-    if ((numElements < 1) || (numElements > 3))
-    {
-      Message message =
-          ERR_LDAP_CONTROL_DECODE_INVALID_ELEMENT_COUNT.get(numElements);
-      throw new LDAPException(PROTOCOL_ERROR, message);
-    }
-
-
-    String oid;
-    try
-    {
-      oid = elements.get(0).decodeAsOctetString().stringValue();
-    }
-    catch (Exception e)
-    {
-      if (debugEnabled())
-      {
-        TRACER.debugCaught(DebugLogLevel.ERROR, e);
-      }
-
-      Message message = ERR_LDAP_CONTROL_DECODE_OID.get(String.valueOf(e));
-      throw new LDAPException(PROTOCOL_ERROR, message, e);
-    }
-
-
-    if (numElements == 1)
-    {
-      return new LDAPControl(oid);
-    }
-    else if (numElements == 2)
-    {
-      boolean         isCritical;
-      ASN1OctetString value;
-
-      ASN1Element e = elements.get(1);
-      switch (e.getType())
-      {
-        case UNIVERSAL_BOOLEAN_TYPE:
-          value = null;
-
-          try
-          {
-            isCritical = e.decodeAsBoolean().booleanValue();
-          }
-          catch (Exception e2)
-          {
-            if (debugEnabled())
-            {
-              TRACER.debugCaught(DebugLogLevel.ERROR, e2);
-            }
-
-            Message message =
-                ERR_LDAP_CONTROL_DECODE_CRITICALITY.get(String.valueOf(e));
-            throw new LDAPException(PROTOCOL_ERROR, message, e2);
-          }
-          break;
-        case UNIVERSAL_OCTET_STRING_TYPE:
-          isCritical = false;
-
-          try
-          {
-            value = e.decodeAsOctetString();
-          }
-          catch (Exception e2)
-          {
-            if (debugEnabled())
-            {
-              TRACER.debugCaught(DebugLogLevel.ERROR, e2);
-            }
-
-            Message message =
-                ERR_LDAP_CONTROL_DECODE_VALUE.get(String.valueOf(e));
-            throw new LDAPException(PROTOCOL_ERROR, message, e2);
-          }
-          break;
-        default:
-          Message message =
-              ERR_LDAP_CONTROL_DECODE_INVALID_TYPE.get(e.getType());
-          throw new LDAPException(PROTOCOL_ERROR, message);
-      }
-
-      return new LDAPControl(oid, isCritical, value);
-    }
-    else
-    {
-      boolean isCritical;
-      try
-      {
-        isCritical = elements.get(1).decodeAsBoolean().booleanValue();
-      }
-      catch (Exception e)
-      {
-        if (debugEnabled())
-        {
-          TRACER.debugCaught(DebugLogLevel.ERROR, e);
-        }
-
-        Message message =
-            ERR_LDAP_CONTROL_DECODE_CRITICALITY.get(String.valueOf(e));
-        throw new LDAPException(PROTOCOL_ERROR, message, e);
-      }
-
-      ASN1OctetString value;
-      try
-      {
-        value = elements.get(2).decodeAsOctetString();
-      }
-      catch (Exception e)
-      {
-        if (debugEnabled())
-        {
-          TRACER.debugCaught(DebugLogLevel.ERROR, e);
-        }
-
-        Message message = ERR_LDAP_CONTROL_DECODE_VALUE.get(String.valueOf(e));
-        throw new LDAPException(PROTOCOL_ERROR, message, e);
-      }
-
-      return new LDAPControl(oid, isCritical, value);
-    }
-  }
-
-
-
-  /**
-   * Decodes the provided ASN.1 element as a set of controls.
-   *
-   * @param  element  The ASN.1 element containing the encoded set of controls.
-   *
-   * @return  The decoded set of controls.
-   *
-   * @throws  LDAPException  If a problem occurs while attempting to decode the
-   *                         controls.
-   */
-  public static ArrayList<LDAPControl> decodeControls(ASN1Element element)
-         throws LDAPException
-  {
-    if (element == null)
-    {
-      Message message = ERR_LDAP_CONTROL_DECODE_CONTROLS_NULL.get();
-      throw new LDAPException(PROTOCOL_ERROR, message);
-    }
-
-
-    ArrayList<ASN1Element> elements;
-    try
-    {
-      elements = element.decodeAsSequence().elements();
-    }
-    catch (Exception e)
-    {
-      Message message =
-          ERR_LDAP_CONTROL_DECODE_CONTROLS_SEQUENCE.get(String.valueOf(e));
-      throw new LDAPException(PROTOCOL_ERROR, message, e);
-    }
-
-
-    ArrayList<LDAPControl> controls =
-         new ArrayList<LDAPControl>(elements.size());
-    for (ASN1Element e : elements)
-    {
-      controls.add(decode(e));
-    }
-
-    return controls;
-  }
-
-
-
-  /**
-   * Retrieves the OID for this control.
-   *
-   * @return  The OID for this control.
-   */
-  public String getOID()
-  {
-    return control.getOID();
-  }
-
-
-
-  /**
-   * Indicates whether this control should be considered critical.
-   *
-   * @return  <CODE>true</CODE> if this control should be considered critical,
-   *          or <CODE>false</CODE> if not.
-   */
-  public boolean isCritical()
-  {
-    return control.isCritical();
-  }
-
-
-
   /**
    * Retrieves the value for this control.
    *
-   * @return  The value for this control, or <CODE>null</CODE> if there is none.
+   * @return  The value for this control, or <CODE>null</CODE> if
+   *          there is no value.
    */
-  public ASN1OctetString getValue()
+  public final ByteString getValue()
   {
-    return control.getValue();
+    return value;
   }
 
 
 
   /**
-   * Retrieves a string representation of this LDAP control.
+   * Indicates whether this control has a value.
    *
-   * @return  A string representation of this LDAP control.
+   * @return  <CODE>true</CODE> if this control has a value, or
+   *          <CODE>false</CODE> if it does not.
    */
-  public String toString()
+  public final boolean hasValue()
   {
-    StringBuilder buffer = new StringBuilder();
-    toString(buffer);
-    return buffer.toString();
+    return (value != null);
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  public void writeValue(ASN1Writer stream) throws IOException
+  {
+    if (value != null)
+    {
+      stream.writeOctetString(value);
+    }
   }
 
 
@@ -446,15 +136,14 @@
   public void toString(StringBuilder buffer)
   {
     buffer.append("LDAPControl(oid=");
-    buffer.append(control.getOID());
+    buffer.append(getOID());
     buffer.append(", criticality=");
-    buffer.append(control.isCritical());
+    buffer.append(isCritical());
 
-    ASN1OctetString value = control.getValue();
     if (value != null)
     {
       buffer.append(", value=");
-      buffer.append(String.valueOf(value));
+      value.toHexPlusAscii(buffer, 4);
     }
 
     buffer.append(")");
@@ -483,20 +172,19 @@
 
     buffer.append(indentBuf);
     buffer.append("  OID:  ");
-    buffer.append(control.getOID());
+    buffer.append(getOID());
     buffer.append(EOL);
 
     buffer.append(indentBuf);
     buffer.append("  Criticality:  ");
-    buffer.append(control.isCritical());
+    buffer.append(isCritical());
     buffer.append(EOL);
 
-    ASN1OctetString value = control.getValue();
     if (value != null)
     {
       buffer.append(indentBuf);
       buffer.append("  Value:");
-      value.toString(buffer, indent+4);
+      value.toHexPlusAscii(buffer, indent+4);
     }
   }
 }
diff --git a/opends/src/server/org/opends/server/protocols/ldap/LDAPFilter.java b/opends/src/server/org/opends/server/protocols/ldap/LDAPFilter.java
index 36942ff..eec8b18 100644
--- a/opends/src/server/org/opends/server/protocols/ldap/LDAPFilter.java
+++ b/opends/src/server/org/opends/server/protocols/ldap/LDAPFilter.java
@@ -28,8 +28,6 @@
 import org.opends.messages.Message;
 
 
-
-import java.nio.ByteBuffer;
 import java.util.ArrayList;
 import java.util.HashSet;
 import java.util.LinkedList;
@@ -39,17 +37,7 @@
 
 import org.opends.server.api.MatchingRule;
 import org.opends.server.core.DirectoryServer;
-import org.opends.server.protocols.asn1.ASN1OctetString;
-import org.opends.server.types.AttributeType;
-import org.opends.server.types.AttributeValue;
-import org.opends.server.types.ByteString;
-import org.opends.server.types.DebugLogLevel;
-import org.opends.server.types.DirectoryException;
-import org.opends.server.types.FilterType;
-import org.opends.server.types.LDAPException;
-import org.opends.server.types.RawFilter;
-import org.opends.server.types.ResultCode;
-import org.opends.server.types.SearchFilter;
+import org.opends.server.types.*;
 
 import static org.opends.server.loggers.debug.DebugLogger.*;
 import org.opends.server.loggers.debug.DebugTracer;
@@ -189,8 +177,7 @@
       case LESS_OR_EQUAL:
       case APPROXIMATE_MATCH:
         attributeType  = filter.getAttributeType().getNameOrOID();
-        assertionValue =
-             filter.getAssertionValue().getValue().toASN1OctetString();
+        assertionValue = filter.getAssertionValue().getValue();
 
         filterComponents  = null;
         notComponent      = null;
@@ -210,7 +197,7 @@
         }
         else
         {
-          subInitialElement = bs.toASN1OctetString();
+          subInitialElement = bs;
         }
 
         bs = filter.getSubFinalElement();
@@ -220,7 +207,7 @@
         }
         else
         {
-          subFinalElement = bs.toASN1OctetString();
+          subFinalElement = bs;
         }
 
         List<ByteString> subAnyStrings = filter.getSubAnyElements();
@@ -272,7 +259,7 @@
         }
         else
         {
-          assertionValue = av.getValue().toASN1OctetString();
+          assertionValue = av.getValue();
         }
 
         filterComponents  = null;
@@ -569,7 +556,7 @@
     if (valueStr.length() == 0)
     {
       return new LDAPFilter(filterType, null, null, attrType,
-                            new ASN1OctetString(), null, null, null, null,
+                            ByteString.empty(), null, null, null, null,
                             false);
     }
     else if (valueStr.equals("*"))
@@ -594,10 +581,11 @@
         }
       }
 
-      ASN1OctetString  value;
+      ByteString value;
       if (hasEscape)
       {
-        ByteBuffer valueBuffer = ByteBuffer.allocate(valueStr.length());
+        ByteStringBuilder valueBuffer =
+            new ByteStringBuilder(valueStr.length());
         for (int i=0; i < valueBytes.length; i++)
         {
           if (valueBytes[i] == 0x5C) // The backslash character
@@ -734,22 +722,19 @@
                 throw new LDAPException(LDAPResultCode.PROTOCOL_ERROR, message);
             }
 
-            valueBuffer.put(byteValue);
+            valueBuffer.append(byteValue);
           }
           else
           {
-            valueBuffer.put(valueBytes[i]);
+            valueBuffer.append(valueBytes[i]);
           }
         }
 
-        valueBytes = new byte[valueBuffer.position()];
-        valueBuffer.flip();
-        valueBuffer.get(valueBytes);
-        value = new ASN1OctetString(valueBytes);
+        value = valueBuffer.toByteString();
       }
       else
       {
-        value = new ASN1OctetString(valueBytes);
+        value = ByteString.wrap(valueBytes);
       }
 
       return new LDAPFilter(filterType, null, null, attrType, value, null, null,
@@ -954,7 +939,7 @@
     {
       if (hasEscape)
       {
-        ByteBuffer buffer = ByteBuffer.allocate(firstPos);
+        ByteStringBuilder buffer = new ByteStringBuilder(firstPos);
         for (int i=0; i < firstPos; i++)
         {
           if (valueBytes[i] == 0x5C)
@@ -1091,24 +1076,19 @@
                 throw new LDAPException(LDAPResultCode.PROTOCOL_ERROR, message);
             }
 
-            buffer.put(byteValue);
+            buffer.append(byteValue);
           }
           else
           {
-            buffer.put(valueBytes[i]);
+            buffer.append(valueBytes[i]);
           }
         }
 
-        byte[] subInitialBytes = new byte[buffer.position()];
-        buffer.flip();
-        buffer.get(subInitialBytes);
-        subInitial = new ASN1OctetString(subInitialBytes);
+        subInitial = buffer.toByteString();
       }
       else
       {
-        byte[] subInitialBytes = new byte[firstPos];
-        System.arraycopy(valueBytes, 0, subInitialBytes, 0, firstPos);
-        subInitial = new ASN1OctetString(subInitialBytes);
+        subInitial = ByteString.wrap(valueBytes, 0, firstPos);
       }
     }
 
@@ -1121,7 +1101,7 @@
 
       if (hasEscape)
       {
-        ByteBuffer buffer = ByteBuffer.allocate(length);
+        ByteStringBuilder buffer = new ByteStringBuilder(length);
         for (int i=firstPos+1; i < asteriskPos; i++)
         {
           if (valueBytes[i] == 0x5C)
@@ -1258,24 +1238,20 @@
                 throw new LDAPException(LDAPResultCode.PROTOCOL_ERROR, message);
             }
 
-            buffer.put(byteValue);
+            buffer.append(byteValue);
           }
           else
           {
-            buffer.put(valueBytes[i]);
+            buffer.append(valueBytes[i]);
           }
         }
 
-        byte[] subAnyBytes = new byte[buffer.position()];
-        buffer.flip();
-        buffer.get(subAnyBytes);
-        subAny.add(new ASN1OctetString(subAnyBytes));
+        subAny.add(buffer.toByteString());
+        buffer.clear();
       }
       else
       {
-        byte[] subAnyBytes = new byte[length];
-        System.arraycopy(valueBytes, firstPos+1, subAnyBytes, 0, length);
-        subAny.add(new ASN1OctetString(subAnyBytes));
+        subAny.add(ByteString.wrap(valueBytes, firstPos+1, length));
       }
 
 
@@ -1296,7 +1272,7 @@
 
       if (hasEscape)
       {
-        ByteBuffer buffer = ByteBuffer.allocate(length);
+        ByteStringBuilder buffer = new ByteStringBuilder(length);
         for (int i=firstPos+1; i < valueBytes.length; i++)
         {
           if (valueBytes[i] == 0x5C)
@@ -1433,24 +1409,19 @@
                 throw new LDAPException(LDAPResultCode.PROTOCOL_ERROR, message);
             }
 
-            buffer.put(byteValue);
+            buffer.append(byteValue);
           }
           else
           {
-            buffer.put(valueBytes[i]);
+            buffer.append(valueBytes[i]);
           }
         }
 
-        byte[] subFinalBytes = new byte[buffer.position()];
-        buffer.flip();
-        buffer.get(subFinalBytes);
-        subFinal = new ASN1OctetString(subFinalBytes);
+        subFinal = buffer.toByteString();
       }
       else
       {
-        byte[] subFinalBytes = new byte[length];
-        System.arraycopy(valueBytes, firstPos+1, subFinalBytes, 0, length);
-        subFinal = new ASN1OctetString(subFinalBytes);
+        subFinal = ByteString.wrap(valueBytes, firstPos+1, length);
       }
     }
 
@@ -1563,7 +1534,7 @@
     ByteString value;
     if (hasEscape)
     {
-      ByteBuffer valueBuffer = ByteBuffer.allocate(valueBytes.length);
+      ByteStringBuilder valueBuffer = new ByteStringBuilder(valueBytes.length);
       for (int i=0; i < valueBytes.length; i++)
       {
         if (valueBytes[i] == 0x5C) // The backslash character
@@ -1700,22 +1671,19 @@
               throw new LDAPException(LDAPResultCode.PROTOCOL_ERROR, message);
           }
 
-          valueBuffer.put(byteValue);
+          valueBuffer.append(byteValue);
         }
         else
         {
-          valueBuffer.put(valueBytes[i]);
+          valueBuffer.append(valueBytes[i]);
         }
       }
 
-      valueBytes = new byte[valueBuffer.position()];
-      valueBuffer.flip();
-      valueBuffer.get(valueBytes);
-      value = new ASN1OctetString(valueBytes);
+      value = valueBuffer.toByteString();
     }
     else
     {
-      value = new ASN1OctetString(valueBytes);
+      value = ByteString.wrap(valueBytes);
     }
 
 
@@ -1763,20 +1731,6 @@
 
 
   /**
-   * Specifies the set of subordinate filter components for AND or OR searches.
-   * This will be ignored for all other filter types.
-   *
-   * @param  filterComponents  The set of subordinate filter components for AND
-   *                           or OR searches.
-   */
-  public void setFilterComponents(ArrayList<RawFilter> filterComponents)
-  {
-    this.filterComponents = filterComponents;
-  }
-
-
-
-  /**
    * Retrieves the subordinate filter component for NOT searches.
    *
    * @return  The subordinate filter component for NOT searches, or
@@ -1790,19 +1744,6 @@
 
 
   /**
-   * Specifies the subordinate filter component for NOT searches.  This will be
-   * ignored for any other type of search.
-   *
-   * @param  notComponent  The subordinate filter component for NOT searches.
-   */
-  public void setNOTComponent(RawFilter notComponent)
-  {
-    this.notComponent = notComponent;
-  }
-
-
-
-  /**
    * Retrieves the attribute type for this search filter.  This will not be
    * applicable for AND, OR, or NOT filters.
    *
@@ -1817,19 +1758,6 @@
 
 
   /**
-   * Specifies the attribute type for this search filter.  This will be ignored
-   * for AND, OR, and NOT searches.
-   *
-   * @param  attributeType  The attribute type for this search filter.
-   */
-  public void setAttributeType(String attributeType)
-  {
-    this.attributeType = attributeType;
-  }
-
-
-
-  /**
    * Retrieves the assertion value for this search filter.  This will only be
    * applicable for equality, greater or equal, less or equal, approximate, or
    * extensible matching filters.
@@ -1845,19 +1773,6 @@
 
 
   /**
-   * Specifies the assertion value for this search filter.  This will be ignored
-   * for types of filters that do not have an assertion value.
-   *
-   * @param  assertionValue  The assertion value for this search filter.
-   */
-  public void setAssertionValue(ByteString assertionValue)
-  {
-    this.assertionValue = assertionValue;
-  }
-
-
-
-  /**
    * Retrieves the subInitial component for this substring filter.  This is only
    * applicable for substring search filters, but even substring filters might
    * not have a value for this component.
@@ -1902,20 +1817,6 @@
 
 
   /**
-   * Specifies the set of subAny values for this substring filter.  This will be
-   * ignored for other filter types.
-   *
-   * @param  subAnyElements  The set of subAny elements for this substring
-   *                         filter.
-   */
-  public void setSubAnyElements(ArrayList<ByteString> subAnyElements)
-  {
-    this.subAnyElements = subAnyElements;
-  }
-
-
-
-  /**
    * Retrieves the subFinal element for this substring filter.  This is not
    * applicable for any other filter type, and may not be provided even for some
    * substring filters.
@@ -1931,19 +1832,6 @@
 
 
   /**
-   * Specifies the subFinal element for this substring filter.  This will be
-   * ignored for all other filter types.
-   *
-   * @param  subFinalElement  The subFinal element for this substring filter.
-   */
-  public void setSubFinalElement(ByteString subFinalElement)
-  {
-    this.subFinalElement = subFinalElement;
-  }
-
-
-
-  /**
    * Retrieves the matching rule ID for this extensible match filter.  This is
    * not applicable for any other type of filter and may not be included in
    * some extensible matching filters.
@@ -1959,20 +1847,6 @@
 
 
   /**
-   * Specifies the matching rule ID for this extensible match filter.  It will
-   * be ignored for all other filter types.
-   *
-   * @param  matchingRuleID  The matching rule ID for this extensible match
-   *                         filter.
-   */
-  public void setMatchingRuleID(String matchingRuleID)
-  {
-    this.matchingRuleID = matchingRuleID;
-  }
-
-
-
-  /**
    * Retrieves the value of the DN attributes flag for this extensible match
    * filter, which indicates whether to perform matching on the components of
    * the DN.  This does not apply for any other type of filter.
@@ -1988,20 +1862,6 @@
 
 
   /**
-   * Specifies the value of the DN attributes flag for this extensible match
-   * filter.  It will be ignored for all other filter types.
-   *
-   * @param  dnAttributes  The value of the DN attributes flag for this
-   *                       extensible match filter.
-   */
-  public void setDNAttributes(boolean dnAttributes)
-  {
-    this.dnAttributes = dnAttributes;
-  }
-
-
-
-  /**
    * Converts this LDAP filter to a search filter that may be used by the
    * Directory Server's core processing.
    *
@@ -2105,13 +1965,14 @@
         else
         {
           ByteString normalizedValue = mr.normalizeValue(assertionValue);
-          value = new AttributeValue(assertionValue, normalizedValue);
+          value = AttributeValues.create(assertionValue,
+              normalizedValue);
         }
       }
     }
     else
     {
-      value = new AttributeValue(attrType, assertionValue);
+      value = AttributeValues.create(attrType, assertionValue);
     }
 
 
diff --git a/opends/src/server/org/opends/server/protocols/ldap/LDAPMessage.java b/opends/src/server/org/opends/server/protocols/ldap/LDAPMessage.java
index 4c3838f..7aefadb 100644
--- a/opends/src/server/org/opends/server/protocols/ldap/LDAPMessage.java
+++ b/opends/src/server/org/opends/server/protocols/ldap/LDAPMessage.java
@@ -25,24 +25,19 @@
  *      Copyright 2006-2008 Sun Microsystems, Inc.
  */
 package org.opends.server.protocols.ldap;
-import org.opends.messages.Message;
-
 
 
 import java.util.ArrayList;
 import java.util.Iterator;
+import java.util.List;
+import java.io.IOException;
 
 import org.opends.server.api.ProtocolElement;
-import org.opends.server.protocols.asn1.ASN1Element;
-import org.opends.server.protocols.asn1.ASN1Integer;
-import org.opends.server.protocols.asn1.ASN1Sequence;
-import org.opends.server.types.DebugLogLevel;
-import org.opends.server.types.LDAPException;
+import org.opends.server.protocols.asn1.*;
+import org.opends.server.types.Control;
 
-import static org.opends.server.loggers.debug.DebugLogger.*;
-import org.opends.server.loggers.debug.DebugTracer;
-import static org.opends.messages.ProtocolMessages.*;
-import static org.opends.server.protocols.ldap.LDAPResultCode.*;
+import static org.opends.server.protocols.ldap.LDAPConstants.
+    TYPE_CONTROL_SEQUENCE;
 import static org.opends.server.util.ServerConstants.*;
 
 
@@ -54,16 +49,11 @@
 public class LDAPMessage
        implements ProtocolElement
 {
-  /**
-   * The tracer object for the debug logger.
-   */
-  private static final DebugTracer TRACER = getTracer();
-
   // The set of controls for this LDAP message.
-  private ArrayList<LDAPControl> controls;
+  private List<Control> controls;
 
   // The message ID for this LDAP message.
-  private int messageID;
+  private final int messageID;
 
   // The protocol op for this LDAP message.
   private ProtocolOp protocolOp;
@@ -82,7 +72,7 @@
     this.messageID  = messageID;
     this.protocolOp = protocolOp;
 
-    controls = new ArrayList<LDAPControl>(0);
+    controls = new ArrayList<Control>(0);
   }
 
 
@@ -96,14 +86,14 @@
    * @param  controls    The set of controls for this LDAP message.
    */
   public LDAPMessage(int messageID, ProtocolOp protocolOp,
-                     ArrayList<LDAPControl> controls)
+                     List<Control> controls)
   {
     this.messageID  = messageID;
     this.protocolOp = protocolOp;
 
     if (controls == null)
     {
-      this.controls = new ArrayList<LDAPControl>(0);
+      this.controls = new ArrayList<Control>(0);
     }
     else
     {
@@ -126,18 +116,6 @@
 
 
   /**
-   * Specifies the message ID for this LDAP message.
-   *
-   * @param  messageID  The message ID for this LDAP message.
-   */
-  public void setMessageID(int messageID)
-  {
-    this.messageID = messageID;
-  }
-
-
-
-  /**
    * Retrieves the protocol op for this LDAP message.
    *
    * @return  The protocol op for this LDAP message.
@@ -551,125 +529,31 @@
    *
    * @return  The set of controls for this LDAP message.
    */
-  public ArrayList<LDAPControl> getControls()
+  public List<Control> getControls()
   {
     return controls;
   }
 
-
-
   /**
-   * Encodes this LDAP message to an ASN.1 element.
+   * Writes this protocol op to an ASN.1 output stream.
    *
-   * @return  The ASN.1 element containing the encoded LDAP message.
+   * @param stream The ASN.1 output stream to write to.
+   * @throws IOException If a problem occurs while writing to the stream.
    */
-  public ASN1Element encode()
+  public void write(ASN1Writer stream) throws IOException
   {
-    ArrayList<ASN1Element> messageElements = new ArrayList<ASN1Element>(3);
-    messageElements.add(new ASN1Integer(messageID));
-    messageElements.add(protocolOp.encode());
+    stream.writeStartSequence();
+    stream.writeInteger(messageID);
+    protocolOp.write(stream);
 
-    if (! controls.isEmpty())
+    stream.writeStartSequence(TYPE_CONTROL_SEQUENCE);
+    for(Control control : controls)
     {
-      messageElements.add(LDAPControl.encodeControls(controls));
+      control.write(stream);
     }
+    stream.writeEndSequence();
 
-    return new ASN1Sequence(messageElements);
-  }
-
-
-
-  /**
-   * Decodes the provided ASN.1 sequence as an LDAP message.
-   *
-   * @param  messageSequence  The ASN.1 sequence to decode as an LDAP message.
-   *
-   * @return  The decoded LDAP message.
-   *
-   * @throws  LDAPException  If a problem occurs while attempting to decode the
-   *                         LDAP message.
-   */
-  public static LDAPMessage decode(ASN1Sequence messageSequence)
-         throws LDAPException
-  {
-    if (messageSequence == null)
-    {
-      Message message = ERR_LDAP_MESSAGE_DECODE_NULL.get();
-      throw new LDAPException(PROTOCOL_ERROR, message);
-    }
-
-    ArrayList<ASN1Element> elements = messageSequence.elements();
-    int numElements = elements.size();
-    if ((numElements < 2) || (numElements > 3))
-    {
-      Message message =
-          ERR_LDAP_MESSAGE_DECODE_INVALID_ELEMENT_COUNT.get(numElements);
-      throw new LDAPException(PROTOCOL_ERROR, message);
-    }
-
-
-    int messageID;
-    try
-    {
-      messageID = elements.get(0).decodeAsInteger().intValue();
-    }
-    catch (Exception e)
-    {
-      if (debugEnabled())
-      {
-        TRACER.debugCaught(DebugLogLevel.ERROR, e);
-      }
-
-      Message message =
-          ERR_LDAP_MESSAGE_DECODE_MESSAGE_ID.get(String.valueOf(e));
-      throw new LDAPException(PROTOCOL_ERROR, message, e);
-    }
-
-
-    ProtocolOp protocolOp;
-    try
-    {
-      protocolOp = ProtocolOp.decode(elements.get(1));
-    }
-    catch (Exception e)
-    {
-      if (debugEnabled())
-      {
-        TRACER.debugCaught(DebugLogLevel.ERROR, e);
-      }
-
-      Message message =
-          ERR_LDAP_MESSAGE_DECODE_PROTOCOL_OP.get(String.valueOf(e));
-      throw new LDAPException(PROTOCOL_ERROR, message, e);
-    }
-
-
-    ArrayList<LDAPControl> controls;
-    if (numElements == 3)
-    {
-      try
-      {
-        controls = LDAPControl.decodeControls(elements.get(2));
-      }
-      catch (Exception e)
-      {
-        if (debugEnabled())
-        {
-          TRACER.debugCaught(DebugLogLevel.ERROR, e);
-        }
-
-        Message message =
-            ERR_LDAP_MESSAGE_DECODE_CONTROLS.get(String.valueOf(e));
-        throw new LDAPException(PROTOCOL_ERROR, message, e);
-      }
-    }
-    else
-    {
-      controls = new ArrayList<LDAPControl>(0);
-    }
-
-
-    return new LDAPMessage(messageID, protocolOp, controls);
+    stream.writeEndSequence();
   }
 
 
@@ -691,6 +575,7 @@
    *
    * @return  A string representation of this LDAP message.
    */
+  @Override
   public String toString()
   {
     StringBuilder buffer = new StringBuilder();
@@ -722,7 +607,7 @@
     {
       buffer.append(", controls={ ");
 
-      Iterator<LDAPControl> iterator = controls.iterator();
+      Iterator<Control> iterator = controls.iterator();
       iterator.next().toString(buffer);
 
       while (iterator.hasNext())
@@ -775,9 +660,10 @@
       buffer.append(indentBuf);
       buffer.append("  Controls:");
 
-      for (LDAPControl c : controls)
+      for (Control c : controls)
       {
-        c.toString(buffer, indent+4);
+        // TODO: Indent
+        c.toString(buffer);//, indent+4);
       }
     }
   }
diff --git a/opends/src/server/org/opends/server/protocols/ldap/LDAPReader.java b/opends/src/server/org/opends/server/protocols/ldap/LDAPReader.java
new file mode 100644
index 0000000..c00c468
--- /dev/null
+++ b/opends/src/server/org/opends/server/protocols/ldap/LDAPReader.java
@@ -0,0 +1,2977 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License").  You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE
+ * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
+ * add the following below this CDDL 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.server.protocols.ldap;
+
+import org.opends.server.protocols.asn1.ASN1Reader;
+import org.opends.server.protocols.asn1.ASN1Exception;
+import org.opends.server.types.*;
+import org.opends.server.loggers.debug.DebugTracer;
+import org.opends.messages.Message;
+
+import static org.opends.messages.ProtocolMessages.*;
+import static org.opends.server.protocols.asn1.ASN1Constants.*;
+import static org.opends.server.protocols.ldap.LDAPResultCode.*;
+import static org.opends.server.protocols.ldap.LDAPConstants.*;
+
+import static org.opends.server.loggers.debug.DebugLogger.debugEnabled;
+import static org.opends.server.loggers.debug.DebugLogger.getTracer;
+import static org.opends.server.util.StaticUtils.byteToHex;
+
+import java.util.ArrayList;
+import java.util.LinkedHashSet;
+import java.util.LinkedList;
+
+
+/**
+ * Utility class used to decode LDAP messages from an ASN1Reader.
+ */
+public class LDAPReader
+{
+  /**
+   * The tracer object for the debug logger.
+   */
+  private static final DebugTracer TRACER = getTracer();
+
+  /**
+   * Decodes the elements from the provided ASN.1 reader as an LDAP message.
+   *
+   * @param reader The ASN.1 reader.
+   *
+   * @return  The decoded LDAP message.
+   *
+   * @throws  LDAPException  If a problem occurs while attempting to decode the
+   *                         LDAP message.
+   */
+  public static LDAPMessage readMessage(ASN1Reader reader)
+      throws LDAPException
+  {
+    try
+    {
+      reader.readStartSequence();
+    }
+    catch(Exception e)
+    {
+      Message message = ERR_LDAP_MESSAGE_DECODE_NULL.get();
+      throw new LDAPException(PROTOCOL_ERROR, message);
+    }
+
+    int messageID;
+    try
+    {
+      messageID = (int)reader.readInteger();
+    }
+    catch(Exception e)
+    {
+      if (debugEnabled())
+      {
+        TRACER.debugCaught(DebugLogLevel.ERROR, e);
+      }
+
+      Message message =
+          ERR_LDAP_MESSAGE_DECODE_MESSAGE_ID.get(String.valueOf(e));
+      throw new LDAPException(PROTOCOL_ERROR, message, e);
+    }
+
+    ProtocolOp protocolOp;
+    try
+    {
+      protocolOp = readProtocolOp(reader);
+    }
+    catch (Exception e)
+    {
+      if (debugEnabled())
+      {
+        TRACER.debugCaught(DebugLogLevel.ERROR, e);
+      }
+
+      Message message =
+          ERR_LDAP_MESSAGE_DECODE_PROTOCOL_OP.get(String.valueOf(e));
+      throw new LDAPException(PROTOCOL_ERROR, message, e);
+    }
+
+    ArrayList<Control> controls = null;
+    try
+    {
+      if(reader.hasNextElement())
+      {
+        controls = readControls(reader);
+      }
+    }
+    catch (Exception e)
+    {
+      if (debugEnabled())
+      {
+        TRACER.debugCaught(DebugLogLevel.ERROR, e);
+      }
+
+      Message message =
+          ERR_LDAP_MESSAGE_DECODE_CONTROLS.get(String.valueOf(e));
+      throw new LDAPException(PROTOCOL_ERROR, message, e);
+    }
+
+    try
+    {
+      reader.readEndSequence();
+    }
+    catch(Exception e)
+    {
+      Message message = ERR_LDAP_MESSAGE_DECODE_NULL.get();
+      throw new LDAPException(PROTOCOL_ERROR, message);
+    }
+
+    return new LDAPMessage(messageID, protocolOp, controls);
+  }
+
+  /**
+   * Decodes the elements from the provided ASN.1 reader as an LDAP
+   * protocol op.
+   *
+   * @param reader The ASN.1 reader.
+   *
+   * @return  The LDAP protocol op decoded from the provided ASN.1 element.
+   *
+   * @throws  LDAPException  If a problem occurs while trying to decode the
+   *                         provided ASN.1 elements as an LDAP protocol op.
+   */
+  public static ProtocolOp readProtocolOp(ASN1Reader reader)
+      throws LDAPException
+  {
+    byte type;
+    try
+    {
+      type = reader.peekType();
+    }
+    catch(Exception e)
+    {
+      Message message = ERR_LDAP_PROTOCOL_OP_DECODE_NULL.get();
+      throw new LDAPException(PROTOCOL_ERROR, message);
+    }
+
+    switch(type)
+    {
+      case OP_TYPE_UNBIND_REQUEST:                                       // 0x42
+        return readUnbindRequest(reader);
+      case 0x43:                                                         // 0x43
+      case 0x44:                                                         // 0x44
+      case 0x45:                                                         // 0x45
+      case 0x46:                                                         // 0x46
+      case 0x47:                                                         // 0x47
+      case 0x48:                                                         // 0x48
+      case 0x49:                                                         // 0x49
+        Message message =
+            ERR_LDAP_PROTOCOL_OP_DECODE_INVALID_TYPE.get(type);
+        throw new LDAPException(PROTOCOL_ERROR, message);
+      case OP_TYPE_DELETE_REQUEST:                                       // 0x4A
+        return readDeleteRequest(reader);
+      case 0x4B:                                                         // 0x4B
+      case 0x4C:                                                         // 0x4C
+      case 0x4D:                                                         // 0x4D
+      case 0x4E:                                                         // 0x4E
+      case 0x4F:                                                         // 0x4F
+        message =
+            ERR_LDAP_PROTOCOL_OP_DECODE_INVALID_TYPE.get(type);
+        throw new LDAPException(PROTOCOL_ERROR, message);
+      case OP_TYPE_ABANDON_REQUEST:                                      // 0x50
+        return readAbandonRequest(reader);
+      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
+        message =
+            ERR_LDAP_PROTOCOL_OP_DECODE_INVALID_TYPE.get(type);
+        throw new LDAPException(PROTOCOL_ERROR, message);
+      case OP_TYPE_BIND_REQUEST:                                         // 0x60
+        return readBindRequest(reader);
+      case OP_TYPE_BIND_RESPONSE:                                        // 0x61
+        return readBindResponse(reader);
+      case 0x62:                                                         // 0x62
+        message =
+            ERR_LDAP_PROTOCOL_OP_DECODE_INVALID_TYPE.get(type);
+        throw new LDAPException(PROTOCOL_ERROR, message);
+      case OP_TYPE_SEARCH_REQUEST:                                       // 0x63
+        return readSearchRequest(reader);
+      case OP_TYPE_SEARCH_RESULT_ENTRY:                                  // 0x64
+        return readSearchEntry(reader);
+      case OP_TYPE_SEARCH_RESULT_DONE:                                   // 0x65
+        return readSearchDone(reader);
+      case OP_TYPE_MODIFY_REQUEST:                                       // 0x66
+        return readModifyRequest(reader);
+      case OP_TYPE_MODIFY_RESPONSE:                                      // 0x67
+        return readModifyResponse(reader);
+      case OP_TYPE_ADD_REQUEST:                                          // 0x68
+        return readAddRequest(reader);
+      case OP_TYPE_ADD_RESPONSE:                                         // 0x69
+        return readAddResponse(reader);
+      case 0x6A:                                                         // 0x6A
+        message =
+            ERR_LDAP_PROTOCOL_OP_DECODE_INVALID_TYPE.get(type);
+        throw new LDAPException(PROTOCOL_ERROR, message);
+      case OP_TYPE_DELETE_RESPONSE:                                      // 0x6B
+        return readDeleteResponse(reader);
+      case OP_TYPE_MODIFY_DN_REQUEST:                                    // 0x6C
+        return readModifyDNRequest(reader);
+      case OP_TYPE_MODIFY_DN_RESPONSE:                                   // 0x6D
+        return readModifyDNResponse(reader);
+      case OP_TYPE_COMPARE_REQUEST:                                      // 0x6E
+        return readCompareRequest(reader);
+      case OP_TYPE_COMPARE_RESPONSE:                                     // 0x6F
+        return readCompareResponse(reader);
+      case 0x70:                                                         // 0x70
+      case 0x71:                                                         // 0x71
+      case 0x72:                                                         // 0x72
+        message =
+            ERR_LDAP_PROTOCOL_OP_DECODE_INVALID_TYPE.get(type);
+        throw new LDAPException(PROTOCOL_ERROR, message);
+      case OP_TYPE_SEARCH_RESULT_REFERENCE:                              // 0x73
+        return readSearchReference(reader);
+      case 0x74:                                                         // 0x74
+      case 0x75:                                                         // 0x75
+      case 0x76:                                                         // 0x76
+        message =
+            ERR_LDAP_PROTOCOL_OP_DECODE_INVALID_TYPE.get(type);
+        throw new LDAPException(PROTOCOL_ERROR, message);
+      case OP_TYPE_EXTENDED_REQUEST:                                     // 0x77
+        return readExtendedRequest(reader);
+      case OP_TYPE_EXTENDED_RESPONSE:                                    // 0x78
+        return readExtendedResponse(reader);
+      case OP_TYPE_INTERMEDIATE_RESPONSE:                                // 0x79
+        return
+            readIntermediateResponse(reader);
+      default:
+        message =
+            ERR_LDAP_PROTOCOL_OP_DECODE_INVALID_TYPE.get(type);
+        throw new LDAPException(PROTOCOL_ERROR, message);
+    }
+  }
+
+
+  /**
+   * Decodes the elements from the provided ASN.1 read as an LDAP
+   *  abandon request protocol op.
+   *
+   * @param  reader The ASN.1 reader.
+   *
+   * @return  The decoded abandon request protocol op.
+   *
+   * @throws  LDAPException  If the provided ASN.1 element cannot be decoded as
+   *                         an abandon request protocol op.
+   */
+  private static AbandonRequestProtocolOp readAbandonRequest(ASN1Reader reader)
+      throws LDAPException
+  {
+    long idToAbandon;
+    try
+    {
+      idToAbandon = reader.readInteger();
+    }
+    catch (Exception e)
+    {
+      if (debugEnabled())
+      {
+        TRACER.debugCaught(DebugLogLevel.ERROR, e);
+      }
+
+      Message message =
+          ERR_LDAP_ABANDON_REQUEST_DECODE_ID.get(String.valueOf(e));
+      throw new LDAPException(PROTOCOL_ERROR, message, e);
+    }
+
+    return new AbandonRequestProtocolOp((int)idToAbandon);
+  }
+
+  /**
+   * Decodes the elements from the provided ASN.1 reader as an LDAP
+   * add request protocol op.
+   *
+   * @param  reader The ASN.1 reader.
+   *
+   * @return  The decoded add request protocol op.
+   *
+   * @throws  LDAPException  If a problem occurs while decoding the provided
+   *                         ASN.1 element as an LDAP add request protocol op.
+   */
+  private static AddRequestProtocolOp readAddRequest(ASN1Reader reader)
+      throws LDAPException
+  {
+    try
+    {
+      reader.readStartSequence();
+    }
+    catch (Exception e)
+    {
+      if (debugEnabled())
+      {
+        TRACER.debugCaught(DebugLogLevel.ERROR, e);
+      }
+
+      Message message =
+          ERR_LDAP_ADD_REQUEST_DECODE_SEQUENCE.get(String.valueOf(e));
+      throw new LDAPException(PROTOCOL_ERROR, message, e);
+    }
+
+
+    ByteString dn;
+    try
+    {
+      dn = reader.readOctetString();
+    }
+    catch (Exception e)
+    {
+      if (debugEnabled())
+      {
+        TRACER.debugCaught(DebugLogLevel.ERROR, e);
+      }
+
+      Message message = ERR_LDAP_ADD_REQUEST_DECODE_DN.get(String.valueOf(e));
+      throw new LDAPException(PROTOCOL_ERROR, message, e);
+    }
+
+
+
+    ArrayList<RawAttribute> attributes;
+    try
+    {
+      reader.readStartSequence();
+      attributes = new ArrayList<RawAttribute>();
+      while(reader.hasNextElement())
+      {
+        attributes.add(LDAPAttribute.decode(reader));
+      }
+      reader.readEndSequence();
+    }
+    catch (Exception e)
+    {
+      if (debugEnabled())
+      {
+        TRACER.debugCaught(DebugLogLevel.ERROR, e);
+      }
+
+      Message message =
+          ERR_LDAP_ADD_REQUEST_DECODE_ATTRS.get(String.valueOf(e));
+      throw new LDAPException(PROTOCOL_ERROR, message, e);
+    }
+
+    try
+    {
+      reader.readEndSequence();
+    }
+    catch (Exception e)
+    {
+      if (debugEnabled())
+      {
+        TRACER.debugCaught(DebugLogLevel.ERROR, e);
+      }
+
+      Message message =
+          ERR_LDAP_ADD_REQUEST_DECODE_SEQUENCE.get(String.valueOf(e));
+      throw new LDAPException(PROTOCOL_ERROR, message, e);
+    }
+
+
+    return new AddRequestProtocolOp(dn, attributes);
+  }
+
+  /**
+   * Decodes the elements from the provided ASN.1 reader as an
+   * add response protocol op.
+   *
+   * @param  reader The ASN.1 reader.
+   *
+   * @return  The decoded add response protocol op.
+   *
+   * @throws  LDAPException  If a problem occurs while attempting to decode the
+   *                         ASN.1 element to a protocol op.
+   */
+  private static AddResponseProtocolOp readAddResponse(ASN1Reader reader)
+      throws LDAPException
+  {
+    try
+    {
+      reader.readStartSequence();
+    }
+    catch (Exception e)
+    {
+      if (debugEnabled())
+      {
+        TRACER.debugCaught(DebugLogLevel.ERROR, e);
+      }
+
+      Message message = ERR_LDAP_RESULT_DECODE_SEQUENCE.get(String.valueOf(e));
+      throw new LDAPException(PROTOCOL_ERROR, message, e);
+    }
+
+    int resultCode;
+    try
+    {
+      resultCode = (int)reader.readInteger();
+    }
+    catch (Exception e)
+    {
+      if (debugEnabled())
+      {
+        TRACER.debugCaught(DebugLogLevel.ERROR, e);
+      }
+
+      Message message =
+          ERR_LDAP_RESULT_DECODE_RESULT_CODE.get(String.valueOf(e));
+      throw new LDAPException(PROTOCOL_ERROR, message, e);
+    }
+
+
+    DN matchedDN;
+    try
+    {
+      String dnString = reader.readOctetStringAsString();
+      if (dnString.length() == 0)
+      {
+        matchedDN = null;
+      }
+      else
+      {
+        matchedDN = DN.decode(dnString);
+      }
+    }
+    catch (Exception e)
+    {
+      if (debugEnabled())
+      {
+        TRACER.debugCaught(DebugLogLevel.ERROR, e);
+      }
+
+      Message message =
+          ERR_LDAP_RESULT_DECODE_MATCHED_DN.get(String.valueOf(e));
+      throw new LDAPException(PROTOCOL_ERROR, message, e);
+    }
+
+
+    Message errorMessage;
+    try
+    {
+      errorMessage = Message.raw(reader.readOctetStringAsString());
+      if (errorMessage.length() == 0)
+      {
+        errorMessage = null;
+      }
+    }
+    catch (Exception e)
+    {
+      if (debugEnabled())
+      {
+        TRACER.debugCaught(DebugLogLevel.ERROR, e);
+      }
+
+      Message message =
+          ERR_LDAP_RESULT_DECODE_ERROR_MESSAGE.get(String.valueOf(e));
+      throw new LDAPException(PROTOCOL_ERROR, message, e);
+    }
+
+    ArrayList<String> referralURLs = null;
+
+    try
+    {
+      if (reader.hasNextElement())
+      {
+        reader.readStartSequence();
+        referralURLs = new ArrayList<String>();
+
+        while(reader.hasNextElement())
+        {
+          referralURLs.add(reader.readOctetStringAsString());
+        }
+        reader.readEndSequence();
+      }
+    }
+    catch (Exception e)
+    {
+      if (debugEnabled())
+      {
+        TRACER.debugCaught(DebugLogLevel.ERROR, e);
+      }
+
+      Message message =
+          ERR_LDAP_RESULT_DECODE_REFERRALS.get(String.valueOf(e));
+      throw new LDAPException(PROTOCOL_ERROR, message, e);
+    }
+
+    try
+    {
+      reader.readEndSequence();
+    }
+    catch (Exception e)
+    {
+      if (debugEnabled())
+      {
+        TRACER.debugCaught(DebugLogLevel.ERROR, e);
+      }
+
+      Message message = ERR_LDAP_RESULT_DECODE_SEQUENCE.get(String.valueOf(e));
+      throw new LDAPException(PROTOCOL_ERROR, message, e);
+    }
+
+    return new AddResponseProtocolOp(resultCode, errorMessage, matchedDN,
+        referralURLs);
+  }
+
+  /**
+   * Decodes the elements from the provided ASN.1 read as an LDAP bind
+   * request protocol op.
+   *
+   * @param  reader The ASN.1 reader
+   *
+   * @return  The decoded LDAP bind request protocol op.
+   *
+   * @throws  LDAPException  If a problem occurs while trying to decode the
+   *                         provided ASN.1 element as an LDAP bind request.
+   */
+  private static BindRequestProtocolOp readBindRequest(ASN1Reader reader)
+      throws LDAPException
+  {
+    try
+    {
+      reader.readStartSequence();
+    }
+    catch (Exception e)
+    {
+      if (debugEnabled())
+      {
+        TRACER.debugCaught(DebugLogLevel.ERROR, e);
+      }
+
+      Message message =
+          ERR_LDAP_BIND_REQUEST_DECODE_SEQUENCE.get(String.valueOf(e));
+      throw new LDAPException(PROTOCOL_ERROR, message, e);
+    }
+
+    int protocolVersion;
+    try
+    {
+      protocolVersion = (int)reader.readInteger();
+    }
+    catch (Exception e)
+    {
+      if (debugEnabled())
+      {
+        TRACER.debugCaught(DebugLogLevel.ERROR, e);
+      }
+
+      Message message =
+          ERR_LDAP_BIND_REQUEST_DECODE_VERSION.get(String.valueOf(e));
+      throw new LDAPException(PROTOCOL_ERROR, message, e);
+    }
+
+
+    ByteString dn;
+    try
+    {
+      dn = reader.readOctetString();
+    }
+    catch (Exception e)
+    {
+      if (debugEnabled())
+      {
+        TRACER.debugCaught(DebugLogLevel.ERROR, e);
+      }
+
+      Message message = ERR_LDAP_BIND_REQUEST_DECODE_DN.get(String.valueOf(e));
+      throw new LDAPException(PROTOCOL_ERROR, message, e);
+    }
+
+    byte type;
+    try
+    {
+      type = reader.peekType();
+
+    }
+    catch (Exception e)
+    {
+      if (debugEnabled())
+      {
+        TRACER.debugCaught(DebugLogLevel.ERROR, e);
+      }
+
+      Message message =
+          ERR_LDAP_BIND_REQUEST_DECODE_CREDENTIALS.get(String.valueOf(e));
+      throw new LDAPException(PROTOCOL_ERROR, message, e);
+    }
+
+    ByteString    simplePassword  = null;
+    String             saslMechanism = null;
+    ByteString    saslCredentials = null;
+    switch (type)
+    {
+      case TYPE_AUTHENTICATION_SIMPLE:
+        try
+        {
+          simplePassword =
+              reader.readOctetString();
+        }
+        catch (Exception e)
+        {
+          Message message =
+              ERR_LDAP_BIND_REQUEST_DECODE_PASSWORD.get(String.valueOf(e));
+          throw new LDAPException(PROTOCOL_ERROR, message, e);
+        }
+        break;
+      case TYPE_AUTHENTICATION_SASL:
+        try
+        {
+          reader.readStartSequence();
+          saslMechanism = reader.readOctetStringAsString();
+          if (reader.hasNextElement())
+          {
+            saslCredentials =
+                reader.readOctetString();
+          }
+          reader.readEndSequence();
+        }
+        catch (Exception e)
+        {
+          Message message =
+              ERR_LDAP_BIND_REQUEST_DECODE_SASL_INFO.get(String.valueOf(e));
+          throw new LDAPException(PROTOCOL_ERROR, message, e);
+        }
+        break;
+      default:
+        Message message = ERR_LDAP_BIND_REQUEST_DECODE_INVALID_CRED_TYPE.get(
+            type);
+        throw new LDAPException(AUTH_METHOD_NOT_SUPPORTED, message);
+    }
+
+    try
+    {
+      reader.readEndSequence();
+    }
+    catch (Exception e)
+    {
+      if (debugEnabled())
+      {
+        TRACER.debugCaught(DebugLogLevel.ERROR, e);
+      }
+
+      Message message =
+          ERR_LDAP_BIND_REQUEST_DECODE_SEQUENCE.get(String.valueOf(e));
+      throw new LDAPException(PROTOCOL_ERROR, message, e);
+    }
+
+    if(type == TYPE_AUTHENTICATION_SIMPLE)
+    {
+      return new BindRequestProtocolOp(dn, protocolVersion, simplePassword);
+    }
+    else
+    {
+      return new BindRequestProtocolOp(dn, saslMechanism, saslCredentials);
+    }
+  }
+
+  /**
+   * Decodes the elements from the provided ASN.1 reader as a bind
+   * response protocol op.
+   *
+   * @param  reader The ASN.1 reader.
+   *
+   * @return  The decoded bind response protocol op.
+   *
+   * @throws  LDAPException  If a problem occurs while attempting to decode the
+   *                         ASN.1 element to a protocol op.
+   */
+  private static BindResponseProtocolOp readBindResponse(ASN1Reader reader)
+      throws LDAPException
+  {
+    try
+    {
+      reader.readStartSequence();
+    }
+    catch (Exception e)
+    {
+      if (debugEnabled())
+      {
+        TRACER.debugCaught(DebugLogLevel.ERROR, e);
+      }
+
+      Message message = ERR_LDAP_RESULT_DECODE_SEQUENCE.get(String.valueOf(e));
+      throw new LDAPException(PROTOCOL_ERROR, message, e);
+    }
+
+    int resultCode;
+    try
+    {
+      resultCode = (int)reader.readInteger();
+    }
+    catch (Exception e)
+    {
+      if (debugEnabled())
+      {
+        TRACER.debugCaught(DebugLogLevel.ERROR, e);
+      }
+
+      Message message =
+          ERR_LDAP_RESULT_DECODE_RESULT_CODE.get(String.valueOf(e));
+      throw new LDAPException(PROTOCOL_ERROR, message, e);
+    }
+
+
+    DN matchedDN;
+    try
+    {
+      String dnString = reader.readOctetStringAsString();
+      if (dnString.length() == 0)
+      {
+        matchedDN = null;
+      }
+      else
+      {
+        matchedDN = DN.decode(dnString);
+      }
+    }
+    catch (Exception e)
+    {
+      if (debugEnabled())
+      {
+        TRACER.debugCaught(DebugLogLevel.ERROR, e);
+      }
+
+      Message message =
+          ERR_LDAP_RESULT_DECODE_MATCHED_DN.get(String.valueOf(e));
+      throw new LDAPException(PROTOCOL_ERROR, message, e);
+    }
+
+
+    Message errorMessage;
+    try
+    {
+      errorMessage = Message.raw(reader.readOctetStringAsString());
+      if (errorMessage.length() == 0)
+      {
+        errorMessage = null;
+      }
+    }
+    catch (Exception e)
+    {
+      if (debugEnabled())
+      {
+        TRACER.debugCaught(DebugLogLevel.ERROR, e);
+      }
+
+      Message message =
+          ERR_LDAP_RESULT_DECODE_ERROR_MESSAGE.get(String.valueOf(e));
+      throw new LDAPException(PROTOCOL_ERROR, message, e);
+    }
+
+    ArrayList<String> referralURLs = null;
+    ByteString   serverSASLCredentials = null;
+
+    try
+    {
+      while(reader.hasNextElement())
+      {
+        switch(reader.peekType())
+        {
+          case TYPE_REFERRAL_SEQUENCE:
+            try
+            {
+              reader.readStartSequence();
+              referralURLs = new ArrayList<String>();
+
+              while(reader.hasNextElement())
+              {
+                referralURLs.add(reader.readOctetStringAsString());
+              }
+              reader.readEndSequence();
+            }
+            catch (Exception e)
+            {
+              if (debugEnabled())
+              {
+                TRACER.debugCaught(DebugLogLevel.ERROR, e);
+              }
+
+              Message message =
+                  ERR_LDAP_RESULT_DECODE_REFERRALS.get(String.valueOf(e));
+              throw new LDAPException(PROTOCOL_ERROR, message, e);
+            }
+
+            break;
+          case TYPE_SERVER_SASL_CREDENTIALS:
+            try
+            {
+              serverSASLCredentials =
+                  reader.readOctetString();
+            }
+            catch (Exception e)
+            {
+              if (debugEnabled())
+              {
+                TRACER.debugCaught(DebugLogLevel.ERROR, e);
+              }
+
+              Message message =
+                  ERR_LDAP_BIND_RESULT_DECODE_SERVER_SASL_CREDENTIALS.
+                      get(String.valueOf(e));
+              throw new LDAPException(PROTOCOL_ERROR, message, e);
+            }
+
+            break;
+          default:
+            Message message =
+                ERR_LDAP_BIND_RESULT_DECODE_INVALID_TYPE.get(reader.peekType());
+            throw new LDAPException(PROTOCOL_ERROR, message);
+        }
+      }
+    }
+    catch(ASN1Exception asn1e)
+    {
+      if (debugEnabled())
+      {
+        TRACER.debugCaught(DebugLogLevel.ERROR, asn1e);
+      }
+    }
+
+    try
+    {
+      reader.readEndSequence();
+    }
+    catch (Exception e)
+    {
+      if (debugEnabled())
+      {
+        TRACER.debugCaught(DebugLogLevel.ERROR, e);
+      }
+
+      Message message = ERR_LDAP_RESULT_DECODE_SEQUENCE.get(String.valueOf(e));
+      throw new LDAPException(PROTOCOL_ERROR, message, e);
+    }
+
+    return new BindResponseProtocolOp(resultCode, errorMessage, matchedDN,
+        referralURLs, serverSASLCredentials);
+  }
+
+  /**
+   * Decodes the elements from the provided ASN.1 reader as an LDAP
+   * compare request protocol op.
+   *
+   * @param  reader The ASN.1 reader
+   *
+   * @return  The decoded LDAP compare request protocol op.
+   *
+   * @throws  LDAPException  If a problem occurs while attempting to decode the
+   *                         ASN.1 element as a compare request protocol op.
+   */
+  private static CompareRequestProtocolOp readCompareRequest(ASN1Reader reader)
+      throws LDAPException
+  {
+    try
+    {
+      reader.readStartSequence();
+    }
+    catch (Exception e)
+    {
+      if (debugEnabled())
+      {
+        TRACER.debugCaught(DebugLogLevel.ERROR, e);
+      }
+
+      Message message =
+          ERR_LDAP_COMPARE_REQUEST_DECODE_SEQUENCE.get(String.valueOf(e));
+      throw new LDAPException(PROTOCOL_ERROR, message, e);
+    }
+
+
+    ByteString dn;
+    try
+    {
+      dn = reader.readOctetString();
+    }
+    catch (Exception e)
+    {
+      if (debugEnabled())
+      {
+        TRACER.debugCaught(DebugLogLevel.ERROR, e);
+      }
+
+      Message message =
+          ERR_LDAP_COMPARE_REQUEST_DECODE_DN.get(String.valueOf(e));
+      throw new LDAPException(PROTOCOL_ERROR, message, e);
+    }
+
+    try
+    {
+      reader.readStartSequence();
+    }
+    catch (Exception e)
+    {
+      if (debugEnabled())
+      {
+        TRACER.debugCaught(DebugLogLevel.ERROR, e);
+      }
+
+      Message message =
+          ERR_LDAP_COMPARE_REQUEST_DECODE_AVA.get(String.valueOf(e));
+      throw new LDAPException(PROTOCOL_ERROR, message, e);
+    }
+
+    String attributeType;
+    try
+    {
+      attributeType = reader.readOctetStringAsString();
+    }
+    catch (Exception e)
+    {
+      if (debugEnabled())
+      {
+        TRACER.debugCaught(DebugLogLevel.ERROR, e);
+      }
+
+      Message message =
+          ERR_LDAP_COMPARE_REQUEST_DECODE_TYPE.get(String.valueOf(e));
+      throw new LDAPException(PROTOCOL_ERROR, message, e);
+    }
+
+
+    ByteString assertionValue;
+    try
+    {
+      assertionValue = reader.readOctetString();
+    }
+    catch (Exception e)
+    {
+      if (debugEnabled())
+      {
+        TRACER.debugCaught(DebugLogLevel.ERROR, e);
+      }
+
+      Message message =
+          ERR_LDAP_COMPARE_REQUEST_DECODE_VALUE.get(String.valueOf(e));
+      throw new LDAPException(PROTOCOL_ERROR, message, e);
+    }
+
+    try
+    {
+      reader.readEndSequence();
+    }
+    catch (Exception e)
+    {
+      if (debugEnabled())
+      {
+        TRACER.debugCaught(DebugLogLevel.ERROR, e);
+      }
+
+      Message message =
+          ERR_LDAP_COMPARE_REQUEST_DECODE_AVA.get(String.valueOf(e));
+      throw new LDAPException(PROTOCOL_ERROR, message, e);
+    }
+
+    try
+    {
+      reader.readEndSequence();
+    }
+    catch (Exception e)
+    {
+      if (debugEnabled())
+      {
+        TRACER.debugCaught(DebugLogLevel.ERROR, e);
+      }
+
+      Message message =
+          ERR_LDAP_COMPARE_REQUEST_DECODE_SEQUENCE.get(String.valueOf(e));
+      throw new LDAPException(PROTOCOL_ERROR, message, e);
+    }
+
+    return new CompareRequestProtocolOp(dn, attributeType, assertionValue);
+  }
+
+  /**
+   * Decodes the elements from the provided ASN.1 reader as a
+   * compare response protocol op.
+   *
+   * @param  reader The ASN.1 reader.
+   *
+   * @return  The decoded compare response protocol op.
+   *
+   * @throws  LDAPException  If a problem occurs while attempting to decode the
+   *                         ASN.1 element to a protocol op.
+   */
+  private static CompareResponseProtocolOp readCompareResponse(ASN1Reader
+      reader)
+      throws LDAPException
+  {
+    try
+    {
+      reader.readStartSequence();
+    }
+    catch (Exception e)
+    {
+      if (debugEnabled())
+      {
+        TRACER.debugCaught(DebugLogLevel.ERROR, e);
+      }
+
+      Message message = ERR_LDAP_RESULT_DECODE_SEQUENCE.get(String.valueOf(e));
+      throw new LDAPException(PROTOCOL_ERROR, message, e);
+    }
+
+    int resultCode;
+    try
+    {
+      resultCode = (int)reader.readInteger();
+    }
+    catch (Exception e)
+    {
+      if (debugEnabled())
+      {
+        TRACER.debugCaught(DebugLogLevel.ERROR, e);
+      }
+
+      Message message =
+          ERR_LDAP_RESULT_DECODE_RESULT_CODE.get(String.valueOf(e));
+      throw new LDAPException(PROTOCOL_ERROR, message, e);
+    }
+
+
+    DN matchedDN;
+    try
+    {
+      String dnString = reader.readOctetStringAsString();
+      if (dnString.length() == 0)
+      {
+        matchedDN = null;
+      }
+      else
+      {
+        matchedDN = DN.decode(dnString);
+      }
+    }
+    catch (Exception e)
+    {
+      if (debugEnabled())
+      {
+        TRACER.debugCaught(DebugLogLevel.ERROR, e);
+      }
+
+      Message message =
+          ERR_LDAP_RESULT_DECODE_MATCHED_DN.get(String.valueOf(e));
+      throw new LDAPException(PROTOCOL_ERROR, message, e);
+    }
+
+
+    Message errorMessage;
+    try
+    {
+      errorMessage = Message.raw(reader.readOctetStringAsString());
+      if (errorMessage.length() == 0)
+      {
+        errorMessage = null;
+      }
+    }
+    catch (Exception e)
+    {
+      if (debugEnabled())
+      {
+        TRACER.debugCaught(DebugLogLevel.ERROR, e);
+      }
+
+      Message message =
+          ERR_LDAP_RESULT_DECODE_ERROR_MESSAGE.get(String.valueOf(e));
+      throw new LDAPException(PROTOCOL_ERROR, message, e);
+    }
+
+    ArrayList<String> referralURLs = null;
+
+    try
+    {
+      if (reader.hasNextElement())
+      {
+        reader.readStartSequence();
+        referralURLs = new ArrayList<String>();
+
+        while(reader.hasNextElement())
+        {
+          referralURLs.add(reader.readOctetStringAsString());
+        }
+        reader.readEndSequence();
+      }
+    }
+    catch (Exception e)
+    {
+      if (debugEnabled())
+      {
+        TRACER.debugCaught(DebugLogLevel.ERROR, e);
+      }
+
+      Message message =
+          ERR_LDAP_RESULT_DECODE_REFERRALS.get(String.valueOf(e));
+      throw new LDAPException(PROTOCOL_ERROR, message, e);
+    }
+
+    try
+    {
+      reader.readEndSequence();
+    }
+    catch (Exception e)
+    {
+      if (debugEnabled())
+      {
+        TRACER.debugCaught(DebugLogLevel.ERROR, e);
+      }
+
+      Message message = ERR_LDAP_RESULT_DECODE_SEQUENCE.get(String.valueOf(e));
+      throw new LDAPException(PROTOCOL_ERROR, message, e);
+    }
+
+    return new CompareResponseProtocolOp(resultCode, errorMessage, matchedDN,
+        referralURLs);
+  }
+
+  /**
+   * Decodes the elements from the provided ASN.1 reader as an LDAP delete
+   * request protocol op.
+   *
+   * @param  reader The ASN.1 reader.
+   *
+   * @return  The decoded delete request protocol op.
+   *
+   * @throws  LDAPException  If the provided ASN.1 element cannot be decoded as
+   *                         an unbind request protocol op.
+   */
+  private static DeleteRequestProtocolOp readDeleteRequest(ASN1Reader reader)
+      throws LDAPException
+  {
+    try
+    {
+      return new DeleteRequestProtocolOp(reader.readOctetString());
+    }
+    catch (Exception e)
+    {
+      if (debugEnabled())
+      {
+        TRACER.debugCaught(DebugLogLevel.ERROR, e);
+      }
+
+      Message message =
+          ERR_LDAP_DELETE_REQUEST_DECODE_DN.get(String.valueOf(e));
+      throw new LDAPException(PROTOCOL_ERROR, message, e);
+    }
+  }
+
+  /**
+   * Decodes the provided ASN.1 element as a delete response protocol op.
+   *
+   * @param  reader The ASN.1 reader.
+   *
+   * @return  The decoded delete response protocol op.
+   *
+   * @throws  LDAPException  If a problem occurs while attempting to decode the
+   *                         ASN.1 element to a protocol op.
+   */
+  private static DeleteResponseProtocolOp readDeleteResponse(ASN1Reader reader)
+      throws LDAPException
+  {
+    try
+    {
+      reader.readStartSequence();
+    }
+    catch (Exception e)
+    {
+      if (debugEnabled())
+      {
+        TRACER.debugCaught(DebugLogLevel.ERROR, e);
+      }
+
+      Message message = ERR_LDAP_RESULT_DECODE_SEQUENCE.get(String.valueOf(e));
+      throw new LDAPException(PROTOCOL_ERROR, message, e);
+    }
+
+    int resultCode;
+    try
+    {
+      resultCode = (int)reader.readInteger();
+    }
+    catch (Exception e)
+    {
+      if (debugEnabled())
+      {
+        TRACER.debugCaught(DebugLogLevel.ERROR, e);
+      }
+
+      Message message =
+          ERR_LDAP_RESULT_DECODE_RESULT_CODE.get(String.valueOf(e));
+      throw new LDAPException(PROTOCOL_ERROR, message, e);
+    }
+
+
+    DN matchedDN;
+    try
+    {
+      String dnString = reader.readOctetStringAsString();
+      if (dnString.length() == 0)
+      {
+        matchedDN = null;
+      }
+      else
+      {
+        matchedDN = DN.decode(dnString);
+      }
+    }
+    catch (Exception e)
+    {
+      if (debugEnabled())
+      {
+        TRACER.debugCaught(DebugLogLevel.ERROR, e);
+      }
+
+      Message message =
+          ERR_LDAP_RESULT_DECODE_MATCHED_DN.get(String.valueOf(e));
+      throw new LDAPException(PROTOCOL_ERROR, message, e);
+    }
+
+
+    Message errorMessage;
+    try
+    {
+      errorMessage = Message.raw(reader.readOctetStringAsString());
+      if (errorMessage.length() == 0)
+      {
+        errorMessage = null;
+      }
+    }
+    catch (Exception e)
+    {
+      if (debugEnabled())
+      {
+        TRACER.debugCaught(DebugLogLevel.ERROR, e);
+      }
+
+      Message message =
+          ERR_LDAP_RESULT_DECODE_ERROR_MESSAGE.get(String.valueOf(e));
+      throw new LDAPException(PROTOCOL_ERROR, message, e);
+    }
+
+    ArrayList<String> referralURLs = null;
+
+    try
+    {
+      if (reader.hasNextElement())
+      {
+        reader.readStartSequence();
+        referralURLs = new ArrayList<String>();
+
+        while(reader.hasNextElement())
+        {
+          referralURLs.add(reader.readOctetStringAsString());
+        }
+        reader.readEndSequence();
+      }
+    }
+    catch (Exception e)
+    {
+      if (debugEnabled())
+      {
+        TRACER.debugCaught(DebugLogLevel.ERROR, e);
+      }
+
+      Message message =
+          ERR_LDAP_RESULT_DECODE_REFERRALS.get(String.valueOf(e));
+      throw new LDAPException(PROTOCOL_ERROR, message, e);
+    }
+
+    try
+    {
+      reader.readEndSequence();
+    }
+    catch (Exception e)
+    {
+      if (debugEnabled())
+      {
+        TRACER.debugCaught(DebugLogLevel.ERROR, e);
+      }
+
+      Message message = ERR_LDAP_RESULT_DECODE_SEQUENCE.get(String.valueOf(e));
+      throw new LDAPException(PROTOCOL_ERROR, message, e);
+    }
+
+
+    return new DeleteResponseProtocolOp(resultCode, errorMessage, matchedDN,
+        referralURLs);
+  }
+
+  /**
+   * Decodes the elements from the provided ASN.1 reader as an
+   * LDAP extended request protocol op.
+   *
+   * @param  reader The ASN.1 reader.
+   *
+   * @return  The decoded extended request protocol op.
+   *
+   * @throws  LDAPException  If a problem occurs while attempting to decode the
+   *                         provided ASN.1 element as an LDAP extended request
+   *                         protocol op.
+   */
+  private static ExtendedRequestProtocolOp readExtendedRequest(ASN1Reader
+      reader)
+      throws LDAPException
+  {
+    try
+    {
+      reader.readStartSequence();
+    }
+    catch (Exception e)
+    {
+      if (debugEnabled())
+      {
+        TRACER.debugCaught(DebugLogLevel.ERROR, e);
+      }
+
+      Message message =
+          ERR_LDAP_EXTENDED_REQUEST_DECODE_SEQUENCE.get(String.valueOf(e));
+      throw new LDAPException(PROTOCOL_ERROR, message, e);
+    }
+
+
+    String oid;
+    try
+    {
+      oid = reader.readOctetStringAsString();
+    }
+    catch (Exception e)
+    {
+      if (debugEnabled())
+      {
+        TRACER.debugCaught(DebugLogLevel.ERROR, e);
+      }
+
+      Message message =
+          ERR_LDAP_EXTENDED_REQUEST_DECODE_OID.get(String.valueOf(e));
+      throw new LDAPException(PROTOCOL_ERROR, message, e);
+    }
+
+
+    ByteString value = null;
+    try
+    {
+      if(reader.hasNextElement())
+      {
+        value = reader.readOctetString();
+      }
+    }
+    catch (Exception e)
+    {
+      if (debugEnabled())
+      {
+        TRACER.debugCaught(DebugLogLevel.ERROR, e);
+      }
+
+      Message message =
+          ERR_LDAP_EXTENDED_REQUEST_DECODE_VALUE.get(String.valueOf(e));
+      throw new LDAPException(PROTOCOL_ERROR, message, e);
+    }
+
+    try
+    {
+      reader.readEndSequence();
+    }
+    catch (Exception e)
+    {
+      if (debugEnabled())
+      {
+        TRACER.debugCaught(DebugLogLevel.ERROR, e);
+      }
+
+      Message message =
+          ERR_LDAP_EXTENDED_REQUEST_DECODE_SEQUENCE.get(String.valueOf(e));
+      throw new LDAPException(PROTOCOL_ERROR, message, e);
+    }
+
+    return new ExtendedRequestProtocolOp(oid, value);
+  }
+
+  /**
+   * Decodes the elements from the provided ASN.1 reader as a
+   * extended response protocol op.
+   *
+   * @param  reader The ASN.1 reader.
+   *
+   * @return  The decoded extended response protocol op.
+   *
+   * @throws  LDAPException  If a problem occurs while attempting to decode the
+   *                         ASN.1 element to a protocol op.
+   */
+  private static ExtendedResponseProtocolOp readExtendedResponse(ASN1Reader
+      reader)
+      throws LDAPException
+  {
+    try
+    {
+      reader.readStartSequence();
+    }
+    catch (Exception e)
+    {
+      if (debugEnabled())
+      {
+        TRACER.debugCaught(DebugLogLevel.ERROR, e);
+      }
+
+      Message message = ERR_LDAP_RESULT_DECODE_SEQUENCE.get(String.valueOf(e));
+      throw new LDAPException(PROTOCOL_ERROR, message, e);
+    }
+
+    int resultCode;
+    try
+    {
+      resultCode = (int)reader.readInteger();
+    }
+    catch (Exception e)
+    {
+      if (debugEnabled())
+      {
+        TRACER.debugCaught(DebugLogLevel.ERROR, e);
+      }
+
+      Message message =
+          ERR_LDAP_RESULT_DECODE_RESULT_CODE.get(String.valueOf(e));
+      throw new LDAPException(PROTOCOL_ERROR, message, e);
+    }
+
+
+    DN matchedDN;
+    try
+    {
+      String dnString = reader.readOctetStringAsString();
+      if (dnString.length() == 0)
+      {
+        matchedDN = null;
+      }
+      else
+      {
+        matchedDN = DN.decode(dnString);
+      }
+    }
+    catch (Exception e)
+    {
+      if (debugEnabled())
+      {
+        TRACER.debugCaught(DebugLogLevel.ERROR, e);
+      }
+
+      Message message =
+          ERR_LDAP_RESULT_DECODE_MATCHED_DN.get(String.valueOf(e));
+      throw new LDAPException(PROTOCOL_ERROR, message, e);
+    }
+
+
+    Message errorMessage;
+    try
+    {
+      errorMessage = Message.raw(reader.readOctetStringAsString());
+      if (errorMessage.length() == 0)
+      {
+        errorMessage = null;
+      }
+    }
+    catch (Exception e)
+    {
+      if (debugEnabled())
+      {
+        TRACER.debugCaught(DebugLogLevel.ERROR, e);
+      }
+
+      Message message =
+          ERR_LDAP_RESULT_DECODE_ERROR_MESSAGE.get(String.valueOf(e));
+      throw new LDAPException(PROTOCOL_ERROR, message, e);
+    }
+
+    ArrayList<String> referralURLs = null;
+    String            oid          = null;
+    ByteString   value        = null;
+
+    try
+    {
+      while(reader.hasNextElement())
+      {
+        switch(reader.peekType())
+        {
+          case TYPE_REFERRAL_SEQUENCE:
+            try
+            {
+              reader.readStartSequence();
+              referralURLs = new ArrayList<String>();
+
+              while(reader.hasNextElement())
+              {
+                referralURLs.add(reader.readOctetStringAsString());
+              }
+              reader.readEndSequence();
+            }
+            catch (Exception e)
+            {
+              if (debugEnabled())
+              {
+                TRACER.debugCaught(DebugLogLevel.ERROR, e);
+              }
+
+              Message message =
+                  ERR_LDAP_RESULT_DECODE_REFERRALS.get(String.valueOf(e));
+              throw new LDAPException(PROTOCOL_ERROR, message, e);
+            }
+            break;
+          case TYPE_EXTENDED_RESPONSE_OID:
+            try
+            {
+              oid = reader.readOctetStringAsString();
+            }
+            catch (Exception e)
+            {
+              if (debugEnabled())
+              {
+                TRACER.debugCaught(DebugLogLevel.ERROR, e);
+              }
+
+              Message message =
+                  ERR_LDAP_EXTENDED_RESULT_DECODE_OID.get(String.valueOf(e));
+              throw new LDAPException(PROTOCOL_ERROR, message, e);
+            }
+
+            break;
+          case TYPE_EXTENDED_RESPONSE_VALUE:
+            try
+            {
+              value = reader.readOctetString();
+            }
+            catch (Exception e)
+            {
+              if (debugEnabled())
+              {
+                TRACER.debugCaught(DebugLogLevel.ERROR, e);
+              }
+
+              Message message =
+                  ERR_LDAP_EXTENDED_RESULT_DECODE_VALUE.get(String.valueOf(e));
+              throw new LDAPException(PROTOCOL_ERROR, message, e);
+            }
+
+            break;
+          default:
+            Message message = ERR_LDAP_EXTENDED_RESULT_DECODE_INVALID_TYPE.get(
+                reader.peekType());
+            throw new LDAPException(PROTOCOL_ERROR, message);
+        }
+      }
+    }
+    catch(ASN1Exception asn1e)
+    {
+      if (debugEnabled())
+      {
+        TRACER.debugCaught(DebugLogLevel.ERROR, asn1e);
+      }
+    }
+
+    try
+    {
+      reader.readEndSequence();
+    }
+    catch (Exception e)
+    {
+      if (debugEnabled())
+      {
+        TRACER.debugCaught(DebugLogLevel.ERROR, e);
+      }
+
+      Message message = ERR_LDAP_RESULT_DECODE_SEQUENCE.get(String.valueOf(e));
+      throw new LDAPException(PROTOCOL_ERROR, message, e);
+    }
+
+    return new ExtendedResponseProtocolOp(resultCode, errorMessage, matchedDN,
+        referralURLs, oid, value);
+  }
+
+  /**
+   * Decodes the elements from the provided ASN.1 reader as an LDAP
+   * intermediate response protocol op.
+   *
+   * @param  reader The ASN.1 reader.
+   *
+   * @return  The decoded intermediate response protocol op.
+   *
+   * @throws  LDAPException  If a problem occurs while attempting to decode the
+   *                         provided ASN.1 element as an LDAP intermediate
+   *                         response protocol op.
+   */
+  private static IntermediateResponseProtocolOp
+  readIntermediateResponse(ASN1Reader reader)
+      throws LDAPException
+  {
+    try
+    {
+      reader.readStartSequence();
+    }
+    catch (Exception e)
+    {
+      if (debugEnabled())
+      {
+        TRACER.debugCaught(DebugLogLevel.ERROR, e);
+      }
+
+      Message message =
+          ERR_LDAP_INTERMEDIATE_RESPONSE_DECODE_SEQUENCE.get(String.valueOf(e));
+      throw new LDAPException(PROTOCOL_ERROR, message, e);
+    }
+
+    String          oid   = null;
+    ByteString value = null;
+
+    try
+    {
+      while(reader.hasNextElement())
+      {
+        switch(reader.peekType())
+        {
+          case TYPE_INTERMEDIATE_RESPONSE_OID:
+            try
+            {
+              if(reader.hasNextElement())
+              {
+                oid = reader.readOctetStringAsString();
+              }
+            }
+            catch (Exception e)
+            {
+              if (debugEnabled())
+              {
+                TRACER.debugCaught(DebugLogLevel.ERROR, e);
+              }
+
+              Message message =
+                  ERR_LDAP_INTERMEDIATE_RESPONSE_CANNOT_DECODE_OID.get(
+                      e.getMessage());
+              throw new LDAPException(PROTOCOL_ERROR, message);
+            }
+            break;
+          case TYPE_INTERMEDIATE_RESPONSE_VALUE:
+            try
+            {
+              value = reader.readOctetString();
+            }
+            catch (Exception e)
+            {
+              if (debugEnabled())
+              {
+                TRACER.debugCaught(DebugLogLevel.ERROR, e);
+              }
+
+              Message message =
+                  ERR_LDAP_INTERMEDIATE_RESPONSE_CANNOT_DECODE_VALUE.
+                      get(e.getMessage());
+              throw new LDAPException(PROTOCOL_ERROR, message);
+            }
+            break;
+          default:
+            Message message =
+                ERR_LDAP_INTERMEDIATE_RESPONSE_INVALID_ELEMENT_TYPE.get(
+                    byteToHex(reader.peekType()));
+            throw new LDAPException(PROTOCOL_ERROR, message);
+        }
+      }
+    }
+    catch(ASN1Exception asn1e)
+    {
+      if (debugEnabled())
+      {
+        TRACER.debugCaught(DebugLogLevel.ERROR, asn1e);
+      }
+    }
+
+    try
+    {
+      reader.readEndSequence();
+    }
+    catch (Exception e)
+    {
+      if (debugEnabled())
+      {
+        TRACER.debugCaught(DebugLogLevel.ERROR, e);
+      }
+
+      Message message =
+          ERR_LDAP_INTERMEDIATE_RESPONSE_DECODE_SEQUENCE.get(String.valueOf(e));
+      throw new LDAPException(PROTOCOL_ERROR, message, e);
+    }
+
+    return new IntermediateResponseProtocolOp(oid, value);
+  }
+
+  /**
+   * Decodes the elements from the provided ASN.1 reader as a
+   * modify DN request protocol op.
+   *
+   * @param  reader The ASN.1 reader.
+   *
+   * @return  The decoded modify DN request protocol op.
+   *
+   * @throws  LDAPException  If a problem occurs while trying to decode the
+   *                         provided ASN.1 element as an LDAP modify DN request
+   *                         protocol op.
+   */
+  private static ModifyDNRequestProtocolOp readModifyDNRequest(ASN1Reader
+      reader)
+      throws LDAPException
+  {
+    try
+    {
+      reader.readStartSequence();
+    }
+    catch (Exception e)
+    {
+      if (debugEnabled())
+      {
+        TRACER.debugCaught(DebugLogLevel.ERROR, e);
+      }
+
+      Message message =
+          ERR_LDAP_MODIFY_DN_REQUEST_DECODE_SEQUENCE.get(String.valueOf(e));
+      throw new LDAPException(PROTOCOL_ERROR, message, e);
+    }
+
+
+    ByteString entryDN;
+    try
+    {
+      entryDN = reader.readOctetString();
+    }
+    catch (Exception e)
+    {
+      if (debugEnabled())
+      {
+        TRACER.debugCaught(DebugLogLevel.ERROR, e);
+      }
+
+      Message message =
+          ERR_LDAP_MODIFY_DN_REQUEST_DECODE_DN.get(String.valueOf(e));
+      throw new LDAPException(PROTOCOL_ERROR, message, e);
+    }
+
+
+    ByteString newRDN;
+    try
+    {
+      newRDN = reader.readOctetString();
+    }
+    catch (Exception e)
+    {
+      if (debugEnabled())
+      {
+        TRACER.debugCaught(DebugLogLevel.ERROR, e);
+      }
+
+      Message message =
+          ERR_LDAP_MODIFY_DN_REQUEST_DECODE_NEW_RDN.get(String.valueOf(e));
+      throw new LDAPException(PROTOCOL_ERROR, message, e);
+    }
+
+
+    boolean deleteOldRDN;
+    try
+    {
+      deleteOldRDN = reader.readBoolean();
+    }
+    catch (Exception e)
+    {
+      if (debugEnabled())
+      {
+        TRACER.debugCaught(DebugLogLevel.ERROR, e);
+      }
+
+      Message message = ERR_LDAP_MODIFY_DN_REQUEST_DECODE_DELETE_OLD_RDN.get(
+          String.valueOf(e));
+      throw new LDAPException(PROTOCOL_ERROR, message, e);
+    }
+
+
+    ByteString newSuperior = null;
+    try
+    {
+      if(reader.hasNextElement())
+      {
+        newSuperior = reader.readOctetString();
+      }
+    }
+    catch (Exception e)
+    {
+      if (debugEnabled())
+      {
+        TRACER.debugCaught(DebugLogLevel.ERROR, e);
+      }
+
+      Message message = ERR_LDAP_MODIFY_DN_REQUEST_DECODE_NEW_SUPERIOR.get(
+          String.valueOf(e));
+      throw new LDAPException(PROTOCOL_ERROR, message, e);
+    }
+
+    try
+    {
+      reader.readEndSequence();
+    }
+    catch (Exception e)
+    {
+      if (debugEnabled())
+      {
+        TRACER.debugCaught(DebugLogLevel.ERROR, e);
+      }
+
+      Message message =
+          ERR_LDAP_MODIFY_DN_REQUEST_DECODE_SEQUENCE.get(String.valueOf(e));
+      throw new LDAPException(PROTOCOL_ERROR, message, e);
+    }
+
+    return new ModifyDNRequestProtocolOp(entryDN, newRDN, deleteOldRDN,
+        newSuperior);
+  }
+
+  /**
+   * Decodes the elements from the provided ASN.1 reader as a
+   * modify DN response protocol op.
+   *
+   * @param  reader The ASN.1 reader.
+   *
+   * @return  The decoded modify DN response protocol op.
+   *
+   * @throws  LDAPException  If a problem occurs while attempting to decode the
+   *                         ASN.1 element to a protocol op.
+   */
+  private static ModifyDNResponseProtocolOp readModifyDNResponse(ASN1Reader
+      reader)
+      throws LDAPException
+  {
+    try
+    {
+      reader.readStartSequence();
+    }
+    catch (Exception e)
+    {
+      if (debugEnabled())
+      {
+        TRACER.debugCaught(DebugLogLevel.ERROR, e);
+      }
+
+      Message message = ERR_LDAP_RESULT_DECODE_SEQUENCE.get(String.valueOf(e));
+      throw new LDAPException(PROTOCOL_ERROR, message, e);
+    }
+
+    int resultCode;
+    try
+    {
+      resultCode = (int)reader.readInteger();
+    }
+    catch (Exception e)
+    {
+      if (debugEnabled())
+      {
+        TRACER.debugCaught(DebugLogLevel.ERROR, e);
+      }
+
+      Message message =
+          ERR_LDAP_RESULT_DECODE_RESULT_CODE.get(String.valueOf(e));
+      throw new LDAPException(PROTOCOL_ERROR, message, e);
+    }
+
+
+    DN matchedDN;
+    try
+    {
+      String dnString = reader.readOctetStringAsString();
+      if (dnString.length() == 0)
+      {
+        matchedDN = null;
+      }
+      else
+      {
+        matchedDN = DN.decode(dnString);
+      }
+    }
+    catch (Exception e)
+    {
+      if (debugEnabled())
+      {
+        TRACER.debugCaught(DebugLogLevel.ERROR, e);
+      }
+
+      Message message =
+          ERR_LDAP_RESULT_DECODE_MATCHED_DN.get(String.valueOf(e));
+      throw new LDAPException(PROTOCOL_ERROR, message, e);
+    }
+
+
+    Message errorMessage;
+    try
+    {
+      errorMessage = Message.raw(reader.readOctetStringAsString());
+      if (errorMessage.length() == 0)
+      {
+        errorMessage = null;
+      }
+    }
+    catch (Exception e)
+    {
+      if (debugEnabled())
+      {
+        TRACER.debugCaught(DebugLogLevel.ERROR, e);
+      }
+
+      Message message =
+          ERR_LDAP_RESULT_DECODE_ERROR_MESSAGE.get(String.valueOf(e));
+      throw new LDAPException(PROTOCOL_ERROR, message, e);
+    }
+
+    ArrayList<String> referralURLs = null;
+
+    try
+    {
+      if (reader.hasNextElement())
+      {
+        reader.readStartSequence();
+        referralURLs = new ArrayList<String>();
+
+        while(reader.hasNextElement())
+        {
+          referralURLs.add(reader.readOctetStringAsString());
+        }
+        reader.readEndSequence();
+      }
+    }
+    catch (Exception e)
+    {
+      if (debugEnabled())
+      {
+        TRACER.debugCaught(DebugLogLevel.ERROR, e);
+      }
+
+      Message message =
+          ERR_LDAP_RESULT_DECODE_REFERRALS.get(String.valueOf(e));
+      throw new LDAPException(PROTOCOL_ERROR, message, e);
+    }
+
+    try
+    {
+      reader.readEndSequence();
+    }
+    catch (Exception e)
+    {
+      if (debugEnabled())
+      {
+        TRACER.debugCaught(DebugLogLevel.ERROR, e);
+      }
+
+      Message message = ERR_LDAP_RESULT_DECODE_SEQUENCE.get(String.valueOf(e));
+      throw new LDAPException(PROTOCOL_ERROR, message, e);
+    }
+
+    return new ModifyDNResponseProtocolOp(resultCode, errorMessage, matchedDN,
+        referralURLs);
+  }
+
+  /**
+   * Decodes the elements from the provided ASN.1 reader as an LDAP
+   * modify request protocol op.
+   *
+   * @param  reader The ASN.1 reader.
+   *
+   * @return  The decoded modify request protocol op.
+   *
+   * @throws  LDAPException  If a problem occurs while decoding the provided
+   *                         ASN.1 element as an LDAP modify request protocol
+   *                         op.
+   */
+  private static ModifyRequestProtocolOp readModifyRequest(ASN1Reader reader)
+      throws LDAPException
+  {
+    try
+    {
+      reader.readStartSequence();
+    }
+    catch (Exception e)
+    {
+      if (debugEnabled())
+      {
+        TRACER.debugCaught(DebugLogLevel.ERROR, e);
+      }
+
+      Message message =
+          ERR_LDAP_MODIFY_REQUEST_DECODE_SEQUENCE.get(String.valueOf(e));
+      throw new LDAPException(PROTOCOL_ERROR, message, e);
+    }
+
+    ByteString dn;
+    try
+    {
+      dn = reader.readOctetString();
+    }
+    catch (Exception e)
+    {
+      if (debugEnabled())
+      {
+        TRACER.debugCaught(DebugLogLevel.ERROR, e);
+      }
+
+      Message message =
+          ERR_LDAP_MODIFY_REQUEST_DECODE_DN.get(String.valueOf(e));
+      throw new LDAPException(PROTOCOL_ERROR, message, e);
+    }
+
+
+
+    ArrayList<RawModification> modifications;
+    try
+    {
+      reader.readStartSequence();
+      modifications = new ArrayList<RawModification>();
+      while(reader.hasNextElement())
+      {
+        modifications.add(LDAPModification.decode(reader));
+      }
+      reader.readEndSequence();
+    }
+    catch (Exception e)
+    {
+      if (debugEnabled())
+      {
+        TRACER.debugCaught(DebugLogLevel.ERROR, e);
+      }
+
+      Message message =
+          ERR_LDAP_MODIFY_REQUEST_DECODE_MODS.get(String.valueOf(e));
+      throw new LDAPException(PROTOCOL_ERROR, message, e);
+    }
+
+    try
+    {
+      reader.readEndSequence();
+    }
+    catch (Exception e)
+    {
+      if (debugEnabled())
+      {
+        TRACER.debugCaught(DebugLogLevel.ERROR, e);
+      }
+
+      Message message =
+          ERR_LDAP_MODIFY_REQUEST_DECODE_SEQUENCE.get(String.valueOf(e));
+      throw new LDAPException(PROTOCOL_ERROR, message, e);
+    }
+
+
+    return new ModifyRequestProtocolOp(dn, modifications);
+  }
+
+  /**
+   * Decodes the elements from the provided ASN.1 reader as a modify
+   * response protocol op.
+   *
+   * @param  reader The ASN.1 reader.
+   *
+   * @return  The decoded modify response protocol op.
+   *
+   * @throws  LDAPException  If a problem occurs while attempting to decode the
+   *                         ASN.1 element to a protocol op.
+   */
+  private static ModifyResponseProtocolOp readModifyResponse(ASN1Reader
+      reader)
+      throws LDAPException
+  {
+    try
+    {
+      reader.readStartSequence();
+    }
+    catch (Exception e)
+    {
+      if (debugEnabled())
+      {
+        TRACER.debugCaught(DebugLogLevel.ERROR, e);
+      }
+
+      Message message = ERR_LDAP_RESULT_DECODE_SEQUENCE.get(String.valueOf(e));
+      throw new LDAPException(PROTOCOL_ERROR, message, e);
+    }
+
+    int resultCode;
+    try
+    {
+      resultCode = (int)reader.readInteger();
+    }
+    catch (Exception e)
+    {
+      if (debugEnabled())
+      {
+        TRACER.debugCaught(DebugLogLevel.ERROR, e);
+      }
+
+      Message message =
+          ERR_LDAP_RESULT_DECODE_RESULT_CODE.get(String.valueOf(e));
+      throw new LDAPException(PROTOCOL_ERROR, message, e);
+    }
+
+
+    DN matchedDN;
+    try
+    {
+      String dnString = reader.readOctetStringAsString();
+      if (dnString.length() == 0)
+      {
+        matchedDN = null;
+      }
+      else
+      {
+        matchedDN = DN.decode(dnString);
+      }
+    }
+    catch (Exception e)
+    {
+      if (debugEnabled())
+      {
+        TRACER.debugCaught(DebugLogLevel.ERROR, e);
+      }
+
+      Message message =
+          ERR_LDAP_RESULT_DECODE_MATCHED_DN.get(String.valueOf(e));
+      throw new LDAPException(PROTOCOL_ERROR, message, e);
+    }
+
+
+    Message errorMessage;
+    try
+    {
+      errorMessage = Message.raw(reader.readOctetStringAsString());
+      if (errorMessage.length() == 0)
+      {
+        errorMessage = null;
+      }
+    }
+    catch (Exception e)
+    {
+      if (debugEnabled())
+      {
+        TRACER.debugCaught(DebugLogLevel.ERROR, e);
+      }
+
+      Message message =
+          ERR_LDAP_RESULT_DECODE_ERROR_MESSAGE.get(String.valueOf(e));
+      throw new LDAPException(PROTOCOL_ERROR, message, e);
+    }
+
+    ArrayList<String> referralURLs = null;
+
+    try
+    {
+      if (reader.hasNextElement())
+      {
+        reader.readStartSequence();
+        referralURLs = new ArrayList<String>();
+
+        while(reader.hasNextElement())
+        {
+          referralURLs.add(reader.readOctetStringAsString());
+        }
+        reader.readEndSequence();
+      }
+    }
+    catch (Exception e)
+    {
+      if (debugEnabled())
+      {
+        TRACER.debugCaught(DebugLogLevel.ERROR, e);
+      }
+
+      Message message =
+          ERR_LDAP_RESULT_DECODE_REFERRALS.get(String.valueOf(e));
+      throw new LDAPException(PROTOCOL_ERROR, message, e);
+    }
+
+    try
+    {
+      reader.readEndSequence();
+    }
+    catch (Exception e)
+    {
+      if (debugEnabled())
+      {
+        TRACER.debugCaught(DebugLogLevel.ERROR, e);
+      }
+
+      Message message = ERR_LDAP_RESULT_DECODE_SEQUENCE.get(String.valueOf(e));
+      throw new LDAPException(PROTOCOL_ERROR, message, e);
+    }
+
+    return new ModifyResponseProtocolOp(resultCode, errorMessage, matchedDN,
+        referralURLs);
+  }
+
+  /**
+   * Decodes the elements from the provided ASN.1 reader as an LDAP search
+   * request protocol op.
+   *
+   * @param  reader The ASN.1 reader.
+   *
+   * @return  The decoded LDAP search request protocol op.
+   *
+   * @throws  LDAPException  If a problem occurs while decoding the provided
+   *                         ASN.1 element as an LDAP search request protocol
+   *                         op.
+   */
+  private static SearchRequestProtocolOp readSearchRequest(ASN1Reader reader)
+      throws LDAPException
+  {
+    try
+    {
+      reader.readStartSequence();
+    }
+    catch (Exception e)
+    {
+      if (debugEnabled())
+      {
+        TRACER.debugCaught(DebugLogLevel.ERROR, e);
+      }
+
+      Message message =
+          ERR_LDAP_SEARCH_REQUEST_DECODE_SEQUENCE.get(String.valueOf(e));
+      throw new LDAPException(PROTOCOL_ERROR, message, e);
+    }
+
+    ByteString baseDN;
+    try
+    {
+      baseDN = reader.readOctetString();
+    }
+    catch (Exception e)
+    {
+      if (debugEnabled())
+      {
+        TRACER.debugCaught(DebugLogLevel.ERROR, e);
+      }
+
+      Message message =
+          ERR_LDAP_SEARCH_REQUEST_DECODE_BASE.get(String.valueOf(e));
+      throw new LDAPException(PROTOCOL_ERROR, message, e);
+    }
+
+
+    SearchScope scope;
+    try
+    {
+      int scopeValue = (int)reader.readInteger();
+      switch (scopeValue)
+      {
+        case SCOPE_BASE_OBJECT:
+          scope = SearchScope.BASE_OBJECT;
+          break;
+        case SCOPE_SINGLE_LEVEL:
+          scope = SearchScope.SINGLE_LEVEL;
+          break;
+        case SCOPE_WHOLE_SUBTREE:
+          scope = SearchScope.WHOLE_SUBTREE;
+          break;
+        case SCOPE_SUBORDINATE_SUBTREE:
+          scope = SearchScope.SUBORDINATE_SUBTREE;
+          break;
+        default:
+          Message message =
+              ERR_LDAP_SEARCH_REQUEST_DECODE_INVALID_SCOPE.get(scopeValue);
+          throw new LDAPException(PROTOCOL_ERROR, message);
+      }
+    }
+    catch (LDAPException le)
+    {
+      throw le;
+    }
+    catch (Exception e)
+    {
+      if (debugEnabled())
+      {
+        TRACER.debugCaught(DebugLogLevel.ERROR, e);
+      }
+
+      Message message =
+          ERR_LDAP_SEARCH_REQUEST_DECODE_SCOPE.get(String.valueOf(e));
+      throw new LDAPException(PROTOCOL_ERROR, message, e);
+    }
+
+
+    DereferencePolicy dereferencePolicy;
+    try
+    {
+      int derefValue = (int)reader.readInteger();
+      switch (derefValue)
+      {
+        case DEREF_NEVER:
+          dereferencePolicy = DereferencePolicy.NEVER_DEREF_ALIASES;
+          break;
+        case DEREF_IN_SEARCHING:
+          dereferencePolicy = DereferencePolicy.DEREF_IN_SEARCHING;
+          break;
+        case DEREF_FINDING_BASE:
+          dereferencePolicy = DereferencePolicy.DEREF_FINDING_BASE_OBJECT;
+          break;
+        case DEREF_ALWAYS:
+          dereferencePolicy = DereferencePolicy.DEREF_ALWAYS;
+          break;
+        default:
+          Message message =
+              ERR_LDAP_SEARCH_REQUEST_DECODE_INVALID_DEREF.get(derefValue);
+          throw new LDAPException(PROTOCOL_ERROR, message);
+      }
+    }
+    catch (LDAPException le)
+    {
+      throw le;
+    }
+    catch (Exception e)
+    {
+      if (debugEnabled())
+      {
+        TRACER.debugCaught(DebugLogLevel.ERROR, e);
+      }
+
+      Message message =
+          ERR_LDAP_SEARCH_REQUEST_DECODE_DEREF.get(String.valueOf(e));
+      throw new LDAPException(PROTOCOL_ERROR, message, e);
+    }
+
+
+    int sizeLimit;
+    try
+    {
+      sizeLimit = (int)reader.readInteger();
+    }
+    catch (Exception e)
+    {
+      if (debugEnabled())
+      {
+        TRACER.debugCaught(DebugLogLevel.ERROR, e);
+      }
+
+      Message message =
+          ERR_LDAP_SEARCH_REQUEST_DECODE_SIZE_LIMIT.get(String.valueOf(e));
+      throw new LDAPException(PROTOCOL_ERROR, message, e);
+    }
+
+
+    int timeLimit;
+    try
+    {
+      timeLimit = (int)reader.readInteger();
+    }
+    catch (Exception e)
+    {
+      if (debugEnabled())
+      {
+        TRACER.debugCaught(DebugLogLevel.ERROR, e);
+      }
+
+      Message message =
+          ERR_LDAP_SEARCH_REQUEST_DECODE_TIME_LIMIT.get(String.valueOf(e));
+      throw new LDAPException(PROTOCOL_ERROR, message, e);
+    }
+
+
+    boolean typesOnly;
+    try
+    {
+      typesOnly = reader.readBoolean();
+    }
+    catch (Exception e)
+    {
+      if (debugEnabled())
+      {
+        TRACER.debugCaught(DebugLogLevel.ERROR, e);
+      }
+
+      Message message =
+          ERR_LDAP_SEARCH_REQUEST_DECODE_TYPES_ONLY.get(String.valueOf(e));
+      throw new LDAPException(PROTOCOL_ERROR, message, e);
+    }
+
+    RawFilter filter;
+    try
+    {
+      filter = RawFilter.decode(reader);
+    }
+    catch (Exception e)
+    {
+      if (debugEnabled())
+      {
+        TRACER.debugCaught(DebugLogLevel.ERROR, e);
+      }
+
+      Message message =
+          ERR_LDAP_SEARCH_REQUEST_DECODE_FILTER.get(String.valueOf(e));
+      throw new LDAPException(PROTOCOL_ERROR, message, e);
+    }
+
+
+    LinkedHashSet<String> attributes;
+    try
+    {
+      reader.readStartSequence();
+      attributes = new LinkedHashSet<String>();
+      while(reader.hasNextElement())
+      {
+        attributes.add(reader.readOctetStringAsString());
+      }
+      reader.readEndSequence();
+    }
+    catch (Exception e)
+    {
+      if (debugEnabled())
+      {
+        TRACER.debugCaught(DebugLogLevel.ERROR, e);
+      }
+
+      Message message =
+          ERR_LDAP_SEARCH_REQUEST_DECODE_ATTRIBUTES.get(String.valueOf(e));
+      throw new LDAPException(PROTOCOL_ERROR, message, e);
+    }
+
+    try
+    {
+      reader.readEndSequence();
+    }
+    catch (Exception e)
+    {
+      if (debugEnabled())
+      {
+        TRACER.debugCaught(DebugLogLevel.ERROR, e);
+      }
+
+      Message message =
+          ERR_LDAP_SEARCH_REQUEST_DECODE_SEQUENCE.get(String.valueOf(e));
+      throw new LDAPException(PROTOCOL_ERROR, message, e);
+    }
+
+    return new SearchRequestProtocolOp(baseDN, scope, dereferencePolicy,
+        sizeLimit, timeLimit, typesOnly, filter,
+        attributes);
+  }
+
+  /**
+   * Decodes the elements from the provided ASN.1 reader as a search
+   * result done protocol op.
+   *
+   * @param  reader The ASN.1 reader
+   *
+   * @return  The decoded search result done protocol op.
+   *
+   * @throws  LDAPException  If a problem occurs while attempting to decode the
+   *                         ASN.1 element to a protocol op.
+   */
+  private static SearchResultDoneProtocolOp readSearchDone(ASN1Reader
+      reader)
+      throws LDAPException
+  {
+    try
+    {
+      reader.readStartSequence();
+    }
+    catch (Exception e)
+    {
+      if (debugEnabled())
+      {
+        TRACER.debugCaught(DebugLogLevel.ERROR, e);
+      }
+
+      Message message = ERR_LDAP_RESULT_DECODE_SEQUENCE.get(String.valueOf(e));
+      throw new LDAPException(PROTOCOL_ERROR, message, e);
+    }
+
+    int resultCode;
+    try
+    {
+      resultCode = (int)reader.readInteger();
+    }
+    catch (Exception e)
+    {
+      if (debugEnabled())
+      {
+        TRACER.debugCaught(DebugLogLevel.ERROR, e);
+      }
+
+      Message message =
+          ERR_LDAP_RESULT_DECODE_RESULT_CODE.get(String.valueOf(e));
+      throw new LDAPException(PROTOCOL_ERROR, message, e);
+    }
+
+
+    DN matchedDN;
+    try
+    {
+      String dnString = reader.readOctetStringAsString();
+      if (dnString.length() == 0)
+      {
+        matchedDN = null;
+      }
+      else
+      {
+        matchedDN = DN.decode(dnString);
+      }
+    }
+    catch (Exception e)
+    {
+      if (debugEnabled())
+      {
+        TRACER.debugCaught(DebugLogLevel.ERROR, e);
+      }
+
+      Message message =
+          ERR_LDAP_RESULT_DECODE_MATCHED_DN.get(String.valueOf(e));
+      throw new LDAPException(PROTOCOL_ERROR, message, e);
+    }
+
+
+    Message errorMessage;
+    try
+    {
+      errorMessage = Message.raw(reader.readOctetStringAsString());
+      if (errorMessage.length() == 0)
+      {
+        errorMessage = null;
+      }
+    }
+    catch (Exception e)
+    {
+      if (debugEnabled())
+      {
+        TRACER.debugCaught(DebugLogLevel.ERROR, e);
+      }
+
+      Message message =
+          ERR_LDAP_RESULT_DECODE_ERROR_MESSAGE.get(String.valueOf(e));
+      throw new LDAPException(PROTOCOL_ERROR, message, e);
+    }
+
+    ArrayList<String> referralURLs = null;
+
+    try
+    {
+      if (reader.hasNextElement())
+      {
+        reader.readStartSequence();
+        referralURLs = new ArrayList<String>();
+
+        while(reader.hasNextElement())
+        {
+          referralURLs.add(reader.readOctetStringAsString());
+        }
+        reader.readEndSequence();
+      }
+    }
+    catch (Exception e)
+    {
+      if (debugEnabled())
+      {
+        TRACER.debugCaught(DebugLogLevel.ERROR, e);
+      }
+
+      Message message =
+          ERR_LDAP_RESULT_DECODE_REFERRALS.get(String.valueOf(e));
+      throw new LDAPException(PROTOCOL_ERROR, message, e);
+    }
+
+    try
+    {
+      reader.readEndSequence();
+    }
+    catch (Exception e)
+    {
+      if (debugEnabled())
+      {
+        TRACER.debugCaught(DebugLogLevel.ERROR, e);
+      }
+
+      Message message = ERR_LDAP_RESULT_DECODE_SEQUENCE.get(String.valueOf(e));
+      throw new LDAPException(PROTOCOL_ERROR, message, e);
+    }
+
+    return new SearchResultDoneProtocolOp(resultCode, errorMessage, matchedDN,
+        referralURLs);
+  }
+
+  /**
+   * Decodes the elements from the provided ASN.1 reader as an LDAP search
+   * result entry protocol op.
+   *
+   * @param  reader The ASN.1 reader.
+   *
+   * @return  The decoded search result entry protocol op.
+   *
+   * @throws  LDAPException  If a problem occurs while decoding the provided
+   *                         ASN.1 element as an LDAP search result entry
+   *                         protocol op.
+   */
+  public static SearchResultEntryProtocolOp readSearchEntry(ASN1Reader
+      reader)
+      throws LDAPException
+  {
+    try
+    {
+      reader.readStartSequence();
+    }
+    catch (Exception e)
+    {
+      if (debugEnabled())
+      {
+        TRACER.debugCaught(DebugLogLevel.ERROR, e);
+      }
+
+      Message message =
+          ERR_LDAP_SEARCH_ENTRY_DECODE_SEQUENCE.get(String.valueOf(e));
+      throw new LDAPException(PROTOCOL_ERROR, message, e);
+    }
+
+
+    DN dn;
+    try
+    {
+      dn = DN.decode(reader.readOctetStringAsString());
+    }
+    catch (Exception e)
+    {
+      if (debugEnabled())
+      {
+        TRACER.debugCaught(DebugLogLevel.ERROR, e);
+      }
+
+      Message message = ERR_LDAP_SEARCH_ENTRY_DECODE_DN.get(String.valueOf(e));
+      throw new LDAPException(PROTOCOL_ERROR, message, e);
+    }
+
+
+
+    LinkedList<LDAPAttribute> attributes;
+    try
+    {
+      reader.readStartSequence();
+      attributes = new LinkedList<LDAPAttribute>();
+      while(reader.hasNextElement())
+      {
+        attributes.add(LDAPAttribute.decode(reader));
+      }
+      reader.readEndSequence();
+    }
+    catch (Exception e)
+    {
+      if (debugEnabled())
+      {
+        TRACER.debugCaught(DebugLogLevel.ERROR, e);
+      }
+
+      Message message =
+          ERR_LDAP_SEARCH_ENTRY_DECODE_ATTRS.get(String.valueOf(e));
+      throw new LDAPException(PROTOCOL_ERROR, message, e);
+    }
+
+    try
+    {
+      reader.readEndSequence();
+    }
+    catch (Exception e)
+    {
+      if (debugEnabled())
+      {
+        TRACER.debugCaught(DebugLogLevel.ERROR, e);
+      }
+
+      Message message =
+          ERR_LDAP_SEARCH_ENTRY_DECODE_SEQUENCE.get(String.valueOf(e));
+      throw new LDAPException(PROTOCOL_ERROR, message, e);
+    }
+
+
+    return new SearchResultEntryProtocolOp(dn, attributes);
+  }
+
+  /**
+   * Decodes the elements from the provided ASN.1 reader as a search
+   * result reference protocol op.
+   *
+   * @param  reader The ASN.1 reader.
+   *
+   * @return  The decoded search result reference protocol op.
+   *
+   * @throws  LDAPException  If a problem occurs while decoding the provided
+   *                         ASN.1 element as an LDAP search result reference
+   *                         protocol op.
+   */
+  private static SearchResultReferenceProtocolOp
+  readSearchReference(ASN1Reader reader)
+      throws LDAPException
+  {
+    try
+    {
+      reader.readStartSequence();
+    }
+    catch (Exception e)
+    {
+      if (debugEnabled())
+      {
+        TRACER.debugCaught(DebugLogLevel.ERROR, e);
+      }
+
+      Message message =
+          ERR_LDAP_SEARCH_REFERENCE_DECODE_SEQUENCE.get(String.valueOf(e));
+      throw new LDAPException(PROTOCOL_ERROR, message, e);
+    }
+
+
+    ArrayList<String> referralURLs = new ArrayList<String>();
+    try
+    {
+      while(reader.hasNextElement())
+      {
+        referralURLs.add(reader.readOctetStringAsString());
+      }
+    }
+    catch (Exception e)
+    {
+      if (debugEnabled())
+      {
+        TRACER.debugCaught(DebugLogLevel.ERROR, e);
+      }
+
+      Message message =
+          ERR_LDAP_SEARCH_REFERENCE_DECODE_URLS.get(String.valueOf(e));
+      throw new LDAPException(PROTOCOL_ERROR, message, e);
+    }
+
+    try
+    {
+      reader.readEndSequence();
+    }
+    catch (Exception e)
+    {
+      if (debugEnabled())
+      {
+        TRACER.debugCaught(DebugLogLevel.ERROR, e);
+      }
+
+      Message message =
+          ERR_LDAP_SEARCH_REFERENCE_DECODE_SEQUENCE.get(String.valueOf(e));
+      throw new LDAPException(PROTOCOL_ERROR, message, e);
+    }
+
+    return new SearchResultReferenceProtocolOp(referralURLs);
+  }
+
+  /**
+   * Decodes the elements from the provided ASN.1 read as an LDAP unbind
+   * request protocol op.
+   *
+   * @param  reader The ASN.1 reader.
+   *
+   * @return  The decoded LDAP unbind request protocol op.
+   *
+   * @throws  LDAPException  If the provided ASN.1 element cannot be decoded as
+   *                         an unbind request protocol op.
+   */
+  private static UnbindRequestProtocolOp readUnbindRequest(ASN1Reader reader)
+      throws LDAPException
+  {
+    try
+    {
+      reader.readNull();
+      return new UnbindRequestProtocolOp();
+    }
+    catch (Exception e)
+    {
+      if (debugEnabled())
+      {
+        TRACER.debugCaught(DebugLogLevel.ERROR, e);
+      }
+
+      Message message = ERR_LDAP_UNBIND_DECODE.get(String.valueOf(e));
+      throw new LDAPException(PROTOCOL_ERROR, message, e);
+    }
+  }
+
+  /**
+   * Decodes the elements from the provided ASN.1 reader as a set of controls.
+   *
+   * @param  reader The ASN.1 reader.
+   *
+   * @return  The decoded set of controls.
+   *
+   * @throws  LDAPException  If a problem occurs while attempting to decode the
+   *                         controls.
+   */
+  private static ArrayList<Control> readControls(ASN1Reader reader)
+      throws LDAPException
+  {
+    try
+    {
+      reader.readStartSequence();
+      ArrayList<Control> controls =
+          new ArrayList<Control>();
+      while(reader.hasNextElement())
+      {
+        controls.add(readControl(reader));
+      }
+
+      reader.readEndSequence();
+      return controls;
+    }
+    catch (Exception e)
+    {
+      Message message =
+          ERR_LDAP_CONTROL_DECODE_CONTROLS_SEQUENCE.get(String.valueOf(e));
+      throw new LDAPException(PROTOCOL_ERROR, message, e);
+    }
+  }
+
+  /**
+   * Decodes the elements from the provided ASN.1 reader as an LDAP control.
+   *
+   * @param  reader The ASN.1 reader.
+   *
+   * @return  The decoded LDAP control.
+   *
+   * @throws  LDAPException  If a problem occurs while attempting to decode the
+   *                         provided ASN.1 element as an LDAP control.
+   */
+  public static LDAPControl readControl(ASN1Reader reader)
+      throws LDAPException
+  {
+    try
+    {
+      reader.readStartSequence();
+    }
+    catch (Exception e)
+    {
+      if (debugEnabled())
+      {
+        TRACER.debugCaught(DebugLogLevel.ERROR, e);
+      }
+
+      Message message = ERR_LDAP_CONTROL_DECODE_SEQUENCE.get(String.valueOf(e));
+      throw new LDAPException(PROTOCOL_ERROR, message, e);
+    }
+
+
+    String oid;
+    try
+    {
+      oid = reader.readOctetStringAsString();
+    }
+    catch (Exception e)
+    {
+      if (debugEnabled())
+      {
+        TRACER.debugCaught(DebugLogLevel.ERROR, e);
+      }
+
+      Message message = ERR_LDAP_CONTROL_DECODE_OID.get(String.valueOf(e));
+      throw new LDAPException(PROTOCOL_ERROR, message, e);
+    }
+
+    boolean isCritical = false;
+    ByteString value = null;
+    try
+    {
+      while(reader.hasNextElement())
+      {
+        switch(reader.peekType())
+        {
+          case UNIVERSAL_BOOLEAN_TYPE:
+            try
+            {
+              isCritical = reader.readBoolean();
+            }
+            catch (Exception e2)
+            {
+              if (debugEnabled())
+              {
+                TRACER.debugCaught(DebugLogLevel.ERROR, e2);
+              }
+
+              Message message =
+                  ERR_LDAP_CONTROL_DECODE_CRITICALITY.get(String.valueOf(e2));
+              throw new LDAPException(PROTOCOL_ERROR, message, e2);
+            }
+            break;
+          case UNIVERSAL_OCTET_STRING_TYPE:
+            try
+            {
+              value = reader.readOctetString();
+            }
+            catch (Exception e2)
+            {
+              if (debugEnabled())
+              {
+                TRACER.debugCaught(DebugLogLevel.ERROR, e2);
+              }
+
+              Message message =
+                  ERR_LDAP_CONTROL_DECODE_VALUE.get(String.valueOf(e2));
+              throw new LDAPException(PROTOCOL_ERROR, message, e2);
+            }
+            break;
+          default:
+            Message message =
+                ERR_LDAP_CONTROL_DECODE_INVALID_TYPE.get(reader.peekType());
+            throw new LDAPException(PROTOCOL_ERROR, message);
+        }
+      }
+    }
+    catch(ASN1Exception asn1e)
+    {
+      if (debugEnabled())
+      {
+        TRACER.debugCaught(DebugLogLevel.ERROR, asn1e);
+      }
+    }
+
+    try
+    {
+      reader.readEndSequence();
+    }
+    catch (Exception e)
+    {
+      if (debugEnabled())
+      {
+        TRACER.debugCaught(DebugLogLevel.ERROR, e);
+      }
+
+      Message message = ERR_LDAP_CONTROL_DECODE_SEQUENCE.get(String.valueOf(e));
+      throw new LDAPException(PROTOCOL_ERROR, message, e);
+    }
+
+    return new LDAPControl(oid, isCritical, value);
+  }
+}
diff --git a/opends/src/server/org/opends/server/protocols/ldap/LDAPRequestHandler.java b/opends/src/server/org/opends/server/protocols/ldap/LDAPRequestHandler.java
index d42ddc9..ecf2be3 100644
--- a/opends/src/server/org/opends/server/protocols/ldap/LDAPRequestHandler.java
+++ b/opends/src/server/org/opends/server/protocols/ldap/LDAPRequestHandler.java
@@ -43,7 +43,6 @@
 import java.util.concurrent.ConcurrentLinkedQueue;
 
 import org.opends.messages.Message;
-import org.opends.server.api.ConnectionSecurityProvider;
 import org.opends.server.api.DirectoryThread;
 import org.opends.server.api.ServerShutdownListener;
 import org.opends.server.core.DirectoryServer;
@@ -222,9 +221,7 @@
 
                 try
                 {
-                  ConnectionSecurityProvider securityProvider =
-                       clientConnection.getConnectionSecurityProvider();
-                  if (! securityProvider.readData())
+                  if (! clientConnection.processDataRead())
                   {
                     key.cancel();
                   }
diff --git a/opends/src/server/org/opends/server/protocols/ldap/LDAPStatistics.java b/opends/src/server/org/opends/server/protocols/ldap/LDAPStatistics.java
index 78627b0..2a81285 100644
--- a/opends/src/server/org/opends/server/protocols/ldap/LDAPStatistics.java
+++ b/opends/src/server/org/opends/server/protocols/ldap/LDAPStatistics.java
@@ -28,62 +28,52 @@
 
 
 
+import static org.opends.messages.ProtocolMessages.*;
+import static org.opends.server.protocols.ldap.LDAPConstants.*;
+import static org.opends.server.types.OperationType.*;
+
 import java.util.ArrayList;
 
 import org.opends.messages.Message;
 import org.opends.server.admin.std.server.MonitorProviderCfg;
 import org.opends.server.api.ConnectionHandler;
 import org.opends.server.api.MonitorProvider;
-import org.opends.server.core.DirectoryServer;
 import org.opends.server.config.ConfigException;
-import org.opends.server.loggers.debug.DebugTracer;
+import org.opends.server.core.DirectoryServer;
 import org.opends.server.monitors.ClientConnectionMonitorProvider;
 import org.opends.server.monitors.OperationMonitor;
-import org.opends.server.protocols.asn1.ASN1OctetString;
 import org.opends.server.types.Attribute;
 import org.opends.server.types.AttributeBuilder;
 import org.opends.server.types.AttributeType;
-import org.opends.server.types.AttributeValue;
-import org.opends.server.types.DebugLogLevel;
-
-import static org.opends.messages.ProtocolMessages.*;
-import static org.opends.server.loggers.debug.DebugLogger.*;
-import static org.opends.server.protocols.ldap.LDAPConstants.*;
-import static org.opends.server.types.OperationType.*;
+import org.opends.server.types.AttributeValues;
 
 
 
 /**
- * This class defines a data structure that will be used to keep track of
- * various metrics related to LDAP communication that the server has conducted.
- * The statistics that will be tracked include:
- *
+ * This class defines a data structure that will be used to keep track
+ * of various metrics related to LDAP communication that the server has
+ * conducted. The statistics that will be tracked include:
  * <UL>
- *   <LI>The total number of LDAP client connections accepted by the
- *       server.</LI>
- *   <LI>The total number of LDAP client connections that have been closed.</LI>
- *   <LI>The total number of LDAP messages read, both overall and broken down
- *       by message type.</LI>
- *   <LI>The total number of LDAP messages written, both overall and broken down
- *       by message type.</LI>
- *   <LI>The total number of bytes read from LDAP clients.</LI>
- *   <LI>The total number of bytes written to LDAP clients.</LI>
+ * <LI>The total number of LDAP client connections accepted by the
+ * server.</LI>
+ * <LI>The total number of LDAP client connections that have been
+ * closed.</LI>
+ * <LI>The total number of LDAP messages read, both overall and broken
+ * down by message type.</LI>
+ * <LI>The total number of LDAP messages written, both overall and
+ * broken down by message type.</LI>
+ * <LI>The total number of bytes read from LDAP clients.</LI>
+ * <LI>The total number of bytes written to LDAP clients.</LI>
  * </UL>
- *
- * <BR><BR>
- * This class may also be used in a hierarchical form if it is desirable to
- * get specific and general statistics at the same time (e.g., information
- * about the interaction with a specific client or aggregated for all clients).
+ * <BR>
+ * <BR>
+ * This class may also be used in a hierarchical form if it is desirable
+ * to get specific and general statistics at the same time (e.g.,
+ * information about the interaction with a specific client or
+ * aggregated for all clients).
  */
-public class LDAPStatistics
-       extends MonitorProvider<MonitorProviderCfg>
+public class LDAPStatistics extends MonitorProvider<MonitorProviderCfg>
 {
-  /**
-   * The tracer object for the debug logger.
-   */
-  private static final DebugTracer TRACER = getTracer();
-
-
 
   // The statistics maintained by this class.
   private long abandonRequests;
@@ -116,57 +106,58 @@
   private long searchResultsDone;
   private long unbindRequests;
 
-  // The parent that should also be updated whenever statistics in this object
-  // are updated.
-  private LDAPStatistics parent;
+  // The parent that should also be updated whenever statistics in this
+  // object are updated.
+  private final LDAPStatistics parent;
 
-  // The locks used to provide threadsafe access to this class.  In this case,
-  // read and write refer to the type of LDAP communication, not access to the
-  // protected data.
-  private Object abandonLock;
-  private Object connectLock;
-  private Object disconnectLock;
-  private Object readLock;
-  private Object writeLock;
+  // The locks used to provide threadsafe access to this class. In this
+  // case, read and write refer to the type of LDAP communication, not
+  // access to the protected data.
+  private final Object abandonLock;
+  private final Object connectLock;
+  private final Object disconnectLock;
+  private final Object readLock;
+  private final Object writeLock;
 
   // The instance name for this monitor provider instance.
-  private String instanceName;
+  private final String instanceName;
 
   // Connection Handler to which the statistics belong to.
-  private ConnectionHandler handler;
+  private final ConnectionHandler handler;
 
+  // Monitor Objects : for Operations.
+  private final OperationMonitor addRequestsMonitor =
+      OperationMonitor.getOperationMonitor(ADD);
+  private final OperationMonitor searchRequestsMonitor =
+      OperationMonitor.getOperationMonitor(SEARCH);
+  private final OperationMonitor delRequestsMonitor =
+      OperationMonitor.getOperationMonitor(DELETE);
+  private final OperationMonitor bindRequestsMonitor =
+      OperationMonitor.getOperationMonitor(BIND);
+  private final OperationMonitor unbindRequestsMonitor =
+      OperationMonitor.getOperationMonitor(UNBIND);
+  private final OperationMonitor compareRequestsMonitor =
+      OperationMonitor.getOperationMonitor(COMPARE);
+  private final OperationMonitor modRequestsMonitor =
+      OperationMonitor.getOperationMonitor(MODIFY);
+  private final OperationMonitor moddnRequestsMonitor =
+      OperationMonitor.getOperationMonitor(MODIFY);
+  private final OperationMonitor abandonRequestsMonitor =
+      OperationMonitor.getOperationMonitor(ABANDON);
+  private final OperationMonitor extendedRequestsMonitor =
+      OperationMonitor.getOperationMonitor(EXTENDED);
 
-    // Monitor Objects : for Operations.
-    private OperationMonitor addRequestsMonitor =
-            OperationMonitor.getOperationMonitor(ADD);
-    private OperationMonitor searchRequestsMonitor =
-            OperationMonitor.getOperationMonitor(SEARCH);
-    private OperationMonitor delRequestsMonitor =
-            OperationMonitor.getOperationMonitor(DELETE);
-    private OperationMonitor bindRequestsMonitor =
-            OperationMonitor.getOperationMonitor(BIND);
-    private OperationMonitor unbindRequestsMonitor =
-            OperationMonitor.getOperationMonitor(UNBIND);
-    private OperationMonitor compareRequestsMonitor =
-            OperationMonitor.getOperationMonitor(COMPARE);
-    private OperationMonitor modRequestsMonitor =
-            OperationMonitor.getOperationMonitor(MODIFY);
-    private OperationMonitor moddnRequestsMonitor =
-            OperationMonitor.getOperationMonitor(MODIFY);
-    private OperationMonitor abandonRequestsMonitor =
-            OperationMonitor.getOperationMonitor(ABANDON);
-    private OperationMonitor extendedRequestsMonitor =
-            OperationMonitor.getOperationMonitor(EXTENDED);
 
 
   /**
    * Creates a new instance of this class with no parent.
    *
-   * @param handler to which the stats belong  to.
-   * @param  instanceName  The name for this monitor provider instance.
+   * @param handler
+   *          to which the stats belong to.
+   * @param instanceName
+   *          The name for this monitor provider instance.
    */
-  public LDAPStatistics(ConnectionHandler handler,
-          String instanceName)
+  public LDAPStatistics(ConnectionHandler handler, String instanceName)
   {
     this(handler, instanceName, null);
 
@@ -178,60 +169,62 @@
   /**
    * Creates a new instance of this class with the specified parent.
    *
-   * @param  handler       the handler to which the stats belong to.
-   * @param  instanceName  The name for this monitor provider instance.
-   * @param  parent        The parent object that should also be updated
-   *                       whenever this class is updated.  It may be null if
-   *                       there should not be a parent.
+   * @param handler
+   *          the handler to which the stats belong to.
+   * @param instanceName
+   *          The name for this monitor provider instance.
+   * @param parent
+   *          The parent object that should also be updated whenever
+   *          this class is updated. It may be null if there should not
+   *          be a parent.
    */
-  public LDAPStatistics(ConnectionHandler handler,
-          String instanceName, LDAPStatistics parent)
+  public LDAPStatistics(ConnectionHandler handler, String instanceName,
+      LDAPStatistics parent)
   {
     super("LDAP Statistics Monitor Provider");
 
-
     this.instanceName = instanceName;
-    this.parent       = parent;
+    this.parent = parent;
     this.handler = handler;
 
-    abandonLock    = new Object();
-    connectLock    = new Object();
+    abandonLock = new Object();
+    connectLock = new Object();
     disconnectLock = new Object();
-    readLock       = new Object();
-    writeLock      = new Object();
+    readLock = new Object();
+    writeLock = new Object();
 
-    abandonRequests        = 0;
-    addRequests            = 0;
-    addResponses           = 0;
-    bindRequests           = 0;
-    bindResponses          = 0;
-    bytesRead              = 0;
-    bytesWritten           = 0;
-    compareRequests        = 0;
-    compareResponses       = 0;
-    connectionsClosed      = 0;
+    abandonRequests = 0;
+    addRequests = 0;
+    addResponses = 0;
+    bindRequests = 0;
+    bindResponses = 0;
+    bytesRead = 0;
+    bytesWritten = 0;
+    compareRequests = 0;
+    compareResponses = 0;
+    connectionsClosed = 0;
     connectionsEstablished = 0;
-    deleteRequests         = 0;
-    deleteResponses        = 0;
-    extendedRequests       = 0;
-    extendedResponses      = 0;
-    messagesRead           = 0;
-    messagesWritten        = 0;
-    modifyRequests         = 0;
-    modifyResponses        = 0;
-    modifyDNRequests       = 0;
-    modifyDNResponses      = 0;
-    operationsAbandoned    = 0;
-    operationsCompleted    = 0;
-    operationsInitiated    = 0;
-    searchRequests         = 0;
-    searchResultEntries    = 0;
+    deleteRequests = 0;
+    deleteResponses = 0;
+    extendedRequests = 0;
+    extendedResponses = 0;
+    messagesRead = 0;
+    messagesWritten = 0;
+    modifyRequests = 0;
+    modifyResponses = 0;
+    modifyDNRequests = 0;
+    modifyDNResponses = 0;
+    operationsAbandoned = 0;
+    operationsCompleted = 0;
+    operationsInitiated = 0;
+    searchRequests = 0;
+    searchResultEntries = 0;
     searchResultReferences = 0;
-    searchResultsDone      = 0;
-    unbindRequests         = 0;
+    searchResultsDone = 0;
+    unbindRequests = 0;
 
     ClientConnectionMonitorProvider connections =
-                new ClientConnectionMonitorProvider(this.handler);
+        new ClientConnectionMonitorProvider(this.handler);
 
     DirectoryServer.registerMonitorProvider(connections);
   }
@@ -241,26 +234,30 @@
   /**
    * {@inheritDoc}
    */
+  @Override
   public void initializeMonitorProvider(MonitorProviderCfg configuration)
-         throws ConfigException
+      throws ConfigException
   {
     // Throw an exception, because this monitor is not intended to be
-    // dynamically loaded from the configuration.  Rather, it should be
-    // explicitly created and registered by the LDAP connection handler or an
-    // LDAP client connection.
-    Message message = ERR_LDAP_STATS_INVALID_MONITOR_INITIALIZATION.get(
-        String.valueOf(configuration.dn()));
+    // dynamically loaded from the configuration. Rather, it should be
+    // explicitly created and registered by the LDAP connection handler
+    // or an LDAP client connection.
+    Message message =
+        ERR_LDAP_STATS_INVALID_MONITOR_INITIALIZATION.get(String
+            .valueOf(configuration.dn()));
     throw new ConfigException(message);
   }
 
 
 
   /**
-   * Retrieves the name of this monitor provider.  It should be unique among all
-   * monitor providers, including all instances of the same monitor provider.
+   * Retrieves the name of this monitor provider. It should be unique
+   * among all monitor providers, including all instances of the same
+   * monitor provider.
    *
-   * @return  The name of this monitor provider.
+   * @return The name of this monitor provider.
    */
+  @Override
   public String getMonitorInstanceName()
   {
     return instanceName;
@@ -269,14 +266,17 @@
 
 
   /**
-   * Retrieves the length of time in milliseconds that should elapse between
-   * calls to the <CODE>updateMonitorData()</CODE> method.  A negative or zero
-   * return value indicates that the <CODE>updateMonitorData()</CODE> method
-   * should not be periodically invoked.
+   * Retrieves the length of time in milliseconds that should elapse
+   * between calls to the <CODE>updateMonitorData()</CODE> method. A
+   * negative or zero return value indicates that the
+   * <CODE>updateMonitorData()</CODE> method should not be periodically
+   * invoked.
    *
-   * @return  The length of time in milliseconds that should elapse between
-   *          calls to the <CODE>updateMonitorData()</CODE> method.
+   * @return The length of time in milliseconds that should elapse
+   *         between calls to the <CODE>updateMonitorData()</CODE>
+   *         method.
    */
+  @Override
   public long getUpdateInterval()
   {
     // This monitor should not run periodically.
@@ -286,27 +286,31 @@
 
 
   /**
-   * Performs any processing periodic processing that may be desired to update
-   * the information associated with this monitor.  Note that best-effort
-   * attempts will be made to ensure that calls to this method come
-   * <CODE>getUpdateInterval()</CODE> milliseconds apart, but no guarantees will
-   * be made.
+   * Performs any processing periodic processing that may be desired to
+   * update the information associated with this monitor. Note that
+   * best-effort attempts will be made to ensure that calls to this
+   * method come <CODE>getUpdateInterval()</CODE> milliseconds apart,
+   * but no guarantees will be made.
    */
+  @Override
   public void updateMonitorData()
   {
-    // No implementation is required since this does not do periodic updates.
+    // No implementation is required since this does not do periodic
+    // updates.
   }
 
 
 
   /**
-   * Retrieves a set of attributes containing monitor data that should be
-   * returned to the client if the corresponding monitor entry is requested.
+   * Retrieves a set of attributes containing monitor data that should
+   * be returned to the client if the corresponding monitor entry is
+   * requested.
    *
-   * @return  A set of attributes containing monitor data that should be
-   *          returned to the client if the corresponding monitor entry is
-   *          requested.
+   * @return A set of attributes containing monitor data that should be
+   *         returned to the client if the corresponding monitor entry
+   *         is requested.
    */
+  @Override
   public ArrayList<Attribute> getMonitorData()
   {
     ArrayList<Attribute> attrs = new ArrayList<Attribute>(29);
@@ -341,9 +345,10 @@
     long tmpSearchResultsDone;
     long tmpUnbindRequests;
 
-    // Quickly grab the locks and store consistent copies of the information.
-    // Note that when grabbing multiple locks, it is essential that they are all
-    // acquired in the same order to prevent deadlocks.
+    // Quickly grab the locks and store consistent copies of the
+    // information. Note that when grabbing multiple locks, it is
+    // essential that they are all acquired in the same order to prevent
+    // deadlocks.
     synchronized (abandonLock)
     {
       synchronized (connectLock)
@@ -354,180 +359,177 @@
           {
             synchronized (readLock)
             {
-              tmpAbandonRequests        = abandonRequests;
-              tmpAddRequests            = addRequests;
-              tmpAddResponses           = addResponses;
-              tmpBindRequests           = bindRequests;
-              tmpBindResponses          = bindResponses;
-              tmpBytesRead              = bytesRead;
-              tmpBytesWritten           = bytesWritten;
-              tmpCompareRequests        = compareRequests;
-              tmpCompareResponses       = compareResponses;
-              tmpConnectionsClosed      = connectionsClosed;
+              tmpAbandonRequests = abandonRequests;
+              tmpAddRequests = addRequests;
+              tmpAddResponses = addResponses;
+              tmpBindRequests = bindRequests;
+              tmpBindResponses = bindResponses;
+              tmpBytesRead = bytesRead;
+              tmpBytesWritten = bytesWritten;
+              tmpCompareRequests = compareRequests;
+              tmpCompareResponses = compareResponses;
+              tmpConnectionsClosed = connectionsClosed;
               tmpConnectionsEstablished = connectionsEstablished;
-              tmpDeleteRequests         = deleteRequests;
-              tmpDeleteResponses        = deleteResponses;
-              tmpExtendedRequests       = extendedRequests;
-              tmpExtendedResponses      = extendedResponses;
-              tmpMessagesRead           = messagesRead;
-              tmpMessagesWritten        = messagesWritten;
-              tmpModifyRequests         = modifyRequests;
-              tmpModifyResponses        = modifyResponses;
-              tmpModifyDNRequests       = modifyDNRequests;
-              tmpModifyDNResponses      = modifyDNResponses;
-              tmpOperationsAbandoned    = operationsAbandoned;
-              tmpOperationsCompleted    = operationsCompleted;
-              tmpOperationsInitiated    = operationsInitiated;
-              tmpSearchRequests         = searchRequests;
-              tmpSearchEntries          = searchResultEntries;
-              tmpSearchReferences       = searchResultReferences;
-              tmpSearchResultsDone      = searchResultsDone;
-              tmpUnbindRequests         = unbindRequests;
+              tmpDeleteRequests = deleteRequests;
+              tmpDeleteResponses = deleteResponses;
+              tmpExtendedRequests = extendedRequests;
+              tmpExtendedResponses = extendedResponses;
+              tmpMessagesRead = messagesRead;
+              tmpMessagesWritten = messagesWritten;
+              tmpModifyRequests = modifyRequests;
+              tmpModifyResponses = modifyResponses;
+              tmpModifyDNRequests = modifyDNRequests;
+              tmpModifyDNResponses = modifyDNResponses;
+              tmpOperationsAbandoned = operationsAbandoned;
+              tmpOperationsCompleted = operationsCompleted;
+              tmpOperationsInitiated = operationsInitiated;
+              tmpSearchRequests = searchRequests;
+              tmpSearchEntries = searchResultEntries;
+              tmpSearchReferences = searchResultReferences;
+              tmpSearchResultsDone = searchResultsDone;
+              tmpUnbindRequests = unbindRequests;
             }
           }
         }
       }
     }
 
-
     // Construct the list of attributes to return.
-    attrs.add(createAttribute("connectionsEstablished",
-                              String.valueOf(tmpConnectionsEstablished)));
-    attrs.add(createAttribute("connectionsClosed",
-                              String.valueOf(tmpConnectionsClosed)));
-    attrs.add(createAttribute("bytesRead", String.valueOf(tmpBytesRead)));
-    attrs.add(createAttribute("bytesWritten", String.valueOf(tmpBytesWritten)));
-    attrs.add(createAttribute("ldapMessagesRead",
-                              String.valueOf(tmpMessagesRead)));
-    attrs.add(createAttribute("ldapMessagesWritten",
-                              String.valueOf(tmpMessagesWritten)));
-    attrs.add(createAttribute("operationsAbandoned",
-                              String.valueOf(tmpOperationsAbandoned)));
-    attrs.add(createAttribute("operationsInitiated",
-                              String.valueOf(tmpOperationsInitiated)));
-    attrs.add(createAttribute("operationsCompleted",
-                              String.valueOf(tmpOperationsCompleted)));
-    attrs.add(createAttribute("abandonRequests",
-                              String.valueOf(tmpAbandonRequests)));
-    attrs.add(createAttribute("addRequests", String.valueOf(tmpAddRequests)));
-    attrs.add(createAttribute("addResponses", String.valueOf(tmpAddResponses)));
-    attrs.add(createAttribute("bindRequests", String.valueOf(tmpBindRequests)));
-    attrs.add(createAttribute("bindResponses",
-                              String.valueOf(tmpBindResponses)));
-    attrs.add(createAttribute("compareRequests",
-                              String.valueOf(tmpCompareRequests)));
-    attrs.add(createAttribute("compareResponses",
-                              String.valueOf(tmpCompareResponses)));
-    attrs.add(createAttribute("deleteRequests",
-                              String.valueOf(tmpDeleteRequests)));
-    attrs.add(createAttribute("deleteResponses",
-                              String.valueOf(tmpDeleteResponses)));
-    attrs.add(createAttribute("extendedRequests",
-                              String.valueOf(tmpExtendedRequests)));
-    attrs.add(createAttribute("extendedResponses",
-                              String.valueOf(tmpExtendedResponses)));
-    attrs.add(createAttribute("modifyRequests",
-                              String.valueOf(tmpModifyRequests)));
-    attrs.add(createAttribute("modifyResponses",
-                              String.valueOf(tmpModifyResponses)));
-    attrs.add(createAttribute("modifyDNRequests",
-                              String.valueOf(tmpModifyDNRequests)));
-    attrs.add(createAttribute("modifyDNResponses",
-                              String.valueOf(tmpModifyDNResponses)));
-    attrs.add(createAttribute("searchRequests",
-                              String.valueOf(tmpSearchRequests)));
-    attrs.add(createAttribute("searchResultEntries",
-                              String.valueOf(tmpSearchEntries)));
-    attrs.add(createAttribute("searchResultReferences",
-                              String.valueOf(tmpSearchReferences)));
-    attrs.add(createAttribute("searchResultsDone",
-                              String.valueOf(tmpSearchResultsDone)));
-    attrs.add(createAttribute("unbindRequests",
-                              String.valueOf(tmpUnbindRequests)));
+    attrs.add(createAttribute("connectionsEstablished", String
+        .valueOf(tmpConnectionsEstablished)));
+    attrs.add(createAttribute("connectionsClosed", String
+        .valueOf(tmpConnectionsClosed)));
+    attrs
+        .add(createAttribute("bytesRead", String.valueOf(tmpBytesRead)));
+    attrs.add(createAttribute("bytesWritten", String
+        .valueOf(tmpBytesWritten)));
+    attrs.add(createAttribute("ldapMessagesRead", String
+        .valueOf(tmpMessagesRead)));
+    attrs.add(createAttribute("ldapMessagesWritten", String
+        .valueOf(tmpMessagesWritten)));
+    attrs.add(createAttribute("operationsAbandoned", String
+        .valueOf(tmpOperationsAbandoned)));
+    attrs.add(createAttribute("operationsInitiated", String
+        .valueOf(tmpOperationsInitiated)));
+    attrs.add(createAttribute("operationsCompleted", String
+        .valueOf(tmpOperationsCompleted)));
+    attrs.add(createAttribute("abandonRequests", String
+        .valueOf(tmpAbandonRequests)));
+    attrs.add(createAttribute("addRequests", String
+        .valueOf(tmpAddRequests)));
+    attrs.add(createAttribute("addResponses", String
+        .valueOf(tmpAddResponses)));
+    attrs.add(createAttribute("bindRequests", String
+        .valueOf(tmpBindRequests)));
+    attrs.add(createAttribute("bindResponses", String
+        .valueOf(tmpBindResponses)));
+    attrs.add(createAttribute("compareRequests", String
+        .valueOf(tmpCompareRequests)));
+    attrs.add(createAttribute("compareResponses", String
+        .valueOf(tmpCompareResponses)));
+    attrs.add(createAttribute("deleteRequests", String
+        .valueOf(tmpDeleteRequests)));
+    attrs.add(createAttribute("deleteResponses", String
+        .valueOf(tmpDeleteResponses)));
+    attrs.add(createAttribute("extendedRequests", String
+        .valueOf(tmpExtendedRequests)));
+    attrs.add(createAttribute("extendedResponses", String
+        .valueOf(tmpExtendedResponses)));
+    attrs.add(createAttribute("modifyRequests", String
+        .valueOf(tmpModifyRequests)));
+    attrs.add(createAttribute("modifyResponses", String
+        .valueOf(tmpModifyResponses)));
+    attrs.add(createAttribute("modifyDNRequests", String
+        .valueOf(tmpModifyDNRequests)));
+    attrs.add(createAttribute("modifyDNResponses", String
+        .valueOf(tmpModifyDNResponses)));
+    attrs.add(createAttribute("searchRequests", String
+        .valueOf(tmpSearchRequests)));
+    attrs.add(createAttribute("searchResultEntries", String
+        .valueOf(tmpSearchEntries)));
+    attrs.add(createAttribute("searchResultReferences", String
+        .valueOf(tmpSearchReferences)));
+    attrs.add(createAttribute("searchResultsDone", String
+        .valueOf(tmpSearchResultsDone)));
+    attrs.add(createAttribute("unbindRequests", String
+        .valueOf(tmpUnbindRequests)));
 
-     // adds
-     attrs.add(createAttribute(
-                "ds-mon-add-operations-total-count",
-                String.valueOf(addRequestsMonitor.getCounter().getCount())));
-     attrs.add(createAttribute(
-                "ds-mon-resident-time-add-operations-total-time",
-                String.valueOf(addRequestsMonitor.getTotalTime())));
+    // adds
+    attrs.add(createAttribute("ds-mon-add-operations-total-count",
+        String.valueOf(addRequestsMonitor.getCounter().getCount())));
+    attrs.add(createAttribute(
+        "ds-mon-resident-time-add-operations-total-time", String
+            .valueOf(addRequestsMonitor.getTotalTime())));
 
-     // search
-     attrs.add(createAttribute(
-              "ds-mon-search-operations-total-count",
-                String.valueOf(searchRequestsMonitor.getCounter().getCount())));
-     attrs.add(createAttribute(
-                "ds-mon-resident-time-search-operations-total-time",
-                String.valueOf(searchRequestsMonitor.getTotalTime())));
+    // search
+    attrs.add(createAttribute("ds-mon-search-operations-total-count",
+        String.valueOf(searchRequestsMonitor.getCounter().getCount())));
+    attrs.add(createAttribute(
+        "ds-mon-resident-time-search-operations-total-time", String
+            .valueOf(searchRequestsMonitor.getTotalTime())));
 
-     // bind
-     attrs.add(createAttribute(
-                "ds-mon-bind-operations-total-count",
-                String.valueOf(bindRequestsMonitor.getCounter().getCount())));
-     attrs.add(createAttribute(
-                "ds-mon-resident-time-bind-operations-total-time",
-                String.valueOf(bindRequestsMonitor.getTotalTime())));
+    // bind
+    attrs.add(createAttribute("ds-mon-bind-operations-total-count",
+        String.valueOf(bindRequestsMonitor.getCounter().getCount())));
+    attrs.add(createAttribute(
+        "ds-mon-resident-time-bind-operations-total-time", String
+            .valueOf(bindRequestsMonitor.getTotalTime())));
 
-     // unbind
-     attrs.add(createAttribute(
-              "ds-mon-unbind-operations-total-count",
-              String.valueOf(unbindRequestsMonitor.getCounter().getCount())));
-     attrs.add(createAttribute(
-                "ds-mon-resident-time-unbind-operations-total-time",
-                String.valueOf(unbindRequestsMonitor.getTotalTime())));
+    // unbind
+    attrs.add(createAttribute("ds-mon-unbind-operations-total-count",
+        String.valueOf(unbindRequestsMonitor.getCounter().getCount())));
+    attrs.add(createAttribute(
+        "ds-mon-resident-time-unbind-operations-total-time", String
+            .valueOf(unbindRequestsMonitor.getTotalTime())));
 
-     // compare
-     attrs.add(createAttribute(
-             "ds-mon-compare-operations-total-count",
-             String.valueOf(
-             compareRequestsMonitor.getCounter().getCount())));
-     attrs.add(createAttribute(
-             "ds-mon-resident-time-compare-operations-total-time",
-             String.valueOf(compareRequestsMonitor.getTotalTime())));
-     // del
-     attrs.add(createAttribute(
-             "ds-mon-delete-operations-total-count",
-             String.valueOf(delRequestsMonitor.getCounter().getCount())));
-     attrs.add(createAttribute(
-             "ds-mon-resident-time-delete-operations-total-time",
-             String.valueOf(delRequestsMonitor.getTotalTime())));
+    // compare
+    attrs
+        .add(createAttribute("ds-mon-compare-operations-total-count",
+            String.valueOf(compareRequestsMonitor.getCounter()
+                .getCount())));
+    attrs.add(createAttribute(
+        "ds-mon-resident-time-compare-operations-total-time", String
+            .valueOf(compareRequestsMonitor.getTotalTime())));
+    // del
+    attrs.add(createAttribute("ds-mon-delete-operations-total-count",
+        String.valueOf(delRequestsMonitor.getCounter().getCount())));
+    attrs.add(createAttribute(
+        "ds-mon-resident-time-delete-operations-total-time", String
+            .valueOf(delRequestsMonitor.getTotalTime())));
 
-     // mod
-     attrs.add(createAttribute(
-             "ds-mon-mod-operations-total-count",
-             String.valueOf(modRequestsMonitor.getCounter().getCount())));
-     attrs.add(createAttribute(
-            "ds-mon-resident-time-mod-operations-total-time",
-            String.valueOf(modRequestsMonitor.getTotalTime())));
+    // mod
+    attrs.add(createAttribute("ds-mon-mod-operations-total-count",
+        String.valueOf(modRequestsMonitor.getCounter().getCount())));
+    attrs.add(createAttribute(
+        "ds-mon-resident-time-mod-operations-total-time", String
+            .valueOf(modRequestsMonitor.getTotalTime())));
 
-     // moddn
-     attrs.add(createAttribute(
-            "ds-mon-moddn-operations-total-count",
-            String.valueOf(moddnRequestsMonitor.getCounter().getCount())));
-     attrs.add(createAttribute(
-            "ds-mon-resident-time-moddn-operations-total-time",
-            String.valueOf(moddnRequestsMonitor.getTotalTime())));
+    // moddn
+    attrs.add(createAttribute("ds-mon-moddn-operations-total-count",
+        String.valueOf(moddnRequestsMonitor.getCounter().getCount())));
+    attrs.add(createAttribute(
+        "ds-mon-resident-time-moddn-operations-total-time", String
+            .valueOf(moddnRequestsMonitor.getTotalTime())));
 
-     // abandon
-     attrs.add(createAttribute(
-             "ds-mon-abandon-operations-total-count",
-             String.valueOf(
-             abandonRequestsMonitor.getCounter().getCount())));
-     attrs.add(createAttribute(
-             "ds-mon-resident-time-abandon-operations-total-time",
-             String.valueOf(abandonRequestsMonitor.getTotalTime())));
+    // abandon
+    attrs
+        .add(createAttribute("ds-mon-abandon-operations-total-count",
+            String.valueOf(abandonRequestsMonitor.getCounter()
+                .getCount())));
+    attrs.add(createAttribute(
+        "ds-mon-resident-time-abandon-operations-total-time", String
+            .valueOf(abandonRequestsMonitor.getTotalTime())));
 
-     // extended
-     attrs.add(createAttribute(
-             "ds-mon-extended-operations-total-count",
-             String.valueOf(
-             extendedRequestsMonitor.getCounter().getCount())));
-     attrs.add(createAttribute(
-             "ds-mon-resident-time-extended-operations-total-time",
-             String.valueOf(extendedRequestsMonitor.getTotalTime())));
+    // extended
+    attrs
+        .add(createAttribute("ds-mon-extended-operations-total-count",
+            String.valueOf(extendedRequestsMonitor.getCounter()
+                .getCount())));
+    attrs.add(createAttribute(
+        "ds-mon-resident-time-extended-operations-total-time", String
+            .valueOf(extendedRequestsMonitor.getTotalTime())));
 
-     return attrs;
+    return attrs;
   }
 
 
@@ -537,9 +539,10 @@
    */
   public void clearStatistics()
   {
-    // Quickly grab the locks and store consistent copies of the information.
-    // Note that when grabbing multiple locks, it is essential that they are all
-    // acquired in the same order to prevent deadlocks.
+    // Quickly grab the locks and store consistent copies of the
+    // information. Note that when grabbing multiple locks, it is
+    // essential that they are all acquired in the same order to prevent
+    // deadlocks.
     synchronized (abandonLock)
     {
       synchronized (connectLock)
@@ -550,35 +553,35 @@
           {
             synchronized (readLock)
             {
-              abandonRequests        = 0;
-              addRequests            = 0;
-              addResponses           = 0;
-              bindRequests           = 0;
-              bindResponses          = 0;
-              bytesRead              = 0;
-              bytesWritten           = 0;
-              compareRequests        = 0;
-              compareResponses       = 0;
-              connectionsClosed      = 0;
+              abandonRequests = 0;
+              addRequests = 0;
+              addResponses = 0;
+              bindRequests = 0;
+              bindResponses = 0;
+              bytesRead = 0;
+              bytesWritten = 0;
+              compareRequests = 0;
+              compareResponses = 0;
+              connectionsClosed = 0;
               connectionsEstablished = 0;
-              deleteRequests         = 0;
-              deleteResponses        = 0;
-              extendedRequests       = 0;
-              extendedResponses      = 0;
-              messagesRead           = 0;
-              messagesWritten        = 0;
-              modifyRequests         = 0;
-              modifyResponses        = 0;
-              modifyDNRequests       = 0;
-              modifyDNResponses      = 0;
-              operationsAbandoned    = 0;
-              operationsCompleted    = 0;
-              operationsInitiated    = 0;
-              searchRequests         = 0;
-              searchResultEntries    = 0;
+              deleteRequests = 0;
+              deleteResponses = 0;
+              extendedRequests = 0;
+              extendedResponses = 0;
+              messagesRead = 0;
+              messagesWritten = 0;
+              modifyRequests = 0;
+              modifyResponses = 0;
+              modifyDNRequests = 0;
+              modifyDNResponses = 0;
+              operationsAbandoned = 0;
+              operationsCompleted = 0;
+              operationsInitiated = 0;
+              searchRequests = 0;
+              searchResultEntries = 0;
               searchResultReferences = 0;
-              searchResultsDone      = 0;
-              unbindRequests         = 0;
+              searchResultsDone = 0;
+              unbindRequests = 0;
             }
           }
         }
@@ -589,8 +592,8 @@
 
 
   /**
-   * Updates the appropriate set of counters to indicate that a new connection
-   * has been established.
+   * Updates the appropriate set of counters to indicate that a new
+   * connection has been established.
    */
   public void updateConnect()
   {
@@ -609,8 +612,8 @@
 
 
   /**
-   * Updates the appropriate set of counters to indicate that a connection has
-   * been closed.
+   * Updates the appropriate set of counters to indicate that a
+   * connection has been closed.
    */
   public void updateDisconnect()
   {
@@ -629,10 +632,11 @@
 
 
   /**
-   * Updates the appropriate set of counters to indicate that the specified
-   * number of bytes have been read by the client.
+   * Updates the appropriate set of counters to indicate that the
+   * specified number of bytes have been read by the client.
    *
-   * @param  bytesRead  The number of bytes read by the client.
+   * @param bytesRead
+   *          The number of bytes read by the client.
    */
   public void updateBytesRead(int bytesRead)
   {
@@ -651,10 +655,11 @@
 
 
   /**
-   * Updates the appropriate set of counters based on the provided message that
-   * has been read from the client.
+   * Updates the appropriate set of counters based on the provided
+   * message that has been read from the client.
    *
-   * @param  message  The message that was read from the client.
+   * @param message
+   *          The message that was read from the client.
    */
   public void updateMessageRead(LDAPMessage message)
   {
@@ -665,36 +670,36 @@
 
       switch (message.getProtocolOp().getType())
       {
-        case OP_TYPE_ABANDON_REQUEST:
-          abandonRequests++;
-          break;
-        case OP_TYPE_ADD_REQUEST:
-          addRequests++;
-          break;
-        case OP_TYPE_BIND_REQUEST:
-          bindRequests++;
-          break;
-        case OP_TYPE_COMPARE_REQUEST:
-          compareRequests++;
-          break;
-        case OP_TYPE_DELETE_REQUEST:
-          deleteRequests++;
-          break;
-        case OP_TYPE_EXTENDED_REQUEST:
-          extendedRequests++;
-          break;
-        case OP_TYPE_MODIFY_REQUEST:
-          modifyRequests++;
-          break;
-        case OP_TYPE_MODIFY_DN_REQUEST:
-          modifyDNRequests++;
-          break;
-        case OP_TYPE_SEARCH_REQUEST:
-          searchRequests++;
-          break;
-        case OP_TYPE_UNBIND_REQUEST:
-          unbindRequests++;
-          break;
+      case OP_TYPE_ABANDON_REQUEST:
+        abandonRequests++;
+        break;
+      case OP_TYPE_ADD_REQUEST:
+        addRequests++;
+        break;
+      case OP_TYPE_BIND_REQUEST:
+        bindRequests++;
+        break;
+      case OP_TYPE_COMPARE_REQUEST:
+        compareRequests++;
+        break;
+      case OP_TYPE_DELETE_REQUEST:
+        deleteRequests++;
+        break;
+      case OP_TYPE_EXTENDED_REQUEST:
+        extendedRequests++;
+        break;
+      case OP_TYPE_MODIFY_REQUEST:
+        modifyRequests++;
+        break;
+      case OP_TYPE_MODIFY_DN_REQUEST:
+        modifyDNRequests++;
+        break;
+      case OP_TYPE_SEARCH_REQUEST:
+        searchRequests++;
+        break;
+      case OP_TYPE_UNBIND_REQUEST:
+        unbindRequests++;
+        break;
       }
     }
 
@@ -708,11 +713,13 @@
 
 
   /**
-   * Updates the appropriate set of counters based on the provided message that
-   * has been written to the client.
+   * Updates the appropriate set of counters based on the provided
+   * message that has been written to the client.
    *
-   * @param  message       The message that was written to the client.
-   * @param  bytesWritten  The size of the message written in bytes.
+   * @param message
+   *          The message that was written to the client.
+   * @param bytesWritten
+   *          The size of the message written in bytes.
    */
   public void updateMessageWritten(LDAPMessage message, int bytesWritten)
   {
@@ -723,50 +730,50 @@
 
       switch (message.getProtocolOp().getType())
       {
-        case OP_TYPE_ADD_RESPONSE:
-          addResponses++;
-          operationsCompleted++;
-          break;
-        case OP_TYPE_BIND_RESPONSE:
-          bindResponses++;
-          operationsCompleted++;
-          break;
-        case OP_TYPE_COMPARE_RESPONSE:
-          compareResponses++;
-          operationsCompleted++;
-          break;
-        case OP_TYPE_DELETE_RESPONSE:
-          deleteResponses++;
-          operationsCompleted++;
-          break;
-        case OP_TYPE_EXTENDED_RESPONSE:
-          extendedResponses++;
+      case OP_TYPE_ADD_RESPONSE:
+        addResponses++;
+        operationsCompleted++;
+        break;
+      case OP_TYPE_BIND_RESPONSE:
+        bindResponses++;
+        operationsCompleted++;
+        break;
+      case OP_TYPE_COMPARE_RESPONSE:
+        compareResponses++;
+        operationsCompleted++;
+        break;
+      case OP_TYPE_DELETE_RESPONSE:
+        deleteResponses++;
+        operationsCompleted++;
+        break;
+      case OP_TYPE_EXTENDED_RESPONSE:
+        extendedResponses++;
 
-          // We don't want to include unsolicited notifications as "completed"
-          // operations.
-          if (message.getMessageID() > 0)
-          {
-            operationsCompleted++;
-          }
-          break;
-        case OP_TYPE_MODIFY_RESPONSE:
-          modifyResponses++;
+        // We don't want to include unsolicited notifications as
+        // "completed" operations.
+        if (message.getMessageID() > 0)
+        {
           operationsCompleted++;
-          break;
-        case OP_TYPE_MODIFY_DN_RESPONSE:
-          modifyDNResponses++;
-          operationsCompleted++;
-          break;
-        case OP_TYPE_SEARCH_RESULT_ENTRY:
-          searchResultEntries++;
-          break;
-        case OP_TYPE_SEARCH_RESULT_REFERENCE:
-          searchResultReferences++;
-          break;
-        case OP_TYPE_SEARCH_RESULT_DONE:
-          searchResultsDone++;
-          operationsCompleted++;
-          break;
+        }
+        break;
+      case OP_TYPE_MODIFY_RESPONSE:
+        modifyResponses++;
+        operationsCompleted++;
+        break;
+      case OP_TYPE_MODIFY_DN_RESPONSE:
+        modifyDNResponses++;
+        operationsCompleted++;
+        break;
+      case OP_TYPE_SEARCH_RESULT_ENTRY:
+        searchResultEntries++;
+        break;
+      case OP_TYPE_SEARCH_RESULT_REFERENCE:
+        searchResultReferences++;
+        break;
+      case OP_TYPE_SEARCH_RESULT_DONE:
+        searchResultsDone++;
+        operationsCompleted++;
+        break;
       }
     }
 
@@ -780,8 +787,8 @@
 
 
   /**
-   * Updates the appropriate set of counters to indicate that an operation was
-   * abandoned without sending a response to the client.
+   * Updates the appropriate set of counters to indicate that an
+   * operation was abandoned without sending a response to the client.
    */
   public void updateAbandonedOperation()
   {
@@ -800,34 +807,22 @@
 
 
   /**
-   * Constructs an attribute using the provided information.  It will have the
-   * default syntax.
+   * Constructs an attribute using the provided information. It will
+   * have the default syntax.
    *
-   * @param  name   The name to use for the attribute.
-   * @param  value  The value to use for the attribute.
-   *
-   * @return  the constructed attribute.
+   * @param name
+   *          The name to use for the attribute.
+   * @param value
+   *          The value to use for the attribute.
+   * @return the constructed attribute.
    */
   private Attribute createAttribute(String name, String value)
   {
-    AttributeType attrType = DirectoryServer.getDefaultAttributeType(name);
+    AttributeType attrType =
+        DirectoryServer.getDefaultAttributeType(name);
 
-    ASN1OctetString encodedValue = new ASN1OctetString(value);
     AttributeBuilder builder = new AttributeBuilder(attrType, name);
-    try
-    {
-      builder.add(new AttributeValue(encodedValue, attrType
-          .normalize(encodedValue)));
-    }
-    catch (Exception e)
-    {
-      if (debugEnabled())
-      {
-        TRACER.debugCaught(DebugLogLevel.ERROR, e);
-      }
-
-      builder.add(new AttributeValue(encodedValue, encodedValue));
-    }
+    builder.add(AttributeValues.create(attrType, value));
 
     return builder.toAttribute();
   }
@@ -854,7 +849,7 @@
   /**
    * Retrieves the number of client connections that have been closed.
    *
-   * @return  The number of client connections that have been closed.
+   * @return The number of client connections that have been closed.
    */
   public long getConnectionsClosed()
   {
@@ -869,7 +864,7 @@
   /**
    * Retrieves the number of bytes that have been received from clients.
    *
-   * @return  The number of bytes that have been received from clients.
+   * @return The number of bytes that have been received from clients.
    */
   public long getBytesRead()
   {
@@ -884,7 +879,7 @@
   /**
    * Retrieves the number of bytes that have been written to clients.
    *
-   * @return  The number of bytes that have been written to clients.
+   * @return The number of bytes that have been written to clients.
    */
   public long getBytesWritten()
   {
@@ -897,9 +892,11 @@
 
 
   /**
-   * Retrieves the number of LDAP messages that have been received from clients.
+   * Retrieves the number of LDAP messages that have been received from
+   * clients.
    *
-   * @return  The number of LDAP messages that have been received from clients.
+   * @return The number of LDAP messages that have been received from
+   *         clients.
    */
   public long getMessagesRead()
   {
@@ -912,9 +909,11 @@
 
 
   /**
-   * Retrieves the number of LDAP messages that have been written to clients.
+   * Retrieves the number of LDAP messages that have been written to
+   * clients.
    *
-   * @return  The number of LDAP messages that have been written to clients.
+   * @return The number of LDAP messages that have been written to
+   *         clients.
    */
   public long getMessagesWritten()
   {
@@ -927,9 +926,11 @@
 
 
   /**
-   * Retrieves the number of operations that have been initiated by clients.
+   * Retrieves the number of operations that have been initiated by
+   * clients.
    *
-   * @return  The number of operations that have been initiated by clients.
+   * @return The number of operations that have been initiated by
+   *         clients.
    */
   public long getOperationsInitiated()
   {
@@ -942,11 +943,11 @@
 
 
   /**
-   * Retrieves the number of operations for which the server has completed
-   * processing.
+   * Retrieves the number of operations for which the server has
+   * completed processing.
    *
-   * @return  The number of operations for which the server has completed
-   *          processing.
+   * @return The number of operations for which the server has completed
+   *         processing.
    */
   public long getOperationsCompleted()
   {
@@ -959,9 +960,11 @@
 
 
   /**
-   * Retrieves the number of operations that have been abandoned by clients.
+   * Retrieves the number of operations that have been abandoned by
+   * clients.
    *
-   * @return  The number of operations that have been abandoned by clients.
+   * @return The number of operations that have been abandoned by
+   *         clients.
    */
   public long getOperationsAbandoned()
   {
@@ -976,7 +979,7 @@
   /**
    * Retrieves the number of abandon requests that have been received.
    *
-   * @return  The number of abandon requests that have been received.
+   * @return The number of abandon requests that have been received.
    */
   public long getAbandonRequests()
   {
@@ -991,7 +994,7 @@
   /**
    * Retrieves the number of add requests that have been received.
    *
-   * @return  The number of add requests that have been received.
+   * @return The number of add requests that have been received.
    */
   public long getAddRequests()
   {
@@ -1006,7 +1009,7 @@
   /**
    * Retrieves the number of add responses that have been sent.
    *
-   * @return  The number of add responses that have been sent.
+   * @return The number of add responses that have been sent.
    */
   public long getAddResponses()
   {
@@ -1021,7 +1024,7 @@
   /**
    * Retrieves the number of bind requests that have been received.
    *
-   * @return  The number of bind requests that have been received.
+   * @return The number of bind requests that have been received.
    */
   public long getBindRequests()
   {
@@ -1036,7 +1039,7 @@
   /**
    * Retrieves the number of bind responses that have been sent.
    *
-   * @return  The number of bind responses that have been sent.
+   * @return The number of bind responses that have been sent.
    */
   public long getBindResponses()
   {
@@ -1051,7 +1054,7 @@
   /**
    * Retrieves the number of compare requests that have been received.
    *
-   * @return  The number of compare requests that have been received.
+   * @return The number of compare requests that have been received.
    */
   public long getCompareRequests()
   {
@@ -1066,7 +1069,7 @@
   /**
    * Retrieves the number of compare responses that have been sent.
    *
-   * @return  The number of compare responses that have been sent.
+   * @return The number of compare responses that have been sent.
    */
   public long getCompareResponses()
   {
@@ -1081,7 +1084,7 @@
   /**
    * Retrieves the number of delete requests that have been received.
    *
-   * @return  The number of delete requests that have been received.
+   * @return The number of delete requests that have been received.
    */
   public long getDeleteRequests()
   {
@@ -1096,7 +1099,7 @@
   /**
    * Retrieves the number of delete responses that have been sent.
    *
-   * @return  The number of delete responses that have been sent.
+   * @return The number of delete responses that have been sent.
    */
   public long getDeleteResponses()
   {
@@ -1111,7 +1114,7 @@
   /**
    * Retrieves the number of extended requests that have been received.
    *
-   * @return  The number of extended requests that have been received.
+   * @return The number of extended requests that have been received.
    */
   public long getExtendedRequests()
   {
@@ -1126,7 +1129,7 @@
   /**
    * Retrieves the number of extended responses that have been sent.
    *
-   * @return  The number of extended responses that have been sent.
+   * @return The number of extended responses that have been sent.
    */
   public long getExtendedResponses()
   {
@@ -1141,7 +1144,7 @@
   /**
    * Retrieves the number of modify requests that have been received.
    *
-   * @return  The number of modify requests that have been received.
+   * @return The number of modify requests that have been received.
    */
   public long getModifyRequests()
   {
@@ -1156,7 +1159,7 @@
   /**
    * Retrieves the number of modify responses that have been sent.
    *
-   * @return  The number of modify responses that have been sent.
+   * @return The number of modify responses that have been sent.
    */
   public long getModifyResponses()
   {
@@ -1171,7 +1174,7 @@
   /**
    * Retrieves the number of modify DN requests that have been received.
    *
-   * @return  The number of modify DN requests that have been received.
+   * @return The number of modify DN requests that have been received.
    */
   public long getModifyDNRequests()
   {
@@ -1186,7 +1189,7 @@
   /**
    * Retrieves the number of modify DN responses that have been sent.
    *
-   * @return  The number of modify DN responses that have been sent.
+   * @return The number of modify DN responses that have been sent.
    */
   public long getModifyDNResponses()
   {
@@ -1201,7 +1204,7 @@
   /**
    * Retrieves the number of search requests that have been received.
    *
-   * @return  The number of search requests that have been received.
+   * @return The number of search requests that have been received.
    */
   public long getSearchRequests()
   {
@@ -1216,7 +1219,7 @@
   /**
    * Retrieves the number of search result entries that have been sent.
    *
-   * @return  The number of search result entries that have been sent.
+   * @return The number of search result entries that have been sent.
    */
   public long getSearchResultEntries()
   {
@@ -1229,9 +1232,10 @@
 
 
   /**
-   * Retrieves the number of search result references that have been sent.
+   * Retrieves the number of search result references that have been
+   * sent.
    *
-   * @return  The number of search result references that have been sent.
+   * @return The number of search result references that have been sent.
    */
   public long getSearchResultReferences()
   {
@@ -1244,9 +1248,11 @@
 
 
   /**
-   * Retrieves the number of search result done messages that have been sent.
+   * Retrieves the number of search result done messages that have been
+   * sent.
    *
-   * @return  The number of search result done messages that have been sent.
+   * @return The number of search result done messages that have been
+   *         sent.
    */
   public long getSearchResultsDone()
   {
@@ -1261,7 +1267,7 @@
   /**
    * Retrieves the number of unbind requests that have been received.
    *
-   * @return  The number of unbind requests that have been received.
+   * @return The number of unbind requests that have been received.
    */
   public long getUnbindRequests()
   {
@@ -1274,61 +1280,69 @@
 
 
   /**
-   * Retrieves the parent statistics tracker that will also be updated whenever
-   * this tracker is updated.
+   * Retrieves the parent statistics tracker that will also be updated
+   * whenever this tracker is updated.
    *
-   * @return  The parent statistics tracker, or {@code null} if there is none.
+   * @return The parent statistics tracker, or {@code null} if there is
+   *         none.
    */
   public LDAPStatistics getParent()
   {
     return parent;
   }
 
-   /**
-     * Updates the monitor object.
-     * @param opMonitor monitor object.
-     */
-    public void updateMonitor(OperationMonitor opMonitor) {
-        synchronized (readLock) {
-            switch (opMonitor.getType()) {
-                case ABANDON:
-                    this.abandonRequestsMonitor.add(opMonitor);
-                    break;
-                case ADD:
-                    this.addRequestsMonitor.add(opMonitor);
-                    break;
-                case BIND:
-                    this.bindRequestsMonitor.add(opMonitor);
-                    break;
-                case COMPARE:
-                    this.compareRequestsMonitor.add(opMonitor);
-                    break;
-                case DELETE:
-                    this.delRequestsMonitor.add(opMonitor);
-                    break;
-                case EXTENDED:
-                    this.extendedRequestsMonitor.add(opMonitor);
-                    break;
-                case MODIFY:
-                    this.modRequestsMonitor.add(opMonitor);
-                    break;
-                case MODIFY_DN:
-                    this.moddnRequestsMonitor.add(opMonitor);
-                    break;
-                case SEARCH:
-                    this.searchRequestsMonitor.add(opMonitor);
-                    break;
-                case UNBIND:
-                    this.unbindRequestsMonitor.add(opMonitor);
-                    break;
-                default:
-            }
-            if (parent!=null) {
-                parent.updateMonitor(opMonitor);
-            }
-            opMonitor.reset();
-        }
+
+
+  /**
+   * Updates the monitor object.
+   *
+   * @param opMonitor
+   *          monitor object.
+   */
+  public void updateMonitor(OperationMonitor opMonitor)
+  {
+    synchronized (readLock)
+    {
+      switch (opMonitor.getType())
+      {
+      case ABANDON:
+        this.abandonRequestsMonitor.add(opMonitor);
+        break;
+      case ADD:
+        this.addRequestsMonitor.add(opMonitor);
+        break;
+      case BIND:
+        this.bindRequestsMonitor.add(opMonitor);
+        break;
+      case COMPARE:
+        this.compareRequestsMonitor.add(opMonitor);
+        break;
+      case DELETE:
+        this.delRequestsMonitor.add(opMonitor);
+        break;
+      case EXTENDED:
+        this.extendedRequestsMonitor.add(opMonitor);
+        break;
+      case MODIFY:
+        this.modRequestsMonitor.add(opMonitor);
+        break;
+      case MODIFY_DN:
+        this.moddnRequestsMonitor.add(opMonitor);
+        break;
+      case SEARCH:
+        this.searchRequestsMonitor.add(opMonitor);
+        break;
+      case UNBIND:
+        this.unbindRequestsMonitor.add(opMonitor);
+        break;
+      default:
+      }
+      if (parent != null)
+      {
+        parent.updateMonitor(opMonitor);
+      }
+      opMonitor.reset();
     }
+  }
 
 }
-
diff --git a/opends/src/server/org/opends/server/protocols/ldap/ModifyDNRequestProtocolOp.java b/opends/src/server/org/opends/server/protocols/ldap/ModifyDNRequestProtocolOp.java
index c12d719..bfaab13 100644
--- a/opends/src/server/org/opends/server/protocols/ldap/ModifyDNRequestProtocolOp.java
+++ b/opends/src/server/org/opends/server/protocols/ldap/ModifyDNRequestProtocolOp.java
@@ -25,24 +25,16 @@
  *      Copyright 2006-2008 Sun Microsystems, Inc.
  */
 package org.opends.server.protocols.ldap;
-import org.opends.messages.Message;
 
 
+import java.io.IOException;
 
-import java.util.ArrayList;
-
-import org.opends.server.protocols.asn1.ASN1Boolean;
-import org.opends.server.protocols.asn1.ASN1Element;
-import org.opends.server.protocols.asn1.ASN1OctetString;
-import org.opends.server.protocols.asn1.ASN1Sequence;
-import org.opends.server.types.DebugLogLevel;
-import org.opends.server.types.LDAPException;
+import org.opends.server.protocols.asn1.*;
+import org.opends.server.types.ByteString;
 
 import static org.opends.server.loggers.debug.DebugLogger.*;
 import org.opends.server.loggers.debug.DebugTracer;
-import static org.opends.messages.ProtocolMessages.*;
 import static org.opends.server.protocols.ldap.LDAPConstants.*;
-import static org.opends.server.protocols.ldap.LDAPResultCode.*;
 import static org.opends.server.util.ServerConstants.*;
 
 
@@ -60,13 +52,13 @@
   private static final DebugTracer TRACER = getTracer();
 
   // The current entry DN for this modify DN request.
-  private ASN1OctetString entryDN;
+  private ByteString entryDN;
 
   // The new RDN for this modify DN request.
-  private ASN1OctetString newRDN;
+  private ByteString newRDN;
 
   // The new superior DN for this modify DN request.
-  private ASN1OctetString newSuperior;
+  private ByteString newSuperior;
 
   // Indicates whether to delete the current RDN value(s).
   private boolean deleteOldRDN;
@@ -80,8 +72,8 @@
    * @param  newRDN        The new RDN for this modify DN request.
    * @param  deleteOldRDN  Indicates whether to delete the current RDN value(s).
    */
-  public ModifyDNRequestProtocolOp(ASN1OctetString entryDN,
-                                   ASN1OctetString newRDN, boolean deleteOldRDN)
+  public ModifyDNRequestProtocolOp(ByteString entryDN,
+                                   ByteString newRDN, boolean deleteOldRDN)
   {
     this.entryDN      = entryDN;
     this.newRDN       = newRDN;
@@ -99,9 +91,9 @@
    * @param  deleteOldRDN  Indicates whether to delete the current RDN value(s).
    * @param  newSuperior   The new superior DN for this modify DN request.
    */
-  public ModifyDNRequestProtocolOp(ASN1OctetString entryDN,
-                                   ASN1OctetString newRDN, boolean deleteOldRDN,
-                                   ASN1OctetString newSuperior)
+  public ModifyDNRequestProtocolOp(ByteString entryDN,
+                                   ByteString newRDN, boolean deleteOldRDN,
+                                   ByteString newSuperior)
   {
     this.entryDN      = entryDN;
     this.newRDN       = newRDN;
@@ -116,7 +108,7 @@
    *
    * @return  The current entry DN for this modify DN request.
    */
-  public ASN1OctetString getEntryDN()
+  public ByteString getEntryDN()
   {
     return entryDN;
   }
@@ -124,23 +116,11 @@
 
 
   /**
-   * Specifies the current entry DN for this modify DN request.
-   *
-   * @param  entryDN  The current entry DN for this modify DN request.
-   */
-  public void setEntryDN(ASN1OctetString entryDN)
-  {
-    this.entryDN = entryDN;
-  }
-
-
-
-  /**
    * Retrieves the new RDN for this modify DN request.
    *
    * @return  The new RDN for this modify DN request.
    */
-  public ASN1OctetString getNewRDN()
+  public ByteString getNewRDN()
   {
     return newRDN;
   }
@@ -148,18 +128,6 @@
 
 
   /**
-   * Specifies the new RDN for this modify DN request.
-   *
-   * @param  newRDN  The new RDN for this modify DN request.
-   */
-  public void setNewRDN(ASN1OctetString newRDN)
-  {
-    this.newRDN = newRDN;
-  }
-
-
-
-  /**
    * Indicates whether the current RDN value(s) should be deleted.
    *
    * @return  <CODE>true</CODE> if the current RDN value(s) should be deleted,
@@ -173,25 +141,12 @@
 
 
   /**
-   * Specifies whether the current RDN value(s) should be deleted.
-   *
-   * @param  deleteOldRDN  Specifies whether the current RDN value(s) should be
-   *                       deleted.
-   */
-  public void setDeleteOldRDN(boolean deleteOldRDN)
-  {
-    this.deleteOldRDN = deleteOldRDN;
-  }
-
-
-
-  /**
    * Retrieves the new superior DN for this modify DN request.
    *
    * @return  The new superior DN for this modify DN request, or
    *          <CODE>null</CODE> if none was provided.
    */
-  public ASN1OctetString getNewSuperior()
+  public ByteString getNewSuperior()
   {
     return newSuperior;
   }
@@ -199,18 +154,6 @@
 
 
   /**
-   * Specifies the new superior DN for this modify DN request.
-   *
-   * @param  newSuperior  The new superior DN for this modify DN request.
-   */
-  public void setNewSuperior(ASN1OctetString newSuperior)
-  {
-    this.newSuperior = newSuperior;
-  }
-
-
-
-  /**
    * Retrieves the BER type for this protocol op.
    *
    * @return  The BER type for this protocol op.
@@ -232,155 +175,25 @@
     return "Modify DN Request";
   }
 
-
-
   /**
-   * Encodes this protocol op to an ASN.1 element suitable for including in an
-   * LDAP message.
+   * Writes this protocol op to an ASN.1 output stream.
    *
-   * @return  The ASN.1 element containing the encoded protocol op.
+   * @param stream The ASN.1 output stream to write to.
+   * @throws IOException If a problem occurs while writing to the stream.
    */
-  public ASN1Element encode()
+  public void write(ASN1Writer stream) throws IOException
   {
-    ArrayList<ASN1Element> elements = new ArrayList<ASN1Element>(4);
-    elements.add(entryDN);
-    elements.add(newRDN);
-    elements.add(new ASN1Boolean(deleteOldRDN));
+    stream.writeStartSequence(OP_TYPE_MODIFY_DN_REQUEST);
+    stream.writeOctetString(entryDN);
+    stream.writeOctetString(newRDN);
+    stream.writeBoolean(deleteOldRDN);
 
-    if (newSuperior != null)
+    if(newSuperior != null)
     {
-      newSuperior.setType(TYPE_MODIFY_DN_NEW_SUPERIOR);
-      elements.add(newSuperior);
+      stream.writeOctetString(TYPE_MODIFY_DN_NEW_SUPERIOR, newSuperior);
     }
 
-    return new ASN1Sequence(OP_TYPE_MODIFY_DN_REQUEST, elements);
-  }
-
-
-
-  /**
-   * Decodes the provided ASN.1 element as a modify DN request protocol op.
-   *
-   * @param  element  The ASN.1 element to decode.
-   *
-   * @return  The decoded modify DN request protocol op.
-   *
-   * @throws  LDAPException  If a problem occurs while trying to decode the
-   *                         provided ASN.1 element as an LDAP modify DN request
-   *                         protocol op.
-   */
-  public static ModifyDNRequestProtocolOp decodeModifyDNRequest(ASN1Element
-                                                                     element)
-         throws LDAPException
-  {
-    ArrayList<ASN1Element> elements;
-    try
-    {
-      elements = element.decodeAsSequence().elements();
-    }
-    catch (Exception e)
-    {
-      if (debugEnabled())
-      {
-        TRACER.debugCaught(DebugLogLevel.ERROR, e);
-      }
-
-      Message message =
-          ERR_LDAP_MODIFY_DN_REQUEST_DECODE_SEQUENCE.get(String.valueOf(e));
-      throw new LDAPException(PROTOCOL_ERROR, message, e);
-    }
-
-
-    int numElements = elements.size();
-    if ((numElements < 3) || (numElements > 4))
-    {
-      Message message = ERR_LDAP_MODIFY_DN_REQUEST_DECODE_INVALID_ELEMENT_COUNT.
-          get(numElements);
-      throw new LDAPException(PROTOCOL_ERROR, message);
-    }
-
-
-    ASN1OctetString entryDN;
-    try
-    {
-      entryDN = elements.get(0).decodeAsOctetString();
-    }
-    catch (Exception e)
-    {
-      if (debugEnabled())
-      {
-        TRACER.debugCaught(DebugLogLevel.ERROR, e);
-      }
-
-      Message message =
-          ERR_LDAP_MODIFY_DN_REQUEST_DECODE_DN.get(String.valueOf(e));
-      throw new LDAPException(PROTOCOL_ERROR, message, e);
-    }
-
-
-    ASN1OctetString newRDN;
-    try
-    {
-      newRDN = elements.get(1).decodeAsOctetString();
-    }
-    catch (Exception e)
-    {
-      if (debugEnabled())
-      {
-        TRACER.debugCaught(DebugLogLevel.ERROR, e);
-      }
-
-      Message message =
-          ERR_LDAP_MODIFY_DN_REQUEST_DECODE_NEW_RDN.get(String.valueOf(e));
-      throw new LDAPException(PROTOCOL_ERROR, message, e);
-    }
-
-
-    boolean deleteOldRDN;
-    try
-    {
-      deleteOldRDN = elements.get(2).decodeAsBoolean().booleanValue();
-    }
-    catch (Exception e)
-    {
-      if (debugEnabled())
-      {
-        TRACER.debugCaught(DebugLogLevel.ERROR, e);
-      }
-
-      Message message = ERR_LDAP_MODIFY_DN_REQUEST_DECODE_DELETE_OLD_RDN.get(
-          String.valueOf(e));
-      throw new LDAPException(PROTOCOL_ERROR, message, e);
-    }
-
-
-    ASN1OctetString newSuperior;
-    if (numElements == 4)
-    {
-      try
-      {
-        newSuperior = elements.get(3).decodeAsOctetString();
-      }
-      catch (Exception e)
-      {
-        if (debugEnabled())
-        {
-          TRACER.debugCaught(DebugLogLevel.ERROR, e);
-        }
-
-        Message message = ERR_LDAP_MODIFY_DN_REQUEST_DECODE_NEW_SUPERIOR.get(
-            String.valueOf(e));
-        throw new LDAPException(PROTOCOL_ERROR, message, e);
-      }
-    }
-    else
-    {
-      newSuperior = null;
-    }
-
-
-    return new ModifyDNRequestProtocolOp(entryDN, newRDN, deleteOldRDN,
-                                         newSuperior);
+    stream.writeEndSequence();
   }
 
 
@@ -394,16 +207,16 @@
   public void toString(StringBuilder buffer)
   {
     buffer.append("ModifyDNRequest(dn=");
-    entryDN.toString(buffer);
+    buffer.append(entryDN.toString());
     buffer.append(", newRDN=");
-    newRDN.toString(buffer);
+    buffer.append(newRDN.toString());
     buffer.append(", deleteOldRDN=");
     buffer.append(deleteOldRDN);
 
     if (newSuperior != null)
     {
       buffer.append(", newSuperior=");
-      newSuperior.toString(buffer);
+      buffer.append(newSuperior.toString());
     }
 
     buffer.append(")");
@@ -433,12 +246,12 @@
 
     buffer.append(indentBuf);
     buffer.append("  Entry DN:  ");
-    entryDN.toString(buffer);
+    buffer.append(entryDN.toString());
     buffer.append(EOL);
 
     buffer.append(indentBuf);
     buffer.append("  New RDN:  ");
-    newRDN.toString(buffer);
+    buffer.append(newRDN.toString());
     buffer.append(EOL);
 
     buffer.append(indentBuf);
@@ -450,7 +263,7 @@
     {
       buffer.append(indentBuf);
       buffer.append("  New Superior:  ");
-      newSuperior.toString(buffer);
+      buffer.append(newSuperior.toString());
       buffer.append(EOL);
     }
   }
diff --git a/opends/src/server/org/opends/server/protocols/ldap/ModifyDNResponseProtocolOp.java b/opends/src/server/org/opends/server/protocols/ldap/ModifyDNResponseProtocolOp.java
index 97b71b7..19b7e3d 100644
--- a/opends/src/server/org/opends/server/protocols/ldap/ModifyDNResponseProtocolOp.java
+++ b/opends/src/server/org/opends/server/protocols/ldap/ModifyDNResponseProtocolOp.java
@@ -28,24 +28,16 @@
 import org.opends.messages.Message;
 
 
-
-import java.util.ArrayList;
 import java.util.Iterator;
 import java.util.List;
+import java.io.IOException;
 
-import org.opends.server.protocols.asn1.ASN1Element;
-import org.opends.server.protocols.asn1.ASN1Enumerated;
-import org.opends.server.protocols.asn1.ASN1OctetString;
-import org.opends.server.protocols.asn1.ASN1Sequence;
-import org.opends.server.types.DebugLogLevel;
+import org.opends.server.protocols.asn1.*;
 import org.opends.server.types.DN;
-import org.opends.server.types.LDAPException;
 
 import static org.opends.server.loggers.debug.DebugLogger.*;
 import org.opends.server.loggers.debug.DebugTracer;
-import static org.opends.messages.ProtocolMessages.*;
 import static org.opends.server.protocols.ldap.LDAPConstants.*;
-import static org.opends.server.protocols.ldap.LDAPResultCode.*;
 import static org.opends.server.util.ServerConstants.*;
 
 
@@ -141,19 +133,6 @@
   }
 
 
-
-  /**
-   * Specifies the result code for this response.
-   *
-   * @param  resultCode  The result code for this response.
-   */
-  public void setResultCode(int resultCode)
-  {
-    this.resultCode = resultCode;
-  }
-
-
-
   /**
    * Retrieves the error message for this response.
    *
@@ -168,18 +147,6 @@
 
 
   /**
-   * Specifies the error message for this response.
-   *
-   * @param  errorMessage  The error message for this response.
-   */
-  public void setErrorMessage(Message errorMessage)
-  {
-    this.errorMessage = errorMessage;
-  }
-
-
-
-  /**
    * Retrieves the matched DN for this response.
    *
    * @return  The matched DN for this response, or <CODE>null</CODE> if none is
@@ -193,18 +160,6 @@
 
 
   /**
-   * Specifies the matched DN for this response.
-   *
-   * @param  matchedDN  The matched DN for this response.
-   */
-  public void setMatchedDN(DN matchedDN)
-  {
-    this.matchedDN = matchedDN;
-  }
-
-
-
-  /**
    * Retrieves the set of referral URLs for this response.
    *
    * @return  The set of referral URLs for this response, or <CODE>null</CODE>
@@ -218,18 +173,6 @@
 
 
   /**
-   * Specifies the set of referral URLs for this response.
-   *
-   * @param  referralURLs  The set of referral URLs for this response.
-   */
-  public void setReferralURLs(List<String> referralURLs)
-  {
-    this.referralURLs = referralURLs;
-  }
-
-
-
-  /**
    * Retrieves the BER type for this protocol op.
    *
    * @return  The BER type for this protocol op.
@@ -251,189 +194,46 @@
     return "Modify DN Response";
   }
 
-
-
   /**
-   * Encodes this protocol op to an ASN.1 element suitable for including in an
-   * LDAP message.
+   * Writes this protocol op to an ASN.1 output stream.
    *
-   * @return  The ASN.1 element containing the encoded protocol op.
+   * @param stream The ASN.1 output stream to write to.
+   * @throws IOException If a problem occurs while writing to the stream.
    */
-  public ASN1Element encode()
+  public void write(ASN1Writer stream) throws IOException
   {
-    ArrayList<ASN1Element> elements = new ArrayList<ASN1Element>(4);
-    elements.add(new ASN1Enumerated(resultCode));
+    stream.writeStartSequence(OP_TYPE_MODIFY_DN_RESPONSE);
+    stream.writeEnumerated(resultCode);
 
-    if (matchedDN == null)
+    if(matchedDN == null)
     {
-      elements.add(new ASN1OctetString());
+      stream.writeOctetString((String)null);
     }
     else
     {
-      elements.add(new ASN1OctetString(matchedDN.toString()));
+      stream.writeOctetString(matchedDN.toString());
     }
 
-    elements.add(new ASN1OctetString(errorMessage));
+    if(errorMessage == null)
+    {
+      stream.writeOctetString((String)null);
+    }
+    else
+    {
+      stream.writeOctetString(errorMessage.toString());
+    }
 
     if ((referralURLs != null) && (! referralURLs.isEmpty()))
     {
-      ArrayList<ASN1Element> referralElements =
-           new ArrayList<ASN1Element>(referralURLs.size());
-
+      stream.writeStartSequence(TYPE_REFERRAL_SEQUENCE);
       for (String s : referralURLs)
       {
-        referralElements.add(new ASN1OctetString(s));
+        stream.writeOctetString(s);
       }
-
-      elements.add(new ASN1Sequence(TYPE_REFERRAL_SEQUENCE, referralElements));
+      stream.writeEndSequence();
     }
 
-    return new ASN1Sequence(OP_TYPE_MODIFY_DN_RESPONSE, elements);
-  }
-
-
-
-  /**
-   * Decodes the provided ASN.1 element as a modify DN response protocol op.
-   *
-   * @param  element  The ASN.1 element to decode.
-   *
-   * @return  The decoded modify DN response protocol op.
-   *
-   * @throws  LDAPException  If a problem occurs while attempting to decode the
-   *                         ASN.1 element to a protocol op.
-   */
-  public static ModifyDNResponseProtocolOp decodeModifyDNResponse(ASN1Element
-                                                                       element)
-         throws LDAPException
-  {
-    ArrayList<ASN1Element> elements;
-    try
-    {
-      elements = element.decodeAsSequence().elements();
-    }
-    catch (Exception e)
-    {
-      if (debugEnabled())
-      {
-        TRACER.debugCaught(DebugLogLevel.ERROR, e);
-      }
-
-      Message message = ERR_LDAP_RESULT_DECODE_SEQUENCE.get(String.valueOf(e));
-      throw new LDAPException(PROTOCOL_ERROR, message, e);
-    }
-
-
-    int numElements = elements.size();
-    if ((numElements < 3) || (numElements > 4))
-    {
-      Message message =
-          ERR_LDAP_RESULT_DECODE_INVALID_ELEMENT_COUNT.get(numElements);
-      throw new LDAPException(PROTOCOL_ERROR, message);
-    }
-
-
-    int resultCode;
-    try
-    {
-      resultCode = elements.get(0).decodeAsInteger().intValue();
-    }
-    catch (Exception e)
-    {
-      if (debugEnabled())
-      {
-        TRACER.debugCaught(DebugLogLevel.ERROR, e);
-      }
-
-      Message message =
-          ERR_LDAP_RESULT_DECODE_RESULT_CODE.get(String.valueOf(e));
-      throw new LDAPException(PROTOCOL_ERROR, message, e);
-    }
-
-
-    DN matchedDN;
-    try
-    {
-      String dnString = elements.get(1).decodeAsOctetString().stringValue();
-      if (dnString.length() == 0)
-      {
-        matchedDN = null;
-      }
-      else
-      {
-        matchedDN = DN.decode(dnString);
-      }
-    }
-    catch (Exception e)
-    {
-      if (debugEnabled())
-      {
-        TRACER.debugCaught(DebugLogLevel.ERROR, e);
-      }
-
-      Message message =
-          ERR_LDAP_RESULT_DECODE_MATCHED_DN.get(String.valueOf(e));
-      throw new LDAPException(PROTOCOL_ERROR, message, e);
-    }
-
-
-    Message errorMessage;
-    try
-    {
-      errorMessage = Message.raw(
-              elements.get(2).decodeAsOctetString().stringValue());
-      if (errorMessage.length() == 0)
-      {
-        errorMessage = null;
-      }
-    }
-    catch (Exception e)
-    {
-      if (debugEnabled())
-      {
-        TRACER.debugCaught(DebugLogLevel.ERROR, e);
-      }
-
-      Message message =
-          ERR_LDAP_RESULT_DECODE_ERROR_MESSAGE.get(String.valueOf(e));
-      throw new LDAPException(PROTOCOL_ERROR, message, e);
-    }
-
-
-    ArrayList<String> referralURLs;
-    if (numElements == 3)
-    {
-      referralURLs = null;
-    }
-    else
-    {
-      try
-      {
-        ArrayList<ASN1Element> referralElements =
-             elements.get(3).decodeAsSequence().elements();
-        referralURLs = new ArrayList<String>(referralElements.size());
-
-        for (ASN1Element e : referralElements)
-        {
-          referralURLs.add(e.decodeAsOctetString().stringValue());
-        }
-      }
-      catch (Exception e)
-      {
-        if (debugEnabled())
-        {
-          TRACER.debugCaught(DebugLogLevel.ERROR, e);
-        }
-
-        Message message =
-            ERR_LDAP_RESULT_DECODE_REFERRALS.get(String.valueOf(e));
-        throw new LDAPException(PROTOCOL_ERROR, message, e);
-      }
-    }
-
-
-    return new ModifyDNResponseProtocolOp(resultCode, errorMessage, matchedDN,
-                                          referralURLs);
+    stream.writeEndSequence();
   }
 
 
diff --git a/opends/src/server/org/opends/server/protocols/ldap/ModifyRequestProtocolOp.java b/opends/src/server/org/opends/server/protocols/ldap/ModifyRequestProtocolOp.java
index 9524954..e9b1ea9 100644
--- a/opends/src/server/org/opends/server/protocols/ldap/ModifyRequestProtocolOp.java
+++ b/opends/src/server/org/opends/server/protocols/ldap/ModifyRequestProtocolOp.java
@@ -25,25 +25,19 @@
  *      Copyright 2006-2008 Sun Microsystems, Inc.
  */
 package org.opends.server.protocols.ldap;
-import org.opends.messages.Message;
-
 
 
 import java.util.ArrayList;
 import java.util.Iterator;
+import java.io.IOException;
 
-import org.opends.server.protocols.asn1.ASN1Element;
-import org.opends.server.protocols.asn1.ASN1OctetString;
-import org.opends.server.protocols.asn1.ASN1Sequence;
-import org.opends.server.types.DebugLogLevel;
-import org.opends.server.types.LDAPException;
+import org.opends.server.protocols.asn1.*;
 import org.opends.server.types.RawModification;
+import org.opends.server.types.ByteString;
 
 import static org.opends.server.loggers.debug.DebugLogger.*;
 import org.opends.server.loggers.debug.DebugTracer;
-import static org.opends.messages.ProtocolMessages.*;
 import static org.opends.server.protocols.ldap.LDAPConstants.*;
-import static org.opends.server.protocols.ldap.LDAPResultCode.*;
 import static org.opends.server.util.ServerConstants.*;
 
 
@@ -64,7 +58,7 @@
   private ArrayList<RawModification> modifications;
 
   // The DN for this modify request.
-  private ASN1OctetString dn;
+  private ByteString dn;
 
 
 
@@ -74,7 +68,7 @@
    *
    * @param  dn  The DN for this modify request.
    */
-  public ModifyRequestProtocolOp(ASN1OctetString dn)
+  public ModifyRequestProtocolOp(ByteString dn)
   {
     this.dn            = dn;
     this.modifications = new ArrayList<RawModification>();
@@ -89,7 +83,7 @@
    * @param  dn             The DN for this modify request.
    * @param  modifications  The set of modifications for this modify request.
    */
-  public ModifyRequestProtocolOp(ASN1OctetString dn,
+  public ModifyRequestProtocolOp(ByteString dn,
                                  ArrayList<RawModification> modifications)
   {
     this.dn = dn;
@@ -111,7 +105,7 @@
    *
    * @return  The DN for this modify request.
    */
-  public ASN1OctetString getDN()
+  public ByteString getDN()
   {
     return dn;
   }
@@ -119,18 +113,6 @@
 
 
   /**
-   * Specifies the DN for this modify request.
-   *
-   * @param  dn  The DN for this modify request.
-   */
-  public void setDN(ASN1OctetString dn)
-  {
-    this.dn = dn;
-  }
-
-
-
-  /**
    * Retrieves the set of modifications for this modify request.  The returned
    * list may be altered by the caller.
    *
@@ -165,119 +147,25 @@
     return "Modify Request";
   }
 
-
-
   /**
-   * Encodes this protocol op to an ASN.1 element suitable for including in an
-   * LDAP message.
+   * Writes this protocol op to an ASN.1 output stream.
    *
-   * @return  The ASN.1 element containing the encoded protocol op.
+   * @param stream The ASN.1 output stream to write to.
+   * @throws IOException If a problem occurs while writing to the stream.
    */
-  public ASN1Element encode()
+  public void write(ASN1Writer stream) throws IOException
   {
-    ArrayList<ASN1Element> elements = new ArrayList<ASN1Element>(2);
-    elements.add(dn);
+    stream.writeStartSequence(OP_TYPE_MODIFY_REQUEST);
+    stream.writeOctetString(dn);
 
-
-    ArrayList<ASN1Element> modElements =
-         new ArrayList<ASN1Element>(modifications.size());
-    for (RawModification mod : modifications)
+    stream.writeStartSequence();
+    for(RawModification mod : modifications)
     {
-      modElements.add(mod.encode());
+      mod.write(stream);
     }
-    elements.add(new ASN1Sequence(modElements));
+    stream.writeEndSequence();
 
-
-    return new ASN1Sequence(OP_TYPE_MODIFY_REQUEST, elements);
-  }
-
-
-
-  /**
-   * Decodes the provided ASN.1 element as an LDAP modify request protocol op.
-   *
-   * @param  element  The ASN.1 element to be decoded.
-   *
-   * @return  The decoded modify request protocol op.
-   *
-   * @throws  LDAPException  If a problem occurs while decoding the provided
-   *                         ASN.1 element as an LDAP modify request protocol
-   *                         op.
-   */
-  public static ModifyRequestProtocolOp decodeModifyRequest(ASN1Element element)
-         throws LDAPException
-  {
-    ArrayList<ASN1Element> elements;
-    try
-    {
-      elements = element.decodeAsSequence().elements();
-    }
-    catch (Exception e)
-    {
-      if (debugEnabled())
-      {
-        TRACER.debugCaught(DebugLogLevel.ERROR, e);
-      }
-
-      Message message =
-          ERR_LDAP_MODIFY_REQUEST_DECODE_SEQUENCE.get(String.valueOf(e));
-      throw new LDAPException(PROTOCOL_ERROR, message, e);
-    }
-
-
-    int numElements = elements.size();
-    if (numElements != 2)
-    {
-      Message message =
-          ERR_LDAP_MODIFY_REQUEST_DECODE_INVALID_ELEMENT_COUNT.get(numElements);
-      throw new LDAPException(PROTOCOL_ERROR, message);
-    }
-
-
-    ASN1OctetString dn;
-    try
-    {
-      dn = elements.get(0).decodeAsOctetString();
-    }
-    catch (Exception e)
-    {
-      if (debugEnabled())
-      {
-        TRACER.debugCaught(DebugLogLevel.ERROR, e);
-      }
-
-      Message message =
-          ERR_LDAP_MODIFY_REQUEST_DECODE_DN.get(String.valueOf(e));
-      throw new LDAPException(PROTOCOL_ERROR, message, e);
-    }
-
-
-
-    ArrayList<RawModification> modifications;
-    try
-    {
-      ArrayList<ASN1Element> modElements =
-           elements.get(1).decodeAsSequence().elements();
-      modifications = new ArrayList<RawModification>(modElements.size());
-      for (ASN1Element e : modElements)
-      {
-        modifications.add(LDAPModification.decode(e));
-      }
-    }
-    catch (Exception e)
-    {
-      if (debugEnabled())
-      {
-        TRACER.debugCaught(DebugLogLevel.ERROR, e);
-      }
-
-      Message message =
-          ERR_LDAP_MODIFY_REQUEST_DECODE_MODS.get(String.valueOf(e));
-      throw new LDAPException(PROTOCOL_ERROR, message, e);
-    }
-
-
-    return new ModifyRequestProtocolOp(dn, modifications);
+    stream.writeEndSequence();
   }
 
 
@@ -291,7 +179,7 @@
   public void toString(StringBuilder buffer)
   {
     buffer.append("ModifyRequest(dn=");
-    dn.toString(buffer);
+    buffer.append(dn.toString());
     buffer.append(", mods={");
 
     if (! modifications.isEmpty())
@@ -333,7 +221,7 @@
 
     buffer.append(indentBuf);
     buffer.append("  DN:  ");
-    dn.toString(buffer);
+    buffer.append(dn.toString());
     buffer.append(EOL);
 
     buffer.append("  Modifications:");
diff --git a/opends/src/server/org/opends/server/protocols/ldap/ModifyResponseProtocolOp.java b/opends/src/server/org/opends/server/protocols/ldap/ModifyResponseProtocolOp.java
index 018493f..5669ee7 100644
--- a/opends/src/server/org/opends/server/protocols/ldap/ModifyResponseProtocolOp.java
+++ b/opends/src/server/org/opends/server/protocols/ldap/ModifyResponseProtocolOp.java
@@ -28,24 +28,16 @@
 import org.opends.messages.Message;
 
 
-
-import java.util.ArrayList;
 import java.util.Iterator;
 import java.util.List;
+import java.io.IOException;
 
-import org.opends.server.protocols.asn1.ASN1Element;
-import org.opends.server.protocols.asn1.ASN1Enumerated;
-import org.opends.server.protocols.asn1.ASN1OctetString;
-import org.opends.server.protocols.asn1.ASN1Sequence;
-import org.opends.server.types.DebugLogLevel;
+import org.opends.server.protocols.asn1.*;
 import org.opends.server.types.DN;
-import org.opends.server.types.LDAPException;
 
 import static org.opends.server.loggers.debug.DebugLogger.*;
 import org.opends.server.loggers.debug.DebugTracer;
-import static org.opends.messages.ProtocolMessages.*;
 import static org.opends.server.protocols.ldap.LDAPConstants.*;
-import static org.opends.server.protocols.ldap.LDAPResultCode.*;
 import static org.opends.server.util.ServerConstants.*;
 
 
@@ -141,19 +133,6 @@
   }
 
 
-
-  /**
-   * Specifies the result code for this response.
-   *
-   * @param  resultCode  The result code for this response.
-   */
-  public void setResultCode(int resultCode)
-  {
-    this.resultCode = resultCode;
-  }
-
-
-
   /**
    * Retrieves the error message for this response.
    *
@@ -166,19 +145,6 @@
   }
 
 
-
-  /**
-   * Specifies the error message for this response.
-   *
-   * @param  errorMessage  The error message for this response.
-   */
-  public void setErrorMessage(Message errorMessage)
-  {
-    this.errorMessage = errorMessage;
-  }
-
-
-
   /**
    * Retrieves the matched DN for this response.
    *
@@ -193,18 +159,6 @@
 
 
   /**
-   * Specifies the matched DN for this response.
-   *
-   * @param  matchedDN  The matched DN for this response.
-   */
-  public void setMatchedDN(DN matchedDN)
-  {
-    this.matchedDN = matchedDN;
-  }
-
-
-
-  /**
    * Retrieves the set of referral URLs for this response.
    *
    * @return  The set of referral URLs for this response, or <CODE>null</CODE>
@@ -216,19 +170,6 @@
   }
 
 
-
-  /**
-   * Specifies the set of referral URLs for this response.
-   *
-   * @param  referralURLs  The set of referral URLs for this response.
-   */
-  public void setReferralURLs(List<String> referralURLs)
-  {
-    this.referralURLs = referralURLs;
-  }
-
-
-
   /**
    * Retrieves the BER type for this protocol op.
    *
@@ -251,189 +192,46 @@
     return "Modify Response";
   }
 
-
-
   /**
-   * Encodes this protocol op to an ASN.1 element suitable for including in an
-   * LDAP message.
+   * Writes this protocol op to an ASN.1 output stream.
    *
-   * @return  The ASN.1 element containing the encoded protocol op.
+   * @param stream The ASN.1 output stream to write to.
+   * @throws IOException If a problem occurs while writing to the stream.
    */
-  public ASN1Element encode()
+  public void write(ASN1Writer stream) throws IOException
   {
-    ArrayList<ASN1Element> elements = new ArrayList<ASN1Element>(4);
-    elements.add(new ASN1Enumerated(resultCode));
+    stream.writeStartSequence(OP_TYPE_MODIFY_RESPONSE);
+    stream.writeEnumerated(resultCode);
 
-    if (matchedDN == null)
+    if(matchedDN == null)
     {
-      elements.add(new ASN1OctetString());
+      stream.writeOctetString((String)null);
     }
     else
     {
-      elements.add(new ASN1OctetString(matchedDN.toString()));
+      stream.writeOctetString(matchedDN.toString());
     }
 
-    elements.add(new ASN1OctetString(errorMessage));
+    if(errorMessage == null)
+    {
+      stream.writeOctetString((String)null);
+    }
+    else
+    {
+      stream.writeOctetString(errorMessage.toString());
+    }
 
     if ((referralURLs != null) && (! referralURLs.isEmpty()))
     {
-      ArrayList<ASN1Element> referralElements =
-           new ArrayList<ASN1Element>(referralURLs.size());
-
+      stream.writeStartSequence(TYPE_REFERRAL_SEQUENCE);
       for (String s : referralURLs)
       {
-        referralElements.add(new ASN1OctetString(s));
+        stream.writeOctetString(s);
       }
-
-      elements.add(new ASN1Sequence(TYPE_REFERRAL_SEQUENCE, referralElements));
+      stream.writeEndSequence();
     }
 
-    return new ASN1Sequence(OP_TYPE_MODIFY_RESPONSE, elements);
-  }
-
-
-
-  /**
-   * Decodes the provided ASN.1 element as a modify response protocol op.
-   *
-   * @param  element  The ASN.1 element to decode.
-   *
-   * @return  The decoded modify response protocol op.
-   *
-   * @throws  LDAPException  If a problem occurs while attempting to decode the
-   *                         ASN.1 element to a protocol op.
-   */
-  public static ModifyResponseProtocolOp decodeModifyResponse(ASN1Element
-                                                                   element)
-         throws LDAPException
-  {
-    ArrayList<ASN1Element> elements;
-    try
-    {
-      elements = element.decodeAsSequence().elements();
-    }
-    catch (Exception e)
-    {
-      if (debugEnabled())
-      {
-        TRACER.debugCaught(DebugLogLevel.ERROR, e);
-      }
-
-      Message message = ERR_LDAP_RESULT_DECODE_SEQUENCE.get(String.valueOf(e));
-      throw new LDAPException(PROTOCOL_ERROR, message, e);
-    }
-
-
-    int numElements = elements.size();
-    if ((numElements < 3) || (numElements > 4))
-    {
-      Message message =
-          ERR_LDAP_RESULT_DECODE_INVALID_ELEMENT_COUNT.get(numElements);
-      throw new LDAPException(PROTOCOL_ERROR, message);
-    }
-
-
-    int resultCode;
-    try
-    {
-      resultCode = elements.get(0).decodeAsInteger().intValue();
-    }
-    catch (Exception e)
-    {
-      if (debugEnabled())
-      {
-        TRACER.debugCaught(DebugLogLevel.ERROR, e);
-      }
-
-      Message message =
-          ERR_LDAP_RESULT_DECODE_RESULT_CODE.get(String.valueOf(e));
-      throw new LDAPException(PROTOCOL_ERROR, message, e);
-    }
-
-
-    DN matchedDN;
-    try
-    {
-      String dnString = elements.get(1).decodeAsOctetString().stringValue();
-      if (dnString.length() == 0)
-      {
-        matchedDN = null;
-      }
-      else
-      {
-        matchedDN = DN.decode(dnString);
-      }
-    }
-    catch (Exception e)
-    {
-      if (debugEnabled())
-      {
-        TRACER.debugCaught(DebugLogLevel.ERROR, e);
-      }
-
-      Message message =
-          ERR_LDAP_RESULT_DECODE_MATCHED_DN.get(String.valueOf(e));
-      throw new LDAPException(PROTOCOL_ERROR, message, e);
-    }
-
-
-    Message errorMessage;
-    try
-    {
-      errorMessage = Message.raw(
-              elements.get(2).decodeAsOctetString().stringValue());
-      if (errorMessage.length() == 0)
-      {
-        errorMessage = null;
-      }
-    }
-    catch (Exception e)
-    {
-      if (debugEnabled())
-      {
-        TRACER.debugCaught(DebugLogLevel.ERROR, e);
-      }
-
-      Message message =
-          ERR_LDAP_RESULT_DECODE_ERROR_MESSAGE.get(String.valueOf(e));
-      throw new LDAPException(PROTOCOL_ERROR, message, e);
-    }
-
-
-    ArrayList<String> referralURLs;
-    if (numElements == 3)
-    {
-      referralURLs = null;
-    }
-    else
-    {
-      try
-      {
-        ArrayList<ASN1Element> referralElements =
-             elements.get(3).decodeAsSequence().elements();
-        referralURLs = new ArrayList<String>(referralElements.size());
-
-        for (ASN1Element e : referralElements)
-        {
-          referralURLs.add(e.decodeAsOctetString().stringValue());
-        }
-      }
-      catch (Exception e)
-      {
-        if (debugEnabled())
-        {
-          TRACER.debugCaught(DebugLogLevel.ERROR, e);
-        }
-
-        Message message =
-            ERR_LDAP_RESULT_DECODE_REFERRALS.get(String.valueOf(e));
-        throw new LDAPException(PROTOCOL_ERROR, message, e);
-      }
-    }
-
-
-    return new ModifyResponseProtocolOp(resultCode, errorMessage, matchedDN,
-                                        referralURLs);
+    stream.writeEndSequence();
   }
 
 
diff --git a/opends/src/server/org/opends/server/protocols/ldap/ProtocolOp.java b/opends/src/server/org/opends/server/protocols/ldap/ProtocolOp.java
index 2d42f04..bd6192c 100644
--- a/opends/src/server/org/opends/server/protocols/ldap/ProtocolOp.java
+++ b/opends/src/server/org/opends/server/protocols/ldap/ProtocolOp.java
@@ -25,17 +25,10 @@
  *      Copyright 2006-2008 Sun Microsystems, Inc.
  */
 package org.opends.server.protocols.ldap;
-import org.opends.messages.Message;
 
+import org.opends.server.protocols.asn1.ASN1Writer;
 
-
-import org.opends.server.protocols.asn1.ASN1Element;
-import org.opends.server.types.LDAPException;
-
-import static org.opends.messages.ProtocolMessages.*;
-import static org.opends.server.protocols.ldap.LDAPConstants.*;
-import static org.opends.server.protocols.ldap.LDAPResultCode.*;
-
+import java.io.IOException;
 
 
 /**
@@ -63,142 +56,12 @@
 
 
   /**
-   * Encodes this protocol op to an ASN.1 element suitable for including in an
-   * LDAP message.
+   * Writes this protocol op to an ASN.1 output stream.
    *
-   * @return  The ASN.1 element containing the encoded protocol op.
+   * @param stream The ASN.1 output stream to write to.
+   * @throws IOException If a problem occurs while writing to the stream.
    */
-  public abstract ASN1Element encode();
-
-
-
-  /**
-   * Decodes the provided ASN.1 element as an LDAP protocol op.
-   *
-   * @param  element  The ASN.1 element containing the encoded LDAP protocol op.
-   *
-   * @return  The LDAP protocol op decoded from the provided ASN.1 element.
-   *
-   * @throws  LDAPException  If a problem occurs while trying to decode the
-   *                         provided ASN.1 element as an LDAP protocol op.
-   */
-  public static ProtocolOp decode(ASN1Element element)
-         throws LDAPException
-  {
-    if (element == null)
-    {
-      Message message = ERR_LDAP_PROTOCOL_OP_DECODE_NULL.get();
-      throw new LDAPException(PROTOCOL_ERROR, message);
-    }
-
-    switch (element.getType())
-    {
-      case OP_TYPE_UNBIND_REQUEST:                                       // 0x42
-        return UnbindRequestProtocolOp.decodeUnbindRequest(element);
-      case 0x43:                                                         // 0x43
-      case 0x44:                                                         // 0x44
-      case 0x45:                                                         // 0x45
-      case 0x46:                                                         // 0x46
-      case 0x47:                                                         // 0x47
-      case 0x48:                                                         // 0x48
-      case 0x49:                                                         // 0x49
-        Message message =
-            ERR_LDAP_PROTOCOL_OP_DECODE_INVALID_TYPE.get(element.getType());
-        throw new LDAPException(PROTOCOL_ERROR, message);
-      case OP_TYPE_DELETE_REQUEST:                                       // 0x4A
-        return DeleteRequestProtocolOp.decodeDeleteRequest(element);
-      case 0x4B:                                                         // 0x4B
-      case 0x4C:                                                         // 0x4C
-      case 0x4D:                                                         // 0x4D
-      case 0x4E:                                                         // 0x4E
-      case 0x4F:                                                         // 0x4F
-        message =
-            ERR_LDAP_PROTOCOL_OP_DECODE_INVALID_TYPE.get(element.getType());
-        throw new LDAPException(PROTOCOL_ERROR, message);
-      case OP_TYPE_ABANDON_REQUEST:                                      // 0x50
-        return AbandonRequestProtocolOp.decodeAbandonRequest(element);
-      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
-        message =
-            ERR_LDAP_PROTOCOL_OP_DECODE_INVALID_TYPE.get(element.getType());
-        throw new LDAPException(PROTOCOL_ERROR, message);
-      case OP_TYPE_BIND_REQUEST:                                         // 0x60
-        return BindRequestProtocolOp.decodeBindRequest(element);
-      case OP_TYPE_BIND_RESPONSE:                                        // 0x61
-        return BindResponseProtocolOp.decodeBindResponse(element);
-      case 0x62:                                                         // 0x62
-        message =
-            ERR_LDAP_PROTOCOL_OP_DECODE_INVALID_TYPE.get(element.getType());
-        throw new LDAPException(PROTOCOL_ERROR, message);
-      case OP_TYPE_SEARCH_REQUEST:                                       // 0x63
-        return SearchRequestProtocolOp.decodeSearchRequest(element);
-      case OP_TYPE_SEARCH_RESULT_ENTRY:                                  // 0x64
-        return SearchResultEntryProtocolOp.decodeSearchEntry(element);
-      case OP_TYPE_SEARCH_RESULT_DONE:                                   // 0x65
-        return SearchResultDoneProtocolOp.decodeSearchDone(element);
-      case OP_TYPE_MODIFY_REQUEST:                                       // 0x66
-        return ModifyRequestProtocolOp.decodeModifyRequest(element);
-      case OP_TYPE_MODIFY_RESPONSE:                                      // 0x67
-        return ModifyResponseProtocolOp.decodeModifyResponse(element);
-      case OP_TYPE_ADD_REQUEST:                                          // 0x68
-        return AddRequestProtocolOp.decodeAddRequest(element);
-      case OP_TYPE_ADD_RESPONSE:                                         // 0x69
-        return AddResponseProtocolOp.decodeAddResponse(element);
-      case 0x6A:                                                         // 0x6A
-        message =
-            ERR_LDAP_PROTOCOL_OP_DECODE_INVALID_TYPE.get(element.getType());
-        throw new LDAPException(PROTOCOL_ERROR, message);
-      case OP_TYPE_DELETE_RESPONSE:                                      // 0x6B
-        return DeleteResponseProtocolOp.decodeDeleteResponse(element);
-      case OP_TYPE_MODIFY_DN_REQUEST:                                    // 0x6C
-        return ModifyDNRequestProtocolOp.decodeModifyDNRequest(element);
-      case OP_TYPE_MODIFY_DN_RESPONSE:                                   // 0x6D
-        return ModifyDNResponseProtocolOp.decodeModifyDNResponse(element);
-      case OP_TYPE_COMPARE_REQUEST:                                      // 0x6E
-        return CompareRequestProtocolOp.decodeCompareRequest(element);
-      case OP_TYPE_COMPARE_RESPONSE:                                     // 0x6F
-        return CompareResponseProtocolOp.decodeCompareResponse(element);
-      case 0x70:                                                         // 0x70
-      case 0x71:                                                         // 0x71
-      case 0x72:                                                         // 0x72
-        message =
-            ERR_LDAP_PROTOCOL_OP_DECODE_INVALID_TYPE.get(element.getType());
-        throw new LDAPException(PROTOCOL_ERROR, message);
-      case OP_TYPE_SEARCH_RESULT_REFERENCE:                              // 0x73
-        return SearchResultReferenceProtocolOp.decodeSearchReference(element);
-      case 0x74:                                                         // 0x74
-      case 0x75:                                                         // 0x75
-      case 0x76:                                                         // 0x76
-        message =
-            ERR_LDAP_PROTOCOL_OP_DECODE_INVALID_TYPE.get(element.getType());
-        throw new LDAPException(PROTOCOL_ERROR, message);
-      case OP_TYPE_EXTENDED_REQUEST:                                     // 0x77
-        return ExtendedRequestProtocolOp.decodeExtendedRequest(element);
-      case OP_TYPE_EXTENDED_RESPONSE:                                    // 0x78
-        return ExtendedResponseProtocolOp.decodeExtendedResponse(element);
-      case OP_TYPE_INTERMEDIATE_RESPONSE:                                // 0x79
-        return
-             IntermediateResponseProtocolOp.decodeIntermediateResponse(element);
-      default:
-        message =
-            ERR_LDAP_PROTOCOL_OP_DECODE_INVALID_TYPE.get(element.getType());
-        throw new LDAPException(PROTOCOL_ERROR, message);
-    }
-  }
-
+  public abstract void write(ASN1Writer stream) throws IOException;
 
 
   /**
diff --git a/opends/src/server/org/opends/server/protocols/ldap/SearchRequestProtocolOp.java b/opends/src/server/org/opends/server/protocols/ldap/SearchRequestProtocolOp.java
index f95b80e..424b5b5 100644
--- a/opends/src/server/org/opends/server/protocols/ldap/SearchRequestProtocolOp.java
+++ b/opends/src/server/org/opends/server/protocols/ldap/SearchRequestProtocolOp.java
@@ -25,31 +25,18 @@
  *      Copyright 2006-2008 Sun Microsystems, Inc.
  */
 package org.opends.server.protocols.ldap;
-import org.opends.messages.Message;
 
 
-
-import java.util.ArrayList;
 import java.util.Iterator;
 import java.util.LinkedHashSet;
+import java.io.IOException;
 
-import org.opends.server.protocols.asn1.ASN1Boolean;
-import org.opends.server.protocols.asn1.ASN1Element;
-import org.opends.server.protocols.asn1.ASN1Enumerated;
-import org.opends.server.protocols.asn1.ASN1Integer;
-import org.opends.server.protocols.asn1.ASN1OctetString;
-import org.opends.server.protocols.asn1.ASN1Sequence;
-import org.opends.server.types.DebugLogLevel;
-import org.opends.server.types.DereferencePolicy;
-import org.opends.server.types.LDAPException;
-import org.opends.server.types.RawFilter;
-import org.opends.server.types.SearchScope;
+import org.opends.server.protocols.asn1.*;
+import org.opends.server.types.*;
 
 import static org.opends.server.loggers.debug.DebugLogger.*;
 import org.opends.server.loggers.debug.DebugTracer;
-import static org.opends.messages.ProtocolMessages.*;
 import static org.opends.server.protocols.ldap.LDAPConstants.*;
-import static org.opends.server.protocols.ldap.LDAPResultCode.*;
 import static org.opends.server.util.ServerConstants.*;
 
 
@@ -73,7 +60,7 @@
   private DereferencePolicy dereferencePolicy;
 
   // The base DN for this search request.
-  private ASN1OctetString baseDN;
+  private ByteString baseDN;
 
   // The size limit for this search request.
   private int sizeLimit;
@@ -106,7 +93,7 @@
    * @param  attributes         The set of requested attributes for this search
    *                            request.
    */
-  public SearchRequestProtocolOp(ASN1OctetString baseDN, SearchScope scope,
+  public SearchRequestProtocolOp(ByteString baseDN, SearchScope scope,
                                  DereferencePolicy dereferencePolicy,
                                  int sizeLimit, int timeLimit,
                                  boolean typesOnly, RawFilter filter,
@@ -137,25 +124,12 @@
    *
    * @return  The base DN for this search request.
    */
-  public ASN1OctetString getBaseDN()
+  public ByteString getBaseDN()
   {
     return baseDN;
   }
 
 
-
-  /**
-   * Specifies the base DN for this search request.
-   *
-   * @param  baseDN  The base DN for this search request.
-   */
-  public void setBaseDN(ASN1OctetString baseDN)
-  {
-    this.baseDN = baseDN;
-  }
-
-
-
   /**
    * Retrieves the scope for this search request.
    *
@@ -167,19 +141,6 @@
   }
 
 
-
-  /**
-   * Specifies the scope for this search request.
-   *
-   * @param  scope  The scope for this search request.
-   */
-  public void setScope(SearchScope scope)
-  {
-    this.scope = scope;
-  }
-
-
-
   /**
    * Retrieves the alias dereferencing policy for this search request.
    *
@@ -193,19 +154,6 @@
 
 
   /**
-   * Specifies the alias dereferencing policy for this search request.
-   *
-   * @param  dereferencePolicy  The alias dereferencing policy for this search
-   *                            request.
-   */
-  public void setDereferencePolicy(DereferencePolicy dereferencePolicy)
-  {
-    this.dereferencePolicy = dereferencePolicy;
-  }
-
-
-
-  /**
    * Retrieves the size limit for this search request.
    *
    * @return  The size limit for this search request.
@@ -218,18 +166,6 @@
 
 
   /**
-   * Specifies the size limit for this search request.
-   *
-   * @param  sizeLimit  The size limit for this search request.
-   */
-  public void setSizeLimit(int sizeLimit)
-  {
-    this.sizeLimit = sizeLimit;
-  }
-
-
-
-  /**
    * Retrieves the time limit for this search request.
    *
    * @return  The time limit for this search request.
@@ -242,18 +178,6 @@
 
 
   /**
-   * Specifies the time limit for this search request.
-   *
-   * @param  timeLimit  The time limit for this search request.
-   */
-  public void setTimeLimit(int timeLimit)
-  {
-    this.timeLimit = timeLimit;
-  }
-
-
-
-  /**
    * Retrieves the value of the typesOnly flag for this search request.
    *
    * @return  The value of tye typesOnly flag for this search request.
@@ -266,18 +190,6 @@
 
 
   /**
-   * Specifies the value of the typesOnly flag for this search request.
-   *
-   * @param  typesOnly  The value of the typesOnly flag for this search request.
-   */
-  public void setTypesOnly(boolean typesOnly)
-  {
-    this.typesOnly = typesOnly;
-  }
-
-
-
-  /**
    * Retrieves the filter for this search request.
    *
    * @return  The filter for this search request.
@@ -290,18 +202,6 @@
 
 
   /**
-   * Specifies the filter for this search request.
-   *
-   * @param  filter  The filter for this search request.
-   */
-  public void setFilter(RawFilter filter)
-  {
-    this.filter = filter;
-  }
-
-
-
-  /**
    * Retrieves the set of requested attributes for this search request.  The
    * returned list may be modified by the caller.
    *
@@ -315,26 +215,6 @@
 
 
   /**
-   * Specifies the set of requested attributes for this search request.
-   *
-   * @param  attributes  The set of requested attributes for this search
-   *                     request.
-   */
-  public void setAttributes(LinkedHashSet<String> attributes)
-  {
-    if (attributes == null)
-    {
-      this.attributes.clear();
-    }
-    else
-    {
-      this.attributes = attributes;
-    }
-  }
-
-
-
-  /**
    * Retrieves the BER type for this protocol op.
    *
    * @return  The BER type for this protocol op.
@@ -356,278 +236,31 @@
     return "Search Request";
   }
 
-
-
   /**
-   * Encodes this protocol op to an ASN.1 element suitable for including in an
-   * LDAP message.
+   * Writes this protocol op to an ASN.1 output stream.
    *
-   * @return  The ASN.1 element containing the encoded protocol op.
+   * @param stream The ASN.1 output stream to write to.
+   * @throws IOException If a problem occurs while writing to the stream.
    */
-  public ASN1Element encode()
+  public void write(ASN1Writer stream) throws IOException
   {
-    ArrayList<ASN1Element> elements = new ArrayList<ASN1Element>(8);
-    elements.add(baseDN);
-    elements.add(new ASN1Enumerated(scope.intValue()));
-    elements.add(new ASN1Enumerated(dereferencePolicy.intValue()));
-    elements.add(new ASN1Integer(sizeLimit));
-    elements.add(new ASN1Integer(timeLimit));
-    elements.add(new ASN1Boolean(typesOnly));
-    elements.add(filter.encode());
+    stream.writeStartSequence(OP_TYPE_SEARCH_REQUEST);
+    stream.writeOctetString(baseDN);
+    stream.writeEnumerated(scope.intValue());
+    stream.writeEnumerated(dereferencePolicy.intValue());
+    stream.writeInteger(sizeLimit);
+    stream.writeInteger(timeLimit);
+    stream.writeBoolean(typesOnly);
+    filter.write(stream);
 
-    ArrayList<ASN1Element> attrElements =
-         new ArrayList<ASN1Element>(attributes.size());
-    for (String attribute : attributes)
+    stream.writeStartSequence();
+    for(String attribute : attributes)
     {
-      attrElements.add(new ASN1OctetString(attribute));
+      stream.writeOctetString(attribute);
     }
-    elements.add(new ASN1Sequence(attrElements));
+    stream.writeEndSequence();
 
-    return new ASN1Sequence(OP_TYPE_SEARCH_REQUEST, elements);
-  }
-
-
-
-  /**
-   * Decodes the provided ASN.1 element as an LDAP search request protocol op.
-   *
-   * @param  element  The ASN.1 element to decode.
-   *
-   * @return  The decoded LDAP search request protocol op.
-   *
-   * @throws  LDAPException  If a problem occurs while decoding the provided
-   *                         ASN.1 element as an LDAP search request protocol
-   *                         op.
-   */
-  public static SearchRequestProtocolOp decodeSearchRequest(ASN1Element element)
-         throws LDAPException
-  {
-    ArrayList<ASN1Element> elements;
-    try
-    {
-      elements = element.decodeAsSequence().elements();
-    }
-    catch (Exception e)
-    {
-      if (debugEnabled())
-      {
-        TRACER.debugCaught(DebugLogLevel.ERROR, e);
-      }
-
-      Message message =
-          ERR_LDAP_SEARCH_REQUEST_DECODE_SEQUENCE.get(String.valueOf(e));
-      throw new LDAPException(PROTOCOL_ERROR, message, e);
-    }
-
-
-    int numElements = elements.size();
-    if (numElements != 8)
-    {
-      Message message =
-          ERR_LDAP_SEARCH_REQUEST_DECODE_INVALID_ELEMENT_COUNT.get(numElements);
-      throw new LDAPException(PROTOCOL_ERROR, message);
-    }
-
-
-    ASN1OctetString baseDN;
-    try
-    {
-      baseDN = elements.get(0).decodeAsOctetString();
-    }
-    catch (Exception e)
-    {
-      if (debugEnabled())
-      {
-        TRACER.debugCaught(DebugLogLevel.ERROR, e);
-      }
-
-      Message message =
-          ERR_LDAP_SEARCH_REQUEST_DECODE_BASE.get(String.valueOf(e));
-      throw new LDAPException(PROTOCOL_ERROR, message, e);
-    }
-
-
-    SearchScope scope;
-    try
-    {
-      switch (elements.get(1).decodeAsEnumerated().intValue())
-      {
-        case SCOPE_BASE_OBJECT:
-          scope = SearchScope.BASE_OBJECT;
-          break;
-        case SCOPE_SINGLE_LEVEL:
-          scope = SearchScope.SINGLE_LEVEL;
-          break;
-        case SCOPE_WHOLE_SUBTREE:
-          scope = SearchScope.WHOLE_SUBTREE;
-          break;
-        case SCOPE_SUBORDINATE_SUBTREE:
-          scope = SearchScope.SUBORDINATE_SUBTREE;
-          break;
-        default:
-          int    scopeValue = elements.get(1).decodeAsEnumerated().intValue();
-          Message message =
-              ERR_LDAP_SEARCH_REQUEST_DECODE_INVALID_SCOPE.get(scopeValue);
-          throw new LDAPException(PROTOCOL_ERROR, message);
-      }
-    }
-    catch (LDAPException le)
-    {
-      throw le;
-    }
-    catch (Exception e)
-    {
-      if (debugEnabled())
-      {
-        TRACER.debugCaught(DebugLogLevel.ERROR, e);
-      }
-
-      Message message =
-          ERR_LDAP_SEARCH_REQUEST_DECODE_SCOPE.get(String.valueOf(e));
-      throw new LDAPException(PROTOCOL_ERROR, message, e);
-    }
-
-
-    DereferencePolicy dereferencePolicy;
-    try
-    {
-      switch (elements.get(2).decodeAsEnumerated().intValue())
-      {
-        case DEREF_NEVER:
-          dereferencePolicy = DereferencePolicy.NEVER_DEREF_ALIASES;
-          break;
-        case DEREF_IN_SEARCHING:
-          dereferencePolicy = DereferencePolicy.DEREF_IN_SEARCHING;
-          break;
-        case DEREF_FINDING_BASE:
-          dereferencePolicy = DereferencePolicy.DEREF_FINDING_BASE_OBJECT;
-          break;
-        case DEREF_ALWAYS:
-          dereferencePolicy = DereferencePolicy.DEREF_ALWAYS;
-          break;
-        default:
-          int    derefValue = elements.get(2).decodeAsEnumerated().intValue();
-          Message message =
-              ERR_LDAP_SEARCH_REQUEST_DECODE_INVALID_DEREF.get(derefValue);
-          throw new LDAPException(PROTOCOL_ERROR, message);
-      }
-    }
-    catch (LDAPException le)
-    {
-      throw le;
-    }
-    catch (Exception e)
-    {
-      if (debugEnabled())
-      {
-        TRACER.debugCaught(DebugLogLevel.ERROR, e);
-      }
-
-      Message message =
-          ERR_LDAP_SEARCH_REQUEST_DECODE_DEREF.get(String.valueOf(e));
-      throw new LDAPException(PROTOCOL_ERROR, message, e);
-    }
-
-
-    int sizeLimit;
-    try
-    {
-      sizeLimit = elements.get(3).decodeAsInteger().intValue();
-    }
-    catch (Exception e)
-    {
-      if (debugEnabled())
-      {
-        TRACER.debugCaught(DebugLogLevel.ERROR, e);
-      }
-
-      Message message =
-          ERR_LDAP_SEARCH_REQUEST_DECODE_SIZE_LIMIT.get(String.valueOf(e));
-      throw new LDAPException(PROTOCOL_ERROR, message, e);
-    }
-
-
-    int timeLimit;
-    try
-    {
-      timeLimit = elements.get(4).decodeAsInteger().intValue();
-    }
-    catch (Exception e)
-    {
-      if (debugEnabled())
-      {
-        TRACER.debugCaught(DebugLogLevel.ERROR, e);
-      }
-
-      Message message =
-          ERR_LDAP_SEARCH_REQUEST_DECODE_TIME_LIMIT.get(String.valueOf(e));
-      throw new LDAPException(PROTOCOL_ERROR, message, e);
-    }
-
-
-    boolean typesOnly;
-    try
-    {
-      typesOnly = elements.get(5).decodeAsBoolean().booleanValue();
-    }
-    catch (Exception e)
-    {
-      if (debugEnabled())
-      {
-        TRACER.debugCaught(DebugLogLevel.ERROR, e);
-      }
-
-      Message message =
-          ERR_LDAP_SEARCH_REQUEST_DECODE_TYPES_ONLY.get(String.valueOf(e));
-      throw new LDAPException(PROTOCOL_ERROR, message, e);
-    }
-
-
-    RawFilter filter;
-    try
-    {
-      filter = RawFilter.decode(elements.get(6));
-    }
-    catch (Exception e)
-    {
-      if (debugEnabled())
-      {
-        TRACER.debugCaught(DebugLogLevel.ERROR, e);
-      }
-
-      Message message =
-          ERR_LDAP_SEARCH_REQUEST_DECODE_FILTER.get(String.valueOf(e));
-      throw new LDAPException(PROTOCOL_ERROR, message, e);
-    }
-
-
-    LinkedHashSet<String> attributes;
-    try
-    {
-      ArrayList<ASN1Element> attrElements =
-           elements.get(7).decodeAsSequence().elements();
-      attributes = new LinkedHashSet<String>(attrElements.size());
-      for (ASN1Element e: attrElements)
-      {
-        attributes.add(e.decodeAsOctetString().stringValue());
-      }
-    }
-    catch (Exception e)
-    {
-      if (debugEnabled())
-      {
-        TRACER.debugCaught(DebugLogLevel.ERROR, e);
-      }
-
-      Message message =
-          ERR_LDAP_SEARCH_REQUEST_DECODE_ATTRIBUTES.get(String.valueOf(e));
-      throw new LDAPException(PROTOCOL_ERROR, message, e);
-    }
-
-
-    return new SearchRequestProtocolOp(baseDN, scope, dereferencePolicy,
-                                       sizeLimit, timeLimit, typesOnly, filter,
-                                       attributes);
+    stream.writeEndSequence();
   }
 
 
@@ -641,7 +274,7 @@
   public void toString(StringBuilder buffer)
   {
     buffer.append("SearchRequest(baseDN=");
-    baseDN.toString(buffer);
+    buffer.append(baseDN.toString());
     buffer.append(", scope=");
     buffer.append(String.valueOf(scope));
     buffer.append(", derefPolicy=");
@@ -695,7 +328,7 @@
 
     buffer.append(indentBuf);
     buffer.append("  Base DN:  ");
-    baseDN.toString(buffer);
+    buffer.append(baseDN.toString());
     buffer.append(EOL);
 
     buffer.append(indentBuf);
diff --git a/opends/src/server/org/opends/server/protocols/ldap/SearchResultDoneProtocolOp.java b/opends/src/server/org/opends/server/protocols/ldap/SearchResultDoneProtocolOp.java
index 4f26dd1..0df28fa 100644
--- a/opends/src/server/org/opends/server/protocols/ldap/SearchResultDoneProtocolOp.java
+++ b/opends/src/server/org/opends/server/protocols/ldap/SearchResultDoneProtocolOp.java
@@ -28,24 +28,16 @@
 import org.opends.messages.Message;
 
 
-
-import java.util.ArrayList;
 import java.util.Iterator;
 import java.util.List;
+import java.io.IOException;
 
-import org.opends.server.protocols.asn1.ASN1Element;
-import org.opends.server.protocols.asn1.ASN1Enumerated;
-import org.opends.server.protocols.asn1.ASN1OctetString;
-import org.opends.server.protocols.asn1.ASN1Sequence;
-import org.opends.server.types.DebugLogLevel;
+import org.opends.server.protocols.asn1.*;
 import org.opends.server.types.DN;
-import org.opends.server.types.LDAPException;
 
 import static org.opends.server.loggers.debug.DebugLogger.*;
 import org.opends.server.loggers.debug.DebugTracer;
-import static org.opends.messages.ProtocolMessages.*;
 import static org.opends.server.protocols.ldap.LDAPConstants.*;
-import static org.opends.server.protocols.ldap.LDAPResultCode.*;
 import static org.opends.server.util.ServerConstants.*;
 
 
@@ -143,18 +135,6 @@
 
 
   /**
-   * Specifies the result code for this response.
-   *
-   * @param  resultCode  The result code for this response.
-   */
-  public void setResultCode(int resultCode)
-  {
-    this.resultCode = resultCode;
-  }
-
-
-
-  /**
    * Retrieves the error message for this response.
    *
    * @return  The error message for this response, or <CODE>null</CODE> if none
@@ -168,18 +148,6 @@
 
 
   /**
-   * Specifies the error message for this response.
-   *
-   * @param  errorMessage  The error message for this response.
-   */
-  public void setErrorMessage(Message errorMessage)
-  {
-    this.errorMessage = errorMessage;
-  }
-
-
-
-  /**
    * Retrieves the matched DN for this response.
    *
    * @return  The matched DN for this response, or <CODE>null</CODE> if none is
@@ -193,18 +161,6 @@
 
 
   /**
-   * Specifies the matched DN for this response.
-   *
-   * @param  matchedDN  The matched DN for this response.
-   */
-  public void setMatchedDN(DN matchedDN)
-  {
-    this.matchedDN = matchedDN;
-  }
-
-
-
-  /**
    * Retrieves the set of referral URLs for this response.
    *
    * @return  The set of referral URLs for this response, or <CODE>null</CODE>
@@ -218,18 +174,6 @@
 
 
   /**
-   * Specifies the set of referral URLs for this response.
-   *
-   * @param  referralURLs  The set of referral URLs for this response.
-   */
-  public void setReferralURLs(List<String> referralURLs)
-  {
-    this.referralURLs = referralURLs;
-  }
-
-
-
-  /**
    * Retrieves the BER type for this protocol op.
    *
    * @return  The BER type for this protocol op.
@@ -251,196 +195,46 @@
     return "Search Result Done";
   }
 
-
-
   /**
-   * Encodes this protocol op to an ASN.1 element suitable for including in an
-   * LDAP message.
+   * Writes this protocol op to an ASN.1 output stream.
    *
-   * @return  The ASN.1 element containing the encoded protocol op.
+   * @param stream The ASN.1 output stream to write to.
+   * @throws IOException If a problem occurs while writing to the stream.
    */
-  public ASN1Element encode()
+  public void write(ASN1Writer stream) throws IOException
   {
-    ArrayList<ASN1Element> elements = new ArrayList<ASN1Element>(4);
-    elements.add(new ASN1Enumerated(resultCode));
+    stream.writeStartSequence(OP_TYPE_SEARCH_RESULT_DONE);
+    stream.writeEnumerated(resultCode);
 
-    if (matchedDN == null)
+    if(matchedDN == null)
     {
-      elements.add(new ASN1OctetString());
+      stream.writeOctetString((String)null);
     }
     else
     {
-      elements.add(new ASN1OctetString(matchedDN.toString()));
+      stream.writeOctetString(matchedDN.toString());
     }
 
-    if (errorMessage == null)
+    if(errorMessage == null)
     {
-      elements.add(new ASN1OctetString());
+      stream.writeOctetString((String)null);
     }
     else
     {
-      elements.add(new ASN1OctetString(errorMessage));
+      stream.writeOctetString(errorMessage.toString());
     }
 
     if ((referralURLs != null) && (! referralURLs.isEmpty()))
     {
-      ArrayList<ASN1Element> referralElements =
-           new ArrayList<ASN1Element>(referralURLs.size());
-
+      stream.writeStartSequence(TYPE_REFERRAL_SEQUENCE);
       for (String s : referralURLs)
       {
-        referralElements.add(new ASN1OctetString(s));
+        stream.writeOctetString(s);
       }
-
-      elements.add(new ASN1Sequence(TYPE_REFERRAL_SEQUENCE, referralElements));
+      stream.writeEndSequence();
     }
 
-    return new ASN1Sequence(OP_TYPE_SEARCH_RESULT_DONE, elements);
-  }
-
-
-
-  /**
-   * Decodes the provided ASN.1 element as a search result done protocol op.
-   *
-   * @param  element  The ASN.1 element to decode.
-   *
-   * @return  The decoded search result done protocol op.
-   *
-   * @throws  LDAPException  If a problem occurs while attempting to decode the
-   *                         ASN.1 element to a protocol op.
-   */
-  public static SearchResultDoneProtocolOp decodeSearchDone(ASN1Element
-                                                                  element)
-         throws LDAPException
-  {
-    ArrayList<ASN1Element> elements;
-    try
-    {
-      elements = element.decodeAsSequence().elements();
-    }
-    catch (Exception e)
-    {
-      if (debugEnabled())
-      {
-        TRACER.debugCaught(DebugLogLevel.ERROR, e);
-      }
-
-      Message message = ERR_LDAP_RESULT_DECODE_SEQUENCE.get(String.valueOf(e));
-      throw new LDAPException(PROTOCOL_ERROR, message, e);
-    }
-
-
-    int numElements = elements.size();
-    if ((numElements < 3) || (numElements > 4))
-    {
-      Message message =
-          ERR_LDAP_RESULT_DECODE_INVALID_ELEMENT_COUNT.get(numElements);
-      throw new LDAPException(PROTOCOL_ERROR, message);
-    }
-
-
-    int resultCode;
-    try
-    {
-      resultCode = elements.get(0).decodeAsInteger().intValue();
-    }
-    catch (Exception e)
-    {
-      if (debugEnabled())
-      {
-        TRACER.debugCaught(DebugLogLevel.ERROR, e);
-      }
-
-      Message message =
-          ERR_LDAP_RESULT_DECODE_RESULT_CODE.get(String.valueOf(e));
-      throw new LDAPException(PROTOCOL_ERROR, message, e);
-    }
-
-
-    DN matchedDN;
-    try
-    {
-      String dnString = elements.get(1).decodeAsOctetString().stringValue();
-      if (dnString.length() == 0)
-      {
-        matchedDN = null;
-      }
-      else
-      {
-        matchedDN = DN.decode(dnString);
-      }
-    }
-    catch (Exception e)
-    {
-      if (debugEnabled())
-      {
-        TRACER.debugCaught(DebugLogLevel.ERROR, e);
-      }
-
-      Message message =
-          ERR_LDAP_RESULT_DECODE_MATCHED_DN.get(String.valueOf(e));
-      throw new LDAPException(PROTOCOL_ERROR, message, e);
-    }
-
-
-    Message errorMessage;
-    try
-    {
-      errorMessage =
-              Message.raw(elements.get(2).decodeAsOctetString().stringValue());
-      if (errorMessage.length() == 0)
-      {
-        errorMessage = null;
-      }
-    }
-    catch (Exception e)
-    {
-      if (debugEnabled())
-      {
-        TRACER.debugCaught(DebugLogLevel.ERROR, e);
-      }
-
-      Message message =
-          ERR_LDAP_RESULT_DECODE_ERROR_MESSAGE.get(String.valueOf(e));
-      throw new LDAPException(PROTOCOL_ERROR, message, e);
-    }
-
-
-    ArrayList<String> referralURLs;
-    if (numElements == 3)
-    {
-      referralURLs = null;
-    }
-    else
-    {
-      try
-      {
-        ArrayList<ASN1Element> referralElements =
-             elements.get(3).decodeAsSequence().elements();
-        referralURLs = new ArrayList<String>(referralElements.size());
-
-        for (ASN1Element e : referralElements)
-        {
-          referralURLs.add(e.decodeAsOctetString().stringValue());
-        }
-      }
-      catch (Exception e)
-      {
-        if (debugEnabled())
-        {
-          TRACER.debugCaught(DebugLogLevel.ERROR, e);
-        }
-
-        Message message =
-            ERR_LDAP_RESULT_DECODE_REFERRALS.get(String.valueOf(e));
-        throw new LDAPException(PROTOCOL_ERROR, message, e);
-      }
-    }
-
-
-    return new SearchResultDoneProtocolOp(resultCode, errorMessage, matchedDN,
-                                          referralURLs);
+    stream.writeEndSequence();
   }
 
 
diff --git a/opends/src/server/org/opends/server/protocols/ldap/SearchResultEntryProtocolOp.java b/opends/src/server/org/opends/server/protocols/ldap/SearchResultEntryProtocolOp.java
index fdb9ee1..40f7a84 100644
--- a/opends/src/server/org/opends/server/protocols/ldap/SearchResultEntryProtocolOp.java
+++ b/opends/src/server/org/opends/server/protocols/ldap/SearchResultEntryProtocolOp.java
@@ -28,13 +28,11 @@
 
 
 
-import static org.opends.messages.ProtocolMessages.*;
-import static org.opends.server.loggers.debug.DebugLogger.*;
 import static org.opends.server.protocols.ldap.LDAPConstants.*;
-import static org.opends.server.protocols.ldap.LDAPResultCode.*;
 import static org.opends.server.util.ServerConstants.*;
 import static org.opends.server.util.StaticUtils.*;
 
+import java.io.IOException;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.Iterator;
@@ -42,17 +40,13 @@
 import java.util.List;
 import java.util.Map;
 
-import org.opends.messages.Message;
 import org.opends.server.core.DirectoryServer;
-import org.opends.server.loggers.debug.DebugTracer;
-import org.opends.server.protocols.asn1.ASN1Element;
-import org.opends.server.protocols.asn1.ASN1OctetString;
-import org.opends.server.protocols.asn1.ASN1Sequence;
+import org.opends.server.protocols.asn1.ASN1Writer;
 import org.opends.server.types.Attribute;
 import org.opends.server.types.AttributeBuilder;
 import org.opends.server.types.AttributeType;
+import org.opends.server.types.ByteString;
 import org.opends.server.types.DN;
-import org.opends.server.types.DebugLogLevel;
 import org.opends.server.types.Entry;
 import org.opends.server.types.LDAPException;
 import org.opends.server.types.ObjectClass;
@@ -69,11 +63,6 @@
 public class SearchResultEntryProtocolOp
        extends ProtocolOp
 {
-  /**
-   * The tracer object for the debug logger.
-   */
-  private static final DebugTracer TRACER = getTracer();
-
   // The set of attributes for this search entry.
   private LinkedList<LDAPAttribute> attributes;
 
@@ -244,19 +233,6 @@
   }
 
 
-
-  /**
-   * Specifies the DN for this search result entry.
-   *
-   * @param  dn  The DN for this search result entry.
-   */
-  public void setDN(DN dn)
-  {
-    this.dn = dn;
-  }
-
-
-
   /**
    * Retrieves the set of attributes for this search result entry.  The returned
    * list may be altered by the caller.
@@ -297,118 +273,25 @@
 
 
   /**
-   * Encodes this protocol op to an ASN.1 element suitable for including in an
-   * LDAP message.
+   * Writes this protocol op to an ASN.1 output stream.
    *
-   * @return  The ASN.1 element containing the encoded protocol op.
+   * @param stream The ASN.1 output stream to write to.
+   * @throws IOException If a problem occurs while writing to the stream.
    */
   @Override
-  public ASN1Element encode()
+  public void write(ASN1Writer stream) throws IOException
   {
-    ArrayList<ASN1Element> elements = new ArrayList<ASN1Element>(2);
-    elements.add(new ASN1OctetString(dn.toString()));
+    stream.writeStartSequence(OP_TYPE_SEARCH_RESULT_ENTRY);
+    stream.writeOctetString(dn.toString());
 
-
-    ArrayList<ASN1Element> attrElements =
-         new ArrayList<ASN1Element>(attributes.size());
-    for (LDAPAttribute attr : attributes)
+    stream.writeStartSequence();
+    for(LDAPAttribute attr : attributes)
     {
-      attrElements.add(attr.encode());
+      attr.write(stream);
     }
-    elements.add(new ASN1Sequence(attrElements));
+    stream.writeEndSequence();
 
-
-    return new ASN1Sequence(OP_TYPE_SEARCH_RESULT_ENTRY, elements);
-  }
-
-
-
-  /**
-   * Decodes the provided ASN.1 element as an LDAP search result entry protocol
-   * op.
-   *
-   * @param  element  The ASN.1 element to be decoded.
-   *
-   * @return  The decoded search result entry protocol op.
-   *
-   * @throws  LDAPException  If a problem occurs while decoding the provided
-   *                         ASN.1 element as an LDAP search result entry
-   *                         protocol op.
-   */
-  public static SearchResultEntryProtocolOp decodeSearchEntry(ASN1Element
-                                                                   element)
-         throws LDAPException
-  {
-    ArrayList<ASN1Element> elements;
-    try
-    {
-      elements = element.decodeAsSequence().elements();
-    }
-    catch (Exception e)
-    {
-      if (debugEnabled())
-      {
-        TRACER.debugCaught(DebugLogLevel.ERROR, e);
-      }
-
-      Message message =
-          ERR_LDAP_SEARCH_ENTRY_DECODE_SEQUENCE.get(String.valueOf(e));
-      throw new LDAPException(PROTOCOL_ERROR, message, e);
-    }
-
-
-    int numElements = elements.size();
-    if (numElements != 2)
-    {
-      Message message =
-          ERR_LDAP_SEARCH_ENTRY_DECODE_INVALID_ELEMENT_COUNT.get(numElements);
-      throw new LDAPException(PROTOCOL_ERROR, message);
-    }
-
-
-    DN dn;
-    try
-    {
-      dn = DN.decode(elements.get(0).decodeAsOctetString().stringValue());
-    }
-    catch (Exception e)
-    {
-      if (debugEnabled())
-      {
-        TRACER.debugCaught(DebugLogLevel.ERROR, e);
-      }
-
-      Message message = ERR_LDAP_SEARCH_ENTRY_DECODE_DN.get(String.valueOf(e));
-      throw new LDAPException(PROTOCOL_ERROR, message, e);
-    }
-
-
-
-    LinkedList<LDAPAttribute> attributes;
-    try
-    {
-      ArrayList<ASN1Element> attrElements =
-           elements.get(1).decodeAsSequence().elements();
-      attributes = new LinkedList<LDAPAttribute>();
-      for (ASN1Element e : attrElements)
-      {
-        attributes.add(LDAPAttribute.decode(e));
-      }
-    }
-    catch (Exception e)
-    {
-      if (debugEnabled())
-      {
-        TRACER.debugCaught(DebugLogLevel.ERROR, e);
-      }
-
-      Message message =
-          ERR_LDAP_SEARCH_ENTRY_DECODE_ATTRS.get(String.valueOf(e));
-      throw new LDAPException(PROTOCOL_ERROR, message, e);
-    }
-
-
-    return new SearchResultEntryProtocolOp(dn, attributes);
+    stream.writeEndSequence();
   }
 
 
@@ -541,12 +424,12 @@
       String name       = a.getAttributeType();
       int    nameLength = name.length();
 
-      for (ASN1OctetString v : a.getValues())
+      for (ByteString v : a.getValues())
       {
         String valueString;
-        if (needsBase64Encoding(v.value()))
+        if (needsBase64Encoding(v))
         {
-          valueString = Base64.encode(v.value());
+          valueString = Base64.encode(v);
           buffer.append(name);
           buffer.append(":: ");
 
@@ -554,7 +437,7 @@
         }
         else
         {
-          valueString = v.stringValue();
+          valueString = v.toString();
           buffer.append(name);
           buffer.append(": ");
 
@@ -627,7 +510,7 @@
 
       if (attrType.isObjectClassType())
       {
-        for (ASN1OctetString os : a.getValues())
+        for (ByteString os : a.getValues())
         {
           String ocName = os.toString();
           ObjectClass oc =
diff --git a/opends/src/server/org/opends/server/protocols/ldap/SearchResultReferenceProtocolOp.java b/opends/src/server/org/opends/server/protocols/ldap/SearchResultReferenceProtocolOp.java
index d5e12ab..a69e23c 100644
--- a/opends/src/server/org/opends/server/protocols/ldap/SearchResultReferenceProtocolOp.java
+++ b/opends/src/server/org/opends/server/protocols/ldap/SearchResultReferenceProtocolOp.java
@@ -25,26 +25,19 @@
  *      Copyright 2006-2008 Sun Microsystems, Inc.
  */
 package org.opends.server.protocols.ldap;
-import org.opends.messages.Message;
-
 
 
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Iterator;
+import java.io.IOException;
 
-import org.opends.server.protocols.asn1.ASN1Element;
-import org.opends.server.protocols.asn1.ASN1OctetString;
-import org.opends.server.protocols.asn1.ASN1Sequence;
+import org.opends.server.protocols.asn1.*;
 import org.opends.server.types.SearchResultReference;
-import org.opends.server.types.DebugLogLevel;
-import org.opends.server.types.LDAPException;
 
 import static org.opends.server.loggers.debug.DebugLogger.*;
 import org.opends.server.loggers.debug.DebugTracer;
-import static org.opends.messages.ProtocolMessages.*;
 import static org.opends.server.protocols.ldap.LDAPConstants.*;
-import static org.opends.server.protocols.ldap.LDAPResultCode.*;
 import static org.opends.server.util.ServerConstants.*;
 
 
@@ -141,84 +134,20 @@
     return "Search Result Reference";
   }
 
-
-
   /**
-   * Encodes this protocol op to an ASN.1 element suitable for including in an
-   * LDAP message.
+   * Writes this protocol op to an ASN.1 output stream.
    *
-   * @return  The ASN.1 element containing the encoded protocol op.
+   * @param stream The ASN.1 output stream to write to.
+   * @throws IOException If a problem occurs while writing to the stream.
    */
-  public ASN1Element encode()
+  public void write(ASN1Writer stream) throws IOException
   {
-    ArrayList<ASN1Element> elements =
-         new ArrayList<ASN1Element>(referralURLs.size());
-    for (String url : referralURLs)
+    stream.writeStartSequence(OP_TYPE_SEARCH_RESULT_REFERENCE);
+    for(String url : referralURLs)
     {
-      elements.add(new ASN1OctetString(url));
+      stream.writeOctetString(url);
     }
-
-    return new ASN1Sequence(OP_TYPE_SEARCH_RESULT_REFERENCE, elements);
-  }
-
-
-
-  /**
-   * Decodes the provided ASN.1 element as a search result reference protocol
-   * op.
-   *
-   * @param  element  The ASN.1 element to decode.
-   *
-   * @return  The decoded search result reference protocol op.
-   *
-   * @throws  LDAPException  If a problem occurs while decoding the provided
-   *                         ASN.1 element as an LDAP search result reference
-   *                         protocol op.
-   */
-  public static SearchResultReferenceProtocolOp
-                     decodeSearchReference(ASN1Element element)
-         throws LDAPException
-  {
-    ArrayList<ASN1Element> elements;
-    try
-    {
-      elements = element.decodeAsSequence().elements();
-    }
-    catch (Exception e)
-    {
-      if (debugEnabled())
-      {
-        TRACER.debugCaught(DebugLogLevel.ERROR, e);
-      }
-
-      Message message =
-          ERR_LDAP_SEARCH_REFERENCE_DECODE_SEQUENCE.get(String.valueOf(e));
-      throw new LDAPException(PROTOCOL_ERROR, message, e);
-    }
-
-
-    ArrayList<String> referralURLs = new ArrayList<String>(elements.size());
-    try
-    {
-      for (ASN1Element e : elements)
-      {
-        referralURLs.add(e.decodeAsOctetString().stringValue());
-      }
-    }
-    catch (Exception e)
-    {
-      if (debugEnabled())
-      {
-        TRACER.debugCaught(DebugLogLevel.ERROR, e);
-      }
-
-      Message message =
-          ERR_LDAP_SEARCH_REFERENCE_DECODE_URLS.get(String.valueOf(e));
-      throw new LDAPException(PROTOCOL_ERROR, message, e);
-    }
-
-
-    return new SearchResultReferenceProtocolOp(referralURLs);
+    stream.writeEndSequence();
   }
 
 
diff --git a/opends/src/server/org/opends/server/protocols/ldap/UnbindRequestProtocolOp.java b/opends/src/server/org/opends/server/protocols/ldap/UnbindRequestProtocolOp.java
index eec7549..41083a4 100644
--- a/opends/src/server/org/opends/server/protocols/ldap/UnbindRequestProtocolOp.java
+++ b/opends/src/server/org/opends/server/protocols/ldap/UnbindRequestProtocolOp.java
@@ -25,22 +25,17 @@
  *      Copyright 2006-2008 Sun Microsystems, Inc.
  */
 package org.opends.server.protocols.ldap;
-import org.opends.messages.Message;
 
 
 
-import org.opends.server.protocols.asn1.ASN1Element;
-import org.opends.server.protocols.asn1.ASN1Null;
-import org.opends.server.types.DebugLogLevel;
-import org.opends.server.types.LDAPException;
+import org.opends.server.protocols.asn1.ASN1Writer;
 
 import static org.opends.server.loggers.debug.DebugLogger.*;
 import org.opends.server.loggers.debug.DebugTracer;
-import static org.opends.messages.ProtocolMessages.*;
 import static org.opends.server.protocols.ldap.LDAPConstants.*;
-import static org.opends.server.protocols.ldap.LDAPResultCode.*;
 import static org.opends.server.util.ServerConstants.*;
 
+import java.io.IOException;
 
 
 /**
@@ -87,49 +82,15 @@
     return "Unbind Request";
   }
 
-
-
   /**
-   * Encodes this protocol op to an ASN.1 element suitable for including in an
-   * LDAP message.
+   * Writes this protocol op to an ASN.1 output stream.
    *
-   * @return  The ASN.1 element containing the encoded protocol op.
+   * @param stream The ASN.1 output stream to write to.
+   * @throws IOException If a problem occurs while writing to the stream.
    */
-  public ASN1Element encode()
+  public void write(ASN1Writer stream) throws IOException
   {
-    return new ASN1Null(OP_TYPE_UNBIND_REQUEST);
-  }
-
-
-
-  /**
-   * Decodes the provided ASN.1 element as an LDAP unbind request protocol op.
-   *
-   * @param  element  The ASN.1 element to decode.
-   *
-   * @return  The decoded LDAP unbind request protocol op.
-   *
-   * @throws  LDAPException  If the provided ASN.1 element cannot be decoded as
-   *                         an unbind request protocol op.
-   */
-  public static UnbindRequestProtocolOp decodeUnbindRequest(ASN1Element element)
-         throws LDAPException
-  {
-    try
-    {
-      element.decodeAsNull();
-      return new UnbindRequestProtocolOp();
-    }
-    catch (Exception e)
-    {
-      if (debugEnabled())
-      {
-        TRACER.debugCaught(DebugLogLevel.ERROR, e);
-      }
-
-      Message message = ERR_LDAP_UNBIND_DECODE.get(String.valueOf(e));
-      throw new LDAPException(PROTOCOL_ERROR, message, e);
-    }
+    stream.writeNull(OP_TYPE_UNBIND_REQUEST);
   }
 
 
diff --git a/opends/src/server/org/opends/server/replication/common/ServerState.java b/opends/src/server/org/opends/server/replication/common/ServerState.java
index cf2f0f8..394902e 100644
--- a/opends/src/server/org/opends/server/replication/common/ServerState.java
+++ b/opends/src/server/org/opends/server/replication/common/ServerState.java
@@ -36,7 +36,7 @@
 import java.util.Set;
 import java.util.zip.DataFormatException;
 
-import org.opends.server.protocols.asn1.ASN1OctetString;
+import org.opends.server.types.ByteString;
 
 
 /**
@@ -230,15 +230,15 @@
    * @return an ArrayList of ANS1OctetString encoding the ChangeNumbers
    * contained in the ServerState.
    */
-  public ArrayList<ASN1OctetString> toASN1ArrayList()
+  public ArrayList<ByteString> toASN1ArrayList()
   {
-    ArrayList<ASN1OctetString> values = new ArrayList<ASN1OctetString>(0);
+    ArrayList<ByteString> values = new ArrayList<ByteString>(0);
 
     synchronized (this)
     {
       for (Short id : list.keySet())
       {
-        ASN1OctetString value = new ASN1OctetString(list.get(id).toString());
+        ByteString value = ByteString.valueOf(list.get(id).toString());
         values.add(value);
       }
     }
diff --git a/opends/src/server/org/opends/server/replication/plugin/HistVal.java b/opends/src/server/org/opends/server/replication/plugin/HistVal.java
index eae4433..7828821 100644
--- a/opends/src/server/org/opends/server/replication/plugin/HistVal.java
+++ b/opends/src/server/org/opends/server/replication/plugin/HistVal.java
@@ -31,12 +31,7 @@
 
 import org.opends.server.core.DirectoryServer;
 import org.opends.server.replication.common.ChangeNumber;
-import org.opends.server.types.Attribute;
-import org.opends.server.types.AttributeBuilder;
-import org.opends.server.types.AttributeType;
-import org.opends.server.types.AttributeValue;
-import org.opends.server.types.Modification;
-import org.opends.server.types.ModificationType;
+import org.opends.server.types.*;
 
 
 /**
@@ -136,7 +131,7 @@
       if (token.length == 4)
       {
         stringValue = token[3];
-        attributeValue = new AttributeValue(attrType, stringValue);
+        attributeValue = AttributeValues.create(attrType, stringValue);
       }
       else
         attributeValue = null;
diff --git a/opends/src/server/org/opends/server/replication/plugin/Historical.java b/opends/src/server/org/opends/server/replication/plugin/Historical.java
index 89443da..0d269fd 100644
--- a/opends/src/server/org/opends/server/replication/plugin/Historical.java
+++ b/opends/src/server/org/opends/server/replication/plugin/Historical.java
@@ -42,14 +42,7 @@
 import org.opends.server.core.DirectoryServer;
 import org.opends.server.replication.common.ChangeNumber;
 import org.opends.server.replication.protocol.OperationContext;
-import org.opends.server.types.Attribute;
-import org.opends.server.types.AttributeBuilder;
-import org.opends.server.types.AttributeType;
-import org.opends.server.types.AttributeValue;
-import org.opends.server.types.Attributes;
-import org.opends.server.types.Entry;
-import org.opends.server.types.Modification;
-import org.opends.server.types.ModificationType;
+import org.opends.server.types.*;
 import org.opends.server.types.operation.PreOperationAddOperation;
 import org.opends.server.types.operation.PreOperationModifyDNOperation;
 import org.opends.server.types.operation.PreOperationModifyOperation;
@@ -250,7 +243,7 @@
       DirectoryServer.getSchema().getAttributeType(HISTORICALATTRIBUTENAME);
 
     String strValue = "dn:" + cn.toString() +":add";
-    AttributeValue val = new AttributeValue(historicalAttrType, strValue);
+    AttributeValue val = AttributeValues.create(historicalAttrType, strValue);
     return val;
   }
 
@@ -271,7 +264,7 @@
       DirectoryServer.getSchema().getAttributeType(HISTORICALATTRIBUTENAME);
 
     String strValue = "dn:" + cn.toString() +":moddn";
-    AttributeValue val = new AttributeValue(historicalAttrType, strValue);
+    AttributeValue val = AttributeValues.create(historicalAttrType, strValue);
     return val;
   }
 
@@ -371,7 +364,7 @@
             strValue = type.getNormalizedPrimaryName() + optionsString + ":" +
             valInfo.getValueDeleteTime().toString() +
             ":del:" + valInfo.getValue().toString();
-            AttributeValue val = new AttributeValue(historicalAttrType,
+            AttributeValue val = AttributeValues.create(historicalAttrType,
                                                     strValue);
             builder.add(val);
           }
@@ -401,7 +394,7 @@
               }
             }
 
-            AttributeValue val = new AttributeValue(historicalAttrType,
+            AttributeValue val = AttributeValues.create(historicalAttrType,
                                                     strValue);
             builder.add(val);
           }
@@ -412,7 +405,8 @@
           String strValue = type.getNormalizedPrimaryName()
               + optionsString + ":" + deleteTime.toString()
               + ":attrDel";
-          AttributeValue val = new AttributeValue(historicalAttrType, strValue);
+          AttributeValue val =
+              AttributeValues.create(historicalAttrType, strValue);
           builder.add(val);
         }
       }
@@ -480,7 +474,7 @@
       {
         for (AttributeValue val : attr)
         {
-          HistVal histVal = new HistVal(val.getStringValue());
+          HistVal histVal = new HistVal(val.getValue().toString());
           AttributeType attrType = histVal.getAttrType();
           Set<String> options = histVal.getOptions();
           ChangeNumber cn = histVal.getCn();
@@ -577,7 +571,7 @@
       {
         for (AttributeValue val : attr)
         {
-          HistVal histVal = new HistVal(val.getStringValue());
+          HistVal histVal = new HistVal(val.getValue().toString());
           if (histVal.isADDOperation())
           {
             // Found some historical information indicating that this
@@ -662,7 +656,7 @@
       if (!uuid.isEmpty())
       {
         AttributeValue uuidVal = uuid.iterator().next();
-        uuidString =  uuidVal.getStringValue();
+        uuidString =  uuidVal.getValue().toString();
       }
     }
     return uuidString;
@@ -690,7 +684,7 @@
       if (!uuid.isEmpty())
       {
         AttributeValue uuidVal = uuid.iterator().next();
-        uuidString =  uuidVal.getStringValue();
+        uuidString =  uuidVal.getValue().toString();
       }
     }
     return uuidString;
diff --git a/opends/src/server/org/opends/server/replication/plugin/HistoricalCsnOrderingMatchingRule.java b/opends/src/server/org/opends/server/replication/plugin/HistoricalCsnOrderingMatchingRule.java
index be77e1e..7566869 100644
--- a/opends/src/server/org/opends/server/replication/plugin/HistoricalCsnOrderingMatchingRule.java
+++ b/opends/src/server/org/opends/server/replication/plugin/HistoricalCsnOrderingMatchingRule.java
@@ -29,8 +29,8 @@
 import java.util.Collection;
 import java.util.Collections;
 import org.opends.server.api.OrderingMatchingRule;
-import org.opends.server.protocols.asn1.ASN1OctetString;
 import org.opends.server.types.ByteString;
+import org.opends.server.types.ByteSequence;
 
 /**
  * Used to establish an order between historical information and index them.
@@ -64,10 +64,10 @@
    * @return 0 when equals, -1 or 1 to establish order
    */
   @Override
-  public int compareValues(ByteString value1, ByteString value2)
+  public int compareValues(ByteSequence value1, ByteSequence value2)
   {
-    String[] token1 = value1.stringValue().split(":", 3);
-    String[] token2 = value2.stringValue().split(":", 3);
+    String[] token1 = value1.toString().split(":", 3);
+    String[] token2 = value2.toString().split(":", 3);
 
     if ((token1[1] == null) || (token2[1] == null))
       return -1;
@@ -133,9 +133,9 @@
    * comparison
    */
   @Override
-  public ByteString normalizeValue(ByteString value)
+  public ByteString normalizeValue(ByteSequence value)
   {
-    String[] token = value.stringValue().split(":", 3);
+    String[] token = value.toString().split(":", 3);
 
     /* Change the format of the value to index and start
      * with the serverId. In that manner, the search response
@@ -147,7 +147,7 @@
     String serverId = token[1].substring(16,20);
     String seqNumber = token[1].substring(20, 28);
 
-    return new ASN1OctetString(serverId + timestamp + seqNumber);
+    return ByteString.valueOf(serverId + timestamp + seqNumber);
   }
 
   /**
diff --git a/opends/src/server/org/opends/server/replication/plugin/LDAPReplicationDomain.java b/opends/src/server/org/opends/server/replication/plugin/LDAPReplicationDomain.java
index ff2a806..df09350 100644
--- a/opends/src/server/org/opends/server/replication/plugin/LDAPReplicationDomain.java
+++ b/opends/src/server/org/opends/server/replication/plugin/LDAPReplicationDomain.java
@@ -87,7 +87,6 @@
 import org.opends.server.core.ModifyOperationBasis;
 import org.opends.server.loggers.debug.DebugTracer;
 import org.opends.server.protocols.asn1.ASN1Exception;
-import org.opends.server.protocols.asn1.ASN1OctetString;
 import org.opends.server.protocols.internal.InternalClientConnection;
 import org.opends.server.protocols.internal.InternalSearchListener;
 import org.opends.server.protocols.internal.InternalSearchOperation;
@@ -115,7 +114,8 @@
 import org.opends.server.types.Attribute;
 import org.opends.server.types.AttributeBuilder;
 import org.opends.server.types.AttributeType;
-import org.opends.server.types.AttributeValue;
+import org.opends.server.types.AttributeValues;
+import org.opends.server.types.ByteString;
 import org.opends.server.types.ConfigChangeResult;
 import org.opends.server.types.Control;
 import org.opends.server.types.DN;
@@ -178,18 +178,19 @@
 
   // The update to replay message queue where the listener thread is going to
   // push incoming update messages.
-  private LinkedBlockingQueue<UpdateToReplay> updateToReplayQueue;
-  private AtomicInteger numResolvedNamingConflicts = new AtomicInteger();
-  private AtomicInteger numResolvedModifyConflicts = new AtomicInteger();
-  private AtomicInteger numUnresolvedNamingConflicts = new AtomicInteger();
-  private int debugCount = 0;
+  private final LinkedBlockingQueue<UpdateToReplay> updateToReplayQueue;
+  private final AtomicInteger numResolvedNamingConflicts = new AtomicInteger();
+  private final AtomicInteger numResolvedModifyConflicts = new AtomicInteger();
+  private final AtomicInteger numUnresolvedNamingConflicts =
+    new AtomicInteger();
+  private final int debugCount = 0;
   private final PersistentServerState state;
   private int numReplayedPostOpCalled = 0;
 
   private long generationId = -1;
   private boolean generationIdSavedStatus = false;
 
-  private ChangeNumberGenerator generator;
+  private final ChangeNumberGenerator generator;
 
   /**
    * This object is used to store the list of update currently being
@@ -198,7 +199,7 @@
    * correct order to the replication server and that the ServerState
    * is not updated too early.
    */
-  private PendingChanges pendingChanges;
+  private final PendingChanges pendingChanges;
 
   /**
    * It contain the updates that were done on other servers, transmitted
@@ -207,15 +208,15 @@
    * are correctly fulfilled and to to make sure that the ServerState is
    * not updated too early.
    */
-  private RemotePendingChanges remotePendingChanges;
+  private final RemotePendingChanges remotePendingChanges;
 
-  private short serverId;
+  private final short serverId;
 
-  private DN baseDn;
+  private final DN baseDn;
 
   private boolean shutdown = false;
 
-  private InternalClientConnection conn =
+  private final InternalClientConnection conn =
       InternalClientConnection.getRootConnection();
 
   private boolean solveConflictFlag = true;
@@ -225,7 +226,7 @@
 
   // This list is used to temporary store operations that needs
   // to be replayed at session establishment time.
-  private TreeSet<FakeOperation> replayOperations  =
+  private final TreeSet<FakeOperation> replayOperations  =
     new TreeSet<FakeOperation>(new FakeOperationComparator());;
 
   /**
@@ -240,7 +241,7 @@
   /**
    * The DN of the configuration entry of this domain.
    */
-  private DN configDn;
+  private final DN configDn;
 
   /**
    * A boolean indicating if the thread used to save the persistentServerState
@@ -1071,8 +1072,9 @@
                * different operation.
                */
               op = msg.createOperation(conn);
-              if (op instanceof DeleteOperation)
-                op.addRequestControl(new SubtreeDeleteControl());
+              if (op instanceof DeleteOperation) {
+                op.addRequestControl(new SubtreeDeleteControl(false));
+              }
             }
           }
           else
@@ -1787,7 +1789,7 @@
 
     AttributeType attrType = DirectoryServer.getAttributeType(DS_SYNC_CONFLICT,
         true);
-    Attribute attr = Attributes.create(attrType, new AttributeValue(
+    Attribute attr = Attributes.create(attrType, AttributeValues.create(
         attrType, conflictDN.toString()));
     List<Modification> mods = new ArrayList<Modification>();
     Modification mod = new Modification(ModificationType.REPLACE, attr);
@@ -2002,6 +2004,7 @@
   /**
    * {@inheritDoc}
    */
+  @Override
   public long getGenerationID()
   {
     return generationId;
@@ -2021,10 +2024,10 @@
   public ResultCode saveGenerationId(long generationId)
   {
     // The generationId is stored in the root entry of the domain.
-    ASN1OctetString asn1BaseDn = new ASN1OctetString(baseDn.toString());
+    ByteString asn1BaseDn = ByteString.valueOf(baseDn.toString());
 
-    ArrayList<ASN1OctetString> values = new ArrayList<ASN1OctetString>();
-    ASN1OctetString value = new ASN1OctetString(Long.toString(generationId));
+    ArrayList<ByteString> values = new ArrayList<ByteString>();
+    ByteString value = ByteString.valueOf(Long.toString(generationId));
     values.add(value);
 
     LDAPAttribute attr =
@@ -2084,7 +2087,7 @@
       TRACER.debugInfo(
           "Attempt to read generation ID from DB " + baseDn.toString());
 
-    ASN1OctetString asn1BaseDn = new ASN1OctetString(baseDn.toString());
+    ByteString asn1BaseDn = ByteString.valueOf(baseDn.toString());
     boolean found = false;
     LDAPFilter filter;
     try
@@ -2145,8 +2148,7 @@
             found=true;
             try
             {
-              generationId = Long.decode(attr.iterator().next().
-                  getStringValue());
+              generationId = Long.decode(attr.iterator().next().toString());
             }
             catch(Exception e)
             {
@@ -2262,6 +2264,7 @@
    *                             be produced.
    * @throws DirectoryException  When needed.
    */
+  @Override
   protected void exportBackend(OutputStream output) throws DirectoryException
   {
     exportBackend(output, false);
@@ -2472,6 +2475,7 @@
    * @param input                The InputStream from which
    * @throws DirectoryException  When needed.
    */
+  @Override
   public void importBackend(InputStream input) throws DirectoryException
   {
     LDIFImportConfig importConfig = null;
@@ -2912,7 +2916,7 @@
     attrs.add(Historical.ENTRYUIDNAME);
     attrs.add("*");
     return conn.processSearch(
-      new ASN1OctetString(baseDn.toString()),
+      ByteString.valueOf(baseDn.toString()),
       SearchScope.WHOLE_SUBTREE,
       DereferencePolicy.NEVER_DEREF_ALIASES,
       0, 0, false, filter,
@@ -2963,6 +2967,7 @@
    *
    * @return The number of objects in the replication domain.
    */
+  @Override
   public long countEntries() throws DirectoryException
   {
     Backend backend = retrievesBackend(baseDn);
@@ -3008,6 +3013,7 @@
    *
    * @return Monitoring attributes specific to the LDAPReplicationDomain.
    */
+  @Override
   public Collection<Attribute> getAdditionalMonitoring()
   {
     ArrayList<Attribute> attributes = new ArrayList<Attribute>();
diff --git a/opends/src/server/org/opends/server/replication/plugin/PersistentServerState.java b/opends/src/server/org/opends/server/replication/plugin/PersistentServerState.java
index 4862099..abeb007 100644
--- a/opends/src/server/org/opends/server/replication/plugin/PersistentServerState.java
+++ b/opends/src/server/org/opends/server/replication/plugin/PersistentServerState.java
@@ -39,7 +39,6 @@
 import org.opends.server.core.DeleteOperationBasis;
 import org.opends.server.core.DirectoryServer;
 import org.opends.server.core.ModifyOperationBasis;
-import org.opends.server.protocols.asn1.ASN1OctetString;
 import org.opends.server.protocols.internal.InternalClientConnection;
 import org.opends.server.protocols.internal.InternalSearchOperation;
 import org.opends.server.protocols.ldap.LDAPAttribute;
@@ -50,6 +49,7 @@
 import org.opends.server.types.Attribute;
 import org.opends.server.types.AttributeType;
 import org.opends.server.types.AttributeValue;
+import org.opends.server.types.ByteString;
 import org.opends.server.types.Control;
 import org.opends.server.types.DN;
 import org.opends.server.types.DereferencePolicy;
@@ -72,7 +72,7 @@
    private final DN baseDn;
    private final InternalClientConnection conn =
        InternalClientConnection.getRootConnection();
-   private final ASN1OctetString asn1BaseDn;
+   private final ByteString asn1BaseDn;
    private final short serverId;
 
    private final ServerState state;
@@ -102,7 +102,7 @@
     this.baseDn = baseDn;
     this.serverId = serverId;
     this.state = new ServerState();
-    asn1BaseDn = new ASN1OctetString(baseDn.toString());
+    this.asn1BaseDn = ByteString.valueOf(baseDn.toString());
     loadState();
   }
 
@@ -118,7 +118,7 @@
     this.baseDn = baseDn;
     this.serverId = serverId;
     this.state = state;
-    asn1BaseDn = new ASN1OctetString(baseDn.toString());
+    this.asn1BaseDn = ByteString.valueOf(baseDn.toString());
     loadState();
   }
 
@@ -299,8 +299,7 @@
       Attribute attr = attrs.get(0);
       for (AttributeValue value : attr)
       {
-        ChangeNumber changeNumber =
-          new ChangeNumber(value.getStringValue());
+        ChangeNumber changeNumber = new ChangeNumber(value.toString());
         update(changeNumber);
       }
     }
@@ -343,7 +342,7 @@
    */
   private ResultCode runUpdateStateEntry(DN serverStateEntryDN)
   {
-    ArrayList<ASN1OctetString> values = state.toASN1ArrayList();
+    ArrayList<ByteString> values = state.toASN1ArrayList();
 
     LDAPAttribute attr =
       new LDAPAttribute(REPLICATION_STATE, values);
@@ -355,7 +354,7 @@
       new ModifyOperationBasis(conn, InternalClientConnection.nextOperationID(),
           InternalClientConnection.nextMessageID(),
           new ArrayList<Control>(0),
-          new ASN1OctetString(serverStateEntryDN.toString()),
+          ByteString.valueOf(serverStateEntryDN.toString()),
           mods);
     op.setInternalOperation(true);
     op.setSynchronizationOperation(true);
@@ -450,7 +449,7 @@
             while (true)
             {
               AttributeValue attrVal = iav.next();
-              HistVal histVal = new HistVal(attrVal.getStringValue());
+              HistVal histVal = new HistVal(attrVal.toString());
               ChangeNumber cn = histVal.getCn();
 
               if ((cn != null) && (cn.getServerId() == serverId))
@@ -514,7 +513,7 @@
    DeleteOperationBasis del =  new DeleteOperationBasis(conn,
        InternalClientConnection.nextOperationID(),
        InternalClientConnection.nextMessageID(), null,
-       new ASN1OctetString(ruvEntry.getDN().toNormalizedString()));
+       ByteString.valueOf(ruvEntry.getDN().toNormalizedString()));
 
    // Run the internal operation
    del.setInternalOperation(true);
@@ -654,7 +653,7 @@
           {
             Iterator<AttributeValue> iav = attrs.get(0).iterator();
             AttributeValue attrVal = iav.next();
-            if (attrVal.getStringValue().
+            if (attrVal.toString().
                 equalsIgnoreCase("ffffffff-ffff-ffff-ffff-ffffffffffff"))
             {
               ruvEntry = ldapSubEntry;
diff --git a/opends/src/server/org/opends/server/replication/plugin/ReplicationRepairRequestControl.java b/opends/src/server/org/opends/server/replication/plugin/ReplicationRepairRequestControl.java
index 00d5e0f..4b5e5cf 100644
--- a/opends/src/server/org/opends/server/replication/plugin/ReplicationRepairRequestControl.java
+++ b/opends/src/server/org/opends/server/replication/plugin/ReplicationRepairRequestControl.java
@@ -27,9 +27,13 @@
 package org.opends.server.replication.plugin;
 
 
+import org.opends.server.types.ByteString;
 import org.opends.server.types.Control;
-import org.opends.server.types.LDAPException;
+import org.opends.server.types.DirectoryException;
+import org.opends.server.controls.ControlDecoder;
+import org.opends.server.protocols.asn1.ASN1Writer;
 
+import java.io.IOException;
 
 
 /**
@@ -40,10 +44,41 @@
  * It also allows to modify attributes like entryuuid and ds-sync-hist that
  * are normally not modifiable from an external connection.
  */
-public class ReplicationRepairRequestControl
-       extends Control
+public class ReplicationRepairRequestControl extends Control
 {
   /**
+   * ControlDecoder implentation to decode this control from a ByteString.
+   */
+  private final static class Decoder
+      implements ControlDecoder<ReplicationRepairRequestControl>
+  {
+    /**
+     * {@inheritDoc}
+     */
+    public ReplicationRepairRequestControl decode(boolean isCritical,
+                                                  ByteString value)
+           throws DirectoryException
+    {
+      return new ReplicationRepairRequestControl(isCritical);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public String getOID()
+    {
+      return OID_REPLICATION_REPAIR_CONTROL;
+    }
+
+  }
+
+  /**
+   * The Control Decoder that can be used to decode this control.
+   */
+  public static final ControlDecoder<ReplicationRepairRequestControl> DECODER =
+    new Decoder();
+
+  /**
    * The OID of the Replication repair Control.
    */
   public static final String
@@ -66,52 +101,25 @@
    * Creates a new instance of the replication repair control with the
    * provided information.
    *
-   * @param  oid         The OID to use for this control.
    * @param  isCritical  Indicates whether support for this control should be
    *                     considered a critical part of the client processing.
    */
-  public ReplicationRepairRequestControl(String oid, boolean isCritical)
+  public ReplicationRepairRequestControl(boolean isCritical)
   {
-    super(oid, isCritical);
+    super(OID_REPLICATION_REPAIR_CONTROL, isCritical);
 
   }
 
-
-
   /**
-   * Creates a new replication repair request control from the contents of the
-   * provided control.
+   * Writes this control's value to an ASN.1 writer. The value (if any) must be
+   * written as an ASN1OctetString.
    *
-   * @param  control  The generic control containing the information to use to
-   *                  create this replication repair request control.
-   *
-   * @return  The replication repair request control decoded from the provided
-   *          control.
-   *
-   * @throws  LDAPException  If this control cannot be decoded as a valid
-   *                         replication repair request control.
+   * @param writer The ASN.1 writer to use.
+   * @throws IOException If a problem occurs while writing to the stream.
    */
-  public static ReplicationRepairRequestControl decodeControl(Control control)
-         throws LDAPException
-  {
-    return new ReplicationRepairRequestControl(control.getOID(),
-                                           control.isCritical());
-  }
-
-
-
-  /**
-   * Retrieves a string representation of this replication repair request
-   * control.
-   *
-   * @return  A string representation of this replication repair request
-   *          control.
-   */
-  public String toString()
-  {
-    StringBuilder buffer = new StringBuilder();
-    toString(buffer);
-    return buffer.toString();
+  @Override
+  protected void writeValue(ASN1Writer writer) throws IOException {
+    // No value element
   }
 
 
@@ -122,6 +130,7 @@
    *
    * @param  buffer  The buffer to which the information should be appended.
    */
+  @Override
   public void toString(StringBuilder buffer)
   {
     buffer.append("ReplicationRepairRequestControl()");
diff --git a/opends/src/server/org/opends/server/replication/protocol/AddMsg.java b/opends/src/server/org/opends/server/replication/protocol/AddMsg.java
index 9cb3e89..688afd6 100644
--- a/opends/src/server/org/opends/server/replication/protocol/AddMsg.java
+++ b/opends/src/server/org/opends/server/replication/protocol/AddMsg.java
@@ -28,9 +28,6 @@
 
 import org.opends.server.core.AddOperationBasis;
 import org.opends.server.core.DirectoryServer;
-import org.opends.server.protocols.asn1.ASN1Element;
-import org.opends.server.protocols.asn1.ASN1Exception;
-import org.opends.server.protocols.asn1.ASN1OctetString;
 
 import java.io.UnsupportedEncodingException;
 import java.util.ArrayList;
@@ -41,14 +38,12 @@
 
 import org.opends.server.protocols.internal.InternalClientConnection;
 import org.opends.server.protocols.ldap.LDAPAttribute;
+import org.opends.server.protocols.asn1.ASN1Writer;
+import org.opends.server.protocols.asn1.ASN1;
+import org.opends.server.protocols.asn1.ASN1Exception;
+import org.opends.server.protocols.asn1.ASN1Reader;
 import org.opends.server.replication.common.ChangeNumber;
-import org.opends.server.types.Attribute;
-import org.opends.server.types.AttributeBuilder;
-import org.opends.server.types.AttributeType;
-import org.opends.server.types.AttributeValue;
-import org.opends.server.types.LDAPException;
-import org.opends.server.types.ObjectClass;
-import org.opends.server.types.RawAttribute;
+import org.opends.server.types.*;
 import org.opends.server.types.operation.PostOperationAddOperation;
 
 import static org.opends.server.replication.protocol.OperationContext.*;
@@ -70,7 +65,7 @@
   public AddMsg(PostOperationAddOperation op)
   {
     super((AddContext) op.getAttachment(SYNCHROCONTEXT),
-          op.getRawEntryDN().stringValue());
+          op.getRawEntryDN().toString());
 
     AddContext ctx = (AddContext) op.getAttachment(SYNCHROCONTEXT);
     this.parentUniqueId = ctx.getParentUid();
@@ -86,43 +81,51 @@
       Map<AttributeType, List<Attribute>> userAttributes,
       Map<AttributeType, List<Attribute>> operationalAttributes)
   {
-    //  Encode the object classes (SET OF LDAPString).
-    AttributeBuilder builder = new AttributeBuilder(
-        DirectoryServer.getObjectClassAttributeType());
-    builder.setInitialCapacity(objectClasses.size());
-    for (String s : objectClasses.values())
+    ByteStringBuilder byteBuilder = new ByteStringBuilder();
+    ASN1Writer writer = ASN1.getWriter(byteBuilder);
+
+    try
     {
-      builder.add(new AttributeValue(new ASN1OctetString(s),
-                         new ASN1OctetString(toLowerCase(s))));
-    }
-    Attribute attr = builder.toAttribute();
-
-    ArrayList<ASN1Element> elems = new ArrayList<ASN1Element>();
-
-    elems.add(new LDAPAttribute(attr).encode());
-
-    // Encode the user attributes (AttributeList).
-    for (List<Attribute> list : userAttributes.values())
-    {
-      for (Attribute a : list)
+      //  Encode the object classes (SET OF LDAPString).
+      AttributeBuilder builder = new AttributeBuilder(
+          DirectoryServer.getObjectClassAttributeType());
+      builder.setInitialCapacity(objectClasses.size());
+      for (String s : objectClasses.values())
       {
-        if (!a.isVirtual())
-          elems.add(new LDAPAttribute(a).encode());
+        builder.add(AttributeValues.create(ByteString.valueOf(s),
+            ByteString.valueOf(toLowerCase(s))));
+      }
+      Attribute attr = builder.toAttribute();
+
+      new LDAPAttribute(attr).write(writer);
+
+      // Encode the user attributes (AttributeList).
+      for (List<Attribute> list : userAttributes.values())
+      {
+        for (Attribute a : list)
+        {
+          if (!a.isVirtual())
+            new LDAPAttribute(a).write(writer);
+        }
+      }
+
+      // Encode the operational attributes (AttributeList).
+      for (List<Attribute> list : operationalAttributes.values())
+      {
+        for (Attribute a : list)
+        {
+          if (!a.isVirtual())
+            new LDAPAttribute(a).write(writer);
+        }
       }
     }
-
-    // Encode the operational attributes (AttributeList).
-    for (List<Attribute> list : operationalAttributes.values())
+    catch(Exception e)
     {
-      for (Attribute a : list)
-      {
-        if (!a.isVirtual())
-          elems.add(new LDAPAttribute(a).encode());
-      }
+      // TODO: DO something
     }
 
     // Encode the sequence.
-    return ASN1Element.encodeValue(elems);
+    return byteBuilder.toByteArray();
   }
 
   /**
@@ -175,17 +178,26 @@
     super (cn, uniqueId, dn);
     this.parentUniqueId = parentId;
 
-    ArrayList<ASN1Element> elems = new ArrayList<ASN1Element>();
-    elems.add(new LDAPAttribute(objectClass).encode());
+    ByteStringBuilder byteBuilder = new ByteStringBuilder();
+    ASN1Writer writer = ASN1.getWriter(byteBuilder);
 
-    for (Attribute a : userAttributes)
-      elems.add(new LDAPAttribute(a).encode());
+    try
+    {
+      new LDAPAttribute(objectClass).write(writer);
 
-    if (operationalAttributes != null)
-      for (Attribute a : operationalAttributes)
-        elems.add(new LDAPAttribute(a).encode());
+      for (Attribute a : userAttributes)
+        new LDAPAttribute(a).write(writer);
 
-    encodedAttributes = ASN1Element.encodeValue(elems);
+      if (operationalAttributes != null)
+        for (Attribute a : operationalAttributes)
+          new LDAPAttribute(a).write(writer);
+    }
+    catch(Exception e)
+    {
+      // Do something
+    }
+
+    encodedAttributes = byteBuilder.toByteArray();
   }
 
   /**
@@ -233,19 +245,18 @@
          InternalClientConnection connection, String newDn)
          throws LDAPException, ASN1Exception
   {
+    ASN1Reader asn1Reader = ASN1.getReader(encodedAttributes);
     ArrayList<RawAttribute> attr = new ArrayList<RawAttribute>();
-    ArrayList<ASN1Element> elems;
 
-    elems = ASN1Element.decodeElements(encodedAttributes);
-    for (ASN1Element elem : elems)
+    while(asn1Reader.hasNextElement())
     {
-      attr.add(LDAPAttribute.decode(elem));
+      attr.add(LDAPAttribute.decode(asn1Reader));
     }
 
     AddOperationBasis add =  new AddOperationBasis(connection,
                             InternalClientConnection.nextOperationID(),
                             InternalClientConnection.nextMessageID(), null,
-                            new ASN1OctetString(newDn), attr);
+        ByteString.valueOf(newDn), attr);
     AddContext ctx = new AddContext(getChangeNumber(), getUniqueId(),
                                     parentUniqueId);
     add.setAttachment(SYNCHROCONTEXT, ctx);
@@ -335,11 +346,21 @@
   public void addAttribute(String name, String value)
          throws ASN1Exception
   {
-    RawAttribute newAttr = new LDAPAttribute(name, value);
-    ArrayList<ASN1Element> elems;
-    elems = ASN1Element.decodeElements(encodedAttributes);
-    elems.add(newAttr.encode());
-    encodedAttributes = ASN1Element.encodeValue(elems);
+    ByteStringBuilder byteBuilder = new ByteStringBuilder();
+    byteBuilder.append(encodedAttributes);
+
+    ASN1Writer writer = ASN1.getWriter(byteBuilder);
+
+    try
+    {
+      new LDAPAttribute(name, value).write(writer);
+
+      encodedAttributes = byteBuilder.toByteArray();
+    }
+    catch(Exception e)
+    {
+      // DO SOMETHING
+    }
   }
 
   /**
diff --git a/opends/src/server/org/opends/server/replication/protocol/DeleteMsg.java b/opends/src/server/org/opends/server/replication/protocol/DeleteMsg.java
index e365b07..c6c9ab0 100644
--- a/opends/src/server/org/opends/server/replication/protocol/DeleteMsg.java
+++ b/opends/src/server/org/opends/server/replication/protocol/DeleteMsg.java
@@ -32,10 +32,10 @@
 import java.util.zip.DataFormatException;
 
 import org.opends.server.core.DeleteOperationBasis;
-import org.opends.server.protocols.asn1.ASN1OctetString;
 import org.opends.server.protocols.internal.InternalClientConnection;
 import org.opends.server.replication.common.ChangeNumber;
 import org.opends.server.types.AbstractOperation;
+import org.opends.server.types.ByteString;
 import org.opends.server.types.operation.PostOperationDeleteOperation;
 
 /**
@@ -51,7 +51,7 @@
   public DeleteMsg(PostOperationDeleteOperation operation)
   {
     super((OperationContext) operation.getAttachment(SYNCHROCONTEXT),
-           operation.getRawEntryDN().stringValue());
+           operation.getRawEntryDN().toString());
   }
 
   /**
@@ -94,7 +94,7 @@
     DeleteOperationBasis del =  new DeleteOperationBasis(connection,
                                InternalClientConnection.nextOperationID(),
                                InternalClientConnection.nextMessageID(), null,
-                               new ASN1OctetString(newDn));
+        ByteString.valueOf(newDn));
     DeleteContext ctx = new DeleteContext(getChangeNumber(), getUniqueId());
     del.setAttachment(SYNCHROCONTEXT, ctx);
     return del;
diff --git a/opends/src/server/org/opends/server/replication/protocol/ModifyCommonMsg.java b/opends/src/server/org/opends/server/replication/protocol/ModifyCommonMsg.java
index 0339bd7..fddd078 100644
--- a/opends/src/server/org/opends/server/replication/protocol/ModifyCommonMsg.java
+++ b/opends/src/server/org/opends/server/replication/protocol/ModifyCommonMsg.java
@@ -22,13 +22,14 @@
  * CDDL HEADER END
  *
  *
- *      Copyright 2008 Sun Microsystems, Inc.
+ *      Copyright 2009 Sun Microsystems, Inc.
  */
 package org.opends.server.replication.protocol;
 
-import java.util.ArrayList;
 import java.util.List;
-import org.opends.server.protocols.asn1.ASN1Element;
+
+import org.opends.server.protocols.asn1.ASN1;
+import org.opends.server.protocols.asn1.ASN1Writer;
 import org.opends.server.protocols.ldap.LDAPAttribute;
 import org.opends.server.protocols.ldap.LDAPModification;
 import org.opends.server.replication.common.ChangeNumber;
@@ -36,6 +37,7 @@
 import org.opends.server.types.Attribute;
 import org.opends.server.types.AttributeType;
 import org.opends.server.types.AttributeUsage;
+import org.opends.server.types.ByteStringBuilder;
 import org.opends.server.types.Modification;
 
 /**
@@ -106,9 +108,9 @@
     if ((mods == null) || (mods.size() == 0))
       return new byte[0];
 
-    ArrayList<ASN1Element> modsASN1;
+    ByteStringBuilder byteBuilder = new ByteStringBuilder();
+    ASN1Writer writer = ASN1.getWriter(byteBuilder);
 
-    modsASN1 = new ArrayList<ASN1Element>(mods.size());
     for (Modification mod : mods)
     {
       Attribute attr = mod.getAttribute();
@@ -127,11 +129,18 @@
       {
         LDAPModification ldapmod = new LDAPModification(
           mod.getModificationType(), new LDAPAttribute(mod.getAttribute()));
-        modsASN1.add(ldapmod.encode());
+        try
+        {
+          ldapmod.write(writer);
+        }
+        catch(Exception e)
+        {
+          // DO SOMETHING
+        }
       }
     }
 
-    return ASN1Element.encodeValue(modsASN1);
+    return byteBuilder.toByteArray();
   }
 
 }
diff --git a/opends/src/server/org/opends/server/replication/protocol/ModifyDNMsg.java b/opends/src/server/org/opends/server/replication/protocol/ModifyDNMsg.java
index e4f3b72..70b162b 100644
--- a/opends/src/server/org/opends/server/replication/protocol/ModifyDNMsg.java
+++ b/opends/src/server/org/opends/server/replication/protocol/ModifyDNMsg.java
@@ -29,18 +29,18 @@
 import static org.opends.server.replication.protocol.OperationContext.*;
 
 import java.io.UnsupportedEncodingException;
-import java.util.ArrayList;
 import java.util.List;
 import java.util.zip.DataFormatException;
 
 import org.opends.server.core.ModifyDNOperationBasis;
-import org.opends.server.protocols.asn1.ASN1Element;
+import org.opends.server.protocols.asn1.ASN1;
 import org.opends.server.protocols.asn1.ASN1Exception;
-import org.opends.server.protocols.asn1.ASN1OctetString;
+import org.opends.server.protocols.asn1.ASN1Reader;
 import org.opends.server.protocols.internal.InternalClientConnection;
 import org.opends.server.protocols.ldap.LDAPModification;
 import org.opends.server.replication.common.ChangeNumber;
 import org.opends.server.types.AbstractOperation;
+import org.opends.server.types.ByteString;
 import org.opends.server.types.DN;
 import org.opends.server.types.DirectoryException;
 import org.opends.server.types.LDAPException;
@@ -66,7 +66,7 @@
   public ModifyDNMsg(PostOperationModifyDNOperation operation)
   {
     super((OperationContext) operation.getAttachment(SYNCHROCONTEXT),
-        operation.getRawEntryDN().stringValue());
+        operation.getRawEntryDN().toString());
 
     encodedMods = modsToByte(operation.getModifications());
 
@@ -76,10 +76,10 @@
 
     deleteOldRdn = operation.deleteOldRDN();
     if (operation.getRawNewSuperior() != null)
-      newSuperior = operation.getRawNewSuperior().stringValue();
+      newSuperior = operation.getRawNewSuperior().toString();
     else
       newSuperior = null;
-    newRDN = operation.getRawNewRDN().stringValue();
+    newRDN = operation.getRawNewRDN().toString();
   }
 
   /**
@@ -219,16 +219,19 @@
     ModifyDNOperationBasis moddn =  new ModifyDNOperationBasis(connection,
                InternalClientConnection.nextOperationID(),
                InternalClientConnection.nextMessageID(), null,
-               new ASN1OctetString(newDn), new ASN1OctetString(newRDN),
+               ByteString.valueOf(newDn), ByteString.valueOf(newRDN),
                deleteOldRdn,
-               (newSuperior == null ? null : new ASN1OctetString(newSuperior)));
+               (newSuperior == null ? null : ByteString.valueOf(newSuperior)));
 
-    ArrayList<ASN1Element> mods = ASN1Element.decodeElements(encodedMods);
-    for (ASN1Element elem : mods)
-      moddn.addModification(LDAPModification.decode(elem).toModification());
+    ASN1Reader asn1Reader = ASN1.getReader(encodedMods);
+    while (asn1Reader.hasNextElement())
+    {
+      moddn.addModification(LDAPModification.decode(asn1Reader)
+          .toModification());
+    }
 
     ModifyDnContext ctx = new ModifyDnContext(getChangeNumber(), getUniqueId(),
-                                              newSuperiorId);
+        newSuperiorId);
     moddn.setAttachment(SYNCHROCONTEXT, ctx);
     return moddn;
   }
diff --git a/opends/src/server/org/opends/server/replication/protocol/ModifyMsg.java b/opends/src/server/org/opends/server/replication/protocol/ModifyMsg.java
index 8986f15..9b6d81c 100644
--- a/opends/src/server/org/opends/server/replication/protocol/ModifyMsg.java
+++ b/opends/src/server/org/opends/server/replication/protocol/ModifyMsg.java
@@ -29,12 +29,13 @@
 import static org.opends.server.replication.protocol.OperationContext.*;
 
 import org.opends.server.core.ModifyOperationBasis;
-import org.opends.server.protocols.asn1.ASN1Exception;
-import org.opends.server.protocols.asn1.ASN1OctetString;
 import org.opends.server.protocols.ldap.LDAPModification;
-import org.opends.server.protocols.asn1.ASN1Element;
 import org.opends.server.protocols.internal.InternalClientConnection;
+import org.opends.server.protocols.asn1.ASN1Exception;
+import org.opends.server.protocols.asn1.ASN1Reader;
+import org.opends.server.protocols.asn1.ASN1;
 import org.opends.server.replication.common.ChangeNumber;
+import org.opends.server.types.*;
 import org.opends.server.types.AbstractOperation;
 import org.opends.server.types.DN;
 import org.opends.server.types.LDAPException;
@@ -61,7 +62,7 @@
   public ModifyMsg(PostOperationModifyOperation op)
   {
     super((OperationContext) op.getAttachment(OperationContext.SYNCHROCONTEXT),
-          op.getRawEntryDN().stringValue());
+          op.getRawEntryDN().toString());
     encodedMods = modsToByte(op.getModifications());
   }
 
@@ -170,20 +171,18 @@
     if (newDn == null)
       newDn = getDn();
 
-    ArrayList<RawModification> ldapmods;
+    ArrayList<RawModification> ldapmods = new ArrayList<RawModification>();
 
-    ArrayList<ASN1Element> mods = null;
-
-    mods = ASN1Element.decodeElements(encodedMods);
-
-    ldapmods = new ArrayList<RawModification>(mods.size());
-    for (ASN1Element elem : mods)
-      ldapmods.add(LDAPModification.decode(elem));
+    ASN1Reader asn1Reader = ASN1.getReader(encodedMods);
+    while(asn1Reader.hasNextElement())
+    {
+      ldapmods.add(LDAPModification.decode(asn1Reader));
+    }
 
     ModifyOperationBasis mod = new ModifyOperationBasis(connection,
                                InternalClientConnection.nextOperationID(),
                                InternalClientConnection.nextMessageID(), null,
-                               new ASN1OctetString(newDn), ldapmods);
+        ByteString.valueOf(newDn), ldapmods);
     ModifyContext ctx = new ModifyContext(getChangeNumber(), getUniqueId());
     mod.setAttachment(SYNCHROCONTEXT, ctx);
     return mod;
diff --git a/opends/src/server/org/opends/server/replication/protocol/MonitorMsg.java b/opends/src/server/org/opends/server/replication/protocol/MonitorMsg.java
index fa3a16c..1b61c9b 100644
--- a/opends/src/server/org/opends/server/replication/protocol/MonitorMsg.java
+++ b/opends/src/server/org/opends/server/replication/protocol/MonitorMsg.java
@@ -26,7 +26,6 @@
  */
 package org.opends.server.replication.protocol;
 
-import java.io.UnsupportedEncodingException;
 import java.util.zip.DataFormatException;
 import java.util.ArrayList;
 import java.util.HashMap;
@@ -34,10 +33,13 @@
 import java.util.Set;
 
 import org.opends.server.replication.common.ServerState;
-import org.opends.server.protocols.asn1.ASN1OctetString;
-import org.opends.server.protocols.asn1.ASN1Sequence;
-import org.opends.server.protocols.asn1.ASN1Element;
+import org.opends.server.protocols.asn1.ASN1Reader;
+import org.opends.server.protocols.asn1.ASN1;
+import org.opends.server.protocols.asn1.ASN1Writer;
 import org.opends.server.replication.common.ChangeNumber;
+import org.opends.server.types.ByteStringBuilder;
+import org.opends.server.types.ByteString;
+import org.opends.server.types.ByteSequenceReader;
 
 /**
  * This message is part of the replication protocol.
@@ -178,93 +180,75 @@
    */
   public MonitorMsg(byte[] in) throws DataFormatException
   {
+    ByteSequenceReader reader = ByteString.wrap(in).asReader();
+
+    /* first byte is the type */
+    if (reader.get() != MSG_TYPE_REPL_SERVER_MONITOR)
+      throw new DataFormatException("input is not a valid " +
+          this.getClass().getCanonicalName());
+    int pos = 1;
+
+    // sender
+    this.senderID = reader.getShort();
+
+    // destination
+    this.destination = reader.getShort();
+
+    ASN1Reader asn1Reader = ASN1.getReader(reader);
     try
     {
-      /* first byte is the type */
-      if (in[0] != MSG_TYPE_REPL_SERVER_MONITOR)
-        throw new DataFormatException("input is not a valid " +
-            this.getClass().getCanonicalName());
-      int pos = 1;
-
-      // sender
-      int length = getNextLength(in, pos);
-      String senderIDString = new String(in, pos, length, "UTF-8");
-      this.senderID = Short.valueOf(senderIDString);
-      pos += length +1;
-
-      // destination
-      length = getNextLength(in, pos);
-      String destinationString = new String(in, pos, length, "UTF-8");
-      this.destination = Short.valueOf(destinationString);
-      pos += length +1;
-
-       /* Read the states : all the remaining bytes but the terminating 0 */
-      byte[] encodedS = new byte[in.length-pos-1];
-      int i =0;
-      while (pos<in.length-1)
+      asn1Reader.readStartSequence();
+      // loop on the servers
+      while(asn1Reader.hasNextElement())
       {
-        encodedS[i++] = in[pos++];
-      }
+        ServerState newState = new ServerState();
+        short serverId = 0;
+        Long outime = (long)0;
+        boolean isLDAPServer = false;
 
-
-      try
-      {
-        ASN1Sequence s0 = ASN1Sequence.decodeAsSequence(encodedS);
-        // loop on the servers
-        for (ASN1Element el0 : s0.elements())
+        asn1Reader.readStartSequence();
+        // loop on the list of CN of the state
+        while(asn1Reader.hasNextElement())
         {
-          ServerState newState = new ServerState();
-          short serverId = 0;
-          Long outime = (long)0;
-          boolean isLDAPServer = false;
-          ASN1Sequence s1 = el0.decodeAsSequence();
-
-          // loop on the list of CN of the state
-          for (ASN1Element el1 : s1.elements())
+          String s = asn1Reader.readOctetStringAsString();
+          ChangeNumber cn = new ChangeNumber(s);
+          if ((data.replServerDbState != null) && (serverId == 0))
           {
-            ASN1OctetString o = el1.decodeAsOctetString();
-            String s = o.stringValue();
-            ChangeNumber cn = new ChangeNumber(s);
-            if ((data.replServerDbState != null) && (serverId == 0))
-            {
-              // we are on the first CN that is a fake CN to store the serverId
-              // and the older update time
-              serverId = cn.getServerId();
-              outime = cn.getTime();
-              isLDAPServer = (cn.getSeqnum()>0);
-            }
-            else
-            {
-              // we are on a normal CN
-              newState.update(cn);
-            }
-          }
-
-          if (data.replServerDbState == null)
-          {
-            // the first state is the replication state
-            data.replServerDbState = newState;
+            // we are on the first CN that is a fake CN to store the serverId
+            // and the older update time
+            serverId = cn.getServerId();
+            outime = cn.getTime();
+            isLDAPServer = (cn.getSeqnum()>0);
           }
           else
           {
-            // the next states are the server states
-            ServerData sd = new ServerData();
-            sd.state = newState;
-            sd.approxFirstMissingDate = outime;
-            if (isLDAPServer)
-              data.ldapStates.put(serverId, sd);
-            else
-              data.rsStates.put(serverId, sd);
+            // we are on a normal CN
+            newState.update(cn);
           }
         }
-      } catch(Exception e)
-      {
+        asn1Reader.readEndSequence();
 
+        if (data.replServerDbState == null)
+        {
+          // the first state is the replication state
+          data.replServerDbState = newState;
+        }
+        else
+        {
+          // the next states are the server states
+          ServerData sd = new ServerData();
+          sd.state = newState;
+          sd.approxFirstMissingDate = outime;
+          if (isLDAPServer)
+            data.ldapStates.put(serverId, sd);
+          else
+            data.rsStates.put(serverId, sd);
+        }
       }
-    }
-    catch (UnsupportedEncodingException e)
+      asn1Reader.readEndSequence();
+    } catch(Exception e)
     {
-      throw new DataFormatException("UTF-8 is not supported by this jvm.");
+
     }
   }
 
@@ -276,128 +260,30 @@
   {
     try
     {
-      byte[] senderBytes = String.valueOf(senderID).getBytes("UTF-8");
-      byte[] destinationBytes = String.valueOf(destination).getBytes("UTF-8");
-
-      int length = 1 + senderBytes.length +
-                   1 + destinationBytes.length;
-
-      ASN1Sequence stateElementSequence = new ASN1Sequence();
-      ArrayList<ASN1Element> stateElementList = new ArrayList<ASN1Element>();
-
-      /**
-       * First loop computes the length
-       */
-
-      /* Put the serverStates ... */
-      stateElementSequence = new ASN1Sequence();
-      stateElementList = new ArrayList<ASN1Element>();
-
-      /* first put the Replication Server state */
-      ArrayList<ASN1OctetString> cnOctetList =
-        data.replServerDbState.toASN1ArrayList();
-      ArrayList<ASN1Element> cnElementList = new ArrayList<ASN1Element>();
-      for (ASN1OctetString soci : cnOctetList)
-      {
-        cnElementList.add(soci);
-      }
-      ASN1Sequence cnSequence = new ASN1Sequence(cnElementList);
-      stateElementList.add(cnSequence);
-
-      // then the LDAP server data
-      Set<Short> servers = data.ldapStates.keySet();
-      for (Short sid : servers)
-      {
-        // State
-        ServerState statei = data.ldapStates.get(sid).state;
-        // First missing date
-        Long outime =  data.ldapStates.get(sid).approxFirstMissingDate;
-
-        // retrieves the change numbers as an arrayList of ANSN1OctetString
-        cnOctetList = statei.toASN1ArrayList();
-        cnElementList = new ArrayList<ASN1Element>();
-
-        // a fake changenumber helps storing the LDAP server ID
-        // and the olderupdatetime
-        ChangeNumber cn = new ChangeNumber(outime,0,sid);
-        cnElementList.add(new ASN1OctetString(cn.toString()));
-
-        // the changenumbers
-        for (ASN1OctetString soci : cnOctetList)
-        {
-          cnElementList.add(soci);
-        }
-
-        cnSequence = new ASN1Sequence(cnElementList);
-        stateElementList.add(cnSequence);
-      }
-
-      // then the rs server data
-      servers = data.rsStates.keySet();
-      for (Short sid : servers)
-      {
-        // State
-        ServerState statei = data.rsStates.get(sid).state;
-        // First missing date
-        Long outime =  data.rsStates.get(sid).approxFirstMissingDate;
-
-        // retrieves the change numbers as an arrayList of ANSN1OctetString
-        cnOctetList = statei.toASN1ArrayList();
-        cnElementList = new ArrayList<ASN1Element>();
-
-        // a fake changenumber helps storing the LDAP server ID
-        // and the olderupdatetime
-        ChangeNumber cn = new ChangeNumber(outime,0,sid);
-        cnElementList.add(new ASN1OctetString(cn.toString()));
-
-        // the changenumbers
-        for (ASN1OctetString soci : cnOctetList)
-        {
-          cnElementList.add(soci);
-        }
-
-        cnSequence = new ASN1Sequence(cnElementList);
-        stateElementList.add(cnSequence);
-      }
-
-      stateElementSequence.setElements(stateElementList);
-      int seqLen = stateElementSequence.encode().length;
-
-      //
-      length += seqLen;
-      length += 2;
-
-      // Allocate the array sized from the computed length
-      byte[] resultByteArray = new byte[length];
-
-      /**
-       * Second loop really builds the array
-       */
+      ByteStringBuilder byteBuilder = new ByteStringBuilder();
+      ASN1Writer writer = ASN1.getWriter(byteBuilder);
 
       /* put the type of the operation */
-      resultByteArray[0] = MSG_TYPE_REPL_SERVER_MONITOR;
-      int pos = 1;
+      byteBuilder.append(MSG_TYPE_REPL_SERVER_MONITOR);
 
-      pos = addByteArray(senderBytes, resultByteArray, pos);
-      pos = addByteArray(destinationBytes, resultByteArray, pos);
+      byteBuilder.append(senderID);
+      byteBuilder.append(destination);
 
       /* Put the serverStates ... */
-      stateElementSequence = new ASN1Sequence();
-      stateElementList = new ArrayList<ASN1Element>();
+      writer.writeStartSequence();
 
       /* first put the Replication Server state */
-      cnOctetList =
+      writer.writeStartSequence();
+      ArrayList<ByteString> cnOctetList =
         data.replServerDbState.toASN1ArrayList();
-      cnElementList = new ArrayList<ASN1Element>();
-      for (ASN1OctetString soci : cnOctetList)
+      for (ByteString soci : cnOctetList)
       {
-        cnElementList.add(soci);
+        writer.writeOctetString(soci);
       }
-      cnSequence = new ASN1Sequence(cnElementList);
-      stateElementList.add(cnSequence);
+      writer.writeEndSequence();
 
       // then the LDAP server datas
-      servers = data.ldapStates.keySet();
+      Set<Short> servers = data.ldapStates.keySet();
       for (Short sid : servers)
       {
         ServerState statei = data.ldapStates.get(sid).state;
@@ -405,20 +291,19 @@
 
         // retrieves the change numbers as an arrayList of ANSN1OctetString
         cnOctetList = statei.toASN1ArrayList();
-        cnElementList = new ArrayList<ASN1Element>();
 
+        writer.writeStartSequence();
         // a fake changenumber helps storing the LDAP server ID
         ChangeNumber cn = new ChangeNumber(outime,1,sid);
-        cnElementList.add(new ASN1OctetString(cn.toString()));
+        writer.writeOctetString(cn.toString());
 
         // the changenumbers that make the state
-        for (ASN1OctetString soci : cnOctetList)
+        for (ByteString soci : cnOctetList)
         {
-          cnElementList.add(soci);
+          writer.writeOctetString(soci);
         }
 
-        cnSequence = new ASN1Sequence(cnElementList);
-        stateElementList.add(cnSequence);
+        writer.writeEndSequence();
       }
 
       // then the RS server datas
@@ -430,29 +315,26 @@
 
         // retrieves the change numbers as an arrayList of ANSN1OctetString
         cnOctetList = statei.toASN1ArrayList();
-        cnElementList = new ArrayList<ASN1Element>();
 
+        writer.writeStartSequence();
         // a fake changenumber helps storing the LDAP server ID
         ChangeNumber cn = new ChangeNumber(outime,0,sid);
-        cnElementList.add(new ASN1OctetString(cn.toString()));
+        writer.writeOctetString(cn.toString());
 
         // the changenumbers that make the state
-        for (ASN1OctetString soci : cnOctetList)
+        for (ByteString soci : cnOctetList)
         {
-          cnElementList.add(soci);
+          writer.writeOctetString(soci);
         }
 
-        cnSequence = new ASN1Sequence(cnElementList);
-        stateElementList.add(cnSequence);
+        writer.writeEndSequence();
       }
 
+      writer.writeEndSequence();
 
-      stateElementSequence.setElements(stateElementList);
-      pos = addByteArray(stateElementSequence.encode(), resultByteArray, pos);
-
-      return resultByteArray;
+      return byteBuilder.toByteArray();
     }
-    catch (UnsupportedEncodingException e)
+    catch (Exception e)
     {
       return null;
     }
diff --git a/opends/src/server/org/opends/server/replication/server/ReplicationBackend.java b/opends/src/server/org/opends/server/replication/server/ReplicationBackend.java
index 1213d35..b794d6a 100644
--- a/opends/src/server/org/opends/server/replication/server/ReplicationBackend.java
+++ b/opends/src/server/org/opends/server/replication/server/ReplicationBackend.java
@@ -841,7 +841,7 @@
       try
       {
         ChangeNumber startingChangeNumber =
-          new ChangeNumber(filter.getAssertionValue().getStringValue());
+          new ChangeNumber(filter.getAssertionValue().getValue().toString());
          return new ChangeNumber(
               startingChangeNumber.getTime(),
               startingChangeNumber.getSeqnum()-1,
diff --git a/opends/src/server/org/opends/server/replication/service/ReplicationDomain.java b/opends/src/server/org/opends/server/replication/service/ReplicationDomain.java
index b51cbd1..f4a8727 100644
--- a/opends/src/server/org/opends/server/replication/service/ReplicationDomain.java
+++ b/opends/src/server/org/opends/server/replication/service/ReplicationDomain.java
@@ -985,6 +985,7 @@
     /**
      * Run method for this class.
      */
+    @Override
     public void run()
     {
       if (debugEnabled())
@@ -1124,6 +1125,7 @@
     /**
      * {@inheritDoc}
      */
+    @Override
     public String toString()
     {
       return new String("[ Entry count=" + this.entryCount +
diff --git a/opends/src/server/org/opends/server/replication/service/ReplicationMonitor.java b/opends/src/server/org/opends/server/replication/service/ReplicationMonitor.java
index 73f3118..3773ecd 100644
--- a/opends/src/server/org/opends/server/replication/service/ReplicationMonitor.java
+++ b/opends/src/server/org/opends/server/replication/service/ReplicationMonitor.java
@@ -37,7 +37,7 @@
 import org.opends.server.types.Attribute;
 import org.opends.server.types.AttributeBuilder;
 import org.opends.server.types.AttributeType;
-import org.opends.server.types.AttributeValue;
+import org.opends.server.types.AttributeValues;
 import org.opends.server.types.Attributes;
 
 /**
@@ -136,7 +136,7 @@
     AttributeBuilder builder = new AttributeBuilder(type, ATTR_SERVER_STATE);
     for (String str : domain.getServerState().toStringSet())
     {
-      builder.add(new AttributeValue(type,str));
+      builder.add(AttributeValues.create(type,str));
     }
     attributes.add(builder.toAttribute());
 
@@ -205,7 +205,7 @@
       for (Short serverId : srSrvNotAckUps.keySet())
       {
         String str = serverId + ":" + srSrvNotAckUps.get(serverId);
-        builder.add(new AttributeValue(type, str));
+        builder.add(AttributeValues.create(type, str));
       }
       attributes.add(builder.toAttribute());
     }
@@ -238,7 +238,7 @@
       for (Short serverId : sdSrvTimUps.keySet())
       {
         String str = serverId + ":" + sdSrvTimUps.get(serverId);
-        builder.add(new AttributeValue(type, str));
+        builder.add(AttributeValues.create(type, str));
       }
       attributes.add(builder.toAttribute());
     }
@@ -270,7 +270,7 @@
       int value)
   {
     AttributeType type = DirectoryServer.getDefaultAttributeType(name);
-    attributes.add(Attributes.create(type, new AttributeValue(type,
+    attributes.add(Attributes.create(type, AttributeValues.create(type,
         String.valueOf(value))));
   }
 
@@ -288,7 +288,7 @@
       long value)
   {
     AttributeType type = DirectoryServer.getDefaultAttributeType(name);
-    attributes.add(Attributes.create(type, new AttributeValue(type,
+    attributes.add(Attributes.create(type, AttributeValues.create(type,
         String.valueOf(value))));
   }
 
@@ -306,7 +306,8 @@
       String value)
   {
     AttributeType type = DirectoryServer.getDefaultAttributeType(name);
-    attributes.add(Attributes.create(type, new AttributeValue(type, value)));
+    attributes
+        .add(Attributes.create(type, AttributeValues.create(type, value)));
   }
 
   /**
diff --git a/opends/src/server/org/opends/server/schema/AbsoluteSubtreeSpecificationSyntax.java b/opends/src/server/org/opends/server/schema/AbsoluteSubtreeSpecificationSyntax.java
index 0372474..0d47c20 100644
--- a/opends/src/server/org/opends/server/schema/AbsoluteSubtreeSpecificationSyntax.java
+++ b/opends/src/server/org/opends/server/schema/AbsoluteSubtreeSpecificationSyntax.java
@@ -26,7 +26,6 @@
  */
 package org.opends.server.schema;
 
-import org.opends.server.types.DebugLogLevel;
 import static org.opends.server.loggers.ErrorLogger.logError;
 import static org.opends.server.loggers.debug.DebugLogger.*;
 import org.opends.server.loggers.debug.DebugTracer;
@@ -44,10 +43,7 @@
 import org.opends.server.config.ConfigException;
 import org.opends.server.core.AbsoluteSubtreeSpecification;
 import org.opends.server.core.DirectoryServer;
-import org.opends.server.types.AttributeValue;
-import org.opends.server.types.ByteString;
-import org.opends.server.types.DirectoryException;
-
+import org.opends.server.types.*;
 
 
 /**
@@ -83,7 +79,7 @@
      */
     public AbsoluteSubtreeSpecification decode(AttributeValue value)
         throws DirectoryException {
-      return AbsoluteSubtreeSpecification.valueOf(value.getStringValue());
+      return AbsoluteSubtreeSpecification.valueOf(value.getValue().toString());
     }
   };
 
@@ -224,12 +220,12 @@
    * @return <CODE>true</CODE> if the provided value is acceptable for
    *         use with this syntax, or <CODE>false</CODE> if not.
    */
-  public boolean valueIsAcceptable(ByteString value,
+  public boolean valueIsAcceptable(ByteSequence value,
                                    MessageBuilder invalidReason)
   {
     // Use the subtree specification code to make this determination.
     try {
-      AbsoluteSubtreeSpecification.valueOf(value.stringValue());
+      AbsoluteSubtreeSpecification.valueOf(value.toString());
 
       return true;
     } catch (DirectoryException e) {
diff --git a/opends/src/server/org/opends/server/schema/AciSyntax.java b/opends/src/server/org/opends/server/schema/AciSyntax.java
index cd2af43..046fa6f 100644
--- a/opends/src/server/org/opends/server/schema/AciSyntax.java
+++ b/opends/src/server/org/opends/server/schema/AciSyntax.java
@@ -36,11 +36,11 @@
 import org.opends.server.api.SubstringMatchingRule;
 import org.opends.server.config.ConfigException;
 import org.opends.server.core.DirectoryServer;
-import org.opends.server.types.ByteString;
 
 
 import org.opends.server.types.DN;
 import org.opends.server.types.DebugLogLevel;
+import org.opends.server.types.ByteSequence;
 
 import static org.opends.server.loggers.ErrorLogger.*;
 import static org.opends.server.loggers.debug.DebugLogger.*;
@@ -232,7 +232,7 @@
    * @return  <CODE>true</CODE> if the provided value is acceptable for use with
    *          this syntax, or <CODE>false</CODE> if not.
    */
-  public boolean valueIsAcceptable(ByteString value,
+  public boolean valueIsAcceptable(ByteSequence value,
                                    MessageBuilder invalidReason)
   {
     try
diff --git a/opends/src/server/org/opends/server/schema/AttributeTypeSyntax.java b/opends/src/server/org/opends/server/schema/AttributeTypeSyntax.java
index 2798880..39fd573 100644
--- a/opends/src/server/org/opends/server/schema/AttributeTypeSyntax.java
+++ b/opends/src/server/org/opends/server/schema/AttributeTypeSyntax.java
@@ -230,7 +230,7 @@
   /**
    * {@inheritDoc}
    */
-  public boolean valueIsAcceptable(ByteString value,
+  public boolean valueIsAcceptable(ByteSequence value,
                                    MessageBuilder invalidReason)
   {
     // We'll use the decodeAttributeType method to determine if the value is
@@ -277,14 +277,14 @@
    * @throws  DirectoryException  If the provided value cannot be decoded as an
    *                              attribute type definition.
    */
-  public static AttributeType decodeAttributeType(ByteString value,
+  public static AttributeType decodeAttributeType(ByteSequence value,
                                                   Schema schema,
                                                   boolean allowUnknownElements)
          throws DirectoryException
   {
     // Get string representations of the provided value using the provided form
     // and with all lowercase characters.
-    String valueStr = value.stringValue();
+    String valueStr = value.toString();
     String lowerStr = toLowerCase(valueStr);
 
 
@@ -927,7 +927,7 @@
     }
 
 
-    return new AttributeType(value.stringValue(), primaryName, typeNames, oid,
+    return new AttributeType(value.toString(), primaryName, typeNames, oid,
                              description, superiorType, syntax,
                              approximateMatchingRule, equalityMatchingRule,
                              orderingMatchingRule, substringMatchingRule,
diff --git a/opends/src/server/org/opends/server/schema/AuthPasswordEqualityMatchingRule.java b/opends/src/server/org/opends/server/schema/AuthPasswordEqualityMatchingRule.java
index 59030df..c68ce62 100644
--- a/opends/src/server/org/opends/server/schema/AuthPasswordEqualityMatchingRule.java
+++ b/opends/src/server/org/opends/server/schema/AuthPasswordEqualityMatchingRule.java
@@ -28,23 +28,21 @@
 
 
 
-import java.util.Arrays;
+import static org.opends.server.loggers.debug.DebugLogger.*;
+import static org.opends.server.schema.SchemaConstants.*;
 
 import java.util.Collection;
 import java.util.Collections;
+
 import org.opends.server.api.EqualityMatchingRule;
 import org.opends.server.api.PasswordStorageScheme;
 import org.opends.server.core.DirectoryServer;
-import org.opends.server.protocols.asn1.ASN1OctetString;
-import org.opends.server.types.AttributeValue;
+import org.opends.server.loggers.debug.DebugTracer;
+import org.opends.server.types.ByteSequence;
 import org.opends.server.types.ByteString;
 import org.opends.server.types.ConditionResult;
-import org.opends.server.types.DirectoryException;
-
-import static org.opends.server.loggers.debug.DebugLogger.*;
-import org.opends.server.loggers.debug.DebugTracer;
 import org.opends.server.types.DebugLogLevel;
-import static org.opends.server.schema.SchemaConstants.*;
+import org.opends.server.types.DirectoryException;
 
 
 
@@ -76,6 +74,7 @@
   /**
    * {@inheritDoc}
    */
+  @Override
   public Collection<String> getAllNames()
   {
     return Collections.singleton(getName());
@@ -89,6 +88,7 @@
    * @return  The common name for this matching rule, or <CODE>null</CODE> if
    * it does not have a name.
    */
+  @Override
   public String getName()
   {
     return EMR_AUTH_PASSWORD_NAME;
@@ -101,6 +101,7 @@
    *
    * @return  The OID for this matching rule.
    */
+  @Override
   public String getOID()
   {
     return EMR_AUTH_PASSWORD_OID;
@@ -114,6 +115,7 @@
    * @return  The description for this matching rule, or <CODE>null</CODE> if
    *          there is none.
    */
+  @Override
   public String getDescription()
   {
     // There is no standard description for this matching rule.
@@ -128,6 +130,7 @@
    *
    * @return  The OID of the syntax with which this matching rule is associated.
    */
+  @Override
   public String getSyntaxOID()
   {
     return SYNTAX_AUTH_PASSWORD_OID;
@@ -146,35 +149,12 @@
    * @throws  DirectoryException  If the provided value is invalid according to
    *                              the associated attribute syntax.
    */
-  public ByteString normalizeValue(ByteString value)
+  @Override
+  public ByteString normalizeValue(ByteSequence value)
          throws DirectoryException
   {
-    // We will not alter the value in any way, but we'll create a new value
-    // just in case something else is using the underlying array.
-    byte[] currentValue = value.value();
-    byte[] newValue     = new byte[currentValue.length];
-    System.arraycopy(currentValue, 0, newValue, 0, currentValue.length);
-
-    return new ASN1OctetString(newValue);
-  }
-
-
-
-  /**
-   * Indicates whether the two provided normalized values are equal to each
-   * other.
-   *
-   * @param  value1  The normalized form of the first value to compare.
-   * @param  value2  The normalized form of the second value to compare.
-   *
-   * @return  <CODE>true</CODE> if the provided values are equal, or
-   *          <CODE>false</CODE> if not.
-   */
-  public boolean areEqual(ByteString value1, ByteString value2)
-  {
-    // Since the values are already normalized, we just need to compare the
-    // associated byte arrays.
-    return Arrays.equals(value1.value(), value2.value());
+    // We will not alter the value in any way.
+    return value.toByteString();
   }
 
 
@@ -194,8 +174,9 @@
    *          match for the provided assertion value, or <CODE>false</CODE> if
    *          not.
    */
-  public ConditionResult valuesMatch(ByteString attributeValue,
-                                     ByteString assertionValue)
+  @Override
+  public ConditionResult valuesMatch(ByteSequence attributeValue,
+                                     ByteSequence assertionValue)
   {
     // We must be able to decode the attribute value using the authentication
     // password syntax.
@@ -203,7 +184,7 @@
     try
     {
       authPWComponents =
-           AuthPasswordSyntax.decodeAuthPassword(attributeValue.stringValue());
+           AuthPasswordSyntax.decodeAuthPassword(attributeValue.toString());
     }
     catch (Exception e)
     {
@@ -257,7 +238,8 @@
    *
    * @return  The hash code generated for the provided attribute value.
    */
-  public int generateHashCode(AttributeValue attributeValue)
+  @Override
+  public int generateHashCode(ByteSequence attributeValue)
   {
     // Because of the variable encoding that may be used, we have no way of
     // comparing two auth password values by hash code and therefore we'll
diff --git a/opends/src/server/org/opends/server/schema/AuthPasswordExactEqualityMatchingRule.java b/opends/src/server/org/opends/server/schema/AuthPasswordExactEqualityMatchingRule.java
index 26333f8..de78205 100644
--- a/opends/src/server/org/opends/server/schema/AuthPasswordExactEqualityMatchingRule.java
+++ b/opends/src/server/org/opends/server/schema/AuthPasswordExactEqualityMatchingRule.java
@@ -28,24 +28,21 @@
 
 
 
-import java.util.Arrays;
-
-import java.util.Collections;
-import java.util.Collection;
-import org.opends.server.api.EqualityMatchingRule;
-import org.opends.server.core.DirectoryServer;
-import org.opends.server.protocols.asn1.ASN1OctetString;
-import org.opends.server.types.ByteString;
-import org.opends.server.types.DirectoryException;
-
-
-
-import org.opends.server.types.DebugLogLevel;
 import static org.opends.server.loggers.ErrorLogger.*;
 import static org.opends.server.loggers.debug.DebugLogger.*;
-import org.opends.server.loggers.debug.DebugTracer;
 import static org.opends.server.schema.SchemaConstants.*;
 
+import java.util.Collection;
+import java.util.Collections;
+
+import org.opends.server.api.EqualityMatchingRule;
+import org.opends.server.core.DirectoryServer;
+import org.opends.server.loggers.debug.DebugTracer;
+import org.opends.server.types.ByteSequence;
+import org.opends.server.types.ByteString;
+import org.opends.server.types.DebugLogLevel;
+import org.opends.server.types.DirectoryException;
+
 
 
 /**
@@ -76,6 +73,7 @@
   /**
    * {@inheritDoc}
    */
+  @Override
   public Collection<String> getAllNames()
   {
     return Collections.singleton(getName());
@@ -89,6 +87,7 @@
    * @return  The common name for this matching rule, or <CODE>null</CODE> if
    * it does not have a name.
    */
+  @Override
   public String getName()
   {
     return EMR_AUTH_PASSWORD_EXACT_NAME;
@@ -101,6 +100,7 @@
    *
    * @return  The OID for this matching rule.
    */
+  @Override
   public String getOID()
   {
     return EMR_AUTH_PASSWORD_EXACT_OID;
@@ -114,6 +114,7 @@
    * @return  The description for this matching rule, or <CODE>null</CODE> if
    *          there is none.
    */
+  @Override
   public String getDescription()
   {
     // There is no standard description for this matching rule.
@@ -128,6 +129,7 @@
    *
    * @return  The OID of the syntax with which this matching rule is associated.
    */
+  @Override
   public String getSyntaxOID()
   {
     return SYNTAX_AUTH_PASSWORD_OID;
@@ -146,13 +148,14 @@
    * @throws  DirectoryException  If the provided value is invalid according to
    *                              the associated attribute syntax.
    */
-  public ByteString normalizeValue(ByteString value)
+  @Override
+  public ByteString normalizeValue(ByteSequence value)
          throws DirectoryException
   {
     try
     {
       StringBuilder[] authPWComponents =
-           AuthPasswordSyntax.decodeAuthPassword(value.stringValue());
+           AuthPasswordSyntax.decodeAuthPassword(value.toString());
 
       StringBuilder normalizedValue =
            new StringBuilder(2 + authPWComponents[0].length() +
@@ -164,7 +167,7 @@
       normalizedValue.append('$');
       normalizedValue.append(authPWComponents[2]);
 
-      return new ASN1OctetString(normalizedValue.toString());
+      return ByteString.valueOf(normalizedValue.toString());
     }
     catch (DirectoryException de)
     {
@@ -179,30 +182,11 @@
           throw de;
         case WARN:
           logError(de.getMessageObject());
-          return new ASN1OctetString(value.stringValue());
+          return ByteString.valueOf(value.toString());
         default:
-          return new ASN1OctetString(value.stringValue());
+          return ByteString.valueOf(value.toString());
       }
     }
   }
-
-
-
-  /**
-   * Indicates whether the two provided normalized values are equal to each
-   * other.
-   *
-   * @param  value1  The normalized form of the first value to compare.
-   * @param  value2  The normalized form of the second value to compare.
-   *
-   * @return  <CODE>true</CODE> if the provided values are equal, or
-   *          <CODE>false</CODE> if not.
-   */
-  public boolean areEqual(ByteString value1, ByteString value2)
-  {
-    // Since the values are already normalized, we just need to compare the
-    // associated byte arrays.
-    return Arrays.equals(value1.value(), value2.value());
-  }
 }
 
diff --git a/opends/src/server/org/opends/server/schema/AuthPasswordSyntax.java b/opends/src/server/org/opends/server/schema/AuthPasswordSyntax.java
index 626b01d..7ad2110 100644
--- a/opends/src/server/org/opends/server/schema/AuthPasswordSyntax.java
+++ b/opends/src/server/org/opends/server/schema/AuthPasswordSyntax.java
@@ -37,11 +37,11 @@
 import org.opends.server.api.SubstringMatchingRule;
 import org.opends.server.config.ConfigException;
 import org.opends.server.core.DirectoryServer;
-import org.opends.server.types.ByteString;
 import org.opends.server.types.DirectoryException;
 
 
 import org.opends.server.types.ResultCode;
+import org.opends.server.types.ByteSequence;
 
 import static org.opends.server.loggers.ErrorLogger.*;
 import static org.opends.messages.SchemaMessages.*;
@@ -78,6 +78,7 @@
   /**
    * {@inheritDoc}
    */
+  @Override
   public void initializeSyntax(AttributeSyntaxCfg configuration)
          throws ConfigException
   {
@@ -97,6 +98,7 @@
    *
    * @return  The common name for this attribute syntax.
    */
+  @Override
   public String getSyntaxName()
   {
     return SYNTAX_AUTH_PASSWORD_NAME;
@@ -109,6 +111,7 @@
    *
    * @return  The OID for this attribute syntax.
    */
+  @Override
   public String getOID()
   {
     return SYNTAX_AUTH_PASSWORD_OID;
@@ -121,6 +124,7 @@
    *
    * @return  A description for this attribute syntax.
    */
+  @Override
   public String getDescription()
   {
     return SYNTAX_AUTH_PASSWORD_DESCRIPTION;
@@ -136,6 +140,7 @@
    *          attributes with this syntax, or <CODE>null</CODE> if equality
    *          matches will not be allowed for this type by default.
    */
+  @Override
   public EqualityMatchingRule getEqualityMatchingRule()
   {
     return defaultEqualityMatchingRule;
@@ -151,6 +156,7 @@
    *          attributes with this syntax, or <CODE>null</CODE> if ordering
    *          matches will not be allowed for this type by default.
    */
+  @Override
   public OrderingMatchingRule getOrderingMatchingRule()
   {
     // There is no ordering matching rule by default.
@@ -167,6 +173,7 @@
    *          attributes with this syntax, or <CODE>null</CODE> if substring
    *          matches will not be allowed for this type by default.
    */
+  @Override
   public SubstringMatchingRule getSubstringMatchingRule()
   {
     // There is no substring matching rule by default.
@@ -183,6 +190,7 @@
    *          attributes with this syntax, or <CODE>null</CODE> if approximate
    *          matches will not be allowed for this type by default.
    */
+  @Override
   public ApproximateMatchingRule getApproximateMatchingRule()
   {
     // There is no approximate matching rule by default.
@@ -203,12 +211,13 @@
    * @return  <CODE>true</CODE> if the provided value is acceptable for use with
    *          this syntax, or <CODE>false</CODE> if not.
    */
-  public boolean valueIsAcceptable(ByteString value,
+  @Override
+  public boolean valueIsAcceptable(ByteSequence value,
                                    MessageBuilder invalidReason)
   {
     try
     {
-      decodeAuthPassword(value.stringValue());
+      decodeAuthPassword(value.toString());
       return true;
     }
     catch (DirectoryException de)
@@ -408,7 +417,6 @@
 
     // The final component must be the authValue element, containing only
     // printable characters other than the dollar sign and space character.
-readAuthValue:
     while (pos < length)
     {
       char c = authPasswordValue.charAt(pos);
@@ -477,7 +485,7 @@
    * @return  <CODE>true</CODE> if the value appears to be encoded using the
    *          auth password syntax, or <CODE>false</CODE> if not.
    */
-  public static boolean isEncoded(ByteString value)
+  public static boolean isEncoded(ByteSequence value)
   {
     // FIXME -- Make this more efficient, and don't use exceptions for flow
     // control.
@@ -485,7 +493,7 @@
 
     try
     {
-      decodeAuthPassword(value.stringValue());
+      decodeAuthPassword(value.toString());
       return true;
     }
     catch (Exception e)
@@ -499,6 +507,7 @@
   /**
    * {@inheritDoc}
    */
+  @Override
   public boolean isBinary()
   {
     return false;
diff --git a/opends/src/server/org/opends/server/schema/BinarySyntax.java b/opends/src/server/org/opends/server/schema/BinarySyntax.java
index c608c86..34a28c0 100644
--- a/opends/src/server/org/opends/server/schema/BinarySyntax.java
+++ b/opends/src/server/org/opends/server/schema/BinarySyntax.java
@@ -32,9 +32,7 @@
 import org.opends.server.api.*;
 import org.opends.server.config.ConfigException;
 import org.opends.server.core.DirectoryServer;
-import org.opends.server.types.ByteString;
-import org.opends.server.types.AttributeValue;
-import org.opends.server.types.DirectoryException;
+import org.opends.server.types.*;
 
 import static org.opends.server.loggers.ErrorLogger.*;
 import static org.opends.messages.SchemaMessages.*;
@@ -65,16 +63,16 @@
   /**
    * A {@code byte[]} attribute value decoder for this syntax.
    */
-  public static final AttributeValueDecoder<byte[]> DECODER =
-    new AttributeValueDecoder<byte[]>()
+  public static final AttributeValueDecoder<ByteString> DECODER =
+    new AttributeValueDecoder<ByteString>()
   {
     /**
      * {@inheritDoc}
      */
-    public byte[] decode(AttributeValue value) throws DirectoryException {
+    public ByteString decode(AttributeValue value) throws DirectoryException {
       // Make sure that the value is valid.
       value.getNormalizedValue();
-      return value.getValueBytes();
+      return value.getValue();
     }
   };
 
@@ -235,7 +233,7 @@
    * @return  <CODE>true</CODE> if the provided value is acceptable for use with
    *          this syntax, or <CODE>false</CODE> if not.
    */
-  public boolean valueIsAcceptable(ByteString value,
+  public boolean valueIsAcceptable(ByteSequence value,
                                    MessageBuilder invalidReason)
   {
     // All values will be acceptable for the binary syntax.
diff --git a/opends/src/server/org/opends/server/schema/BitStringEqualityMatchingRule.java b/opends/src/server/org/opends/server/schema/BitStringEqualityMatchingRule.java
index fb200ec..d35129b 100644
--- a/opends/src/server/org/opends/server/schema/BitStringEqualityMatchingRule.java
+++ b/opends/src/server/org/opends/server/schema/BitStringEqualityMatchingRule.java
@@ -28,23 +28,21 @@
 
 
 
-import java.util.Arrays;
+import static org.opends.messages.SchemaMessages.*;
+import static org.opends.server.loggers.ErrorLogger.*;
+import static org.opends.server.schema.SchemaConstants.*;
 
-import java.util.Collections;
 import java.util.Collection;
+import java.util.Collections;
+
+import org.opends.messages.Message;
 import org.opends.server.api.EqualityMatchingRule;
 import org.opends.server.core.DirectoryServer;
-
-import org.opends.server.protocols.asn1.ASN1OctetString;
+import org.opends.server.types.ByteSequence;
 import org.opends.server.types.ByteString;
 import org.opends.server.types.DirectoryException;
 import org.opends.server.types.ResultCode;
 
-import static org.opends.server.loggers.ErrorLogger.*;
-import static org.opends.messages.SchemaMessages.*;
-import org.opends.messages.Message;
-import static org.opends.server.schema.SchemaConstants.*;
-
 
 /**
  * This class defines the bitStringMatch matching rule defined in X.520 and
@@ -66,6 +64,7 @@
   /**
    * {@inheritDoc}
    */
+  @Override
   public Collection<String> getAllNames()
   {
     return Collections.singleton(getName());
@@ -79,6 +78,7 @@
    * @return  The common name for this matching rule, or <CODE>null</CODE> if
    * it does not have a name.
    */
+  @Override
   public String getName()
   {
     return EMR_BIT_STRING_NAME;
@@ -91,6 +91,7 @@
    *
    * @return  The OID for this matching rule.
    */
+  @Override
   public String getOID()
   {
     return EMR_BIT_STRING_OID;
@@ -104,6 +105,7 @@
    * @return  The description for this matching rule, or <CODE>null</CODE> if
    *          there is none.
    */
+  @Override
   public String getDescription()
   {
     // There is no standard description for this matching rule.
@@ -118,6 +120,7 @@
    *
    * @return  The OID of the syntax with which this matching rule is associated.
    */
+  @Override
   public String getSyntaxOID()
   {
     return SYNTAX_BIT_STRING_OID;
@@ -136,17 +139,18 @@
    * @throws  DirectoryException  If the provided value is invalid according to
    *                              the associated attribute syntax.
    */
-  public ByteString normalizeValue(ByteString value)
+  @Override
+  public ByteString normalizeValue(ByteSequence value)
          throws DirectoryException
   {
-    String valueString = value.stringValue().toUpperCase();
+    String valueString = value.toString().toUpperCase();
 
     int length = valueString.length();
     if (length < 3)
     {
 
       Message message = WARN_ATTR_SYNTAX_BIT_STRING_TOO_SHORT.get(
-              value.stringValue());
+              value.toString());
       switch (DirectoryServer.getSyntaxEnforcementPolicy())
       {
         case REJECT:
@@ -154,9 +158,9 @@
                                        message);
         case WARN:
           logError(message);
-          return new ASN1OctetString(valueString);
+          return ByteString.valueOf(valueString);
         default:
-          return new ASN1OctetString(valueString);
+          return ByteString.valueOf(valueString);
       }
     }
 
@@ -167,7 +171,7 @@
     {
 
       Message message = WARN_ATTR_SYNTAX_BIT_STRING_NOT_QUOTED.get(
-              value.stringValue());
+              value.toString());
 
       switch (DirectoryServer.getSyntaxEnforcementPolicy())
       {
@@ -177,9 +181,9 @@
         case WARN:
           logError(
                   message);
-          return new ASN1OctetString(valueString);
+          return ByteString.valueOf(valueString);
         default:
-          return new ASN1OctetString(valueString);
+          return ByteString.valueOf(valueString);
       }
     }
 
@@ -195,7 +199,7 @@
         default:
 
           Message message = WARN_ATTR_SYNTAX_BIT_STRING_INVALID_BIT.get(
-                  value.stringValue(), String.valueOf(valueString.charAt(i)));
+                  value.toString(), String.valueOf(valueString.charAt(i)));
 
         switch (DirectoryServer.getSyntaxEnforcementPolicy())
         {
@@ -204,33 +208,14 @@
                                          message);
           case WARN:
             logError(message);
-            return new ASN1OctetString(valueString);
+            return ByteString.valueOf(valueString);
           default:
-            return new ASN1OctetString(valueString);
+            return ByteString.valueOf(valueString);
         }
       }
     }
 
-    return new ASN1OctetString(valueString);
-  }
-
-
-
-  /**
-   * Indicates whether the two provided normalized values are equal to each
-   * other.
-   *
-   * @param  value1  The normalized form of the first value to compare.
-   * @param  value2  The normalized form of the second value to compare.
-   *
-   * @return  <CODE>true</CODE> if the provided values are equal, or
-   *          <CODE>false</CODE> if not.
-   */
-  public boolean areEqual(ByteString value1, ByteString value2)
-  {
-    // Since the values are already normalized, we just need to compare the
-    // associated byte arrays.
-    return Arrays.equals(value1.value(), value2.value());
+    return ByteString.valueOf(valueString);
   }
 }
 
diff --git a/opends/src/server/org/opends/server/schema/BitStringSyntax.java b/opends/src/server/org/opends/server/schema/BitStringSyntax.java
index 95e47d3..5174973 100644
--- a/opends/src/server/org/opends/server/schema/BitStringSyntax.java
+++ b/opends/src/server/org/opends/server/schema/BitStringSyntax.java
@@ -36,8 +36,7 @@
 import org.opends.server.api.SubstringMatchingRule;
 import org.opends.server.config.ConfigException;
 import org.opends.server.core.DirectoryServer;
-import org.opends.server.types.ByteString;
-
+import org.opends.server.types.ByteSequence;
 
 
 import static org.opends.server.loggers.ErrorLogger.*;
@@ -200,16 +199,16 @@
    * @return  <CODE>true</CODE> if the provided value is acceptable for use with
    *          this syntax, or <CODE>false</CODE> if not.
    */
-  public boolean valueIsAcceptable(ByteString value,
+  public boolean valueIsAcceptable(ByteSequence value,
                                    MessageBuilder invalidReason)
   {
-    String valueString = value.stringValue().toUpperCase();
+    String valueString = value.toString().toUpperCase();
 
     int length = valueString.length();
     if (length < 3)
     {
       invalidReason.append(
-              WARN_ATTR_SYNTAX_BIT_STRING_TOO_SHORT.get(value.stringValue()));
+              WARN_ATTR_SYNTAX_BIT_STRING_TOO_SHORT.get(value.toString()));
       return false;
     }
 
@@ -219,7 +218,7 @@
         (valueString.charAt(length-1) != 'B'))
     {
       invalidReason.append(
-              WARN_ATTR_SYNTAX_BIT_STRING_NOT_QUOTED.get(value.stringValue()));
+              WARN_ATTR_SYNTAX_BIT_STRING_NOT_QUOTED.get(value.toString()));
       return false;
     }
 
@@ -234,7 +233,7 @@
           break;
         default:
           invalidReason.append(WARN_ATTR_SYNTAX_BIT_STRING_INVALID_BIT.get(
-                  value.stringValue(), String.valueOf(valueString.charAt(i))));
+                  value.toString(), String.valueOf(valueString.charAt(i))));
           return false;
       }
     }
diff --git a/opends/src/server/org/opends/server/schema/BooleanEqualityMatchingRule.java b/opends/src/server/org/opends/server/schema/BooleanEqualityMatchingRule.java
index 560e9ad..54fd3ee 100644
--- a/opends/src/server/org/opends/server/schema/BooleanEqualityMatchingRule.java
+++ b/opends/src/server/org/opends/server/schema/BooleanEqualityMatchingRule.java
@@ -25,24 +25,24 @@
  *      Copyright 2006-2008 Sun Microsystems, Inc.
  */
 package org.opends.server.schema;
-import org.opends.messages.Message;
 
 
 
-import java.util.Arrays;
-
-import java.util.Collection;
-import java.util.Collections;
-import org.opends.server.api.EqualityMatchingRule;
-import org.opends.server.core.DirectoryServer;
-import org.opends.server.protocols.asn1.ASN1OctetString;
-import org.opends.server.types.ByteString;
-import org.opends.server.types.DirectoryException;
-import org.opends.server.types.ResultCode;
-
 import static org.opends.messages.SchemaMessages.*;
 import static org.opends.server.schema.SchemaConstants.*;
+
+import java.util.Collection;
+import java.util.Collections;
+
+import org.opends.messages.Message;
+import org.opends.server.api.EqualityMatchingRule;
+import org.opends.server.core.DirectoryServer;
 import org.opends.server.loggers.ErrorLogger;
+import org.opends.server.types.ByteSequence;
+import org.opends.server.types.ByteString;
+import org.opends.server.types.DirectoryException;
+import org.opends.server.types.ResultCode;
+import org.opends.server.util.ServerConstants;
 
 
 /**
@@ -65,6 +65,7 @@
   /**
    * {@inheritDoc}
    */
+  @Override
   public Collection<String> getAllNames()
   {
     return Collections.singleton(getName());
@@ -78,6 +79,7 @@
    * @return  The common name for this matching rule, or <CODE>null</CODE> if
    * it does not have a name.
    */
+  @Override
   public String getName()
   {
     return EMR_BOOLEAN_NAME;
@@ -90,6 +92,7 @@
    *
    * @return  The OID for this matching rule.
    */
+  @Override
   public String getOID()
   {
     return EMR_BOOLEAN_OID;
@@ -103,6 +106,7 @@
    * @return  The description for this matching rule, or <CODE>null</CODE> if
    *          there is none.
    */
+  @Override
   public String getDescription()
   {
     // There is no standard description for this matching rule.
@@ -117,6 +121,7 @@
    *
    * @return  The OID of the syntax with which this matching rule is associated.
    */
+  @Override
   public String getSyntaxOID()
   {
     return SYNTAX_BOOLEAN_OID;
@@ -135,24 +140,25 @@
    * @throws  DirectoryException  If the provided value is invalid according to
    *                              the associated attribute syntax.
    */
-  public ByteString normalizeValue(ByteString value)
+  @Override
+  public ByteString normalizeValue(ByteSequence value)
          throws DirectoryException
   {
-    String valueString = value.stringValue().toUpperCase();
+    String valueString = value.toString().toUpperCase();
     if (valueString.equals("TRUE") || valueString.equals("YES") ||
         valueString.equals("ON") || valueString.equals("1"))
     {
-      return new ASN1OctetString("TRUE");
+      return ServerConstants.TRUE_VALUE;
     }
     else if (valueString.equals("FALSE") || valueString.equals("NO") ||
              valueString.equals("OFF") || valueString.equals("0"))
     {
-      return new ASN1OctetString("FALSE");
+      return ServerConstants.FALSE_VALUE;
     }
     else
     {
       Message message = WARN_ATTR_SYNTAX_ILLEGAL_BOOLEAN.get(
-              value.stringValue());
+              value.toString());
 
       switch (DirectoryServer.getSyntaxEnforcementPolicy())
       {
@@ -161,30 +167,11 @@
                                        message);
         case WARN:
           ErrorLogger.logError(message);
-          return new ASN1OctetString(valueString);
+          return ByteString.valueOf(valueString);
         default:
-          return new ASN1OctetString(valueString);
+          return ByteString.valueOf(valueString);
       }
     }
   }
-
-
-
-  /**
-   * Indicates whether the two provided normalized values are equal to each
-   * other.
-   *
-   * @param  value1  The normalized form of the first value to compare.
-   * @param  value2  The normalized form of the second value to compare.
-   *
-   * @return  <CODE>true</CODE> if the provided values are equal, or
-   *          <CODE>false</CODE> if not.
-   */
-  public boolean areEqual(ByteString value1, ByteString value2)
-  {
-    // Since the values are already normalized, we just need to compare the
-    // associated byte arrays.
-    return Arrays.equals(value1.value(), value2.value());
-  }
 }
 
diff --git a/opends/src/server/org/opends/server/schema/BooleanSyntax.java b/opends/src/server/org/opends/server/schema/BooleanSyntax.java
index 2130923..b474f7f 100644
--- a/opends/src/server/org/opends/server/schema/BooleanSyntax.java
+++ b/opends/src/server/org/opends/server/schema/BooleanSyntax.java
@@ -38,18 +38,15 @@
 import org.opends.server.api.SubstringMatchingRule;
 import org.opends.server.config.ConfigException;
 import org.opends.server.core.DirectoryServer;
-import org.opends.server.protocols.asn1.ASN1OctetString;
-import org.opends.server.types.AttributeValue;
-import org.opends.server.types.ByteString;
-import org.opends.server.types.DirectoryException;
 
 
-import org.opends.server.types.ResultCode;
+import org.opends.server.types.*;
 
 import static org.opends.server.loggers.ErrorLogger.*;
 import static org.opends.messages.SchemaMessages.*;
 import org.opends.messages.MessageBuilder;
 import static org.opends.server.schema.SchemaConstants.*;
+import org.opends.server.util.ServerConstants;
 
 
 /**
@@ -78,8 +75,22 @@
      */
     public Boolean decode(AttributeValue value) throws DirectoryException
     {
-      ByteString octetString = value.getNormalizedValue();
-      return decodeBooleanValue(octetString);
+      ByteString normalizedValue = value.getNormalizedValue();
+      if (normalizedValue.equals(ServerConstants.TRUE_VALUE))
+      {
+        return true;
+      }
+      else if (normalizedValue.equals(ServerConstants.FALSE_VALUE))
+      {
+        return false;
+      }
+      else
+      {
+        Message message =
+            WARN_ATTR_SYNTAX_ILLEGAL_BOOLEAN.get(normalizedValue.toString());
+        throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX,
+            message);
+      }
     }
   };
 
@@ -226,10 +237,10 @@
    * @return  <CODE>true</CODE> if the provided value is acceptable for use with
    *          this syntax, or <CODE>false</CODE> if not.
    */
-  public boolean valueIsAcceptable(ByteString value,
+  public boolean valueIsAcceptable(ByteSequence value,
                                    MessageBuilder invalidReason)
   {
-    String valueString = value.stringValue().toUpperCase();
+    String valueString = value.toString().toUpperCase();
 
     boolean returnValue = (valueString.equals("TRUE") ||
                            valueString.equals("YES") ||
@@ -243,7 +254,7 @@
     if (! returnValue)
     {
       invalidReason.append(WARN_ATTR_SYNTAX_ILLEGAL_BOOLEAN.get(
-              value.stringValue()));
+              value.toString()));
     }
 
     return returnValue;
@@ -263,45 +274,13 @@
   {
     if (b)
     {
-      return new AttributeValue(new ASN1OctetString("TRUE"),
-                                new ASN1OctetString("TRUE"));
+      return AttributeValues.create(ServerConstants.TRUE_VALUE,
+                                ServerConstants.TRUE_VALUE);
     }
     else
     {
-      return new AttributeValue(new ASN1OctetString("FALSE"),
-                                new ASN1OctetString("FALSE"));
-    }
-  }
-
-
-
-  /**
-   * Decodes the provided normalized value as a boolean.
-   *
-   * @param  normalizedValue  The normalized value to decode as a boolean.
-   *
-   * @return  The decoded boolean value.
-   *
-   * @throws  DirectoryException  If the provided value cannot be decoded as a
-   *                              boolean.
-   */
-  public static boolean decodeBooleanValue(ByteString normalizedValue)
-         throws DirectoryException
-  {
-    String valueString = normalizedValue.stringValue();
-    if (valueString.equals("TRUE"))
-    {
-      return true;
-    }
-    else if (valueString.equals("FALSE"))
-    {
-      return false;
-    }
-    else
-    {
-      Message message = WARN_ATTR_SYNTAX_ILLEGAL_BOOLEAN.get(valueString);
-      throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX,
-                                   message);
+      return AttributeValues.create(ServerConstants.FALSE_VALUE,
+                                ServerConstants.FALSE_VALUE);
     }
   }
 
diff --git a/opends/src/server/org/opends/server/schema/CaseExactEqualityMatchingRule.java b/opends/src/server/org/opends/server/schema/CaseExactEqualityMatchingRule.java
index fcdffa9..12b0362 100644
--- a/opends/src/server/org/opends/server/schema/CaseExactEqualityMatchingRule.java
+++ b/opends/src/server/org/opends/server/schema/CaseExactEqualityMatchingRule.java
@@ -28,17 +28,16 @@
 
 
 
-import java.util.Arrays;
-
-import java.util.Collections;
-import java.util.Collection;
-import org.opends.server.api.EqualityMatchingRule;
-import org.opends.server.protocols.asn1.ASN1OctetString;
-import org.opends.server.types.ByteString;
-import org.opends.server.types.DirectoryException;
-
 import static org.opends.server.schema.SchemaConstants.*;
 
+import java.util.Collection;
+import java.util.Collections;
+
+import org.opends.server.api.EqualityMatchingRule;
+import org.opends.server.types.ByteSequence;
+import org.opends.server.types.ByteString;
+import org.opends.server.types.DirectoryException;
+import org.opends.server.util.ServerConstants;
 
 
 /**
@@ -61,6 +60,7 @@
   /**
    * {@inheritDoc}
    */
+  @Override
   public String getName()
   {
     return EMR_CASE_EXACT_NAME;
@@ -71,6 +71,7 @@
   /**
    * {@inheritDoc}
    */
+  @Override
   public Collection<String> getAllNames()
   {
     return Collections.singleton(getName());
@@ -83,6 +84,7 @@
    *
    * @return  The OID for this matching rule.
    */
+  @Override
   public String getOID()
   {
     return EMR_CASE_EXACT_OID;
@@ -96,6 +98,7 @@
    * @return  The description for this matching rule, or <CODE>null</CODE> if
    *          there is none.
    */
+  @Override
   public String getDescription()
   {
     // There is no standard description for this matching rule.
@@ -110,6 +113,7 @@
    *
    * @return  The OID of the syntax with which this matching rule is associated.
    */
+  @Override
   public String getSyntaxOID()
   {
     return SYNTAX_DIRECTORY_STRING_OID;
@@ -128,25 +132,26 @@
    * @throws  DirectoryException  If the provided value is invalid according to
    *                              the associated attribute syntax.
    */
-  public ByteString normalizeValue(ByteString value)
+  @Override
+  public ByteString normalizeValue(ByteSequence value)
          throws DirectoryException
   {
     StringBuilder buffer = new StringBuilder();
-    buffer.append(value.stringValue().trim());
+    buffer.append(value.toString().trim());
 
     int bufferLength = buffer.length();
     if (bufferLength == 0)
     {
-      if (value.value().length > 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 ASN1OctetString(" ");
+        return ServerConstants.SINGLE_SPACE_VALUE;
       }
       else
       {
         // The value is empty, so it is already normalized.
-        return new ASN1OctetString();
+        return ByteString.empty();
       }
     }
 
@@ -163,26 +168,7 @@
       }
     }
 
-    return new ASN1OctetString(buffer.toString());
-  }
-
-
-
-  /**
-   * Indicates whether the two provided normalized values are equal to each
-   * other.
-   *
-   * @param  value1  The normalized form of the first value to compare.
-   * @param  value2  The normalized form of the second value to compare.
-   *
-   * @return  <CODE>true</CODE> if the provided values are equal, or
-   *          <CODE>false</CODE> if not.
-   */
-  public boolean areEqual(ByteString value1, ByteString value2)
-  {
-    // Since the values are already normalized, we just need to compare the
-    // associated byte arrays.
-    return Arrays.equals(value1.value(), value2.value());
+    return ByteString.valueOf(buffer.toString());
   }
 }
 
diff --git a/opends/src/server/org/opends/server/schema/CaseExactIA5EqualityMatchingRule.java b/opends/src/server/org/opends/server/schema/CaseExactIA5EqualityMatchingRule.java
index 04bd75e..0dd9e9b 100644
--- a/opends/src/server/org/opends/server/schema/CaseExactIA5EqualityMatchingRule.java
+++ b/opends/src/server/org/opends/server/schema/CaseExactIA5EqualityMatchingRule.java
@@ -25,24 +25,25 @@
  *      Copyright 2006-2008 Sun Microsystems, Inc.
  */
 package org.opends.server.schema;
-import org.opends.messages.Message;
 
 
 
-import java.util.Arrays;
-
-import java.util.Collection;
-import java.util.Collections;
-import org.opends.server.api.EqualityMatchingRule;
-import org.opends.server.core.DirectoryServer;
-import org.opends.server.protocols.asn1.ASN1OctetString;
-import org.opends.server.types.ByteString;
-import org.opends.server.types.DirectoryException;
-import org.opends.server.types.ResultCode;
-
 import static org.opends.messages.SchemaMessages.*;
 import static org.opends.server.schema.SchemaConstants.*;
+
+import java.util.Collection;
+import java.util.Collections;
+
+import org.opends.messages.Message;
+import org.opends.server.api.EqualityMatchingRule;
+import org.opends.server.core.DirectoryServer;
 import org.opends.server.loggers.ErrorLogger;
+import org.opends.server.types.ByteSequence;
+import org.opends.server.types.ByteString;
+import org.opends.server.types.DirectoryException;
+import org.opends.server.types.ResultCode;
+import org.opends.server.util.ServerConstants;
+
 
 
 /**
@@ -68,6 +69,7 @@
    * @return  The common name for this matching rule, or <CODE>null</CODE> if
    * it does not have a name.
    */
+  @Override
   public String getName()
   {
     return EMR_CASE_EXACT_IA5_NAME;
@@ -78,6 +80,7 @@
   /**
    * {@inheritDoc}
    */
+  @Override
   public Collection<String> getAllNames()
   {
     return Collections.singleton(getName());
@@ -90,6 +93,7 @@
    *
    * @return  The OID for this matching rule.
    */
+  @Override
   public String getOID()
   {
     return EMR_CASE_EXACT_IA5_OID;
@@ -103,6 +107,7 @@
    * @return  The description for this matching rule, or <CODE>null</CODE> if
    *          there is none.
    */
+  @Override
   public String getDescription()
   {
     // There is no standard description for this matching rule.
@@ -117,6 +122,7 @@
    *
    * @return  The OID of the syntax with which this matching rule is associated.
    */
+  @Override
   public String getSyntaxOID()
   {
     return SYNTAX_IA5_STRING_OID;
@@ -135,25 +141,26 @@
    * @throws  DirectoryException  If the provided value is invalid according to
    *                              the associated attribute syntax.
    */
-  public ByteString normalizeValue(ByteString value)
+  @Override
+  public ByteString normalizeValue(ByteSequence value)
          throws DirectoryException
   {
     StringBuilder buffer = new StringBuilder();
-    buffer.append(value.stringValue().trim());
+    buffer.append(value.toString().trim());
 
     int bufferLength = buffer.length();
     if (bufferLength == 0)
     {
-      if (value.value().length > 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 ASN1OctetString(" ");
+        return ServerConstants.SINGLE_SPACE_VALUE;
       }
       else
       {
         // The value is empty, so it is already normalized.
-        return new ASN1OctetString();
+        return ByteString.empty();
       }
     }
 
@@ -178,7 +185,7 @@
         // we'll get rid of the character.
 
         Message message = WARN_ATTR_SYNTAX_IA5_ILLEGAL_CHARACTER.get(
-                value.stringValue(), String.valueOf(c));
+                value.toString(), String.valueOf(c));
 
         switch (DirectoryServer.getSyntaxEnforcementPolicy())
         {
@@ -202,26 +209,7 @@
       }
     }
 
-    return new ASN1OctetString(buffer.toString());
-  }
-
-
-
-  /**
-   * Indicates whether the two provided normalized values are equal to each
-   * other.
-   *
-   * @param  value1  The normalized form of the first value to compare.
-   * @param  value2  The normalized form of the second value to compare.
-   *
-   * @return  <CODE>true</CODE> if the provided values are equal, or
-   *          <CODE>false</CODE> if not.
-   */
-  public boolean areEqual(ByteString value1, ByteString value2)
-  {
-    // Since the values are already normalized, we just need to compare the
-    // associated byte arrays.
-    return Arrays.equals(value1.value(), value2.value());
+    return ByteString.valueOf(buffer.toString());
   }
 }
 
diff --git a/opends/src/server/org/opends/server/schema/CaseExactIA5SubstringMatchingRule.java b/opends/src/server/org/opends/server/schema/CaseExactIA5SubstringMatchingRule.java
index 55a3532..9219919 100644
--- a/opends/src/server/org/opends/server/schema/CaseExactIA5SubstringMatchingRule.java
+++ b/opends/src/server/org/opends/server/schema/CaseExactIA5SubstringMatchingRule.java
@@ -22,28 +22,28 @@
  * CDDL HEADER END
  *
  *
- *      Copyright 2006-2008 Sun Microsystems, Inc.
+ *      Copyright 2006-2009 Sun Microsystems, Inc.
  */
 package org.opends.server.schema;
 
 
 
+import static org.opends.messages.SchemaMessages.*;
+import static org.opends.server.loggers.ErrorLogger.*;
+import static org.opends.server.schema.SchemaConstants.*;
+
 import java.util.Collection;
 import java.util.Collections;
-import java.util.List;
 
+import org.opends.messages.Message;
 import org.opends.server.api.SubstringMatchingRule;
 import org.opends.server.core.DirectoryServer;
-
-import org.opends.server.protocols.asn1.ASN1OctetString;
+import org.opends.server.types.ByteSequence;
 import org.opends.server.types.ByteString;
 import org.opends.server.types.DirectoryException;
 import org.opends.server.types.ResultCode;
+import org.opends.server.util.ServerConstants;
 
-import static org.opends.server.loggers.ErrorLogger.*;
-import static org.opends.messages.SchemaMessages.*;
-import org.opends.messages.Message;
-import static org.opends.server.schema.SchemaConstants.*;
 
 
 /**
@@ -68,6 +68,7 @@
   /**
    * {@inheritDoc}
    */
+  @Override
   public Collection<String> getAllNames()
   {
     return Collections.singleton(getName());
@@ -81,6 +82,7 @@
    * @return  The common name for this matching rule, or <CODE>null</CODE> if
    * it does not have a name.
    */
+  @Override
   public String getName()
   {
     return SMR_CASE_EXACT_IA5_NAME;
@@ -93,6 +95,7 @@
    *
    * @return  The OID for this matching rule.
    */
+  @Override
   public String getOID()
   {
     return SMR_CASE_EXACT_IA5_OID;
@@ -106,6 +109,7 @@
    * @return  The description for this matching rule, or <CODE>null</CODE> if
    *          there is none.
    */
+  @Override
   public String getDescription()
   {
     // There is no standard description for this matching rule.
@@ -120,6 +124,7 @@
    *
    * @return  The OID of the syntax with which this matching rule is associated.
    */
+  @Override
   public String getSyntaxOID()
   {
     return SYNTAX_SUBSTRING_ASSERTION_OID;
@@ -138,25 +143,26 @@
    * @throws  DirectoryException  If the provided value is invalid according to
    *                              the associated attribute syntax.
    */
-  public ByteString normalizeValue(ByteString value)
+  @Override
+  public ByteString normalizeValue(ByteSequence value)
          throws DirectoryException
   {
     StringBuilder buffer = new StringBuilder();
-    buffer.append(value.stringValue().trim());
+    buffer.append(value.toString().trim());
 
     int bufferLength = buffer.length();
     if (bufferLength == 0)
     {
-      if (value.value().length > 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 ASN1OctetString(" ");
+        return ServerConstants.SINGLE_SPACE_VALUE;
       }
       else
       {
         // The value is empty, so it is already normalized.
-        return new ASN1OctetString();
+        return ByteString.empty();
       }
     }
 
@@ -180,7 +186,7 @@
         // enforcement is enabled, then we'll throw an exception.  Otherwise,
         // we'll get rid of the character.
         Message message = WARN_ATTR_SYNTAX_IA5_ILLEGAL_CHARACTER.get(
-                value.stringValue(), String.valueOf(c));
+                value.toString(), String.valueOf(c));
 
         switch (DirectoryServer.getSyntaxEnforcementPolicy())
         {
@@ -204,7 +210,7 @@
       }
     }
 
-    return new ASN1OctetString(buffer.toString());
+    return ByteString.valueOf(buffer.toString());
   }
 
 
@@ -220,28 +226,29 @@
    * @throws  DirectoryException  If the provided value fragment is not
    *                              acceptable according to the associated syntax.
    */
-  public ByteString normalizeSubstring(ByteString substring)
+  @Override
+  public ByteString normalizeSubstring(ByteSequence substring)
          throws DirectoryException
   {
     // 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.
     StringBuilder buffer = new StringBuilder();
-    buffer.append(substring.stringValue());
+    buffer.append(substring.toString());
 
     int bufferLength = buffer.length();
     if (bufferLength == 0)
     {
-      if (substring.value().length > 0)
+      if (substring.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 ASN1OctetString(" ");
+        return ServerConstants.SINGLE_SPACE_VALUE;
       }
       else
       {
         // The value is empty, so it is already normalized.
-        return substring;
+        return substring.toByteString();
       }
     }
 
@@ -265,7 +272,7 @@
         // enforcement is enabled, then we'll throw an exception.  Otherwise,
         // we'll get rid of the character.
         Message message = WARN_ATTR_SYNTAX_IA5_ILLEGAL_CHARACTER.get(
-                substring.stringValue(), String.valueOf(c));
+                substring.toString(), String.valueOf(c));
 
         switch (DirectoryServer.getSyntaxEnforcementPolicy())
         {
@@ -289,120 +296,7 @@
       }
     }
 
-    return new ASN1OctetString(buffer.toString());
-  }
-
-
-
-  /**
-   * Determines whether the provided value matches the given substring filter
-   * components.  Note that any of the substring filter components may be
-   * <CODE>null</CODE> but at least one of them must be non-<CODE>null</CODE>.
-   *
-   * @param  value           The normalized value against which to compare the
-   *                         substring components.
-   * @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  <CODE>true</CODE> if the provided value does match the given
-   *          substring components, or <CODE>false</CODE> if not.
-   */
-  public boolean valueMatchesSubstring(ByteString value, ByteString subInitial,
-                                       List<ByteString> subAnyElements,
-                                       ByteString subFinal)
-  {
-    byte[] valueBytes = value.value();
-    int valueLength = valueBytes.length;
-
-    int pos = 0;
-    if (subInitial != null)
-    {
-      byte[] initialBytes = subInitial.value();
-      int initialLength = initialBytes.length;
-      if (initialLength > valueLength)
-      {
-        return false;
-      }
-
-      for (; pos < initialLength; pos++)
-      {
-        if (initialBytes[pos] != valueBytes[pos])
-        {
-          return false;
-        }
-      }
-    }
-
-
-    if ((subAnyElements != null) && (! subAnyElements.isEmpty()))
-    {
-      for (ByteString element : subAnyElements)
-      {
-        byte[] anyBytes = element.value();
-        int anyLength = anyBytes.length;
-
-        int end = valueLength - anyLength;
-        boolean match = false;
-        for (; pos <= end; pos++)
-        {
-          if (anyBytes[0] == valueBytes[pos])
-          {
-            boolean subMatch = true;
-            for (int i=1; i < anyLength; i++)
-            {
-              if (anyBytes[i] != valueBytes[pos+i])
-              {
-                subMatch = false;
-                break;
-              }
-            }
-
-            if (subMatch)
-            {
-              match = subMatch;
-              break;
-            }
-          }
-        }
-
-        if (match)
-        {
-          pos += anyLength;
-        }
-        else
-        {
-          return false;
-        }
-      }
-    }
-
-
-    if (subFinal != null)
-    {
-      byte[] finalBytes = subFinal.value();
-      int finalLength = finalBytes.length;
-
-      if ((valueLength - finalLength) < pos)
-      {
-        return false;
-      }
-
-      pos = valueLength - finalLength;
-      for (int i=0; i < finalLength; i++,pos++)
-      {
-        if (finalBytes[i] != valueBytes[pos])
-        {
-          return false;
-        }
-      }
-    }
-
-
-    return true;
+    return ByteString.valueOf(buffer.toString());
   }
 }
 
diff --git a/opends/src/server/org/opends/server/schema/CaseExactOrderingMatchingRule.java b/opends/src/server/org/opends/server/schema/CaseExactOrderingMatchingRule.java
index 6661de5..af478c7 100644
--- a/opends/src/server/org/opends/server/schema/CaseExactOrderingMatchingRule.java
+++ b/opends/src/server/org/opends/server/schema/CaseExactOrderingMatchingRule.java
@@ -28,15 +28,17 @@
 
 
 
+import static org.opends.server.schema.SchemaConstants.*;
+
 import java.util.Collection;
 import java.util.Collections;
+
 import org.opends.server.api.OrderingMatchingRule;
-import org.opends.server.protocols.asn1.ASN1OctetString;
+import org.opends.server.types.ByteSequence;
 import org.opends.server.types.ByteString;
 import org.opends.server.types.DirectoryException;
-
-import static org.opends.server.schema.SchemaConstants.*;
-import static org.opends.server.util.StaticUtils.*;
+import org.opends.server.util.ServerConstants;
+import org.opends.server.util.StaticUtils;
 
 
 
@@ -70,6 +72,7 @@
   /**
    * {@inheritDoc}
    */
+  @Override
   public Collection<String> getAllNames()
   {
     return Collections.singleton(getName());
@@ -83,6 +86,7 @@
    * @return  The common name for this matching rule, or <CODE>null</CODE> if
    * it does not have a name.
    */
+  @Override
   public String getName()
   {
     return OMR_CASE_EXACT_NAME;
@@ -95,6 +99,7 @@
    *
    * @return  The OID for this matching rule.
    */
+  @Override
   public String getOID()
   {
     return OMR_CASE_EXACT_OID;
@@ -108,6 +113,7 @@
    * @return  The description for this matching rule, or <CODE>null</CODE> if
    *          there is none.
    */
+  @Override
   public String getDescription()
   {
     // There is no standard description for this matching rule.
@@ -122,6 +128,7 @@
    *
    * @return  The OID of the syntax with which this matching rule is associated.
    */
+  @Override
   public String getSyntaxOID()
   {
     return SYNTAX_DIRECTORY_STRING_OID;
@@ -140,25 +147,26 @@
    * @throws  DirectoryException  If the provided value is invalid according to
    *                              the associated attribute syntax.
    */
-  public ByteString normalizeValue(ByteString value)
+  @Override
+  public ByteString normalizeValue(ByteSequence value)
          throws DirectoryException
   {
     StringBuilder buffer = new StringBuilder();
-    buffer.append(value.stringValue().trim());
+    buffer.append(value.toString().trim());
 
     int bufferLength = buffer.length();
     if (bufferLength == 0)
     {
-      if (value.value().length > 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 ASN1OctetString(" ");
+        return ServerConstants.SINGLE_SPACE_VALUE;
       }
       else
       {
         // The value is empty, so it is already normalized.
-        return new ASN1OctetString();
+        return ByteString.empty();
       }
     }
 
@@ -175,7 +183,7 @@
       }
     }
 
-    return new ASN1OctetString(buffer.toString());
+    return ByteString.valueOf(buffer.toString());
   }
 
 
@@ -193,9 +201,10 @@
    *          ascending order, or zero if there is no difference between the
    *          values with regard to ordering.
    */
-  public int compareValues(ByteString value1, ByteString value2)
+  @Override
+  public int compareValues(ByteSequence value1, ByteSequence value2)
   {
-    return compare(value1.value(), value2.value());
+    return StaticUtils.compare(value1, value2);
   }
 
 
@@ -215,36 +224,7 @@
    */
   public int compare(byte[] b1, byte[] b2)
   {
-    int minLength = Math.min(b1.length, b2.length);
-
-    for (int i=0; i < minLength; i++)
-    {
-      if (b1[i] == b2[i])
-      {
-        continue;
-      }
-      else if (b1[i] < b2[i])
-      {
-        return -1;
-      }
-      else if (b1[i] > b2[i])
-      {
-        return 1;
-      }
-    }
-
-    if (b1.length == b2.length)
-    {
-      return 0;
-    }
-    else if (b1.length < b2.length)
-    {
-      return -1;
-    }
-    else
-    {
-      return 1;
-    }
+    return StaticUtils.compare(b1, b2);
   }
 }
 
diff --git a/opends/src/server/org/opends/server/schema/CaseExactSubstringMatchingRule.java b/opends/src/server/org/opends/server/schema/CaseExactSubstringMatchingRule.java
index d2ba95a..8e33811 100644
--- a/opends/src/server/org/opends/server/schema/CaseExactSubstringMatchingRule.java
+++ b/opends/src/server/org/opends/server/schema/CaseExactSubstringMatchingRule.java
@@ -22,22 +22,22 @@
  * CDDL HEADER END
  *
  *
- *      Copyright 2006-2008 Sun Microsystems, Inc.
+ *      Copyright 2006-2009 Sun Microsystems, Inc.
  */
 package org.opends.server.schema;
 
 
 
+import static org.opends.server.schema.SchemaConstants.*;
+
 import java.util.Collection;
 import java.util.Collections;
-import java.util.List;
 
 import org.opends.server.api.SubstringMatchingRule;
-import org.opends.server.protocols.asn1.ASN1OctetString;
+import org.opends.server.types.ByteSequence;
 import org.opends.server.types.ByteString;
 import org.opends.server.types.DirectoryException;
-
-import static org.opends.server.schema.SchemaConstants.*;
+import org.opends.server.util.ServerConstants;
 
 
 
@@ -61,6 +61,7 @@
   /**
    * {@inheritDoc}
    */
+  @Override
   public Collection<String> getAllNames()
   {
     return Collections.singleton(getName());
@@ -74,6 +75,7 @@
    * @return  The common name for this matching rule, or <CODE>null</CODE> if
    * it does not have a name.
    */
+  @Override
   public String getName()
   {
     return SMR_CASE_EXACT_NAME;
@@ -86,6 +88,7 @@
    *
    * @return  The OID for this matching rule.
    */
+  @Override
   public String getOID()
   {
     return SMR_CASE_EXACT_OID;
@@ -99,6 +102,7 @@
    * @return  The description for this matching rule, or <CODE>null</CODE> if
    *          there is none.
    */
+  @Override
   public String getDescription()
   {
     // There is no standard description for this matching rule.
@@ -113,6 +117,7 @@
    *
    * @return  The OID of the syntax with which this matching rule is associated.
    */
+  @Override
   public String getSyntaxOID()
   {
     return SYNTAX_SUBSTRING_ASSERTION_OID;
@@ -131,25 +136,26 @@
    * @throws  DirectoryException  If the provided value is invalid according to
    *                              the associated attribute syntax.
    */
-  public ByteString normalizeValue(ByteString value)
+  @Override
+  public ByteString normalizeValue(ByteSequence value)
          throws DirectoryException
   {
     StringBuilder buffer = new StringBuilder();
-    buffer.append(value.stringValue().trim());
+    buffer.append(value.toString().trim());
 
     int bufferLength = buffer.length();
     if (bufferLength == 0)
     {
-      if (value.value().length > 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 ASN1OctetString(" ");
+        return ServerConstants.SINGLE_SPACE_VALUE;
       }
       else
       {
         // The value is empty, so it is already normalized.
-        return new ASN1OctetString();
+        return ByteString.empty();
       }
     }
 
@@ -166,7 +172,7 @@
       }
     }
 
-    return new ASN1OctetString(buffer.toString());
+    return ByteString.valueOf(buffer.toString());
   }
 
 
@@ -182,28 +188,29 @@
    * @throws  DirectoryException  If the provided value fragment is not
    *                              acceptable according to the associated syntax.
    */
-  public ByteString normalizeSubstring(ByteString substring)
+  @Override
+  public ByteString normalizeSubstring(ByteSequence substring)
          throws DirectoryException
   {
     // 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.
     StringBuilder buffer = new StringBuilder();
-    buffer.append(substring.stringValue());
+    buffer.append(substring.toString());
 
     int bufferLength = buffer.length();
     if (bufferLength == 0)
     {
-      if (substring.value().length > 0)
+      if (substring.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 ASN1OctetString(" ");
+        return ServerConstants.SINGLE_SPACE_VALUE;
       }
       else
       {
         // The value is empty, so it is already normalized.
-        return substring;
+        return substring.toByteString();
       }
     }
 
@@ -220,120 +227,7 @@
       }
     }
 
-    return new ASN1OctetString(buffer.toString());
-  }
-
-
-
-  /**
-   * Determines whether the provided value matches the given substring filter
-   * components.  Note that any of the substring filter components may be
-   * <CODE>null</CODE> but at least one of them must be non-<CODE>null</CODE>.
-   *
-   * @param  value           The normalized value against which to compare the
-   *                         substring components.
-   * @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  <CODE>true</CODE> if the provided value does match the given
-   *          substring components, or <CODE>false</CODE> if not.
-   */
-  public boolean valueMatchesSubstring(ByteString value, ByteString subInitial,
-                                       List<ByteString> subAnyElements,
-                                       ByteString subFinal)
-  {
-    byte[] valueBytes = value.value();
-    int valueLength = valueBytes.length;
-
-    int pos = 0;
-    if (subInitial != null)
-    {
-      byte[] initialBytes = subInitial.value();
-      int initialLength = initialBytes.length;
-      if (initialLength > valueLength)
-      {
-        return false;
-      }
-
-      for (; pos < initialLength; pos++)
-      {
-        if (initialBytes[pos] != valueBytes[pos])
-        {
-          return false;
-        }
-      }
-    }
-
-
-    if ((subAnyElements != null) && (! subAnyElements.isEmpty()))
-    {
-      for (ByteString element : subAnyElements)
-      {
-        byte[] anyBytes = element.value();
-        int anyLength = anyBytes.length;
-
-        int end = valueLength - anyLength;
-        boolean match = false;
-        for (; pos <= end; pos++)
-        {
-          if (anyBytes[0] == valueBytes[pos])
-          {
-            boolean subMatch = true;
-            for (int i=1; i < anyLength; i++)
-            {
-              if (anyBytes[i] != valueBytes[pos+i])
-              {
-                subMatch = false;
-                break;
-              }
-            }
-
-            if (subMatch)
-            {
-              match = subMatch;
-              break;
-            }
-          }
-        }
-
-        if (match)
-        {
-          pos += anyLength;
-        }
-        else
-        {
-          return false;
-        }
-      }
-    }
-
-
-    if (subFinal != null)
-    {
-      byte[] finalBytes = subFinal.value();
-      int finalLength = finalBytes.length;
-
-      if ((valueLength - finalLength) < pos)
-      {
-        return false;
-      }
-
-      pos = valueLength - finalLength;
-      for (int i=0; i < finalLength; i++,pos++)
-      {
-        if (finalBytes[i] != valueBytes[pos])
-        {
-          return false;
-        }
-      }
-    }
-
-
-    return true;
+    return ByteString.valueOf(buffer.toString());
   }
 }
 
diff --git a/opends/src/server/org/opends/server/schema/CaseIgnoreEqualityMatchingRule.java b/opends/src/server/org/opends/server/schema/CaseIgnoreEqualityMatchingRule.java
index 2f028de..c10f44e 100644
--- a/opends/src/server/org/opends/server/schema/CaseIgnoreEqualityMatchingRule.java
+++ b/opends/src/server/org/opends/server/schema/CaseIgnoreEqualityMatchingRule.java
@@ -28,16 +28,18 @@
 
 
 
-import java.util.Collection;
-import java.util.Collections;
-import org.opends.server.api.EqualityMatchingRule;
-import org.opends.server.protocols.asn1.ASN1OctetString;
-import org.opends.server.types.ByteString;
-import org.opends.server.types.DirectoryException;
-
 import static org.opends.server.schema.SchemaConstants.*;
 import static org.opends.server.util.StaticUtils.*;
 
+import java.util.Collection;
+import java.util.Collections;
+
+import org.opends.server.api.EqualityMatchingRule;
+import org.opends.server.types.ByteSequence;
+import org.opends.server.types.ByteString;
+import org.opends.server.types.DirectoryException;
+import org.opends.server.util.ServerConstants;
+
 
 
 /**
@@ -60,6 +62,7 @@
   /**
    * {@inheritDoc}
    */
+  @Override
   public Collection<String> getAllNames()
   {
     return Collections.singleton(getName());
@@ -73,6 +76,7 @@
    * @return  The common name for this matching rule, or <CODE>null</CODE> if
    * it does not have a name.
    */
+  @Override
   public String getName()
   {
     return EMR_CASE_IGNORE_NAME;
@@ -85,6 +89,7 @@
    *
    * @return  The OID for this matching rule.
    */
+  @Override
   public String getOID()
   {
     return EMR_CASE_IGNORE_OID;
@@ -98,6 +103,7 @@
    * @return  The description for this matching rule, or <CODE>null</CODE> if
    *          there is none.
    */
+  @Override
   public String getDescription()
   {
     // There is no standard description for this matching rule.
@@ -112,6 +118,7 @@
    *
    * @return  The OID of the syntax with which this matching rule is associated.
    */
+  @Override
   public String getSyntaxOID()
   {
     return SYNTAX_DIRECTORY_STRING_OID;
@@ -130,15 +137,15 @@
    * @throws  DirectoryException  If the provided value is invalid according to
    *                              the associated attribute syntax.
    */
-  public ByteString normalizeValue(ByteString value)
+  @Override
+  public ByteString normalizeValue(ByteSequence value)
          throws DirectoryException
   {
-    byte[]        valueBytes  = value.value();
-    int           valueLength = valueBytes.length;
+    int           valueLength = value.length();
 
     // Find the first non-space character.
     int startPos = 0;
-    while ((startPos < valueLength) && (valueBytes[startPos] == ' '))
+    while ((startPos < valueLength) && (value.byteAt(startPos) == ' '))
     {
       startPos++;
     }
@@ -147,13 +154,13 @@
     {
       // This should only happen if the value is composed entirely of spaces.
       // In that case, the normalized value is a single space.
-      return new ASN1OctetString(" ");
+      return ServerConstants.SINGLE_SPACE_VALUE;
     }
 
 
     // Find the last non-space character;
     int endPos = (valueLength-1);
-    while ((endPos > startPos) && (valueBytes[endPos] == ' '))
+    while ((endPos > startPos) && (value.byteAt(endPos) == ' '))
     {
       endPos--;
     }
@@ -166,7 +173,7 @@
     boolean lastWasSpace = false;
     for (int i=startPos; i <= endPos; i++)
     {
-      byte b = valueBytes[i];
+      byte b = value.byteAt(i);
       if ((b & 0x7F) != b)
       {
         return normalizeNonASCII(value);
@@ -293,7 +300,7 @@
     }
 
 
-    return new ASN1OctetString(buffer.toString());
+    return ByteString.valueOf(buffer.toString());
   }
 
 
@@ -305,24 +312,24 @@
    *
    * @return  The normalized form of the provided value.
    */
-  private ByteString normalizeNonASCII(ByteString value)
+  private ByteString normalizeNonASCII(ByteSequence value)
   {
     StringBuilder buffer = new StringBuilder();
-    toLowerCase(value.value(), buffer, true);
+    toLowerCase(value.toString(), buffer);
 
     int bufferLength = buffer.length();
     if (bufferLength == 0)
     {
-      if (value.value().length > 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 ASN1OctetString(" ");
+        return ServerConstants.SINGLE_SPACE_VALUE;
       }
       else
       {
         // The value is empty, so it is already normalized.
-        return new ASN1OctetString();
+        return ByteString.empty();
       }
     }
 
@@ -339,41 +346,7 @@
       }
     }
 
-    return new ASN1OctetString(buffer.toString());
-  }
-
-
-
-  /**
-   * Indicates whether the two provided normalized values are equal to each
-   * other.
-   *
-   * @param  value1  The normalized form of the first value to compare.
-   * @param  value2  The normalized form of the second value to compare.
-   *
-   * @return  <CODE>true</CODE> if the provided values are equal, or
-   *          <CODE>false</CODE> if not.
-   */
-  public boolean areEqual(ByteString value1, ByteString value2)
-  {
-    byte[] b1 = value1.value();
-    byte[] b2 = value2.value();
-
-    int length = b1.length;
-    if (b2.length != length)
-    {
-      return false;
-    }
-
-    for (int i=0; i < length; i++)
-    {
-      if (b1[i] != b2[i])
-      {
-        return false;
-      }
-    }
-
-    return true;
+    return ByteString.valueOf(buffer.toString());
   }
 }
 
diff --git a/opends/src/server/org/opends/server/schema/CaseIgnoreIA5EqualityMatchingRule.java b/opends/src/server/org/opends/server/schema/CaseIgnoreIA5EqualityMatchingRule.java
index df8d712..5222362 100644
--- a/opends/src/server/org/opends/server/schema/CaseIgnoreIA5EqualityMatchingRule.java
+++ b/opends/src/server/org/opends/server/schema/CaseIgnoreIA5EqualityMatchingRule.java
@@ -25,25 +25,26 @@
  *      Copyright 2006-2008 Sun Microsystems, Inc.
  */
 package org.opends.server.schema;
-import org.opends.messages.Message;
 
 
 
-import java.util.Arrays;
-
-import java.util.Collection;
-import java.util.Collections;
-import org.opends.server.api.EqualityMatchingRule;
-import org.opends.server.core.DirectoryServer;
-import org.opends.server.protocols.asn1.ASN1OctetString;
-import org.opends.server.types.ByteString;
-import org.opends.server.types.DirectoryException;
-import org.opends.server.types.ResultCode;
-
 import static org.opends.messages.SchemaMessages.*;
 import static org.opends.server.schema.SchemaConstants.*;
 import static org.opends.server.util.StaticUtils.*;
+
+import java.util.Collection;
+import java.util.Collections;
+
+import org.opends.messages.Message;
+import org.opends.server.api.EqualityMatchingRule;
+import org.opends.server.core.DirectoryServer;
 import org.opends.server.loggers.ErrorLogger;
+import org.opends.server.types.ByteSequence;
+import org.opends.server.types.ByteString;
+import org.opends.server.types.DirectoryException;
+import org.opends.server.types.ResultCode;
+import org.opends.server.util.ServerConstants;
+
 
 
 /**
@@ -66,6 +67,7 @@
   /**
    * {@inheritDoc}
    */
+  @Override
   public Collection<String> getAllNames()
   {
     return Collections.singleton(getName());
@@ -79,6 +81,7 @@
    * @return  The common name for this matching rule, or <CODE>null</CODE> if
    * it does not have a name.
    */
+  @Override
   public String getName()
   {
     return EMR_CASE_IGNORE_IA5_NAME;
@@ -91,6 +94,7 @@
    *
    * @return  The OID for this matching rule.
    */
+  @Override
   public String getOID()
   {
     return EMR_CASE_IGNORE_IA5_OID;
@@ -104,6 +108,7 @@
    * @return  The description for this matching rule, or <CODE>null</CODE> if
    *          there is none.
    */
+  @Override
   public String getDescription()
   {
     // There is no standard description for this matching rule.
@@ -118,6 +123,7 @@
    *
    * @return  The OID of the syntax with which this matching rule is associated.
    */
+  @Override
   public String getSyntaxOID()
   {
     return SYNTAX_IA5_STRING_OID;
@@ -136,25 +142,26 @@
    * @throws  DirectoryException  If the provided value is invalid according to
    *                              the associated attribute syntax.
    */
-  public ByteString normalizeValue(ByteString value)
+  @Override
+  public ByteString normalizeValue(ByteSequence value)
          throws DirectoryException
   {
     StringBuilder buffer = new StringBuilder();
-    toLowerCase(value.value(), buffer, true);
+    toLowerCase(value, buffer, true);
 
     int bufferLength = buffer.length();
     if (bufferLength == 0)
     {
-      if (value.value().length > 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 ASN1OctetString(" ");
+        return ServerConstants.SINGLE_SPACE_VALUE;
       }
       else
       {
         // The value is empty, so it is already normalized.
-        return new ASN1OctetString();
+        return ByteString.empty();
       }
     }
 
@@ -179,7 +186,7 @@
         // we'll get rid of the character.
 
         Message message = WARN_ATTR_SYNTAX_IA5_ILLEGAL_CHARACTER.get(
-                value.stringValue(), String.valueOf(c));
+                value.toString(), String.valueOf(c));
 
         switch (DirectoryServer.getSyntaxEnforcementPolicy())
         {
@@ -203,26 +210,7 @@
       }
     }
 
-    return new ASN1OctetString(buffer.toString());
-  }
-
-
-
-  /**
-   * Indicates whether the two provided normalized values are equal to each
-   * other.
-   *
-   * @param  value1  The normalized form of the first value to compare.
-   * @param  value2  The normalized form of the second value to compare.
-   *
-   * @return  <CODE>true</CODE> if the provided values are equal, or
-   *          <CODE>false</CODE> if not.
-   */
-  public boolean areEqual(ByteString value1, ByteString value2)
-  {
-    // Since the values are already normalized, we just need to compare the
-    // associated byte arrays.
-    return Arrays.equals(value1.value(), value2.value());
+    return ByteString.valueOf(buffer.toString());
   }
 }
 
diff --git a/opends/src/server/org/opends/server/schema/CaseIgnoreIA5SubstringMatchingRule.java b/opends/src/server/org/opends/server/schema/CaseIgnoreIA5SubstringMatchingRule.java
index 21d5bad..5d79493 100644
--- a/opends/src/server/org/opends/server/schema/CaseIgnoreIA5SubstringMatchingRule.java
+++ b/opends/src/server/org/opends/server/schema/CaseIgnoreIA5SubstringMatchingRule.java
@@ -22,26 +22,29 @@
  * CDDL HEADER END
  *
  *
- *      Copyright 2006-2008 Sun Microsystems, Inc.
+ *      Copyright 2006-2009 Sun Microsystems, Inc.
  */
 package org.opends.server.schema;
 
-import java.util.Collections;
-import java.util.Collection;
-import org.opends.messages.Message;
-import java.util.List;
 
-import org.opends.server.api.SubstringMatchingRule;
-import org.opends.server.core.DirectoryServer;
-import org.opends.server.protocols.asn1.ASN1OctetString;
-import org.opends.server.types.ByteString;
-import org.opends.server.types.DirectoryException;
-import org.opends.server.types.ResultCode;
 
 import static org.opends.messages.SchemaMessages.*;
 import static org.opends.server.schema.SchemaConstants.*;
 import static org.opends.server.util.StaticUtils.*;
+
+import java.util.Collection;
+import java.util.Collections;
+
+import org.opends.messages.Message;
+import org.opends.server.api.SubstringMatchingRule;
+import org.opends.server.core.DirectoryServer;
 import org.opends.server.loggers.ErrorLogger;
+import org.opends.server.types.ByteSequence;
+import org.opends.server.types.ByteString;
+import org.opends.server.types.DirectoryException;
+import org.opends.server.types.ResultCode;
+import org.opends.server.util.ServerConstants;
+
 
 
 /**
@@ -64,6 +67,7 @@
   /**
    * {@inheritDoc}
    */
+  @Override
   public Collection<String> getAllNames()
   {
     return Collections.singleton(getName());
@@ -77,6 +81,7 @@
    * @return  The common name for this matching rule, or <CODE>null</CODE> if
    * it does not have a name.
    */
+  @Override
   public String getName()
   {
     return SMR_CASE_IGNORE_IA5_NAME;
@@ -89,6 +94,7 @@
    *
    * @return  The OID for this matching rule.
    */
+  @Override
   public String getOID()
   {
     return SMR_CASE_IGNORE_IA5_OID;
@@ -102,6 +108,7 @@
    * @return  The description for this matching rule, or <CODE>null</CODE> if
    *          there is none.
    */
+  @Override
   public String getDescription()
   {
     // There is no standard description for this matching rule.
@@ -116,6 +123,7 @@
    *
    * @return  The OID of the syntax with which this matching rule is associated.
    */
+  @Override
   public String getSyntaxOID()
   {
     return SYNTAX_SUBSTRING_ASSERTION_OID;
@@ -134,25 +142,26 @@
    * @throws  DirectoryException  If the provided value is invalid according to
    *                              the associated attribute syntax.
    */
-  public ByteString normalizeValue(ByteString value)
+  @Override
+  public ByteString normalizeValue(ByteSequence value)
          throws DirectoryException
   {
     StringBuilder buffer = new StringBuilder();
-    toLowerCase(value.value(), buffer, true);
+    toLowerCase(value, buffer, true);
 
     int bufferLength = buffer.length();
     if (bufferLength == 0)
     {
-      if (value.value().length > 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 ASN1OctetString(" ");
+        return ServerConstants.SINGLE_SPACE_VALUE;
       }
       else
       {
         // The value is empty, so it is already normalized.
-        return new ASN1OctetString();
+        return ByteString.empty();
       }
     }
 
@@ -176,7 +185,7 @@
         // enforcement is enabled, then we'll throw an exception.  Otherwise,
         // we'll get rid of the character.
         Message message = WARN_ATTR_SYNTAX_IA5_ILLEGAL_CHARACTER.get(
-                value.stringValue(), String.valueOf(c));
+                value.toString(), String.valueOf(c));
 
         switch (DirectoryServer.getSyntaxEnforcementPolicy())
         {
@@ -200,7 +209,7 @@
       }
     }
 
-    return new ASN1OctetString(buffer.toString());
+    return ByteString.valueOf(buffer.toString());
   }
 
 
@@ -216,28 +225,29 @@
    * @throws  DirectoryException  If the provided value fragment is not
    *                              acceptable according to the associated syntax.
    */
-  public ByteString normalizeSubstring(ByteString substring)
+  @Override
+  public ByteString normalizeSubstring(ByteSequence substring)
          throws DirectoryException
   {
     // 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.
     StringBuilder buffer = new StringBuilder();
-    toLowerCase(substring.value(), buffer, false);
+    toLowerCase(substring, buffer, false);
 
     int bufferLength = buffer.length();
     if (bufferLength == 0)
     {
-      if (substring.value().length > 0)
+      if (substring.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 ASN1OctetString(" ");
+        return ServerConstants.SINGLE_SPACE_VALUE;
       }
       else
       {
         // The value is empty, so it is already normalized.
-        return substring;
+        return substring.toByteString();
       }
     }
 
@@ -261,7 +271,7 @@
         // enforcement is enabled, then we'll throw an exception.  Otherwise,
         // we'll get rid of the character.
         Message message = WARN_ATTR_SYNTAX_IA5_ILLEGAL_CHARACTER.get(
-                substring.stringValue(), String.valueOf(c));
+                substring.toString(), String.valueOf(c));
 
         switch (DirectoryServer.getSyntaxEnforcementPolicy())
         {
@@ -285,120 +295,7 @@
       }
     }
 
-    return new ASN1OctetString(buffer.toString());
-  }
-
-
-
-  /**
-   * Determines whether the provided value matches the given substring filter
-   * components.  Note that any of the substring filter components may be
-   * <CODE>null</CODE> but at least one of them must be non-<CODE>null</CODE>.
-   *
-   * @param  value           The normalized value against which to compare the
-   *                         substring components.
-   * @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  <CODE>true</CODE> if the provided value does match the given
-   *          substring components, or <CODE>false</CODE> if not.
-   */
-  public boolean valueMatchesSubstring(ByteString value, ByteString subInitial,
-                                       List<ByteString> subAnyElements,
-                                       ByteString subFinal)
-  {
-    byte[] valueBytes = value.value();
-    int valueLength = valueBytes.length;
-
-    int pos = 0;
-    if (subInitial != null)
-    {
-      byte[] initialBytes = subInitial.value();
-      int initialLength = initialBytes.length;
-      if (initialLength > valueLength)
-      {
-        return false;
-      }
-
-      for (; pos < initialLength; pos++)
-      {
-        if (initialBytes[pos] != valueBytes[pos])
-        {
-          return false;
-        }
-      }
-    }
-
-
-    if ((subAnyElements != null) && (! subAnyElements.isEmpty()))
-    {
-      for (ByteString element : subAnyElements)
-      {
-        byte[] anyBytes = element.value();
-        int anyLength = anyBytes.length;
-
-        int end = valueLength - anyLength;
-        boolean match = false;
-        for (; pos <= end; pos++)
-        {
-          if (anyBytes[0] == valueBytes[pos])
-          {
-            boolean subMatch = true;
-            for (int i=1; i < anyLength; i++)
-            {
-              if (anyBytes[i] != valueBytes[pos+i])
-              {
-                subMatch = false;
-                break;
-              }
-            }
-
-            if (subMatch)
-            {
-              match = subMatch;
-              break;
-            }
-          }
-        }
-
-        if (match)
-        {
-          pos += anyLength;
-        }
-        else
-        {
-          return false;
-        }
-      }
-    }
-
-
-    if (subFinal != null)
-    {
-      byte[] finalBytes = subFinal.value();
-      int finalLength = finalBytes.length;
-
-      if ((valueLength - finalLength) < pos)
-      {
-        return false;
-      }
-
-      pos = valueLength - finalLength;
-      for (int i=0; i < finalLength; i++,pos++)
-      {
-        if (finalBytes[i] != valueBytes[pos])
-        {
-          return false;
-        }
-      }
-    }
-
-
-    return true;
+    return ByteString.valueOf(buffer.toString());
   }
 }
 
diff --git a/opends/src/server/org/opends/server/schema/CaseIgnoreListEqualityMatchingRule.java b/opends/src/server/org/opends/server/schema/CaseIgnoreListEqualityMatchingRule.java
index 8f694ff..a1426ff 100644
--- a/opends/src/server/org/opends/server/schema/CaseIgnoreListEqualityMatchingRule.java
+++ b/opends/src/server/org/opends/server/schema/CaseIgnoreListEqualityMatchingRule.java
@@ -28,18 +28,18 @@
 
 
 
-import java.util.Arrays;
-
-import java.util.Collections;
-import java.util.Collection;
-import org.opends.server.api.EqualityMatchingRule;
-import org.opends.server.protocols.asn1.ASN1OctetString;
-import org.opends.server.types.ByteString;
-import org.opends.server.types.DirectoryException;
-
 import static org.opends.server.schema.SchemaConstants.*;
 import static org.opends.server.util.StaticUtils.*;
 
+import java.util.Collection;
+import java.util.Collections;
+
+import org.opends.server.api.EqualityMatchingRule;
+import org.opends.server.types.ByteSequence;
+import org.opends.server.types.ByteString;
+import org.opends.server.types.DirectoryException;
+import org.opends.server.util.ServerConstants;
+
 
 
 /**
@@ -62,6 +62,7 @@
   /**
    * {@inheritDoc}
    */
+  @Override
   public Collection<String> getAllNames()
   {
     return Collections.singleton(getName());
@@ -75,6 +76,7 @@
    * @return  The common name for this matching rule, or <CODE>null</CODE> if
    * it does not have a name.
    */
+  @Override
   public String getName()
   {
     return EMR_CASE_IGNORE_LIST_NAME;
@@ -87,6 +89,7 @@
    *
    * @return  The OID for this matching rule.
    */
+  @Override
   public String getOID()
   {
     return EMR_CASE_IGNORE_LIST_OID;
@@ -100,6 +103,7 @@
    * @return  The description for this matching rule, or <CODE>null</CODE> if
    *          there is none.
    */
+  @Override
   public String getDescription()
   {
     // There is no standard description for this matching rule.
@@ -114,6 +118,7 @@
    *
    * @return  The OID of the syntax with which this matching rule is associated.
    */
+  @Override
   public String getSyntaxOID()
   {
     return SYNTAX_POSTAL_ADDRESS_OID;
@@ -132,25 +137,26 @@
    * @throws  DirectoryException  If the provided value is invalid according to
    *                              the associated attribute syntax.
    */
-  public ByteString normalizeValue(ByteString value)
+  @Override
+  public ByteString normalizeValue(ByteSequence value)
          throws DirectoryException
   {
     StringBuilder buffer = new StringBuilder();
-    toLowerCase(value.value(), buffer, true);
+    toLowerCase(value, buffer, true);
 
     int bufferLength = buffer.length();
     if (bufferLength == 0)
     {
-      if (value.value().length > 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 ASN1OctetString(" ");
+        return ServerConstants.SINGLE_SPACE_VALUE;
       }
       else
       {
         // The value is empty, so it is already normalized.
-        return new ASN1OctetString();
+        return ByteString.empty();
       }
     }
 
@@ -180,26 +186,7 @@
       }
     }
 
-    return new ASN1OctetString(buffer.toString());
-  }
-
-
-
-  /**
-   * Indicates whether the two provided normalized values are equal to each
-   * other.
-   *
-   * @param  value1  The normalized form of the first value to compare.
-   * @param  value2  The normalized form of the second value to compare.
-   *
-   * @return  <CODE>true</CODE> if the provided values are equal, or
-   *          <CODE>false</CODE> if not.
-   */
-  public boolean areEqual(ByteString value1, ByteString value2)
-  {
-    // Since the values are already normalized, we just need to compare the
-    // associated byte arrays.
-    return Arrays.equals(value1.value(), value2.value());
+    return ByteString.valueOf(buffer.toString());
   }
 }
 
diff --git a/opends/src/server/org/opends/server/schema/CaseIgnoreListSubstringMatchingRule.java b/opends/src/server/org/opends/server/schema/CaseIgnoreListSubstringMatchingRule.java
index f715801..6027211 100644
--- a/opends/src/server/org/opends/server/schema/CaseIgnoreListSubstringMatchingRule.java
+++ b/opends/src/server/org/opends/server/schema/CaseIgnoreListSubstringMatchingRule.java
@@ -22,24 +22,24 @@
  * CDDL HEADER END
  *
  *
- *      Copyright 2006-2008 Sun Microsystems, Inc.
+ *      Copyright 2006-2009 Sun Microsystems, Inc.
  */
 package org.opends.server.schema;
 
 
 
-import java.util.Collection;
-import java.util.Collections;
-import java.util.List;
-
-import org.opends.server.api.SubstringMatchingRule;
-import org.opends.server.protocols.asn1.ASN1OctetString;
-import org.opends.server.types.ByteString;
-import org.opends.server.types.DirectoryException;
-
 import static org.opends.server.schema.SchemaConstants.*;
 import static org.opends.server.util.StaticUtils.*;
 
+import java.util.Collection;
+import java.util.Collections;
+
+import org.opends.server.api.SubstringMatchingRule;
+import org.opends.server.types.ByteSequence;
+import org.opends.server.types.ByteString;
+import org.opends.server.types.DirectoryException;
+import org.opends.server.util.ServerConstants;
+
 
 
 /**
@@ -62,6 +62,7 @@
   /**
    * {@inheritDoc}
    */
+  @Override
   public Collection<String> getAllNames()
   {
     return Collections.singleton(getName());
@@ -75,6 +76,7 @@
    * @return  The common name for this matching rule, or <CODE>null</CODE> if
    * it does not have a name.
    */
+  @Override
   public String getName()
   {
     return SMR_CASE_IGNORE_LIST_NAME;
@@ -87,6 +89,7 @@
    *
    * @return  The OID for this matching rule.
    */
+  @Override
   public String getOID()
   {
     return SMR_CASE_IGNORE_LIST_OID;
@@ -100,6 +103,7 @@
    * @return  The description for this matching rule, or <CODE>null</CODE> if
    *          there is none.
    */
+  @Override
   public String getDescription()
   {
     // There is no standard description for this matching rule.
@@ -114,6 +118,7 @@
    *
    * @return  The OID of the syntax with which this matching rule is associated.
    */
+  @Override
   public String getSyntaxOID()
   {
     return SYNTAX_SUBSTRING_ASSERTION_OID;
@@ -132,25 +137,26 @@
    * @throws  DirectoryException  If the provided value is invalid according to
    *                              the associated attribute syntax.
    */
-  public ByteString normalizeValue(ByteString value)
+  @Override
+  public ByteString normalizeValue(ByteSequence value)
          throws DirectoryException
   {
     StringBuilder buffer = new StringBuilder();
-    toLowerCase(value.value(), buffer, true);
+    toLowerCase(value, buffer, true);
 
     int bufferLength = buffer.length();
     if (bufferLength == 0)
     {
-      if (value.value().length > 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 ASN1OctetString(" ");
+        return ServerConstants.SINGLE_SPACE_VALUE;
       }
       else
       {
         // The value is empty, so it is already normalized.
-        return new ASN1OctetString();
+        return ByteString.empty();
       }
     }
 
@@ -180,7 +186,7 @@
       }
     }
 
-    return new ASN1OctetString(buffer.toString());
+    return ByteString.valueOf(buffer.toString());
   }
 
 
@@ -196,28 +202,29 @@
    * @throws  DirectoryException  If the provided value fragment is not
    *                              acceptable according to the associated syntax.
    */
-  public ByteString normalizeSubstring(ByteString substring)
+  @Override
+  public ByteString normalizeSubstring(ByteSequence substring)
          throws DirectoryException
   {
     // 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.
     StringBuilder buffer = new StringBuilder();
-    toLowerCase(substring.value(), buffer, false);
+    toLowerCase(substring, buffer, false);
 
     int bufferLength = buffer.length();
     if (bufferLength == 0)
     {
-      if (substring.value().length > 0)
+      if (substring.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 ASN1OctetString(" ");
+        return ServerConstants.SINGLE_SPACE_VALUE;
       }
       else
       {
         // The value is empty, so it is already normalized.
-        return substring;
+        return substring.toByteString();
       }
     }
 
@@ -234,120 +241,7 @@
       }
     }
 
-    return new ASN1OctetString(buffer.toString());
-  }
-
-
-
-  /**
-   * Determines whether the provided value matches the given substring filter
-   * components.  Note that any of the substring filter components may be
-   * <CODE>null</CODE> but at least one of them must be non-<CODE>null</CODE>.
-   *
-   * @param  value           The normalized value against which to compare the
-   *                         substring components.
-   * @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  <CODE>true</CODE> if the provided value does match the given
-   *          substring components, or <CODE>false</CODE> if not.
-   */
-  public boolean valueMatchesSubstring(ByteString value, ByteString subInitial,
-                                       List<ByteString> subAnyElements,
-                                       ByteString subFinal)
-  {
-    byte[] valueBytes = value.value();
-    int valueLength = valueBytes.length;
-
-    int pos = 0;
-    if (subInitial != null)
-    {
-      byte[] initialBytes = subInitial.value();
-      int initialLength = initialBytes.length;
-      if (initialLength > valueLength)
-      {
-        return false;
-      }
-
-      for (; pos < initialLength; pos++)
-      {
-        if (initialBytes[pos] != valueBytes[pos])
-        {
-          return false;
-        }
-      }
-    }
-
-
-    if ((subAnyElements != null) && (! subAnyElements.isEmpty()))
-    {
-      for (ByteString element : subAnyElements)
-      {
-        byte[] anyBytes = element.value();
-        int anyLength = anyBytes.length;
-
-        int end = valueLength - anyLength;
-        boolean match = false;
-        for (; pos <= end; pos++)
-        {
-          if (anyBytes[0] == valueBytes[pos])
-          {
-            boolean subMatch = true;
-            for (int i=1; i < anyLength; i++)
-            {
-              if (anyBytes[i] != valueBytes[pos+i])
-              {
-                subMatch = false;
-                break;
-              }
-            }
-
-            if (subMatch)
-            {
-              match = subMatch;
-              break;
-            }
-          }
-        }
-
-        if (match)
-        {
-          pos += anyLength;
-        }
-        else
-        {
-          return false;
-        }
-      }
-    }
-
-
-    if (subFinal != null)
-    {
-      byte[] finalBytes = subFinal.value();
-      int finalLength = finalBytes.length;
-
-      if ((valueLength - finalLength) < pos)
-      {
-        return false;
-      }
-
-      pos = valueLength - finalLength;
-      for (int i=0; i < finalLength; i++,pos++)
-      {
-        if (finalBytes[i] != valueBytes[pos])
-        {
-          return false;
-        }
-      }
-    }
-
-
-    return true;
+    return ByteString.valueOf(buffer.toString());
   }
 }
 
diff --git a/opends/src/server/org/opends/server/schema/CaseIgnoreOrderingMatchingRule.java b/opends/src/server/org/opends/server/schema/CaseIgnoreOrderingMatchingRule.java
index c0353f7..2286476 100644
--- a/opends/src/server/org/opends/server/schema/CaseIgnoreOrderingMatchingRule.java
+++ b/opends/src/server/org/opends/server/schema/CaseIgnoreOrderingMatchingRule.java
@@ -28,16 +28,19 @@
 
 
 
-import java.util.Collections;
-import java.util.Collection;
-import org.opends.server.api.OrderingMatchingRule;
-import org.opends.server.protocols.asn1.ASN1OctetString;
-import org.opends.server.types.ByteString;
-import org.opends.server.types.DirectoryException;
-
 import static org.opends.server.schema.SchemaConstants.*;
 import static org.opends.server.util.StaticUtils.*;
 
+import java.util.Collection;
+import java.util.Collections;
+
+import org.opends.server.api.OrderingMatchingRule;
+import org.opends.server.types.ByteSequence;
+import org.opends.server.types.ByteString;
+import org.opends.server.types.DirectoryException;
+import org.opends.server.util.ServerConstants;
+import org.opends.server.util.StaticUtils;
+
 
 
 /**
@@ -70,6 +73,7 @@
   /**
    * {@inheritDoc}
    */
+  @Override
   public Collection<String> getAllNames()
   {
     return Collections.singleton(getName());
@@ -83,6 +87,7 @@
    * @return  The common name for this matching rule, or <CODE>null</CODE> if
    * it does not have a name.
    */
+  @Override
   public String getName()
   {
     return OMR_CASE_IGNORE_NAME;
@@ -95,6 +100,7 @@
    *
    * @return  The OID for this matching rule.
    */
+  @Override
   public String getOID()
   {
     return OMR_CASE_IGNORE_OID;
@@ -108,6 +114,7 @@
    * @return  The description for this matching rule, or <CODE>null</CODE> if
    *          there is none.
    */
+  @Override
   public String getDescription()
   {
     // There is no standard description for this matching rule.
@@ -122,6 +129,7 @@
    *
    * @return  The OID of the syntax with which this matching rule is associated.
    */
+  @Override
   public String getSyntaxOID()
   {
     return SYNTAX_DIRECTORY_STRING_OID;
@@ -140,25 +148,26 @@
    * @throws  DirectoryException  If the provided value is invalid according to
    *                              the associated attribute syntax.
    */
-  public ByteString normalizeValue(ByteString value)
+  @Override
+  public ByteString normalizeValue(ByteSequence value)
          throws DirectoryException
   {
     StringBuilder buffer = new StringBuilder();
-    toLowerCase(value.value(), buffer, true);
+    toLowerCase(value, buffer, true);
 
     int bufferLength = buffer.length();
     if (bufferLength == 0)
     {
-      if (value.value().length > 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 ASN1OctetString(" ");
+        return ServerConstants.SINGLE_SPACE_VALUE;
       }
       else
       {
         // The value is empty, so it is already normalized.
-        return new ASN1OctetString();
+        return ByteString.empty();
       }
     }
 
@@ -175,7 +184,7 @@
       }
     }
 
-    return new ASN1OctetString(buffer.toString());
+    return ByteString.valueOf(buffer.toString());
   }
 
 
@@ -193,9 +202,10 @@
    *          ascending order, or zero if there is no difference between the
    *          values with regard to ordering.
    */
-  public int compareValues(ByteString value1, ByteString value2)
+  @Override
+  public int compareValues(ByteSequence value1, ByteSequence value2)
   {
-    return compare(value1.value(),value2.value());
+    return StaticUtils.compare(value1, value2);
   }
 
 
@@ -215,36 +225,7 @@
    */
   public int compare(byte[] b1, byte[] b2)
   {
-    int minLength = Math.min(b1.length, b2.length);
-
-    for (int i=0; i < minLength; i++)
-    {
-      if (b1[i] == b2[i])
-      {
-        continue;
-      }
-      else if (b1[i] < b2[i])
-      {
-        return -1;
-      }
-      else if (b1[i] > b2[i])
-      {
-        return 1;
-      }
-    }
-
-    if (b1.length == b2.length)
-    {
-      return 0;
-    }
-    else if (b1.length < b2.length)
-    {
-      return -1;
-    }
-    else
-    {
-      return 1;
-    }
+    return StaticUtils.compare(b1, b2);
   }
 }
 
diff --git a/opends/src/server/org/opends/server/schema/CaseIgnoreSubstringMatchingRule.java b/opends/src/server/org/opends/server/schema/CaseIgnoreSubstringMatchingRule.java
index 5513c1d..7659e82 100644
--- a/opends/src/server/org/opends/server/schema/CaseIgnoreSubstringMatchingRule.java
+++ b/opends/src/server/org/opends/server/schema/CaseIgnoreSubstringMatchingRule.java
@@ -22,24 +22,24 @@
  * CDDL HEADER END
  *
  *
- *      Copyright 2006-2008 Sun Microsystems, Inc.
+ *      Copyright 2006-2009 Sun Microsystems, Inc.
  */
 package org.opends.server.schema;
 
 
 
-import java.util.Collection;
-import java.util.Collections;
-import java.util.List;
-
-import org.opends.server.api.SubstringMatchingRule;
-import org.opends.server.protocols.asn1.ASN1OctetString;
-import org.opends.server.types.ByteString;
-import org.opends.server.types.DirectoryException;
-
 import static org.opends.server.schema.SchemaConstants.*;
 import static org.opends.server.util.StaticUtils.*;
 
+import java.util.Collection;
+import java.util.Collections;
+
+import org.opends.server.api.SubstringMatchingRule;
+import org.opends.server.types.ByteSequence;
+import org.opends.server.types.ByteString;
+import org.opends.server.types.DirectoryException;
+import org.opends.server.util.ServerConstants;
+
 
 
 /**
@@ -62,6 +62,7 @@
   /**
    * {@inheritDoc}
    */
+  @Override
   public Collection<String> getAllNames()
   {
     return Collections.singleton(getName());
@@ -75,6 +76,7 @@
    * @return  The common name for this matching rule, or <CODE>null</CODE> if
    * it does not have a name.
    */
+  @Override
   public String getName()
   {
     return SMR_CASE_IGNORE_NAME;
@@ -87,6 +89,7 @@
    *
    * @return  The OID for this matching rule.
    */
+  @Override
   public String getOID()
   {
     return SMR_CASE_IGNORE_OID;
@@ -100,6 +103,7 @@
    * @return  The description for this matching rule, or <CODE>null</CODE> if
    *          there is none.
    */
+  @Override
   public String getDescription()
   {
     // There is no standard description for this matching rule.
@@ -114,6 +118,7 @@
    *
    * @return  The OID of the syntax with which this matching rule is associated.
    */
+  @Override
   public String getSyntaxOID()
   {
     return SYNTAX_SUBSTRING_ASSERTION_OID;
@@ -132,25 +137,26 @@
    * @throws  DirectoryException  If the provided value is invalid according to
    *                              the associated attribute syntax.
    */
-  public ByteString normalizeValue(ByteString value)
+  @Override
+  public ByteString normalizeValue(ByteSequence value)
          throws DirectoryException
   {
     StringBuilder buffer = new StringBuilder();
-    toLowerCase(value.value(), buffer, true);
+    toLowerCase(value, buffer, true);
 
     int bufferLength = buffer.length();
     if (bufferLength == 0)
     {
-      if (value.value().length > 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 ASN1OctetString(" ");
+        return ServerConstants.SINGLE_SPACE_VALUE;
       }
       else
       {
         // The value is empty, so it is already normalized.
-        return new ASN1OctetString();
+        return ByteString.empty();
       }
     }
 
@@ -167,7 +173,7 @@
       }
     }
 
-    return new ASN1OctetString(buffer.toString());
+    return ByteString.valueOf(buffer.toString());
   }
 
 
@@ -183,28 +189,29 @@
    * @throws  DirectoryException  If the provided value fragment is not
    *                              acceptable according to the associated syntax.
    */
-  public ByteString normalizeSubstring(ByteString substring)
+  @Override
+  public ByteString normalizeSubstring(ByteSequence substring)
          throws DirectoryException
   {
     // 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.
     StringBuilder buffer = new StringBuilder();
-    toLowerCase(substring.value(), buffer, false);
+    toLowerCase(substring, buffer, false);
 
     int bufferLength = buffer.length();
     if (bufferLength == 0)
     {
-      if (substring.value().length > 0)
+      if (substring.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 ASN1OctetString(" ");
+        return ServerConstants.SINGLE_SPACE_VALUE;
       }
       else
       {
         // The value is empty, so it is already normalized.
-        return substring;
+        return substring.toByteString();
       }
     }
 
@@ -221,120 +228,7 @@
       }
     }
 
-    return new ASN1OctetString(buffer.toString());
-  }
-
-
-
-  /**
-   * Determines whether the provided value matches the given substring filter
-   * components.  Note that any of the substring filter components may be
-   * <CODE>null</CODE> but at least one of them must be non-<CODE>null</CODE>.
-   *
-   * @param  value           The normalized value against which to compare the
-   *                         substring components.
-   * @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  <CODE>true</CODE> if the provided value does match the given
-   *          substring components, or <CODE>false</CODE> if not.
-   */
-  public boolean valueMatchesSubstring(ByteString value, ByteString subInitial,
-                                       List<ByteString> subAnyElements,
-                                       ByteString subFinal)
-  {
-    byte[] valueBytes = value.value();
-    int valueLength = valueBytes.length;
-
-    int pos = 0;
-    if (subInitial != null)
-    {
-      byte[] initialBytes = subInitial.value();
-      int initialLength = initialBytes.length;
-      if (initialLength > valueLength)
-      {
-        return false;
-      }
-
-      for (; pos < initialLength; pos++)
-      {
-        if (initialBytes[pos] != valueBytes[pos])
-        {
-          return false;
-        }
-      }
-    }
-
-
-    if ((subAnyElements != null) && (! subAnyElements.isEmpty()))
-    {
-      for (ByteString element : subAnyElements)
-      {
-        byte[] anyBytes = element.value();
-        int anyLength = anyBytes.length;
-
-        int end = valueLength - anyLength;
-        boolean match = false;
-        for (; pos <= end; pos++)
-        {
-          if (anyBytes[0] == valueBytes[pos])
-          {
-            boolean subMatch = true;
-            for (int i=1; i < anyLength; i++)
-            {
-              if (anyBytes[i] != valueBytes[pos+i])
-              {
-                subMatch = false;
-                break;
-              }
-            }
-
-            if (subMatch)
-            {
-              match = subMatch;
-              break;
-            }
-          }
-        }
-
-        if (match)
-        {
-          pos += anyLength;
-        }
-        else
-        {
-          return false;
-        }
-      }
-    }
-
-
-    if (subFinal != null)
-    {
-      byte[] finalBytes = subFinal.value();
-      int finalLength = finalBytes.length;
-
-      if ((valueLength - finalLength) < pos)
-      {
-        return false;
-      }
-
-      pos = valueLength - finalLength;
-      for (int i=0; i < finalLength; i++,pos++)
-      {
-        if (finalBytes[i] != valueBytes[pos])
-        {
-          return false;
-        }
-      }
-    }
-
-
-    return true;
+    return ByteString.valueOf(buffer.toString());
   }
 }
 
diff --git a/opends/src/server/org/opends/server/schema/CertificateListSyntax.java b/opends/src/server/org/opends/server/schema/CertificateListSyntax.java
index 5b549b6..bc04f98 100644
--- a/opends/src/server/org/opends/server/schema/CertificateListSyntax.java
+++ b/opends/src/server/org/opends/server/schema/CertificateListSyntax.java
@@ -36,8 +36,7 @@
 import org.opends.server.api.SubstringMatchingRule;
 import org.opends.server.config.ConfigException;
 import org.opends.server.core.DirectoryServer;
-import org.opends.server.types.ByteString;
-
+import org.opends.server.types.ByteSequence;
 
 
 import static org.opends.server.loggers.ErrorLogger.*;
@@ -221,7 +220,7 @@
    * @return  <CODE>true</CODE> if the provided value is acceptable for use with
    *          this syntax, or <CODE>false</CODE> if not.
    */
-  public boolean valueIsAcceptable(ByteString value,
+  public boolean valueIsAcceptable(ByteSequence value,
                                    MessageBuilder invalidReason)
   {
     // All values will be acceptable for the certificate list syntax.
diff --git a/opends/src/server/org/opends/server/schema/CertificatePairSyntax.java b/opends/src/server/org/opends/server/schema/CertificatePairSyntax.java
index 3af559c..b0c467d 100644
--- a/opends/src/server/org/opends/server/schema/CertificatePairSyntax.java
+++ b/opends/src/server/org/opends/server/schema/CertificatePairSyntax.java
@@ -36,8 +36,7 @@
 import org.opends.server.api.SubstringMatchingRule;
 import org.opends.server.config.ConfigException;
 import org.opends.server.core.DirectoryServer;
-import org.opends.server.types.ByteString;
-
+import org.opends.server.types.ByteSequence;
 
 
 import static org.opends.server.loggers.ErrorLogger.*;
@@ -221,7 +220,7 @@
    * @return  <CODE>true</CODE> if the provided value is acceptable for use with
    *          this syntax, or <CODE>false</CODE> if not.
    */
-  public boolean valueIsAcceptable(ByteString value,
+  public boolean valueIsAcceptable(ByteSequence value,
                                    MessageBuilder invalidReason)
   {
     // All values will be acceptable for the certificate pair syntax.
diff --git a/opends/src/server/org/opends/server/schema/CertificateSyntax.java b/opends/src/server/org/opends/server/schema/CertificateSyntax.java
index 1a4b6ee..00724f4 100644
--- a/opends/src/server/org/opends/server/schema/CertificateSyntax.java
+++ b/opends/src/server/org/opends/server/schema/CertificateSyntax.java
@@ -36,8 +36,7 @@
 import org.opends.server.api.SubstringMatchingRule;
 import org.opends.server.config.ConfigException;
 import org.opends.server.core.DirectoryServer;
-import org.opends.server.types.ByteString;
-
+import org.opends.server.types.ByteSequence;
 
 
 import static org.opends.server.loggers.ErrorLogger.*;
@@ -220,7 +219,7 @@
    * @return  <CODE>true</CODE> if the provided value is acceptable for use with
    *          this syntax, or <CODE>false</CODE> if not.
    */
-  public boolean valueIsAcceptable(ByteString value,
+  public boolean valueIsAcceptable(ByteSequence value,
                                    MessageBuilder invalidReason)
   {
     // All values will be acceptable for the certificate syntax.
diff --git a/opends/src/server/org/opends/server/schema/CollationMatchingRuleFactory.java b/opends/src/server/org/opends/server/schema/CollationMatchingRuleFactory.java
index 0237d4a..8e9995a 100644
--- a/opends/src/server/org/opends/server/schema/CollationMatchingRuleFactory.java
+++ b/opends/src/server/org/opends/server/schema/CollationMatchingRuleFactory.java
@@ -25,14 +25,22 @@
  *      Copyright 2008-2009 Sun Microsystems, Inc.
  */
 
-
 package org.opends.server.schema;
 
+
+
+import static org.opends.messages.ConfigMessages.*;
+import static org.opends.messages.CoreMessages.*;
+import static org.opends.messages.SchemaMessages.*;
+import static org.opends.server.loggers.ErrorLogger.*;
+import static org.opends.server.schema.SchemaConstants.*;
+import static org.opends.server.util.ServerConstants.*;
+import static org.opends.server.util.StaticUtils.*;
+
+import java.nio.CharBuffer;
 import java.text.CollationKey;
 import java.text.Collator;
-import java.nio.CharBuffer;
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
@@ -40,99 +48,90 @@
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Locale;
-
 import java.util.Map;
 import java.util.Set;
 import java.util.SortedSet;
 import java.util.TreeSet;
+
 import org.opends.messages.Message;
 import org.opends.server.admin.server.ConfigurationChangeListener;
-import org.opends.server.admin.std.meta.CollationMatchingRuleCfgDefn.
-        MatchingRuleType;
-import org.opends.server.api.ExtensibleIndexer;
-import org.opends.server.api.IndexQueryFactory;
-import org.opends.server.api.MatchingRuleFactory;
+import org.opends.server.admin.std.meta.
+  CollationMatchingRuleCfgDefn.MatchingRuleType;
 import org.opends.server.admin.std.server.CollationMatchingRuleCfg;
+import org.opends.server.api.ExtensibleIndexer;
 import org.opends.server.api.ExtensibleMatchingRule;
+import org.opends.server.api.IndexQueryFactory;
 import org.opends.server.api.MatchingRule;
+import org.opends.server.api.MatchingRuleFactory;
 import org.opends.server.backends.jeb.AttributeIndex;
 import org.opends.server.config.ConfigException;
 import org.opends.server.core.DirectoryServer;
-import org.opends.server.protocols.asn1.ASN1OctetString;
 import org.opends.server.types.AttributeValue;
+import org.opends.server.types.ByteSequence;
 import org.opends.server.types.ByteString;
 import org.opends.server.types.ConditionResult;
 import org.opends.server.types.ConfigChangeResult;
 import org.opends.server.types.DirectoryException;
 import org.opends.server.types.IndexConfig;
 import org.opends.server.types.InitializationException;
-
 import org.opends.server.types.ResultCode;
-import static org.opends.server.schema.SchemaConstants.*;
-import static org.opends.server.loggers.ErrorLogger.logError;
-import static org.opends.messages.SchemaMessages.*;
-import static org.opends.messages.CoreMessages.*;
-import static org.opends.messages.ConfigMessages.*;
-import static org.opends.server.util.StaticUtils.*;
-import static org.opends.server.api.ExtensibleIndexer.*;
-import static org.opends.server.util.ServerConstants.*;
 
 
 
 /**
- * This class is a factory class for Collation matching rules. It creates
- * different matching rules based on the configuration entries.
+ * This class is a factory class for Collation matching rules. It
+ * creates different matching rules based on the configuration entries.
  */
-public final class CollationMatchingRuleFactory
-        extends MatchingRuleFactory<CollationMatchingRuleCfg>
-        implements ConfigurationChangeListener<CollationMatchingRuleCfg>
+public final class CollationMatchingRuleFactory extends
+    MatchingRuleFactory<CollationMatchingRuleCfg> implements
+    ConfigurationChangeListener<CollationMatchingRuleCfg>
 {
 
-  //Whether equality matching rules are enabled.
+  // Whether equality matching rules are enabled.
   private boolean equalityMatchingRuleType;
 
-  //Whether less-than matching rules are enabled.
+  // Whether less-than matching rules are enabled.
   private boolean lessThanMatchingRuleType;
 
-  //Whether less-than-equal-to matching rules are enabled.
+  // Whether less-than-equal-to matching rules are enabled.
   private boolean lessThanEqualToMatchingRuleType;
 
-  //Whether less-than-equal-to matching rules are enabled.
+  // Whether less-than-equal-to matching rules are enabled.
   private boolean greaterThanMatchingRuleType;
 
-  //Whether greater-than matching rules are enabled.
+  // Whether greater-than matching rules are enabled.
   private boolean greaterThanEqualToMatchingRuleType;
 
-  //Whether greater-than-equal-to matching rules are enabled.
+  // Whether greater-than-equal-to matching rules are enabled.
   private boolean substringMatchingRuleType;
 
-  //Stores the list of available locales on this JVM.
+  // Stores the list of available locales on this JVM.
   private static final Set<Locale> supportedLocales;
 
-  //Current Configuration.
+  // Current Configuration.
   private CollationMatchingRuleCfg currentConfig;
 
-  //Map of OID and the Matching Rule.
-  private  final Map<String, MatchingRule> matchingRules;
-
+  // Map of OID and the Matching Rule.
+  private final Map<String, MatchingRule> matchingRules;
 
   static
   {
     supportedLocales = new HashSet<Locale>();
-    for(Locale l:Locale.getAvailableLocales())
+    for (Locale l : Locale.getAvailableLocales())
     {
       supportedLocales.add(l);
     }
   }
 
 
+
   /**
    * Creates a new instance of CollationMatchingRuleFactory.
    */
   public CollationMatchingRuleFactory()
   {
-    //Initialize the matchingRules.
-    matchingRules = new HashMap<String,MatchingRule>();
+    // Initialize the matchingRules.
+    matchingRules = new HashMap<String, MatchingRule>();
   }
 
 
@@ -151,11 +150,13 @@
   /**
    * Adds a new mapping of OID and MatchingRule.
    *
-   * @param oid OID of the matching rule
-   * @param matchingRule instance of a MatchingRule.
+   * @param oid
+   *          OID of the matching rule
+   * @param matchingRule
+   *          instance of a MatchingRule.
    */
   private final void addMatchingRule(String oid,
-          MatchingRule matchingRule)
+      MatchingRule matchingRule)
   {
     matchingRules.put(oid, matchingRule);
   }
@@ -165,8 +166,9 @@
   /**
    * Returns the Matching rule for the specified OID.
    *
-   * @param oid OID of the matching rule to be searched.
-   * @return  MatchingRule corresponding to an OID.
+   * @param oid
+   *          OID of the matching rule to be searched.
+   * @return MatchingRule corresponding to an OID.
    */
   private final MatchingRule getMatchingRule(String oid)
   {
@@ -175,7 +177,6 @@
 
 
 
-
   /**
    * Clears the Map containing matching Rules.
    */
@@ -189,35 +190,36 @@
   /**
    * Reads the configuration and initializes matching rule types.
    *
-   * @param  ruleTypes  The Set containing allowed matching rule types.
+   * @param ruleTypes
+   *          The Set containing allowed matching rule types.
    */
-  private void initializeMatchingRuleTypes(SortedSet<MatchingRuleType>
-          ruleTypes)
+  private void initializeMatchingRuleTypes(
+      SortedSet<MatchingRuleType> ruleTypes)
   {
-    for(MatchingRuleType type:ruleTypes)
+    for (MatchingRuleType type : ruleTypes)
     {
-      switch(type)
+      switch (type)
       {
-        case EQUALITY:
-          equalityMatchingRuleType = true;
-          break;
-        case LESS_THAN:
-          lessThanMatchingRuleType = true;
-          break;
-        case LESS_THAN_OR_EQUAL_TO:
-          lessThanEqualToMatchingRuleType = true;
-          break;
-        case GREATER_THAN:
-          greaterThanMatchingRuleType = true;
-          break;
-        case GREATER_THAN_OR_EQUAL_TO:
-          greaterThanEqualToMatchingRuleType = true;
-          break;
-        case SUBSTRING:
-          substringMatchingRuleType = true;
-          break;
-        default:
-        //No default values allowed.
+      case EQUALITY:
+        equalityMatchingRuleType = true;
+        break;
+      case LESS_THAN:
+        lessThanMatchingRuleType = true;
+        break;
+      case LESS_THAN_OR_EQUAL_TO:
+        lessThanEqualToMatchingRuleType = true;
+        break;
+      case GREATER_THAN:
+        greaterThanMatchingRuleType = true;
+        break;
+      case GREATER_THAN_OR_EQUAL_TO:
+        greaterThanEqualToMatchingRuleType = true;
+        break;
+      case SUBSTRING:
+        substringMatchingRuleType = true;
+        break;
+      default:
+        // No default values allowed.
       }
     }
   }
@@ -227,7 +229,8 @@
   /**
    * Creates a new Collator instance.
    *
-   * @param locale Locale for the collator
+   * @param locale
+   *          Locale for the collator
    * @return Returns a new Collator instance
    */
   private Collator createCollator(Locale locale)
@@ -244,49 +247,52 @@
    * {@inheritDoc}
    */
   @Override
-  public void initializeMatchingRule(CollationMatchingRuleCfg configuration)
-  throws ConfigException, InitializationException
+  public void initializeMatchingRule(
+      CollationMatchingRuleCfg configuration) throws ConfigException,
+      InitializationException
   {
     initializeMatchingRuleTypes(configuration.getMatchingRuleType());
-    for(String collation:configuration.getCollation())
+    for (String collation : configuration.getCollation())
     {
       CollationMapper mapper = new CollationMapper(collation);
 
       String nOID = mapper.getNumericOID();
       String languageTag = mapper.getLanguageTag();
-      if(nOID==null || languageTag==null)
+      if (nOID == null || languageTag == null)
       {
         Message msg =
-                WARN_ATTR_INVALID_COLLATION_MATCHING_RULE_FORMAT.
-                get(collation);
+            WARN_ATTR_INVALID_COLLATION_MATCHING_RULE_FORMAT
+                .get(collation);
         logError(msg);
         continue;
       }
 
       Locale locale = getLocale(languageTag);
-      if(locale!=null)
+      if (locale != null)
       {
-        createLessThanMatchingRule(mapper,locale);
-        createLessThanOrEqualToMatchingRule(mapper,locale);
-        createEqualityMatchingRule(mapper,locale);
-        createGreaterThanOrEqualToMatchingRule(mapper,locale);
-        createGreaterThanMatchingRule(mapper,locale);
-        createSubstringMatchingRule(mapper,locale);
+        createLessThanMatchingRule(mapper, locale);
+        createLessThanOrEqualToMatchingRule(mapper, locale);
+        createEqualityMatchingRule(mapper, locale);
+        createGreaterThanOrEqualToMatchingRule(mapper, locale);
+        createGreaterThanMatchingRule(mapper, locale);
+        createSubstringMatchingRule(mapper, locale);
       }
       else
       {
-        //This locale is not supported by JVM.
+        // This locale is not supported by JVM.
         Message msg =
-              WARN_ATTR_INVALID_COLLATION_MATCHING_RULE_LOCALE.
-              get(collation,configuration.dn().toNormalizedString(),
+            WARN_ATTR_INVALID_COLLATION_MATCHING_RULE_LOCALE.get(
+                collation, configuration.dn().toNormalizedString(),
                 languageTag);
 
         logError(msg);
       }
     }
-    //Save this configuration.
+
+    // Save this configuration.
     currentConfig = configuration;
-    //Register for change events.
+
+    // Register for change events.
     currentConfig.addCollationChangeListener(this);
   }
 
@@ -298,7 +304,7 @@
   @Override
   public void finalizeMatchingRule()
   {
-    //De-register the listener.
+    // De-register the listener.
     currentConfig.removeCollationChangeListener(this);
   }
 
@@ -308,64 +314,68 @@
    * {@inheritDoc}
    */
   public ConfigChangeResult applyConfigurationChange(
-                                 CollationMatchingRuleCfg configuration)
+      CollationMatchingRuleCfg configuration)
   {
-    ResultCode        resultCode          = ResultCode.SUCCESS;
-    boolean           adminActionRequired = false;
-    ArrayList<Message> messages            = new ArrayList<Message>();
+    ResultCode resultCode = ResultCode.SUCCESS;
+    boolean adminActionRequired = false;
+    ArrayList<Message> messages = new ArrayList<Message>();
 
-    if(!configuration.isEnabled() ||
-            currentConfig.isEnabled()!=configuration.isEnabled())
+    if (!configuration.isEnabled()
+        || currentConfig.isEnabled() != configuration.isEnabled())
     {
-      //Don't do anything if:
+      // Don't do anything if:
       // 1. The configuration is disabled.
       // 2. There is a change in the enable status
-      //  i.e. (disable->enable or enable->disable). In this case, the
-      //     ConfigManager will have already created the new Factory object.
-      return new ConfigChangeResult(resultCode,
-              adminActionRequired, messages);
+      // i.e. (disable->enable or enable->disable). In this case, the
+      // ConfigManager will have already created the new Factory object.
+      return new ConfigChangeResult(resultCode, adminActionRequired,
+          messages);
     }
 
-    //Since we have come here it means that this Factory is enabled and
-    //there is a change in the CollationMatchingRuleFactory's configuration.
-    // Deregister all the Matching Rule corresponding to this factory..
-    for(MatchingRule rule: getMatchingRules())
+    // Since we have come here it means that this Factory is enabled and
+    // there is a change in the CollationMatchingRuleFactory's
+    // configuration.
+    // Deregister all the Matching Rule corresponding to this factory.
+    for (MatchingRule rule : getMatchingRules())
     {
       DirectoryServer.deregisterMatchingRule(rule);
     }
-    //Clear the associated matching rules.
+
+    // Clear the associated matching rules.
     resetRules();
 
     initializeMatchingRuleTypes(configuration.getMatchingRuleType());
-    for(String collation:configuration.getCollation())
+    for (String collation : configuration.getCollation())
     {
       CollationMapper mapper = new CollationMapper(collation);
       String languageTag = mapper.getLanguageTag();
       Locale locale = getLocale(languageTag);
-      createLessThanMatchingRule(mapper,locale);
-      createLessThanOrEqualToMatchingRule(mapper,locale);
-      createEqualityMatchingRule(mapper,locale);
-      createGreaterThanOrEqualToMatchingRule(mapper,locale);
-      createGreaterThanMatchingRule(mapper,locale);
-      createSubstringMatchingRule(mapper,locale);
+      createLessThanMatchingRule(mapper, locale);
+      createLessThanOrEqualToMatchingRule(mapper, locale);
+      createEqualityMatchingRule(mapper, locale);
+      createGreaterThanOrEqualToMatchingRule(mapper, locale);
+      createGreaterThanMatchingRule(mapper, locale);
+      createSubstringMatchingRule(mapper, locale);
     }
 
     try
     {
-      for(MatchingRule matchingRule: getMatchingRules())
+      for (MatchingRule matchingRule : getMatchingRules())
       {
         DirectoryServer.registerMatchingRule(matchingRule, false);
       }
     }
     catch (DirectoryException de)
     {
-      Message message = WARN_CONFIG_SCHEMA_MR_CONFLICTING_MR.get(
-              String.valueOf(configuration.dn()), de.getMessageObject());
+      Message message =
+          WARN_CONFIG_SCHEMA_MR_CONFLICTING_MR.get(String
+              .valueOf(configuration.dn()), de.getMessageObject());
       adminActionRequired = true;
       messages.add(message);
     }
     currentConfig = configuration;
-    return new ConfigChangeResult(resultCode, adminActionRequired, messages);
+    return new ConfigChangeResult(resultCode, adminActionRequired,
+        messages);
   }
 
 
@@ -374,44 +384,45 @@
    * {@inheritDoc}
    */
   public boolean isConfigurationChangeAcceptable(
-          CollationMatchingRuleCfg configuration,
-                      List<Message> unacceptableReasons)
+      CollationMatchingRuleCfg configuration,
+      List<Message> unacceptableReasons)
   {
     boolean configAcceptable = true;
 
-    //If the new configuration disables this factory, don't do anything.
-    if(!configuration.isEnabled())
+    // If the new configuration disables this factory, don't do
+    // anything.
+    if (!configuration.isEnabled())
     {
       return configAcceptable;
     }
 
-
-    //If it comes here we don't need to verify MatchingRuleType; it should be
-    //okay as its syntax is verified by the admin framework. Iterate over the
-    //collations and verify if the format is okay. Also, verify if the
-    //locale is allowed by the JVM.
-    for(String collation:configuration.getCollation())
+    // If it comes here we don't need to verify MatchingRuleType; it
+    // should be okay as its syntax is verified by the admin framework.
+    // Iterate over the collations and verify if the format is okay.
+    // Also,
+    // verify if the locale is allowed by the JVM.
+    for (String collation : configuration.getCollation())
     {
       CollationMapper mapper = new CollationMapper(collation);
 
       String nOID = mapper.getNumericOID();
       String languageTag = mapper.getLanguageTag();
-      if(nOID==null || languageTag==null)
+      if (nOID == null || languageTag == null)
       {
         configAcceptable = false;
         Message msg =
-                WARN_ATTR_INVALID_COLLATION_MATCHING_RULE_FORMAT.
-                get(collation);
+            WARN_ATTR_INVALID_COLLATION_MATCHING_RULE_FORMAT
+                .get(collation);
         unacceptableReasons.add(msg);
         continue;
       }
 
       Locale locale = getLocale(languageTag);
-      if(locale==null)
+      if (locale == null)
       {
         Message msg =
-              WARN_ATTR_INVALID_COLLATION_MATCHING_RULE_LOCALE.
-              get(collation,configuration.dn().toNormalizedString(),
+            WARN_ATTR_INVALID_COLLATION_MATCHING_RULE_LOCALE.get(
+                collation, configuration.dn().toNormalizedString(),
                 languageTag);
         unacceptableReasons.add(msg);
         configAcceptable = false;
@@ -426,31 +437,34 @@
   /**
    * Creates Less-than Matching Rule.
    *
-   * @param mapper CollationMapper containing OID and the language Tag.
-   * @param locale  Locale value
+   * @param mapper
+   *          CollationMapper containing OID and the language Tag.
+   * @param locale
+   *          Locale value
    */
-  private void createLessThanMatchingRule(CollationMapper mapper,Locale locale)
+  private void createLessThanMatchingRule(CollationMapper mapper,
+      Locale locale)
   {
-    if(!lessThanMatchingRuleType)
-      return;
+    if (!lessThanMatchingRuleType) return;
 
-    String oid = mapper.getNumericOID()+".1";
+    String oid = mapper.getNumericOID() + ".1";
     String lTag = mapper.getLanguageTag();
 
     Collection<String> names = new HashSet<String>();
     MatchingRule matchingRule = getMatchingRule(oid);
-    if(matchingRule!=null)
+    if (matchingRule != null)
     {
-      for(String name: matchingRule.getAllNames())
+      for (String name : matchingRule.getAllNames())
       {
         names.add(name);
       }
     }
 
-    names.add(lTag+".lt");
+    names.add(lTag + ".lt");
     names.add(lTag + ".1");
 
-    matchingRule = new CollationLessThanMatchingRule(oid, names, locale);
+    matchingRule =
+        new CollationLessThanMatchingRule(oid, names, locale);
     addMatchingRule(oid, matchingRule);
   }
 
@@ -459,33 +473,34 @@
   /**
    * Creates Less-Than-Equal-To Matching Rule.
    *
-   * @param mapper CollationMapper containing OID and the language Tag.
-   * @param locale  Locale value
+   * @param mapper
+   *          CollationMapper containing OID and the language Tag.
+   * @param locale
+   *          Locale value
    */
-  private void createLessThanOrEqualToMatchingRule(CollationMapper mapper,
-          Locale locale)
+  private void createLessThanOrEqualToMatchingRule(
+      CollationMapper mapper, Locale locale)
   {
-    if(!lessThanEqualToMatchingRuleType)
-      return;
+    if (!lessThanEqualToMatchingRuleType) return;
 
-    String oid = mapper.getNumericOID()+".2";
+    String oid = mapper.getNumericOID() + ".2";
     String lTag = mapper.getLanguageTag();
 
     Collection<String> names = new HashSet<String>();
     MatchingRule matchingRule = getMatchingRule(oid);
-    if(matchingRule!=null)
+    if (matchingRule != null)
     {
-      for(String name: matchingRule.getAllNames())
+      for (String name : matchingRule.getAllNames())
       {
         names.add(name);
       }
     }
 
-    names.add(lTag+".lte");
+    names.add(lTag + ".lte");
     names.add(lTag + ".2");
 
     matchingRule =
-            new CollationLessThanOrEqualToMatchingRule(oid,names,locale);
+        new CollationLessThanOrEqualToMatchingRule(oid, names, locale);
     addMatchingRule(oid, matchingRule);
   }
 
@@ -494,22 +509,28 @@
   /**
    * Creates Equality Matching Rule.
    *
-   * @param mapper CollationMapper containing OID and the language Tag.
-   * @param locale  Locale value
+   * @param mapper
+   *          CollationMapper containing OID and the language Tag.
+   * @param locale
+   *          Locale value
    */
-  private void createEqualityMatchingRule(CollationMapper mapper,Locale locale)
+  private void createEqualityMatchingRule(CollationMapper mapper,
+      Locale locale)
   {
-    if(!equalityMatchingRuleType)
+    if (!equalityMatchingRuleType)
+    {
       return;
-    //Register the default OID as equality matching rule.
+    }
+
+    // Register the default OID as equality matching rule.
     String lTag = mapper.getLanguageTag();
     String nOID = mapper.getNumericOID();
 
     MatchingRule matchingRule = getMatchingRule(nOID);
     Collection<String> names = new HashSet<String>();
-    if(matchingRule!=null)
+    if (matchingRule != null)
     {
-      for(String name: matchingRule.getAllNames())
+      for (String name : matchingRule.getAllNames())
       {
         names.add(name);
       }
@@ -517,26 +538,26 @@
 
     names.add(lTag);
     matchingRule =
-          new CollationEqualityMatchingRule(nOID,
-                  Collections.<String>emptySet(),locale);
+        new CollationEqualityMatchingRule(nOID, Collections
+            .<String> emptySet(), locale);
     addMatchingRule(nOID, matchingRule);
 
     // Register OID.3 as the equality matching rule.
     String OID = mapper.getNumericOID() + ".3";
     MatchingRule equalityMatchingRule = getMatchingRule(OID);
-    if(equalityMatchingRule!=null)
+    if (equalityMatchingRule != null)
     {
-      for(String name: equalityMatchingRule.getAllNames())
+      for (String name : equalityMatchingRule.getAllNames())
       {
         names.add(name);
       }
     }
 
-    names.add(lTag+".eq");
-    names.add(lTag+".3");
+    names.add(lTag + ".eq");
+    names.add(lTag + ".3");
 
     equalityMatchingRule =
-          new CollationEqualityMatchingRule(OID,names,locale);
+        new CollationEqualityMatchingRule(OID, names, locale);
     addMatchingRule(OID, equalityMatchingRule);
   }
 
@@ -545,32 +566,34 @@
   /**
    * Creates Greater-than-equal-to Matching Rule.
    *
-   * @param mapper CollationMapper containing OID and the language Tag.
-   * @param locale  Locale value
+   * @param mapper
+   *          CollationMapper containing OID and the language Tag.
+   * @param locale
+   *          Locale value
    */
-  private void createGreaterThanOrEqualToMatchingRule(CollationMapper mapper,
-          Locale locale)
+  private void createGreaterThanOrEqualToMatchingRule(
+      CollationMapper mapper, Locale locale)
   {
-    if(!greaterThanEqualToMatchingRuleType)
-      return;
+    if (!greaterThanEqualToMatchingRuleType) return;
 
-    String oid = mapper.getNumericOID()+".4";
+    String oid = mapper.getNumericOID() + ".4";
     String lTag = mapper.getLanguageTag();
 
     Collection<String> names = new HashSet<String>();
     MatchingRule matchingRule = getMatchingRule(oid);
-    if(matchingRule!=null)
+    if (matchingRule != null)
     {
-      for(String name: matchingRule.getAllNames())
+      for (String name : matchingRule.getAllNames())
       {
         names.add(name);
       }
     }
 
-    names.add(lTag+".gte");
+    names.add(lTag + ".gte");
     names.add(lTag + ".4");
     matchingRule =
-          new CollationGreaterThanOrEqualToMatchingRule(oid,names,locale);
+        new CollationGreaterThanOrEqualToMatchingRule(oid, names,
+            locale);
     addMatchingRule(oid, matchingRule);
   }
 
@@ -579,32 +602,33 @@
   /**
    * Creates Greater-than Matching Rule.
    *
-   * @param mapper CollationMapper containing OID and the language Tag.
-   * @param locale  Locale value
+   * @param mapper
+   *          CollationMapper containing OID and the language Tag.
+   * @param locale
+   *          Locale value
    */
   private void createGreaterThanMatchingRule(CollationMapper mapper,
-          Locale locale)
+      Locale locale)
   {
-    if(!greaterThanMatchingRuleType)
-      return;
+    if (!greaterThanMatchingRuleType) return;
 
-    String oid = mapper.getNumericOID()+".5";
+    String oid = mapper.getNumericOID() + ".5";
     String lTag = mapper.getLanguageTag();
 
     Collection<String> names = new HashSet<String>();
     MatchingRule matchingRule = getMatchingRule(oid);
-    if(matchingRule!=null)
+    if (matchingRule != null)
     {
-      for(String name: matchingRule.getAllNames())
+      for (String name : matchingRule.getAllNames())
       {
         names.add(name);
       }
     }
 
-    names.add(lTag+".gt");
+    names.add(lTag + ".gt");
     names.add(lTag + ".5");
     matchingRule =
-          new CollationGreaterThanMatchingRule(oid,names,locale);
+        new CollationGreaterThanMatchingRule(oid, names, locale);
     addMatchingRule(oid, matchingRule);
   }
 
@@ -613,45 +637,47 @@
   /**
    * Creates substring Matching Rule.
    *
-   * @param mapper CollationMapper containing OID and the language Tag.
-   * @param locale  Locale value
+   * @param mapper
+   *          CollationMapper containing OID and the language Tag.
+   * @param locale
+   *          Locale value
    */
-  private void createSubstringMatchingRule(CollationMapper mapper,Locale locale)
+  private void createSubstringMatchingRule(CollationMapper mapper,
+      Locale locale)
   {
-    if(!substringMatchingRuleType)
-      return;
+    if (!substringMatchingRuleType) return;
 
-    String oid = mapper.getNumericOID()+".6";
+    String oid = mapper.getNumericOID() + ".6";
     String lTag = mapper.getLanguageTag();
 
     Collection<String> names = new HashSet<String>();
     MatchingRule matchingRule = getMatchingRule(oid);
-    if(matchingRule!=null)
+    if (matchingRule != null)
     {
-      for(String name: matchingRule.getAllNames())
+      for (String name : matchingRule.getAllNames())
       {
         names.add(name);
       }
     }
-    names.add(lTag+".sub");
+    names.add(lTag + ".sub");
     names.add(lTag + ".6");
     matchingRule =
-          new CollationSubstringMatchingRule(oid,names,locale);
+        new CollationSubstringMatchingRule(oid, names, locale);
     addMatchingRule(oid, matchingRule);
   }
 
 
 
-
   /**
    * Verifies if the locale is supported by the JVM.
    *
-   * @param  lTag  The language tag specified in the configuration.
-   * @return  Locale The locale correspoding to the languageTag.
+   * @param lTag
+   *          The language tag specified in the configuration.
+   * @return Locale The locale correspoding to the languageTag.
    */
   private Locale getLocale(String lTag)
   {
-    //Separates the language and the country from the locale.
+    // Separates the language and the country from the locale.
     Locale locale;
     String lang = null;
     String country = null;
@@ -660,20 +686,20 @@
     int countryIndex = lTag.indexOf("-");
     int variantIndex = lTag.lastIndexOf("-");
 
-    if(countryIndex > 0)
+    if (countryIndex > 0)
     {
-      lang = lTag.substring(0,countryIndex);
+      lang = lTag.substring(0, countryIndex);
 
-      if(variantIndex>countryIndex)
+      if (variantIndex > countryIndex)
       {
-        country = lTag.substring(countryIndex+1,variantIndex);
-        variant = lTag.substring(variantIndex+1,lTag.length());
-        locale = new Locale(lang,country,variant);
+        country = lTag.substring(countryIndex + 1, variantIndex);
+        variant = lTag.substring(variantIndex + 1, lTag.length());
+        locale = new Locale(lang, country, variant);
       }
       else
       {
-        country = lTag.substring(countryIndex+1,lTag.length());
-        locale = new Locale(lang,country);
+        country = lTag.substring(countryIndex + 1, lTag.length());
+        locale = new Locale(lang, country);
       }
     }
     else
@@ -682,9 +708,9 @@
       locale = new Locale(lTag);
     }
 
-    if(!supportedLocales.contains(locale))
+    if (!supportedLocales.contains(locale))
     {
-      //This locale is not supported by this JVM.
+      // This locale is not supported by this JVM.
       locale = null;
     }
     return locale;
@@ -695,30 +721,22 @@
   /**
    * Collation Extensible matching rule.
    */
-  private abstract class CollationMatchingRule
-          extends ExtensibleMatchingRule
+  private abstract class CollationMatchingRule extends
+      ExtensibleMatchingRule
   {
-    //Names for this class.
+    // Names for this class.
     private final Collection<String> names;
 
-
-
-    //Collator for performing equality match.
+    // Collator for performing equality match.
     protected final Collator collator;
 
-
-
-    //Numeric OID of the rule.
+    // Numeric OID of the rule.
     private final String nOID;
 
-
-
-    //Locale associated with this rule.
+    // Locale associated with this rule.
     private final Locale locale;
 
-
-
-    //Indexer of this rule.
+    // Indexer of this rule.
     protected ExtensibleIndexer indexer;
 
 
@@ -726,14 +744,16 @@
     /**
      * Constructs a new CollationMatchingRule.
      *
-     * @param nOID OID of the collation matching rule
-     * @param names names of this matching rule
-     * @param locale Locale of the collation matching rule
+     * @param nOID
+     *          OID of the collation matching rule
+     * @param names
+     *          names of this matching rule
+     * @param locale
+     *          Locale of the collation matching rule
      */
-    private CollationMatchingRule(String nOID,Collection<String> names,
-            Locale locale)
+    private CollationMatchingRule(String nOID,
+        Collection<String> names, Locale locale)
     {
-      super();
       this.names = names;
       this.collator = createCollator(locale);
       this.locale = locale;
@@ -748,9 +768,9 @@
     @Override
     public String getName()
     {
-      //Concatenate all the names and return.
+      // Concatenate all the names and return.
       StringBuilder builder = new StringBuilder();
-      for(String name: getAllNames())
+      for (String name : getAllNames())
       {
         builder.append(name);
         builder.append("\b");
@@ -806,12 +826,13 @@
 
 
     /**
-    * Returns the name of the index database for this matching rule.
-    * An index name for this rule will be based upon the Locale. This will
-    * ensure that multiple collation matching rules corresponding to the same
-    * Locale can share the same index database.
-    * @return  The name of the index for this matching rule.
-    */
+     * Returns the name of the index database for this matching rule. An
+     * index name for this rule will be based upon the Locale. This will
+     * ensure that multiple collation matching rules corresponding to
+     * the same Locale can share the same index database.
+     *
+     * @return The name of the index for this matching rule.
+     */
     public String getIndexName()
     {
       String language = locale.getLanguage();
@@ -833,42 +854,42 @@
 
 
 
-
     /**
      * {@inheritDoc}
      */
     @Override
     public Collection<ExtensibleIndexer> getIndexers(IndexConfig config)
     {
-      if(indexer == null)
+      if (indexer == null)
       {
-        //The default implementation contains shared indexer and doesn't use the
-        //config.
+        // The default implementation contains shared indexer and
+        // doesn't use the config.
         indexer = new CollationSharedExtensibleIndexer(this);
       }
       return Collections.singletonList(indexer);
     }
   }
 
-
-
   /**
-   *Collation rule for Equality matching rule.
+   * Collation rule for Equality matching rule.
    */
-  private final class CollationEqualityMatchingRule
-          extends CollationMatchingRule
+  private final class CollationEqualityMatchingRule extends
+      CollationMatchingRule
   {
     /**
      * Constructs a new CollationEqualityMatchingRule.
      *
-     * @param nOID OID of the collation matching rule
-     * @param names names of this matching rule
-     * @param locale Locale of the collation matching rule
+     * @param nOID
+     *          OID of the collation matching rule
+     * @param names
+     *          names of this matching rule
+     * @param locale
+     *          Locale of the collation matching rule
      */
-    private CollationEqualityMatchingRule(String nOID,Collection<String> names,
-            Locale locale)
+    private CollationEqualityMatchingRule(String nOID,
+        Collection<String> names, Locale locale)
     {
-      super(nOID,names,locale);
+      super(nOID, names, locale);
     }
 
 
@@ -877,30 +898,11 @@
      * {@inheritDoc}
      */
     @Override
-    public ByteString normalizeValue(ByteString value)
-           throws DirectoryException
+    public ByteString normalizeValue(ByteSequence value)
+        throws DirectoryException
     {
-      CollationKey key = collator.getCollationKey(value.stringValue());
-      return new ASN1OctetString(key.toByteArray());
-    }
-
-
-
-    /**
-     * Indicates whether the two provided normalized values are equal to
-     * each other.
-     *
-     * @param  value1  The normalized form of the first value to
-     *                 compare.
-     * @param  value2  The normalized form of the second value to
-     *                 compare.
-     *
-     * @return  {@code true} if the provided values are equal, or
-     *          {@code false} if not.
-     */
-    private boolean areEqual(ByteString value1, ByteString value2)
-    {
-      return Arrays.equals(value1.value(), value2.value());
+      CollationKey key = collator.getCollationKey(value.toString());
+      return ByteString.wrap(key.toByteArray());
     }
 
 
@@ -909,10 +911,10 @@
      * {@inheritDoc}
      */
     @Override
-    public ConditionResult valuesMatch(ByteString attributeValue,
-                                     ByteString assertionValue)
+    public ConditionResult valuesMatch(ByteSequence attributeValue,
+        ByteSequence assertionValue)
     {
-      if (areEqual(attributeValue, assertionValue))
+      if (assertionValue.equals(attributeValue))
       {
         return ConditionResult.TRUE;
       }
@@ -928,26 +930,22 @@
      * {@inheritDoc}
      */
     @Override
-    public <T> T createIndexQuery(ByteString assertionValue,
-            IndexQueryFactory<T> factory) throws DirectoryException
+    public <T> T createIndexQuery(ByteSequence assertionValue,
+        IndexQueryFactory<T> factory) throws DirectoryException
     {
-      //Normalize the assertion value.
-      ByteString normalValue = normalizeValue(assertionValue);
-      return factory.createExactMatchQuery(
-                indexer.getExtensibleIndexID(),
-                normalValue.value());
+      // Normalize the assertion value.
+      return factory.createExactMatchQuery(indexer
+          .getExtensibleIndexID(), normalizeValue(assertionValue));
     }
   }
 
-
-
   /**
    * Collation rule for Substring matching rule.
    */
-  private final class CollationSubstringMatchingRule
-          extends CollationMatchingRule
+  private final class CollationSubstringMatchingRule extends
+      CollationMatchingRule
   {
-    //Substring Indexer associated with this instance.
+    // Substring Indexer associated with this instance.
     private CollationSubstringExtensibleIndexer subIndexer;
 
 
@@ -955,14 +953,17 @@
     /**
      * Constructs a new CollationSubstringMatchingRule.
      *
-     * @param nOID OID of the collation matching rule
-     * @param names names of this matching rule
-     * @param locale Locale of the collation matching rule
+     * @param nOID
+     *          OID of the collation matching rule
+     * @param names
+     *          names of this matching rule
+     * @param locale
+     *          Locale of the collation matching rule
      */
     private CollationSubstringMatchingRule(String nOID,
-            Collection<String> names,Locale locale)
+        Collection<String> names, Locale locale)
     {
-      super(nOID,names,locale);
+      super(nOID, names, locale);
     }
 
 
@@ -971,11 +972,11 @@
      * {@inheritDoc}
      */
     @Override
-    public ByteString normalizeValue(ByteString value)
-           throws DirectoryException
+    public ByteString normalizeValue(ByteSequence value)
+        throws DirectoryException
     {
-      CollationKey key = collator.getCollationKey(value.stringValue());
-      return new ASN1OctetString(key.toByteArray());
+      CollationKey key = collator.getCollationKey(value.toString());
+      return ByteString.wrap(key.toByteArray());
     }
 
 
@@ -985,26 +986,29 @@
      */
     private final class Assertion
     {
-      //Initial part of the substring filter.
+      // Initial part of the substring filter.
       private String subInitial;
 
-
-      //any parts of the substring filter.
+      // any parts of the substring filter.
       private List<String> subAny;
 
-
-      //Final part of the substring filter.
+      // Final part of the substring filter.
       private String subFinal;
 
 
 
       /**
        * Creates a new instance of Assertion.
-       * @param subInitial Initial part of the filter.
-       * @param subAny  Any part of the filter.
-       * @param subFinal Final part of the filter.
+       *
+       * @param subInitial
+       *          Initial part of the filter.
+       * @param subAny
+       *          Any part of the filter.
+       * @param subFinal
+       *          Final part of the filter.
        */
-      Assertion(String subInitial, List<String> subAny, String subFinal)
+      private Assertion(String subInitial, List<String> subAny,
+          String subFinal)
       {
         this.subInitial = subInitial;
         this.subAny = subAny;
@@ -1015,6 +1019,7 @@
 
       /**
        * Returns the Initial part of the assertion.
+       *
        * @return Initial part of assertion.
        */
       private String getInitial()
@@ -1026,6 +1031,7 @@
 
       /**
        * Returns the any part of the assertion.
+       *
        * @return Any part of the assertion.
        */
       private List<String> getAny()
@@ -1037,6 +1043,7 @@
 
       /**
        * Returns the final part of the assertion.
+       *
        * @return Final part of the assertion.
        */
       private String getFinal()
@@ -1049,23 +1056,25 @@
 
     /**
      * Parses the assertion from a given value.
-     * @param value The value that needs to be parsed.
+     *
+     * @param value
+     *          The value that needs to be parsed.
      * @return The parsed Assertion object containing the
      * @throws org.opends.server.types.DirectoryException
      */
-    private Assertion parseAssertion(ByteString value)
-            throws DirectoryException
+    private Assertion parseAssertion(ByteSequence value)
+        throws DirectoryException
     {
-      // Get a string  representation of the value.
-      String filterString = value.stringValue();
+      // Get a string representation of the value.
+      String filterString = value.toString();
       int endPos = filterString.length();
 
-      // Find the locations of all the asterisks in the value.  Also,
+      // 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;
       LinkedList<Integer> asteriskPositions = new LinkedList<Integer>();
-      for (int i=0; i < endPos; i++)
+      for (int i = 0; i < endPos; i++)
       {
         if (filterString.charAt(i) == 0x2A) // The asterisk.
         {
@@ -1077,18 +1086,17 @@
         }
       }
 
-
       // If there were no asterisks, then this isn't a substring filter.
       if (asteriskPositions.isEmpty())
       {
-        Message message = ERR_SEARCH_FILTER_SUBSTRING_NO_ASTERISKS.get(
-                filterString, 0, endPos);
-        throw new DirectoryException(
-                ResultCode.PROTOCOL_ERROR, message);
+        Message message =
+            ERR_SEARCH_FILTER_SUBSTRING_NO_ASTERISKS.get(filterString,
+                0, endPos);
+        throw new DirectoryException(ResultCode.PROTOCOL_ERROR, message);
       }
 
       // If the value starts with an asterisk, then there is no
-      // subInitial component.  Otherwise, parse out the subInitial.
+      // subInitial component. Otherwise, parse out the subInitial.
       String subInitial;
       int firstPos = asteriskPositions.removeFirst();
       if (firstPos == 0)
@@ -1100,12 +1108,12 @@
         if (hasEscape)
         {
           CharBuffer buffer = CharBuffer.allocate(firstPos);
-          for (int i=0; i < firstPos; i++)
+          for (int i = 0; i < firstPos; i++)
           {
             if (filterString.charAt(i) == 0x5C)
             {
-              char escapeValue = hexToEscapedChar(filterString, i +1);
-              i +=2; //Move to the next sequence.
+              char escapeValue = hexToEscapedChar(filterString, i + 1);
+              i += 2; // Move to the next sequence.
               buffer.put(escapeValue);
             }
             else
@@ -1121,11 +1129,10 @@
         }
         else
         {
-          subInitial = filterString.substring(0,firstPos);
+          subInitial = filterString.substring(0, firstPos);
         }
       }
 
-
       // Next, process through the rest of the asterisks to get the
       // subAny values.
       List<String> subAny = new ArrayList<String>();
@@ -1136,12 +1143,12 @@
         if (hasEscape)
         {
           CharBuffer buffer = CharBuffer.allocate(length);
-          for (int i=firstPos+1; i < asteriskPos; i++)
+          for (int i = firstPos + 1; i < asteriskPos; i++)
           {
             if (filterString.charAt(i) == 0x5C)
             {
               char escapeValue = hexToEscapedChar(filterString, i + 1);
-              i +=2; //Move to the next sequence.
+              i += 2; // Move to the next sequence.
               buffer.put(escapeValue);
             }
             else
@@ -1157,18 +1164,17 @@
         }
         else
         {
-          subAny.add(filterString.substring(firstPos+1, firstPos+length+1));
+          subAny.add(filterString.substring(firstPos + 1, firstPos
+              + length + 1));
         }
 
-
         firstPos = asteriskPos;
       }
 
-
       // Finally, see if there is anything after the last asterisk,
       // which would be the subFinal value.
       String subFinal;
-      if (firstPos == (endPos-1))
+      if (firstPos == (endPos - 1))
       {
         subFinal = null;
       }
@@ -1179,12 +1185,12 @@
         if (hasEscape)
         {
           CharBuffer buffer = CharBuffer.allocate(length);
-          for (int i=firstPos+1; i < endPos; i++)
+          for (int i = firstPos + 1; i < endPos; i++)
           {
             if (filterString.charAt(i) == 0x5C)
             {
               char escapeValue = hexToEscapedChar(filterString, i + 1);
-              i +=2; //Move to the next sequence.
+              i += 2; // Move to the next sequence.
               buffer.put(escapeValue);
             }
             else
@@ -1200,9 +1206,12 @@
         }
         else
         {
-          subFinal = filterString.substring(firstPos+1, length + firstPos + 1);
+          subFinal =
+              filterString.substring(firstPos + 1, length + firstPos
+                  + 1);
         }
       }
+
       return new Assertion(subInitial, subAny, subFinal);
     }
 
@@ -1212,17 +1221,20 @@
      * {@inheritDoc}
      */
     @Override
-    public ByteString normalizeAssertionValue(ByteString value)
-            throws DirectoryException {
+    public ByteString normalizeAssertionValue(ByteSequence value)
+        throws DirectoryException
+    {
       Assertion assertion = parseAssertion(value);
       String subInitial = assertion.getInitial();
+
       // Normalize the Values in the following format:
-      // initialLength, initial, numberofany, anyLength1, any1, anyLength2,
-      // any2, ..., anyLengthn, anyn, finalLength, final
+      // initialLength, initial, numberofany, anyLength1, any1,
+      // anyLength2, any2, ..., anyLengthn, anyn, finalLength,
+      // final
       CollationKey key = null;
       List<Integer> normalizedList = new ArrayList<Integer>();
 
-      if(subInitial == null)
+      if (subInitial == null)
       {
         normalizedList.add(0);
       }
@@ -1230,33 +1242,37 @@
       {
         key = collator.getCollationKey(subInitial);
         byte[] initialBytes = key.toByteArray();
-        // Last 4 bytes are 0s with PRIMARY strenght.
-        int length = initialBytes.length - 4 ;
+
+        // Last 4 bytes are 0s with PRIMARY strength.
+        int length = initialBytes.length - 4;
         normalizedList.add(length);
-        for(int i=0;i<length;i++)
+        for (int i = 0; i < length; i++)
         {
-          normalizedList.add((int)initialBytes[i]);
+          normalizedList.add((int) initialBytes[i]);
         }
       }
+
       List<String> subAny = assertion.getAny();
-      if (subAny.size() == 0) {
+      if (subAny.size() == 0)
+      {
         normalizedList.add(0);
       }
       else
       {
         normalizedList.add(subAny.size());
-        for(String any:subAny)
+        for (String any : subAny)
         {
           key = collator.getCollationKey(any);
           byte[] anyBytes = key.toByteArray();
           int length = anyBytes.length - 4;
           normalizedList.add(length);
-          for(int i=0;i<length;i++)
+          for (int i = 0; i < length; i++)
           {
-            normalizedList.add((int)anyBytes[i]);
+            normalizedList.add((int) anyBytes[i]);
           }
         }
       }
+
       String subFinal = assertion.getFinal();
       if (subFinal == null)
       {
@@ -1268,18 +1284,19 @@
         byte[] subFinalBytes = key.toByteArray();
         int length = subFinalBytes.length - 4;
         normalizedList.add(length);
-        for(int i=0;i<length;i++)
+        for (int i = 0; i < length; i++)
         {
-          normalizedList.add((int)subFinalBytes[i]);
+          normalizedList.add((int) subFinalBytes[i]);
         }
       }
 
       byte[] normalizedBytes = new byte[normalizedList.size()];
-      for(int i=0;i<normalizedList.size();i++)
+      for (int i = 0; i < normalizedList.size(); i++)
       {
         normalizedBytes[i] = normalizedList.get(i).byteValue();
       }
-      return new ASN1OctetString(normalizedBytes);
+
+      return ByteString.wrap(normalizedBytes);
     }
 
 
@@ -1288,69 +1305,68 @@
      * {@inheritDoc}
      */
     @Override
-    public ConditionResult valuesMatch(ByteString attributeValue,
-                                       ByteString assertionValue)
+    public ConditionResult valuesMatch(ByteSequence attributeValue,
+        ByteSequence assertionValue)
     {
-      byte[] valueBytes = attributeValue.value();
-      int valueLength = valueBytes.length - 4;
-
-      byte[] assertionBytes = assertionValue.value();
-
+      int valueLength = attributeValue.length() - 4;
       int valuePos = 0; // position in the value bytes array.
       int assertPos = 0; // position in the assertion bytes array.
-      int subInitialLength = 0xFF & assertionBytes[0];
-      //First byte is the length of subInitial.
 
-      if(subInitialLength!= 0)
+      // First byte is the length of subInitial.
+      int subInitialLength = 0xFF & assertionValue.byteAt(0);
+
+      if (subInitialLength != 0)
       {
-        if(subInitialLength > valueLength)
+        if (subInitialLength > valueLength)
         {
           return ConditionResult.FALSE;
         }
 
-        for(;valuePos < subInitialLength; valuePos++)
+        for (; valuePos < subInitialLength; valuePos++)
         {
-          if(valueBytes[valuePos]!=assertionBytes[valuePos+1])
+          if (attributeValue.byteAt(valuePos) != assertionValue
+              .byteAt(valuePos + 1))
           {
             return ConditionResult.FALSE;
           }
         }
       }
+
       assertPos = subInitialLength + 1;
-      int anySize = 0xFF & assertionBytes[assertPos++];
-      if(anySize!=0)
+      int anySize = 0xFF & assertionValue.byteAt(assertPos++);
+      if (anySize != 0)
       {
-        while(anySize-- > 0)
+        while (anySize-- > 0)
         {
-          int anyLength = 0xFF & assertionBytes[assertPos++];
+          int anyLength = 0xFF & assertionValue.byteAt(assertPos++);
           int end = valueLength - anyLength;
           boolean match = false;
-          for(; valuePos <= end; valuePos++)
-          {
 
-            if(assertionBytes[assertPos] == valueBytes[valuePos])
+          for (; valuePos <= end; valuePos++)
+          {
+            if (assertionValue.byteAt(assertPos) == attributeValue
+                .byteAt(valuePos))
             {
               boolean subMatch = true;
-              for(int i=1;i<anyLength;i++)
+              for (int i = 1; i < anyLength; i++)
               {
-
-                if(assertionBytes[assertPos+i] != valueBytes[valuePos+i])
+                if (assertionValue.byteAt(assertPos + i) != attributeValue
+                    .byteAt(valuePos + i))
                 {
                   subMatch = false;
                   break;
                 }
               }
 
-              if(subMatch)
+              if (subMatch)
               {
                 match = subMatch;
                 break;
               }
-
             }
           }
 
-          if(match)
+          if (match)
           {
             valuePos += anyLength;
           }
@@ -1358,30 +1374,32 @@
           {
             return ConditionResult.FALSE;
           }
+
           assertPos = assertPos + anyLength;
         }
       }
 
-      int finalLength = 0xFF & assertionBytes[assertPos++];
-      if(finalLength!=0)
+      int finalLength = 0xFF & assertionValue.byteAt(assertPos++);
+      if (finalLength != 0)
       {
-        if((valueLength - finalLength) < valuePos)
+        if ((valueLength - finalLength) < valuePos)
         {
           return ConditionResult.FALSE;
         }
 
         valuePos = valueLength - finalLength;
 
-        if(finalLength != assertionBytes.length - assertPos )
+        if (finalLength != assertionValue.length() - assertPos)
         {
-          //Some issue with the encoding.
+          // Some issue with the encoding.
           return ConditionResult.FALSE;
         }
 
         valuePos = valueLength - finalLength;
-        for (int i=0; i < finalLength; i++,valuePos++)
+        for (int i = 0; i < finalLength; i++, valuePos++)
         {
-          if (assertionBytes[assertPos+i] != valueBytes[valuePos])
+          if (assertionValue.byteAt(assertPos + i) != attributeValue
+              .byteAt(valuePos))
           {
             return ConditionResult.FALSE;
           }
@@ -1397,37 +1415,41 @@
      * {@inheritDoc}
      */
     @Override
-    public final Collection<ExtensibleIndexer> getIndexers(IndexConfig config)
+    public final Collection<ExtensibleIndexer> getIndexers(
+        IndexConfig config)
     {
       Collection<ExtensibleIndexer> indexers =
-              new ArrayList<ExtensibleIndexer>();
-      int substrLength = 6; //Default substring length;
-      if(subIndexer == null)
+          new ArrayList<ExtensibleIndexer>();
+      int substrLength = 6; // Default substring length;
+      if (subIndexer == null)
       {
-        if(config != null)
+        if (config != null)
         {
           substrLength = config.getSubstringLength();
         }
-        subIndexer = new CollationSubstringExtensibleIndexer(this,
-                substrLength);
+        subIndexer =
+            new CollationSubstringExtensibleIndexer(this, substrLength);
       }
       else
       {
-        if(config !=null)
+        if (config != null)
         {
-          if(config.getSubstringLength() !=subIndexer.gerSubstringLength())
+          if (config.getSubstringLength() != subIndexer
+              .gerSubstringLength())
           {
             subIndexer.setSubstringLength(substrLength);
           }
         }
       }
 
-      if(indexer == null)
+      if (indexer == null)
       {
         indexer = new CollationSharedExtensibleIndexer(this);
       }
+
       indexers.add(subIndexer);
       indexers.add(indexer);
+
       return indexers;
     }
 
@@ -1436,13 +1458,14 @@
     /**
      * Decomposes an attribute value into a set of substring index keys.
      *
-     * @param attValue Tthe normalized attribute value
-     * @param set A set into which the keys will be inserted.
+     * @param attValue
+     *          The normalized attribute value
+     * @param set
+     *          A set into which the keys will be inserted.
      */
-    private void subtringKeys(ByteString attValue,
-            Set<byte[]> keys)
+    private void subtringKeys(ByteString attValue, Set<byte[]> keys)
     {
-      String value = attValue.stringValue();
+      String value = attValue.toString();
       int keyLength = subIndexer.gerSubstringLength();
       for (int i = 0, remain = value.length(); remain > 0; i++, remain--)
       {
@@ -1457,17 +1480,18 @@
     /**
      * Decomposes an attribute value into a set of substring index keys.
      *
-     * @param value The normalized attribute value
-     * @param modifiedKeys The map into which the modified
-     *  keys will be inserted.
-     * @param insert <code>true</code> if generated keys should
-     * be inserted or <code>false</code> otherwise.
+     * @param value
+     *          The normalized attribute value
+     * @param modifiedKeys
+     *          The map into which the modified keys will be inserted.
+     * @param insert
+     *          <code>true</code> if generated keys should be inserted
+     *          or <code>false</code> otherwise.
      */
     private void substringKeys(ByteString attValue,
-            Map<byte[], Boolean> modifiedKeys,
-            Boolean insert)
+        Map<byte[], Boolean> modifiedKeys, Boolean insert)
     {
-      String value = attValue.stringValue();
+      String value = attValue.toString();
       int keyLength = subIndexer.gerSubstringLength();
       for (int i = 0, remain = value.length(); remain > 0; i++, remain--)
       {
@@ -1488,12 +1512,15 @@
 
 
     /**
-     * Makes a byte array representing a substring index key for
-     * one substring of a value.
+     * Makes a byte array representing a substring index key for one
+     * substring of a value.
      *
-     * @param value  The String containing the value.
-     * @param pos The starting position of the substring.
-     * @param len The length of the substring.
+     * @param value
+     *          The String containing the value.
+     * @param pos
+     *          The starting position of the substring.
+     * @param len
+     *          The length of the substring.
      * @return A byte array containing a substring key.
      */
     private byte[] makeSubstringKey(String value, int pos, int len)
@@ -1509,13 +1536,15 @@
 
 
     /**
-     * Uses an equality index to retrieve the entry IDs that might contain a
-     * given initial substring.
-     * @param bytes A normalized initial substring of an attribute value.
+     * Uses an equality index to retrieve the entry IDs that might
+     * contain a given initial substring.
+     *
+     * @param bytes
+     *          A normalized initial substring of an attribute value.
      * @return The candidate entry IDs.
      */
     private <T> T matchInitialSubstring(String value,
-            IndexQueryFactory<T> factory)
+        IndexQueryFactory<T> factory)
     {
       byte[] lower = makeSubstringKey(value, 0, value.length());
       byte[] upper = new byte[lower.length];
@@ -1535,26 +1564,27 @@
           break;
         }
       }
-      //Use the shared equality indexer.
-      return factory.createRangeMatchQuery(
-                              indexer.getExtensibleIndexID(),
-                              lower,
-                              upper,
-                              true,
-                              false);
+      // Use the shared equality indexer.
+      return factory.createRangeMatchQuery(indexer
+          .getExtensibleIndexID(), ByteString.wrap(lower), ByteString
+          .wrap(upper), true, false);
     }
 
 
 
     /**
      * Retrieves the Index Records that might contain a given substring.
-     * @param value A String representing  the attribute value.
-     * @param factory An IndexQueryFactory which issues calls to the backend.
-     * @param substrLength The length of the substring.
+     *
+     * @param value
+     *          A String representing the attribute value.
+     * @param factory
+     *          An IndexQueryFactory which issues calls to the backend.
+     * @param substrLength
+     *          The length of the substring.
      * @return The candidate entry IDs.
      */
     private <T> T matchSubstring(String value,
-            IndexQueryFactory<T> factory)
+        IndexQueryFactory<T> factory)
     {
       T intersectionQuery = null;
       int substrLength = subIndexer.gerSubstringLength();
@@ -1567,9 +1597,11 @@
         {
           if (upper[i] == 0xFF)
           {
-            // We have to carry the overflow to the more significant byte.
+            // We have to carry the overflow to the more significant
+            // byte.
             upper[i] = 0;
-          } else
+          }
+          else
           {
             // No overflow, we can stop.
             upper[i] = (byte) (upper[i] + 1);
@@ -1578,20 +1610,18 @@
         }
         // Read the range: lower <= keys < upper.
         intersectionQuery =
-                factory.createRangeMatchQuery(
-                subIndexer.getExtensibleIndexID(),
-                lower,
-                upper,
-                true,
-                false);
+            factory.createRangeMatchQuery(subIndexer
+                .getExtensibleIndexID(), ByteString.wrap(lower),
+                ByteString.wrap(upper), true, false);
       }
       else
       {
         List<T> queryList = new ArrayList<T>();
         Set<byte[]> set =
-                new TreeSet<byte[]>(new AttributeIndex.KeyComparator());
+            new TreeSet<byte[]>(new AttributeIndex.KeyComparator());
         for (int first = 0, last = substrLength;
-                last <= value.length(); first++, last++)
+             last <= value.length();
+             first++, last++)
         {
           byte[] keyBytes;
           keyBytes = makeSubstringKey(value, first, substrLength);
@@ -1600,13 +1630,12 @@
 
         for (byte[] keyBytes : set)
         {
-          T single = factory.createExactMatchQuery(
-                  subIndexer.getExtensibleIndexID(),
-                  keyBytes);
+          T single =
+              factory.createExactMatchQuery(subIndexer
+                  .getExtensibleIndexID(), ByteString.wrap(keyBytes));
           queryList.add(single);
         }
-        intersectionQuery =
-                factory.createIntersectionQuery(queryList);
+        intersectionQuery = factory.createIntersectionQuery(queryList);
       }
       return intersectionQuery;
     }
@@ -1617,8 +1646,8 @@
      * {@inheritDoc}
      */
     @Override
-    public <T> T createIndexQuery(ByteString assertionValue,
-            IndexQueryFactory<T> factory) throws DirectoryException
+    public <T> T createIndexQuery(ByteSequence assertionValue,
+        IndexQueryFactory<T> factory) throws DirectoryException
     {
       Assertion assertion = parseAssertion(assertionValue);
       String subInitial = assertion.getInitial();
@@ -1628,14 +1657,14 @@
 
       if (subInitial == null && subAny.size() == 0 && subFinal == null)
       {
-        //Can happen with a filter like "cn:en.6:=*".
-        //Just return an empty record.
+        // Can happen with a filter like "cn:en.6:=*".
+        // Just return an empty record.
         return factory.createMatchAllQuery();
       }
       List<String> elements = new ArrayList<String>();
       if (subInitial != null)
       {
-        //Always use the shared indexer for initial match.
+        // Always use the shared indexer for initial match.
         T query = matchInitialSubstring(subInitial, factory);
         queries.add(query);
       }
@@ -1650,7 +1679,6 @@
         elements.add(subFinal);
       }
 
-
       for (String element : elements)
       {
         queries.add(matchSubstring(element, factory));
@@ -1659,126 +1687,75 @@
     }
   }
 
-
-
   /**
-   *An abstract Collation rule for Ordering  matching rule.
+   * An abstract Collation rule for Ordering matching rule.
    */
-  private abstract class CollationOrderingMatchingRule
-          extends CollationMatchingRule
+  private abstract class CollationOrderingMatchingRule extends
+      CollationMatchingRule
   {
     /**
      * Constructs a new CollationOrderingMatchingRule.
      *
-     * @param nOID OID of the collation matching rule
-     * @param names names of this matching rule
-     * @param locale Locale of the collation matching rule
+     * @param nOID
+     *          OID of the collation matching rule
+     * @param names
+     *          names of this matching rule
+     * @param locale
+     *          Locale of the collation matching rule
      */
     private CollationOrderingMatchingRule(String nOID,
-            Collection<String> names, Locale locale)
-    {
-      super(nOID,names,locale);
-    }
-
-
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public ByteString normalizeValue(ByteString value)
-           throws DirectoryException
-    {
-      CollationKey key = collator.getCollationKey(value.stringValue());
-      return new ASN1OctetString(key.toByteArray());
-    }
-
-
-
-    /**
-     * Compares the first value to the second and returns a value that
-     * indicates their relative order.
-     *
-     * @param  b1  The normalized form of the first value to
-     *                 compare.
-     * @param  b2  The normalized form of the second value to
-     *                 compare.
-     *
-     * @return  A negative integer if {@code value1} should come before
-     *          {@code value2} in ascending order, a positive integer if
-     *          {@code value1} should come after {@code value2} in
-     *          ascending order, or zero if there is no difference
-     *          between the values with regard to ordering.
-     */
-    protected int compare(byte[] b1, byte[] b2) {
-      //Compare values using byte arrays.
-      int minLength = Math.min(b1.length, b2.length);
-
-      for (int i=0; i < minLength; i++)
-      {
-        int firstByte = 0xFF & ((int)b1[i]);
-        int secondByte = 0xFF & ((int)b2[i]);
-
-        if (firstByte == secondByte)
-        {
-          continue;
-        }
-        else if (firstByte < secondByte)
-        {
-          return -1;
-        }
-        else if (firstByte > secondByte)
-        {
-          return 1;
-        }
-      }
-
-      if (b1.length == b2.length)
-      {
-        return 0;
-      }
-      else if (b1.length < b2.length)
-      {
-        return -1;
-      }
-      else
-      {
-        return 1;
-      }
-    }
-  }
-
-  /**
-   * Collation matching rule for Less-than matching rule.
-   */
-  private final class CollationLessThanMatchingRule
-          extends CollationOrderingMatchingRule
-  {
-
-    /**
-     * Constructs a new CollationLessThanMatchingRule.
-     *
-     * @param nOID OID of the collation matching rule
-     * @param names names of this matching rule
-     * @param locale Locale of the collation matching rule
-     */
-    private CollationLessThanMatchingRule(String nOID,
-            Collection<String> names, Locale locale)
+        Collection<String> names, Locale locale)
     {
       super(nOID, names, locale);
     }
 
 
 
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public ByteString normalizeValue(ByteSequence value)
+        throws DirectoryException
+    {
+      CollationKey key = collator.getCollationKey(value.toString());
+      return ByteString.wrap(key.toByteArray());
+    }
+  }
+
+  /**
+   * Collation matching rule for Less-than matching rule.
+   */
+  private final class CollationLessThanMatchingRule extends
+      CollationOrderingMatchingRule
+  {
+
+    /**
+     * Constructs a new CollationLessThanMatchingRule.
+     *
+     * @param nOID
+     *          OID of the collation matching rule
+     * @param names
+     *          names of this matching rule
+     * @param locale
+     *          Locale of the collation matching rule
+     */
+    private CollationLessThanMatchingRule(String nOID,
+        Collection<String> names, Locale locale)
+    {
+      super(nOID, names, locale);
+    }
+
+
 
     /**
      * {@inheritDoc}
      */
     @Override
-    public ConditionResult valuesMatch(ByteString attributeValue,
-            ByteString assertionValue)
+    public ConditionResult valuesMatch(ByteSequence attributeValue,
+        ByteSequence assertionValue)
     {
-      int ret = compare(attributeValue.value(), assertionValue.value());
+      int ret = attributeValue.compareTo(assertionValue);
 
       if (ret < 0)
       {
@@ -1792,58 +1769,52 @@
 
 
 
-
     /**
      * {@inheritDoc}
      */
     @Override
-    public <T> T createIndexQuery(ByteString assertionValue,
-            IndexQueryFactory<T> factory) throws DirectoryException
+    public <T> T createIndexQuery(ByteSequence assertionValue,
+        IndexQueryFactory<T> factory) throws DirectoryException
     {
-      byte[] lower = new byte[0];
-      byte[] upper = normalizeValue(assertionValue).value();
-      return factory.createRangeMatchQuery(indexer.getExtensibleIndexID(),
-              lower,
-              upper,
-              false,
-              false);
+      return factory.createRangeMatchQuery(indexer
+          .getExtensibleIndexID(), ByteString.empty(),
+          normalizeValue(assertionValue), false, false);
     }
   }
 
-
-
   /**
    * Collation rule for less-than-equal-to matching rule.
    */
-  private final class CollationLessThanOrEqualToMatchingRule
-          extends CollationOrderingMatchingRule
+  private final class CollationLessThanOrEqualToMatchingRule extends
+      CollationOrderingMatchingRule
   {
 
     /**
      * Constructs a new CollationLessThanOrEqualToMatchingRule.
      *
-     * @param nOID OID of the collation matching rule
-     * @param names names of this matching rule
-     * @param locale Locale of the collation matching rule
+     * @param nOID
+     *          OID of the collation matching rule
+     * @param names
+     *          names of this matching rule
+     * @param locale
+     *          Locale of the collation matching rule
      */
     private CollationLessThanOrEqualToMatchingRule(String nOID,
-            Collection<String> names,
-            Locale locale)
+        Collection<String> names, Locale locale)
     {
       super(nOID, names, locale);
     }
 
 
 
-
     /**
      * {@inheritDoc}
      */
     @Override
-    public ConditionResult valuesMatch(ByteString attributeValue,
-            ByteString assertionValue)
+    public ConditionResult valuesMatch(ByteSequence attributeValue,
+        ByteSequence assertionValue)
     {
-      int ret = compare(attributeValue.value(), assertionValue.value());
+      int ret = attributeValue.compareTo(assertionValue);
 
       if (ret <= 0)
       {
@@ -1857,44 +1828,39 @@
 
 
 
-
     /**
      * {@inheritDoc}
      */
     @Override
-    public <T> T createIndexQuery(ByteString assertionValue,
-            IndexQueryFactory<T> factory)
-            throws DirectoryException
+    public <T> T createIndexQuery(ByteSequence assertionValue,
+        IndexQueryFactory<T> factory) throws DirectoryException
     {
-      byte[] lower = new byte[0];
-      byte[] upper = normalizeValue(assertionValue).value();
       // Read the range: lower < keys <= upper.
-      return factory.createRangeMatchQuery(indexer.getExtensibleIndexID(),
-              lower,
-              upper,
-              false,
-              true);
+      return factory.createRangeMatchQuery(indexer
+          .getExtensibleIndexID(), ByteString.empty(),
+          normalizeValue(assertionValue), false, true);
     }
   }
 
-
-
   /**
    * Collation rule for greater-than matching rule.
    */
-  private final class CollationGreaterThanMatchingRule
-          extends CollationOrderingMatchingRule
+  private final class CollationGreaterThanMatchingRule extends
+      CollationOrderingMatchingRule
   {
 
     /**
      * Constructs a new CollationGreaterThanMatchingRule.
      *
-     * @param nOID OID of the collation matching rule
-     * @param names names of this matching rule
-     * @param locale Locale of the collation matching rule
+     * @param nOID
+     *          OID of the collation matching rule
+     * @param names
+     *          names of this matching rule
+     * @param locale
+     *          Locale of the collation matching rule
      */
     private CollationGreaterThanMatchingRule(String nOID,
-            Collection<String> names, Locale locale)
+        Collection<String> names, Locale locale)
     {
       super(nOID, names, locale);
     }
@@ -1905,71 +1871,69 @@
      * {@inheritDoc}
      */
     @Override
-    public ConditionResult valuesMatch(ByteString attributeValue,
-            ByteString assertionValue)
+    public ConditionResult valuesMatch(ByteSequence attributeValue,
+        ByteSequence assertionValue)
     {
-      int ret = compare(attributeValue.value(), assertionValue.value());
+      int ret = attributeValue.compareTo(assertionValue);
 
-      if (ret > 0) {
+      if (ret > 0)
+      {
         return ConditionResult.TRUE;
-      } else {
+      }
+      else
+      {
         return ConditionResult.FALSE;
       }
     }
 
 
 
-
     /**
      * {@inheritDoc}
      */
     @Override
-    public <T> T createIndexQuery(ByteString assertionValue,
-            IndexQueryFactory<T> factory)
-            throws DirectoryException
+    public <T> T createIndexQuery(ByteSequence assertionValue,
+        IndexQueryFactory<T> factory) throws DirectoryException
     {
-      byte[] lower = normalizeValue(assertionValue).value();
-      byte[] upper = new byte[0];
-      return factory.createRangeMatchQuery(indexer.getExtensibleIndexID(),
-              lower,
-              upper,
-              false,
-              false);
+      return factory.createRangeMatchQuery(indexer
+          .getExtensibleIndexID(), normalizeValue(assertionValue),
+          ByteString.empty(), false, false);
     }
   }
 
   /**
    * Collation rule for greater-than-equal-to matching rule.
    */
-  private final class CollationGreaterThanOrEqualToMatchingRule
-          extends CollationOrderingMatchingRule
+  private final class CollationGreaterThanOrEqualToMatchingRule extends
+      CollationOrderingMatchingRule
   {
 
     /**
      * Constructs a new CollationGreaterThanOrEqualToMatchingRule.
      *
-     * @param nOID OID of the collation matching rule
-     * @param names names of this matching rule
-     * @param locale Locale of the collation matching rule
+     * @param nOID
+     *          OID of the collation matching rule
+     * @param names
+     *          names of this matching rule
+     * @param locale
+     *          Locale of the collation matching rule
      */
     private CollationGreaterThanOrEqualToMatchingRule(String nOID,
-            Collection<String> names,
-            Locale locale)
+        Collection<String> names, Locale locale)
     {
       super(nOID, names, locale);
     }
 
 
 
-
     /**
      * {@inheritDoc}
      */
     @Override
-    public ConditionResult valuesMatch(ByteString attributeValue,
-            ByteString assertionValue)
+    public ConditionResult valuesMatch(ByteSequence attributeValue,
+        ByteSequence assertionValue)
     {
-      int ret = compare(attributeValue.value(),assertionValue.value());
+      int ret = attributeValue.compareTo(assertionValue);
 
       if (ret >= 0)
       {
@@ -1987,29 +1951,23 @@
      * {@inheritDoc}
      */
     @Override
-    public <T> T createIndexQuery(ByteString assertionValue,
-            IndexQueryFactory<T> factory)
-            throws DirectoryException
+    public <T> T createIndexQuery(ByteSequence assertionValue,
+        IndexQueryFactory<T> factory) throws DirectoryException
     {
-      byte[] lower = normalizeValue(assertionValue).value();
-      byte[] upper = new byte[0];
       // Read the range: lower <= keys < upper.
-      return factory.createRangeMatchQuery(indexer.getExtensibleIndexID(),
-              lower,
-              upper,
-              true,
-              false);
+      return factory.createRangeMatchQuery(indexer
+          .getExtensibleIndexID(), normalizeValue(assertionValue),
+          ByteString.empty(), true, false);
     }
   }
 
-
   /**
-   * Extensible Indexer class for Collation Matching rules which share the
-   * same index. This Indexer is shared by Equality and Ordering Collation
-   * Matching Rules.
+   * Extensible Indexer class for Collation Matching rules which share
+   * the same index. This Indexer is shared by Equality and Ordering
+   * Collation Matching Rules.
    */
-  private final class CollationSharedExtensibleIndexer
-          extends ExtensibleIndexer
+  private final class CollationSharedExtensibleIndexer extends
+      ExtensibleIndexer
   {
 
     /**
@@ -2022,10 +1980,11 @@
     /**
      * Creates a new instance of CollationSharedExtensibleIndexer.
      *
-     * @param matchingRule The Collation Matching Rule.
+     * @param matchingRule
+     *          The Collation Matching Rule.
      */
     private CollationSharedExtensibleIndexer(
-            CollationMatchingRule matchingRule)
+        CollationMatchingRule matchingRule)
     {
       this.matchingRule = matchingRule;
     }
@@ -2047,14 +2006,13 @@
      * {@inheritDoc}
      */
     @Override
-    public final void getKeys(AttributeValue value,
-            Set<byte[]> keys)
+    public final void getKeys(AttributeValue value, Set<byte[]> keys)
     {
       ByteString key;
       try
       {
         key = matchingRule.normalizeValue(value.getValue());
-        keys.add(key.value());
+        keys.add(key.toByteArray());
       }
       catch (DirectoryException de)
       {
@@ -2068,8 +2026,7 @@
      */
     @Override
     public final void getKeys(AttributeValue value,
-            Map<byte[], Boolean> modifiedKeys,
-            Boolean insert)
+        Map<byte[], Boolean> modifiedKeys, Boolean insert)
     {
       Set<byte[]> keys = new HashSet<byte[]>();
       getKeys(value, keys);
@@ -2101,17 +2058,15 @@
 
   /**
    * Extensible Indexer class for Collation Substring Matching rules.
-   * This Indexer is used  by Substring Collation Matching Rules.
+   * This Indexer is used by Substring Collation Matching Rules.
    */
-  private final class CollationSubstringExtensibleIndexer
-          extends ExtensibleIndexer
+  private final class CollationSubstringExtensibleIndexer extends
+      ExtensibleIndexer
   {
-    //The CollationSubstringMatching Rule.
+    // The CollationSubstringMatching Rule.
     private final CollationSubstringMatchingRule matchingRule;
 
-
-
-    //The substring length.
+    // The substring length.
     private int substringLen;
 
 
@@ -2119,12 +2074,13 @@
     /**
      * Creates a new instance of CollationSubstringExtensibleIndexer.
      *
-     * @param matchingRule The CollationSubstringMatching Rule.
-     * @param substringLen The substring length.
+     * @param matchingRule
+     *          The CollationSubstringMatching Rule.
+     * @param substringLen
+     *          The substring length.
      */
     private CollationSubstringExtensibleIndexer(
-            CollationSubstringMatchingRule matchingRule,
-            int substringLen)
+        CollationSubstringMatchingRule matchingRule, int substringLen)
     {
       this.matchingRule = matchingRule;
       this.substringLen = substringLen;
@@ -2136,11 +2092,9 @@
      * {@inheritDoc}
      */
     @Override
-    public void getKeys(AttributeValue value,
-                                Set<byte[]> keys)
+    public void getKeys(AttributeValue value, Set<byte[]> keys)
     {
-      matchingRule.subtringKeys(value.getValue(),
-                                keys);
+      matchingRule.subtringKeys(value.getValue(), keys);
     }
 
 
@@ -2150,12 +2104,10 @@
      */
     @Override
     public void getKeys(AttributeValue attValue,
-            Map<byte[], Boolean> modifiedKeys,
-            Boolean insert)
+        Map<byte[], Boolean> modifiedKeys, Boolean insert)
     {
-      matchingRule.substringKeys(attValue.getValue(),
-              modifiedKeys,
-              insert);
+      matchingRule.substringKeys(attValue.getValue(), modifiedKeys,
+          insert);
     }
 
 
@@ -2184,6 +2136,7 @@
 
     /**
      * Returns the substring length.
+     *
      * @return The length of the substring.
      */
     private int gerSubstringLength()
@@ -2195,7 +2148,9 @@
 
     /**
      * Sets the substring length.
-     * @param substringLen The substring length.
+     *
+     * @param substringLen
+     *          The substring length.
      */
     private void setSubstringLength(int substringLen)
     {
@@ -2203,33 +2158,33 @@
     }
   }
 
-
-
   /**
    * A utility class for extracting the OID and Language Tag from the
    * configuration entry.
    */
   private final class CollationMapper
   {
-    //OID of the collation rule.
-    private  String oid;
+    // OID of the collation rule.
+    private String oid;
 
-    //Language Tag.
-    private  String lTag;
+    // Language Tag.
+    private String lTag;
+
 
 
     /**
      * Creates a new instance of CollationMapper.
      *
-     * @param collation The collation text in the LOCALE:OID format.
+     * @param collation
+     *          The collation text in the LOCALE:OID format.
      */
     private CollationMapper(String collation)
     {
       int index = collation.indexOf(":");
-      if(index>0)
+      if (index > 0)
       {
-        oid = collation.substring(index+1,collation.length());
-        lTag = collation.substring(0,index);
+        oid = collation.substring(index + 1, collation.length());
+        lTag = collation.substring(0, index);
       }
     }
 
@@ -2257,4 +2212,4 @@
       return lTag;
     }
   }
-}
\ No newline at end of file
+}
diff --git a/opends/src/server/org/opends/server/schema/CountryStringSyntax.java b/opends/src/server/org/opends/server/schema/CountryStringSyntax.java
index 0f0ef2e..98462cb 100644
--- a/opends/src/server/org/opends/server/schema/CountryStringSyntax.java
+++ b/opends/src/server/org/opends/server/schema/CountryStringSyntax.java
@@ -36,8 +36,7 @@
 import org.opends.server.api.SubstringMatchingRule;
 import org.opends.server.config.ConfigException;
 import org.opends.server.core.DirectoryServer;
-import org.opends.server.types.ByteString;
-
+import org.opends.server.types.ByteSequence;
 
 
 import static org.opends.server.loggers.ErrorLogger.*;
@@ -233,10 +232,10 @@
    * @return  <CODE>true</CODE> if the provided value is acceptable for use with
    *          this syntax, or <CODE>false</CODE> if not.
    */
-  public boolean valueIsAcceptable(ByteString value,
+  public boolean valueIsAcceptable(ByteSequence value,
                                    MessageBuilder invalidReason)
   {
-    String stringValue = toLowerCase(value.stringValue());
+    String stringValue = toLowerCase(value.toString());
     if (stringValue.length() != 2)
     {
       invalidReason.append(
diff --git a/opends/src/server/org/opends/server/schema/DITContentRuleSyntax.java b/opends/src/server/org/opends/server/schema/DITContentRuleSyntax.java
index f286458..ef74be8 100644
--- a/opends/src/server/org/opends/server/schema/DITContentRuleSyntax.java
+++ b/opends/src/server/org/opends/server/schema/DITContentRuleSyntax.java
@@ -42,19 +42,10 @@
 import org.opends.server.api.SubstringMatchingRule;
 import org.opends.server.config.ConfigException;
 import org.opends.server.core.DirectoryServer;
-import org.opends.server.types.AttributeType;
-import org.opends.server.types.ByteString;
-import org.opends.server.types.DirectoryException;
-import org.opends.server.types.DITContentRule;
-import org.opends.server.types.InitializationException;
-import org.opends.server.types.ObjectClass;
-import org.opends.server.types.ObjectClassType;
-import org.opends.server.types.ResultCode;
-import org.opends.server.types.Schema;
 
 import static org.opends.server.loggers.debug.DebugLogger.*;
 import org.opends.server.loggers.debug.DebugTracer;
-import org.opends.server.types.DebugLogLevel;
+import org.opends.server.types.*;
 import static org.opends.messages.SchemaMessages.*;
 import org.opends.messages.MessageBuilder;
 import static org.opends.server.schema.SchemaConstants.*;
@@ -212,7 +203,7 @@
   /**
    * {@inheritDoc}
    */
-  public boolean valueIsAcceptable(ByteString value,
+  public boolean valueIsAcceptable(ByteSequence value,
                                    MessageBuilder invalidReason)
   {
     // We'll use the decodeDITContentRule method to determine if the value is
@@ -259,13 +250,13 @@
    * @throws  DirectoryException  If the provided value cannot be decoded as an
    *                              DIT content rule definition.
    */
-  public static DITContentRule decodeDITContentRule(ByteString value,
+  public static DITContentRule decodeDITContentRule(ByteSequence value,
                                     Schema schema, boolean allowUnknownElements)
          throws DirectoryException
   {
     // Get string representations of the provided value using the provided form
     // and with all lowercase characters.
-    String valueStr = value.stringValue();
+    String valueStr = value.toString();
     String lowerStr = toLowerCase(valueStr);
 
 
@@ -943,7 +934,7 @@
     }
 
 
-    return new DITContentRule(value.stringValue(), structuralClass, names,
+    return new DITContentRule(value.toString(), structuralClass, names,
                               description, auxiliaryClasses, requiredAttributes,
                               optionalAttributes, prohibitedAttributes,
                               isObsolete, extraProperties);
diff --git a/opends/src/server/org/opends/server/schema/DITStructureRuleSyntax.java b/opends/src/server/org/opends/server/schema/DITStructureRuleSyntax.java
index 595f23a..41036bd 100644
--- a/opends/src/server/org/opends/server/schema/DITStructureRuleSyntax.java
+++ b/opends/src/server/org/opends/server/schema/DITStructureRuleSyntax.java
@@ -42,17 +42,10 @@
 import org.opends.server.api.SubstringMatchingRule;
 import org.opends.server.config.ConfigException;
 import org.opends.server.core.DirectoryServer;
-import org.opends.server.types.ByteString;
-import org.opends.server.types.DirectoryException;
-import org.opends.server.types.DITStructureRule;
-import org.opends.server.types.InitializationException;
-import org.opends.server.types.NameForm;
-import org.opends.server.types.ResultCode;
-import org.opends.server.types.Schema;
 
 import static org.opends.server.loggers.debug.DebugLogger.*;
 import org.opends.server.loggers.debug.DebugTracer;
-import org.opends.server.types.DebugLogLevel;
+import org.opends.server.types.*;
 import static org.opends.messages.SchemaMessages.*;
 import org.opends.messages.MessageBuilder;
 import static org.opends.server.schema.SchemaConstants.*;
@@ -210,7 +203,7 @@
   /**
    * {@inheritDoc}
    */
-  public boolean valueIsAcceptable(ByteString value,
+  public boolean valueIsAcceptable(ByteSequence value,
                                    MessageBuilder invalidReason)
   {
     // We'll use the decodeDITStructureRule method to determine if the value is
@@ -257,14 +250,14 @@
    * @throws  DirectoryException  If the provided value cannot be decoded as an
    *                              DIT structure rule definition.
    */
-  public static DITStructureRule decodeDITStructureRule(ByteString value,
+  public static DITStructureRule decodeDITStructureRule(ByteSequence value,
                                       Schema schema,
                                       boolean allowUnknownElements)
          throws DirectoryException
   {
     // Get string representations of the provided value using the provided form
     // and with all lowercase characters.
-    String valueStr = value.stringValue();
+    String valueStr = value.toString();
     String lowerStr = toLowerCase(valueStr);
 
 
@@ -689,7 +682,7 @@
     }
 
 
-    return new DITStructureRule(value.stringValue(), names, ruleID, description,
+    return new DITStructureRule(value.toString(), names, ruleID, description,
                                 isObsolete, nameForm, superiorRules,
                                 extraProperties);
   }
diff --git a/opends/src/server/org/opends/server/schema/DeliveryMethodSyntax.java b/opends/src/server/org/opends/server/schema/DeliveryMethodSyntax.java
index af8074e..2b37358 100644
--- a/opends/src/server/org/opends/server/schema/DeliveryMethodSyntax.java
+++ b/opends/src/server/org/opends/server/schema/DeliveryMethodSyntax.java
@@ -39,8 +39,7 @@
 import org.opends.server.api.SubstringMatchingRule;
 import org.opends.server.config.ConfigException;
 import org.opends.server.core.DirectoryServer;
-import org.opends.server.types.ByteString;
-
+import org.opends.server.types.ByteSequence;
 
 
 import static org.opends.server.loggers.ErrorLogger.*;
@@ -277,15 +276,15 @@
    * @return  <CODE>true</CODE> if the provided value is acceptable for use with
    *          this syntax, or <CODE>false</CODE> if not.
    */
-  public boolean valueIsAcceptable(ByteString value,
+  public boolean valueIsAcceptable(ByteSequence value,
                                    MessageBuilder invalidReason)
   {
-    String stringValue = toLowerCase(value.stringValue());
+    String stringValue = toLowerCase(value.toString());
     StringTokenizer tokenizer = new StringTokenizer(stringValue, " $");
     if (! tokenizer.hasMoreTokens())
     {
       invalidReason.append(ERR_ATTR_SYNTAX_DELIVERY_METHOD_NO_ELEMENTS.get(
-              value.stringValue()));
+              value.toString()));
       return false;
     }
 
@@ -295,7 +294,7 @@
       if (! allowedValues.contains(token))
       {
         invalidReason.append(ERR_ATTR_SYNTAX_DELIVERY_METHOD_INVALID_ELEMENT
-                .get(value.stringValue(), token));
+                .get(value.toString(), token));
         return false;
       }
     }
diff --git a/opends/src/server/org/opends/server/schema/DirectoryStringFirstComponentEqualityMatchingRule.java b/opends/src/server/org/opends/server/schema/DirectoryStringFirstComponentEqualityMatchingRule.java
index 9f9f80e..595ae30 100644
--- a/opends/src/server/org/opends/server/schema/DirectoryStringFirstComponentEqualityMatchingRule.java
+++ b/opends/src/server/org/opends/server/schema/DirectoryStringFirstComponentEqualityMatchingRule.java
@@ -28,17 +28,18 @@
 
 
 
-import java.util.Collection;
-import java.util.Collections;
-import org.opends.server.api.EqualityMatchingRule;
-import org.opends.server.protocols.asn1.ASN1OctetString;
-import org.opends.server.types.AttributeValue;
-import org.opends.server.types.ByteString;
-import org.opends.server.types.DirectoryException;
-
 import static org.opends.server.schema.SchemaConstants.*;
 import static org.opends.server.util.StaticUtils.*;
 
+import java.util.Collection;
+import java.util.Collections;
+
+import org.opends.server.api.EqualityMatchingRule;
+import org.opends.server.types.ByteSequence;
+import org.opends.server.types.ByteString;
+import org.opends.server.types.DirectoryException;
+import org.opends.server.util.ServerConstants;
+
 
 
 /**
@@ -66,6 +67,7 @@
   /**
    * {@inheritDoc}
    */
+  @Override
   public Collection<String> getAllNames()
   {
     return Collections.singleton(getName());
@@ -79,6 +81,7 @@
    * @return  The common name for this matching rule, or <CODE>null</CODE> if
    * it does not have a name.
    */
+  @Override
   public String getName()
   {
     return EMR_DIRECTORY_STRING_FIRST_COMPONENT_NAME;
@@ -91,6 +94,7 @@
    *
    * @return  The OID for this matching rule.
    */
+  @Override
   public String getOID()
   {
     return EMR_DIRECTORY_STRING_FIRST_COMPONENT_OID;
@@ -104,6 +108,7 @@
    * @return  The description for this matching rule, or <CODE>null</CODE> if
    *          there is none.
    */
+  @Override
   public String getDescription()
   {
     // There is no standard description for this matching rule.
@@ -118,6 +123,7 @@
    *
    * @return  The OID of the syntax with which this matching rule is associated.
    */
+  @Override
   public String getSyntaxOID()
   {
     return SYNTAX_DIRECTORY_STRING_OID;
@@ -136,25 +142,26 @@
    * @throws  DirectoryException  If the provided value is invalid according to
    *                              the associated attribute syntax.
    */
-  public ByteString normalizeValue(ByteString value)
+  @Override
+  public ByteString normalizeValue(ByteSequence value)
          throws DirectoryException
   {
     StringBuilder buffer = new StringBuilder();
-    toLowerCase(value.value(), buffer, true);
+    toLowerCase(value, buffer, true);
 
     int bufferLength = buffer.length();
     if (bufferLength == 0)
     {
-      if (value.value().length > 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 ASN1OctetString(" ");
+        return ServerConstants.SINGLE_SPACE_VALUE;
       }
       else
       {
         // The value is empty, so it is already normalized.
-        return new ASN1OctetString();
+        return ByteString.empty();
       }
     }
 
@@ -171,7 +178,7 @@
       }
     }
 
-    return new ASN1OctetString(buffer.toString());
+    return ByteString.valueOf(buffer.toString());
   }
 
 
@@ -186,12 +193,13 @@
    * @return  <CODE>true</CODE> if the provided values are equal, or
    *          <CODE>false</CODE> if not.
    */
-  public boolean areEqual(ByteString value1, ByteString value2)
+  @Override
+  public boolean areEqual(ByteSequence value1, ByteSequence value2)
   {
     // For this purpose, the first value will be considered the attribute value,
     // and the second the assertion value.  The attribute value must start with
     // an open parenthesis, followed by one or more spaces.
-    String value1String = value1.stringValue();
+    String value1String = value1.toString();
     int    value1Length = value1String.length();
 
     if ((value1Length == 0) || (value1String.charAt(0) != '('))
@@ -201,9 +209,8 @@
       return false;
     }
 
-    char c;
     int  pos = 1;
-    while ((pos < value1Length) && ((c = value1String.charAt(pos)) == ' '))
+    while ((pos < value1Length) && ((value1String.charAt(pos)) == ' '))
     {
       pos++;
     }
@@ -218,7 +225,7 @@
     // The current position must be the start position for the value.  Keep
     // reading until we find the next space.
     int startPos = pos++;
-    while ((pos < value1Length) && ((c = value1String.charAt(pos)) != ' '))
+    while ((pos < value1Length) && ((value1String.charAt(pos)) != ' '))
     {
       pos++;
     }
@@ -233,7 +240,7 @@
     // Grab the substring between the start pos and the current pos and compare
     // it with the assertion value.
     String compareStr   = value1String.substring(startPos, pos);
-    String value2String = value2.stringValue();
+    String value2String = value2.toString();
     return value2String.equals(compareStr);
   }
 
@@ -252,7 +259,8 @@
    *                         code.
    *
    * @return  The hash code generated for the provided attribute value.*/
-  public int generateHashCode(AttributeValue attributeValue)
+  @Override
+  public int generateHashCode(ByteSequence attributeValue)
   {
     // In this case, we'll always return the same value because the matching
     // isn't based on the entire value.
diff --git a/opends/src/server/org/opends/server/schema/DirectoryStringSyntax.java b/opends/src/server/org/opends/server/schema/DirectoryStringSyntax.java
index b795b2d..443c85e 100644
--- a/opends/src/server/org/opends/server/schema/DirectoryStringSyntax.java
+++ b/opends/src/server/org/opends/server/schema/DirectoryStringSyntax.java
@@ -41,13 +41,9 @@
 import org.opends.server.api.SubstringMatchingRule;
 import org.opends.server.config.ConfigException;
 import org.opends.server.core.DirectoryServer;
-import org.opends.server.types.AttributeValue;
-import org.opends.server.types.ByteString;
-import org.opends.server.types.ConfigChangeResult;
-import org.opends.server.types.DirectoryException;
 
 
-import org.opends.server.types.ResultCode;
+import org.opends.server.types.*;
 
 import static org.opends.server.loggers.ErrorLogger.*;
 import static org.opends.messages.SchemaMessages.*;
@@ -99,7 +95,7 @@
     {
       // Make sure that the value is valid.
       value.getNormalizedValue();
-      return value.getStringValue();
+      return value.getValue().toString();
     }
   };
 
@@ -291,10 +287,10 @@
    * @return  <CODE>true</CODE> if the provided value is acceptable for use with
    *          this syntax, or <CODE>false</CODE> if not.
    */
-  public boolean valueIsAcceptable(ByteString value,
+  public boolean valueIsAcceptable(ByteSequence value,
                                    MessageBuilder invalidReason)
   {
-    if (allowZeroLengthValues || (value.value().length > 0))
+    if (allowZeroLengthValues || (value.length() > 0))
     {
       return true;
     }
diff --git a/opends/src/server/org/opends/server/schema/DistinguishedNameEqualityMatchingRule.java b/opends/src/server/org/opends/server/schema/DistinguishedNameEqualityMatchingRule.java
index 8bdb1b8..f838429 100644
--- a/opends/src/server/org/opends/server/schema/DistinguishedNameEqualityMatchingRule.java
+++ b/opends/src/server/org/opends/server/schema/DistinguishedNameEqualityMatchingRule.java
@@ -25,30 +25,29 @@
  *      Copyright 2006-2008 Sun Microsystems, Inc.
  */
 package org.opends.server.schema;
-import org.opends.messages.Message;
 
 
 
-import java.util.Arrays;
-
-import java.util.Collections;
-import java.util.Collection;
-import org.opends.server.api.EqualityMatchingRule;
-import org.opends.server.core.DirectoryServer;
-import org.opends.server.protocols.asn1.ASN1OctetString;
-import org.opends.server.types.AcceptRejectWarn;
-import org.opends.server.types.ByteString;
-import org.opends.server.types.DirectoryException;
-import org.opends.server.types.DN;
-import org.opends.server.types.ResultCode;
-
-import static org.opends.server.loggers.debug.DebugLogger.*;
-import org.opends.server.loggers.debug.DebugTracer;
-import org.opends.server.types.DebugLogLevel;
 import static org.opends.messages.SchemaMessages.*;
+import static org.opends.server.loggers.debug.DebugLogger.*;
 import static org.opends.server.schema.SchemaConstants.*;
 import static org.opends.server.util.StaticUtils.*;
 
+import java.util.Collection;
+import java.util.Collections;
+
+import org.opends.messages.Message;
+import org.opends.server.api.EqualityMatchingRule;
+import org.opends.server.core.DirectoryServer;
+import org.opends.server.loggers.debug.DebugTracer;
+import org.opends.server.types.AcceptRejectWarn;
+import org.opends.server.types.ByteSequence;
+import org.opends.server.types.ByteString;
+import org.opends.server.types.DN;
+import org.opends.server.types.DebugLogLevel;
+import org.opends.server.types.DirectoryException;
+import org.opends.server.types.ResultCode;
+
 
 
 /**
@@ -79,6 +78,7 @@
   /**
    * {@inheritDoc}
    */
+  @Override
   public Collection<String> getAllNames()
   {
     return Collections.singleton(getName());
@@ -92,6 +92,7 @@
    * @return  The common name for this matching rule, or <CODE>null</CODE> if
    * it does not have a name.
    */
+  @Override
   public String getName()
   {
     return EMR_DN_NAME;
@@ -104,6 +105,7 @@
    *
    * @return  The OID for this matching rule.
    */
+  @Override
   public String getOID()
   {
     return EMR_DN_OID;
@@ -117,6 +119,7 @@
    * @return  The description for this matching rule, or <CODE>null</CODE> if
    *          there is none.
    */
+  @Override
   public String getDescription()
   {
     // There is no standard description for this matching rule.
@@ -131,6 +134,7 @@
    *
    * @return  The OID of the syntax with which this matching rule is associated.
    */
+  @Override
   public String getSyntaxOID()
   {
     return SYNTAX_DN_OID;
@@ -149,7 +153,8 @@
    * @throws  DirectoryException  If the provided value is invalid according to
    *                              the associated attribute syntax.
    */
-  public ByteString normalizeValue(ByteString value)
+  @Override
+  public ByteString normalizeValue(ByteSequence value)
          throws DirectoryException
   {
     // Since the normalization for DNs is so complex, it will be handled
@@ -157,7 +162,7 @@
     DN dn;
     try
     {
-      dn = DN.decode(value.stringValue());
+      dn = DN.decode(value.toString());
     }
     catch (DirectoryException de)
     {
@@ -173,7 +178,7 @@
         throw de;
       }
 
-      return bestEffortNormalize(toLowerCase(value.stringValue()));
+      return bestEffortNormalize(toLowerCase(value.toString()));
     }
     catch (Exception e)
     {
@@ -186,17 +191,17 @@
           AcceptRejectWarn.REJECT)
       {
         Message message = ERR_ATTR_SYNTAX_DN_INVALID.get(
-            value.stringValue(), String.valueOf(e));
+            value.toString(), String.valueOf(e));
         throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX,
                                      message);
       }
       else
       {
-        return bestEffortNormalize(toLowerCase(value.stringValue()));
+        return bestEffortNormalize(toLowerCase(value.toString()));
       }
     }
 
-    return new ASN1OctetString(dn.toNormalizedString());
+    return ByteString.valueOf(dn.toNormalizedString());
   }
 
 
@@ -270,26 +275,7 @@
       }
     }
 
-    return new ASN1OctetString(buffer.toString());
-  }
-
-
-
-  /**
-   * Indicates whether the two provided normalized values are equal to each
-   * other.
-   *
-   * @param  value1  The normalized form of the first value to compare.
-   * @param  value2  The normalized form of the second value to compare.
-   *
-   * @return  <CODE>true</CODE> if the provided values are equal, or
-   *          <CODE>false</CODE> if not.
-   */
-  public boolean areEqual(ByteString value1, ByteString value2)
-  {
-    // Since the values are already normalized, we just need to compare the
-    // associated byte arrays.
-    return Arrays.equals(value1.value(), value2.value());
+    return ByteString.valueOf(buffer.toString());
   }
 }
 
diff --git a/opends/src/server/org/opends/server/schema/DistinguishedNameSyntax.java b/opends/src/server/org/opends/server/schema/DistinguishedNameSyntax.java
index 1d981b6..5060b27 100644
--- a/opends/src/server/org/opends/server/schema/DistinguishedNameSyntax.java
+++ b/opends/src/server/org/opends/server/schema/DistinguishedNameSyntax.java
@@ -37,15 +37,11 @@
 import org.opends.server.api.SubstringMatchingRule;
 import org.opends.server.config.ConfigException;
 import org.opends.server.core.DirectoryServer;
-import org.opends.server.types.AttributeValue;
-import org.opends.server.types.ByteString;
-import org.opends.server.types.DirectoryException;
-import org.opends.server.types.DN;
 
 import static org.opends.server.loggers.ErrorLogger.*;
 import static org.opends.server.loggers.debug.DebugLogger.*;
 import org.opends.server.loggers.debug.DebugTracer;
-import org.opends.server.types.DebugLogLevel;
+import org.opends.server.types.*;
 import static org.opends.messages.SchemaMessages.*;
 import org.opends.messages.MessageBuilder;
 import static org.opends.server.schema.SchemaConstants.*;
@@ -85,7 +81,7 @@
      */
     public DN decode(AttributeValue value) throws DirectoryException
     {
-      return DN.decode(value.getStringValue());
+      return DN.decode(value.getValue().toString());
     }
   };
 
@@ -239,13 +235,13 @@
    * @return  <CODE>true</CODE> if the provided value is acceptable for use with
    *          this syntax, or <CODE>false</CODE> if not.
    */
-  public boolean valueIsAcceptable(ByteString value,
+  public boolean valueIsAcceptable(ByteSequence value,
                                    MessageBuilder invalidReason)
   {
     // Use the DN code to make this determination.
     try
     {
-      DN.decode(value.stringValue());
+      DN.decode(value.toString());
 
       return true;
     }
@@ -267,7 +263,7 @@
       }
 
 
-      invalidReason.append(ERR_ATTR_SYNTAX_DN_INVALID.get(value.stringValue(),
+      invalidReason.append(ERR_ATTR_SYNTAX_DN_INVALID.get(value.toString(),
                                       String.valueOf(e)));
 
       return false;
diff --git a/opends/src/server/org/opends/server/schema/DoubleMetaphoneApproximateMatchingRule.java b/opends/src/server/org/opends/server/schema/DoubleMetaphoneApproximateMatchingRule.java
index 4a79b64..7f2dc7b 100644
--- a/opends/src/server/org/opends/server/schema/DoubleMetaphoneApproximateMatchingRule.java
+++ b/opends/src/server/org/opends/server/schema/DoubleMetaphoneApproximateMatchingRule.java
@@ -28,19 +28,18 @@
 
 
 
-import java.util.Arrays;
+import static org.opends.server.loggers.debug.DebugLogger.*;
+import static org.opends.server.schema.SchemaConstants.*;
 
 import java.util.Collection;
 import java.util.Collections;
-import org.opends.server.api.ApproximateMatchingRule;
-import org.opends.server.protocols.asn1.ASN1OctetString;
-import org.opends.server.types.ByteString;
-import org.opends.server.types.DirectoryException;
-import org.opends.server.types.DebugLogLevel;
 
-import static org.opends.server.loggers.debug.DebugLogger.*;
+import org.opends.server.api.ApproximateMatchingRule;
 import org.opends.server.loggers.debug.DebugTracer;
-import static org.opends.server.schema.SchemaConstants.*;
+import org.opends.server.types.ByteSequence;
+import org.opends.server.types.ByteString;
+import org.opends.server.types.DebugLogLevel;
+import org.opends.server.types.DirectoryException;
 
 
 
@@ -86,6 +85,7 @@
   /**
    * {@inheritDoc}
    */
+  @Override
   public Collection<String> getAllNames()
   {
     return Collections.singleton(getName());
@@ -99,6 +99,7 @@
    * @return  The common name for this matching rule, or <CODE>null</CODE> if
    * it does not have a name.
    */
+  @Override
   public String getName()
   {
     return AMR_DOUBLE_METAPHONE_NAME;
@@ -111,6 +112,7 @@
    *
    * @return  The OID for this matching rule.
    */
+  @Override
   public String getOID()
   {
     return AMR_DOUBLE_METAPHONE_OID;
@@ -124,6 +126,7 @@
    * @return  The description for this matching rule, or <CODE>null</CODE> if
    *          there is none.
    */
+  @Override
   public String getDescription()
   {
     // There is no standard description for this matching rule.
@@ -138,6 +141,7 @@
    *
    * @return  The OID of the syntax with which this matching rule is associated.
    */
+  @Override
   public String getSyntaxOID()
   {
     // Approximate matching is really only appropriate for DirectoryString
@@ -158,15 +162,16 @@
    * @throws  DirectoryException  If the provided value is invalid according to
    *                              the associated attribute syntax.
    */
-  public ByteString normalizeValue(ByteString value)
+  @Override
+  public ByteString normalizeValue(ByteSequence value)
          throws DirectoryException
   {
-    String valueString = value.stringValue();
+    String valueString = value.toString();
     int length = valueString.length();
     if (length == 0)
     {
       // The value is empty, so it is already normalized.
-      return new ASN1OctetString();
+      return ByteString.empty();
     }
 
     int last = length - 1;
@@ -1144,7 +1149,7 @@
     }
 
 
-    return new ASN1OctetString(metaphone.toString());
+    return ByteString.valueOf(metaphone.toString());
   }
 
 
@@ -1159,11 +1164,12 @@
    * @return  <CODE>true</CODE> if the provided values are approximately equal,
    *          or <CODE>false</CODE> if not.
    */
-  public boolean approximatelyMatch(ByteString value1, ByteString value2)
+  @Override
+  public boolean approximatelyMatch(ByteSequence value1, ByteSequence value2)
   {
     // If the values have been normalized, then we just need to compare their
     // byte arrays.
-    return Arrays.equals(value1.value(), value2.value());
+    return value1.equals(value2);
   }
 
 
diff --git a/opends/src/server/org/opends/server/schema/EnhancedGuideSyntax.java b/opends/src/server/org/opends/server/schema/EnhancedGuideSyntax.java
index 7c0db07..1d567b8 100644
--- a/opends/src/server/org/opends/server/schema/EnhancedGuideSyntax.java
+++ b/opends/src/server/org/opends/server/schema/EnhancedGuideSyntax.java
@@ -36,8 +36,7 @@
 import org.opends.server.api.SubstringMatchingRule;
 import org.opends.server.config.ConfigException;
 import org.opends.server.core.DirectoryServer;
-import org.opends.server.types.ByteString;
-
+import org.opends.server.types.ByteSequence;
 
 
 import static org.opends.server.loggers.ErrorLogger.*;
@@ -221,11 +220,11 @@
    * @return  <CODE>true</CODE> if the provided value is acceptable for use with
    *          this syntax, or <CODE>false</CODE> if not.
    */
-  public boolean valueIsAcceptable(ByteString value,
+  public boolean valueIsAcceptable(ByteSequence value,
                                    MessageBuilder invalidReason)
   {
     // Get a lowercase string version of the provided value.
-    String valueStr = toLowerCase(value.stringValue());
+    String valueStr = toLowerCase(value.toString());
 
 
     // Find the position of the first octothorpe.  It should denote the end of
diff --git a/opends/src/server/org/opends/server/schema/FaxNumberSyntax.java b/opends/src/server/org/opends/server/schema/FaxNumberSyntax.java
index 7b08db5..d8d9d5e 100644
--- a/opends/src/server/org/opends/server/schema/FaxNumberSyntax.java
+++ b/opends/src/server/org/opends/server/schema/FaxNumberSyntax.java
@@ -38,8 +38,7 @@
 import org.opends.server.api.SubstringMatchingRule;
 import org.opends.server.config.ConfigException;
 import org.opends.server.core.DirectoryServer;
-import org.opends.server.types.ByteString;
-
+import org.opends.server.types.ByteSequence;
 
 
 import static org.opends.server.loggers.ErrorLogger.*;
@@ -254,11 +253,11 @@
    * @return  <CODE>true</CODE> if the provided value is acceptable for use with
    *          this syntax, or <CODE>false</CODE> if not.
    */
-  public boolean valueIsAcceptable(ByteString value,
+  public boolean valueIsAcceptable(ByteSequence value,
                                    MessageBuilder invalidReason)
   {
     // Get a lowercase string representation of the value and find its length.
-    String valueString = toLowerCase(value.stringValue());
+    String valueString = toLowerCase(value.toString());
     int    valueLength = valueString.length();
 
 
diff --git a/opends/src/server/org/opends/server/schema/FaxSyntax.java b/opends/src/server/org/opends/server/schema/FaxSyntax.java
index 33d96ab..450d364 100644
--- a/opends/src/server/org/opends/server/schema/FaxSyntax.java
+++ b/opends/src/server/org/opends/server/schema/FaxSyntax.java
@@ -36,8 +36,7 @@
 import org.opends.server.api.SubstringMatchingRule;
 import org.opends.server.config.ConfigException;
 import org.opends.server.core.DirectoryServer;
-import org.opends.server.types.ByteString;
-
+import org.opends.server.types.ByteSequence;
 
 
 import static org.opends.server.loggers.ErrorLogger.*;
@@ -220,7 +219,7 @@
    * @return  <CODE>true</CODE> if the provided value is acceptable for use with
    *          this syntax, or <CODE>false</CODE> if not.
    */
-  public boolean valueIsAcceptable(ByteString value,
+  public boolean valueIsAcceptable(ByteSequence value,
                                    MessageBuilder invalidReason)
   {
     // All values will be acceptable for the fax syntax.
diff --git a/opends/src/server/org/opends/server/schema/GeneralizedTimeEqualityMatchingRule.java b/opends/src/server/org/opends/server/schema/GeneralizedTimeEqualityMatchingRule.java
index 40e8522..2d22cc6 100644
--- a/opends/src/server/org/opends/server/schema/GeneralizedTimeEqualityMatchingRule.java
+++ b/opends/src/server/org/opends/server/schema/GeneralizedTimeEqualityMatchingRule.java
@@ -28,19 +28,21 @@
 
 
 
-import java.util.Collections;
+import static org.opends.server.loggers.ErrorLogger.*;
+import static org.opends.server.loggers.debug.DebugLogger.*;
+import static org.opends.server.schema.SchemaConstants.*;
+
 import java.util.Collection;
+import java.util.Collections;
+
 import org.opends.server.api.EqualityMatchingRule;
 import org.opends.server.core.DirectoryServer;
 import org.opends.server.loggers.debug.DebugTracer;
-import org.opends.server.protocols.asn1.ASN1OctetString;
+import org.opends.server.types.ByteSequence;
 import org.opends.server.types.ByteString;
 import org.opends.server.types.DebugLogLevel;
 import org.opends.server.types.DirectoryException;
 
-import static org.opends.server.loggers.ErrorLogger.*;
-import static org.opends.server.loggers.debug.DebugLogger.*;
-import static org.opends.server.schema.SchemaConstants.*;
 
 
 /**
@@ -70,6 +72,7 @@
   /**
    * {@inheritDoc}
    */
+  @Override
   public Collection<String> getAllNames()
   {
     return Collections.singleton(getName());
@@ -83,6 +86,7 @@
    * @return  The common name for this matching rule, or <CODE>null</CODE> if
    * it does not have a name.
    */
+  @Override
   public String getName()
   {
     return EMR_GENERALIZED_TIME_NAME;
@@ -95,6 +99,7 @@
    *
    * @return  The OID for this matching rule.
    */
+  @Override
   public String getOID()
   {
     return EMR_GENERALIZED_TIME_OID;
@@ -108,6 +113,7 @@
    * @return  The description for this matching rule, or <CODE>null</CODE> if
    *          there is none.
    */
+  @Override
   public String getDescription()
   {
     // There is no standard description for this matching rule.
@@ -122,6 +128,7 @@
    *
    * @return  The OID of the syntax with which this matching rule is associated.
    */
+  @Override
   public String getSyntaxOID()
   {
     return SYNTAX_GENERALIZED_TIME_OID;
@@ -140,13 +147,14 @@
    * @throws  DirectoryException  If the provided value is invalid according to
    *                              the associated attribute syntax.
    */
-  public ByteString normalizeValue(ByteString value)
+  @Override
+  public ByteString normalizeValue(ByteSequence value)
          throws DirectoryException
   {
     try
     {
       long timestamp = GeneralizedTimeSyntax.decodeGeneralizedTimeValue(value);
-      return new ASN1OctetString(GeneralizedTimeSyntax.format(timestamp));
+      return ByteString.valueOf(GeneralizedTimeSyntax.format(timestamp));
     }
     catch (DirectoryException de)
     {
@@ -162,10 +170,10 @@
 
         case WARN:
           logError(de.getMessageObject());
-          return new ASN1OctetString(value.value());
+          return value.toByteString();
 
         default:
-          return new ASN1OctetString(value.value());
+          return value.toByteString();
       }
     }
   }
@@ -182,7 +190,8 @@
    * @return  <CODE>true</CODE> if the provided values are equal, or
    *          <CODE>false</CODE> if not.
    */
-  public boolean areEqual(ByteString value1, ByteString value2)
+  @Override
+  public boolean areEqual(ByteSequence value1, ByteSequence value2)
   {
     try
     {
diff --git a/opends/src/server/org/opends/server/schema/GeneralizedTimeOrderingMatchingRule.java b/opends/src/server/org/opends/server/schema/GeneralizedTimeOrderingMatchingRule.java
index 54335ee..01c02e0 100644
--- a/opends/src/server/org/opends/server/schema/GeneralizedTimeOrderingMatchingRule.java
+++ b/opends/src/server/org/opends/server/schema/GeneralizedTimeOrderingMatchingRule.java
@@ -28,20 +28,21 @@
 
 
 
-import java.util.Collection;
-import java.util.Collections;
-import org.opends.server.api.OrderingMatchingRule;
-import org.opends.server.core.DirectoryServer;
-import org.opends.server.loggers.debug.DebugTracer;
-import org.opends.server.protocols.asn1.ASN1OctetString;
-import org.opends.server.types.ByteString;
-import org.opends.server.types.DebugLogLevel;
-import org.opends.server.types.DirectoryException;
-
 import static org.opends.server.loggers.ErrorLogger.*;
 import static org.opends.server.loggers.debug.DebugLogger.*;
 import static org.opends.server.schema.SchemaConstants.*;
 
+import java.util.Collection;
+import java.util.Collections;
+
+import org.opends.server.api.OrderingMatchingRule;
+import org.opends.server.core.DirectoryServer;
+import org.opends.server.loggers.debug.DebugTracer;
+import org.opends.server.types.ByteSequence;
+import org.opends.server.types.ByteString;
+import org.opends.server.types.DebugLogLevel;
+import org.opends.server.types.DirectoryException;
+
 
 
 /**
@@ -81,6 +82,7 @@
   /**
    * {@inheritDoc}
    */
+  @Override
   public Collection<String> getAllNames()
   {
     return Collections.singleton(getName());
@@ -94,6 +96,7 @@
    * @return  The common name for this matching rule, or <CODE>null</CODE> if
    * it does not have a name.
    */
+  @Override
   public String getName()
   {
     return OMR_GENERALIZED_TIME_NAME;
@@ -106,6 +109,7 @@
    *
    * @return  The OID for this matching rule.
    */
+  @Override
   public String getOID()
   {
     return OMR_GENERALIZED_TIME_OID;
@@ -119,6 +123,7 @@
    * @return  The description for this matching rule, or <CODE>null</CODE> if
    *          there is none.
    */
+  @Override
   public String getDescription()
   {
     // There is no standard description for this matching rule.
@@ -133,6 +138,7 @@
    *
    * @return  The OID of the syntax with which this matching rule is associated.
    */
+  @Override
   public String getSyntaxOID()
   {
     return SYNTAX_GENERALIZED_TIME_OID;
@@ -151,13 +157,14 @@
    * @throws  DirectoryException  If the provided value is invalid according to
    *                              the associated attribute syntax.
    */
-  public ByteString normalizeValue(ByteString value)
+  @Override
+  public ByteString normalizeValue(ByteSequence value)
          throws DirectoryException
   {
     try
     {
       long timestamp = GeneralizedTimeSyntax.decodeGeneralizedTimeValue(value);
-      return new ASN1OctetString(GeneralizedTimeSyntax.format(timestamp));
+      return ByteString.valueOf(GeneralizedTimeSyntax.format(timestamp));
     }
     catch (DirectoryException de)
     {
@@ -173,10 +180,10 @@
 
         case WARN:
           logError(de.getMessageObject());
-          return new ASN1OctetString(value.value());
+          return value.toByteString();
 
         default:
-          return new ASN1OctetString(value.value());
+          return value.toByteString();
       }
     }
   }
@@ -196,7 +203,8 @@
    *          ascending order, or zero if there is no difference between the
    *          values with regard to ordering.
    */
-  public int compareValues(ByteString value1, ByteString value2)
+  @Override
+  public int compareValues(ByteSequence value1, ByteSequence value2)
   {
     try
     {
@@ -244,7 +252,7 @@
    */
   public int compare(byte[] b1, byte[] b2)
   {
-    return compareValues(new ASN1OctetString(b1), new ASN1OctetString(b2));
+    return compareValues(ByteString.wrap(b1), ByteString.wrap(b2));
   }
 }
 
diff --git a/opends/src/server/org/opends/server/schema/GeneralizedTimeSyntax.java b/opends/src/server/org/opends/server/schema/GeneralizedTimeSyntax.java
index ec0ef9f..ad27471 100644
--- a/opends/src/server/org/opends/server/schema/GeneralizedTimeSyntax.java
+++ b/opends/src/server/org/opends/server/schema/GeneralizedTimeSyntax.java
@@ -45,12 +45,7 @@
 import org.opends.server.config.ConfigException;
 import org.opends.server.core.DirectoryServer;
 import org.opends.server.loggers.debug.DebugTracer;
-import org.opends.server.protocols.asn1.ASN1OctetString;
-import org.opends.server.types.AttributeValue;
-import org.opends.server.types.ByteString;
-import org.opends.server.types.DebugLogLevel;
-import org.opends.server.types.DirectoryException;
-import org.opends.server.types.ResultCode;
+import org.opends.server.types.*;
 
 import static org.opends.messages.SchemaMessages.*;
 import static org.opends.server.loggers.ErrorLogger.*;
@@ -272,7 +267,7 @@
    * @return  <CODE>true</CODE> if the provided value is acceptable for use with
    *          this syntax, or <CODE>false</CODE> if not.
    */
-  public boolean valueIsAcceptable(ByteString value,
+  public boolean valueIsAcceptable(ByteSequence value,
                                    MessageBuilder invalidReason)
   {
     try
@@ -341,8 +336,8 @@
       valueString = dateFormat.format(new Date(time));
     }
 
-    return new AttributeValue(new ASN1OctetString(valueString),
-                              new ASN1OctetString(valueString));
+    return AttributeValues.create(ByteString.valueOf(valueString),
+        ByteString.valueOf(valueString));
   }
 
 
@@ -359,7 +354,7 @@
    * @throws  DirectoryException  If the provided value cannot be parsed as a
    *                              valid generalized time string.
    */
-  public static long decodeGeneralizedTimeValue(ByteString value)
+  public static long decodeGeneralizedTimeValue(ByteSequence value)
          throws DirectoryException
   {
     int year        = 0;
@@ -372,7 +367,7 @@
 
     // Get the value as a string and verify that it is at least long enough for
     // "YYYYMMDDhhZ", which is the shortest allowed value.
-    String valueString = value.stringValue().toUpperCase();
+    String valueString = value.toString().toUpperCase();
     int    length      = valueString.length();
     if (length < 11)
     {
diff --git a/opends/src/server/org/opends/server/schema/GuideSyntax.java b/opends/src/server/org/opends/server/schema/GuideSyntax.java
index fb62e79..8990a07 100644
--- a/opends/src/server/org/opends/server/schema/GuideSyntax.java
+++ b/opends/src/server/org/opends/server/schema/GuideSyntax.java
@@ -36,8 +36,7 @@
 import org.opends.server.api.SubstringMatchingRule;
 import org.opends.server.config.ConfigException;
 import org.opends.server.core.DirectoryServer;
-import org.opends.server.types.ByteString;
-
+import org.opends.server.types.ByteSequence;
 
 
 import static org.opends.server.loggers.ErrorLogger.*;
@@ -221,11 +220,11 @@
    * @return  <CODE>true</CODE> if the provided value is acceptable for use with
    *          this syntax, or <CODE>false</CODE> if not.
    */
-  public boolean valueIsAcceptable(ByteString value,
+  public boolean valueIsAcceptable(ByteSequence value,
                                    MessageBuilder invalidReason)
   {
     // Get a lowercase string version of the provided value.
-    String valueStr = toLowerCase(value.stringValue());
+    String valueStr = toLowerCase(value.toString());
 
 
     // Find the position of the octothorpe.  If there isn't one, then the entire
diff --git a/opends/src/server/org/opends/server/schema/IA5StringSyntax.java b/opends/src/server/org/opends/server/schema/IA5StringSyntax.java
index a2e1176..6ddccd4 100644
--- a/opends/src/server/org/opends/server/schema/IA5StringSyntax.java
+++ b/opends/src/server/org/opends/server/schema/IA5StringSyntax.java
@@ -37,8 +37,7 @@
 import org.opends.server.api.SubstringMatchingRule;
 import org.opends.server.config.ConfigException;
 import org.opends.server.core.DirectoryServer;
-import org.opends.server.types.ByteString;
-
+import org.opends.server.types.ByteSequence;
 
 
 import static org.opends.server.loggers.ErrorLogger.*;
@@ -232,18 +231,20 @@
    * @return  <CODE>true</CODE> if the provided value is acceptable for use with
    *          this syntax, or <CODE>false</CODE> if not.
    */
-  public boolean valueIsAcceptable(ByteString value,
+  public boolean valueIsAcceptable(ByteSequence value,
                                    MessageBuilder invalidReason)
   {
     // We will allow any value that does not contain any non-ASCII characters.
     // Empty values are acceptable as well.
-    for (byte b : value.value())
+    byte b;
+    for (int i = 0; i < value.length(); i++)
     {
+      b = value.byteAt(i);
       if ((b & 0x7F) != b)
       {
 
         Message message = WARN_ATTR_SYNTAX_IA5_ILLEGAL_CHARACTER.get(
-                value.stringValue(), String.valueOf(b));
+                value.toString(), String.valueOf(b));
         invalidReason.append(message);
         return false;
       }
diff --git a/opends/src/server/org/opends/server/schema/IntegerEqualityMatchingRule.java b/opends/src/server/org/opends/server/schema/IntegerEqualityMatchingRule.java
index 2acf40d..28a725d 100644
--- a/opends/src/server/org/opends/server/schema/IntegerEqualityMatchingRule.java
+++ b/opends/src/server/org/opends/server/schema/IntegerEqualityMatchingRule.java
@@ -25,24 +25,24 @@
  *      Copyright 2006-2008 Sun Microsystems, Inc.
  */
 package org.opends.server.schema;
-import org.opends.messages.Message;
 
 
 
-import java.util.Arrays;
+import static org.opends.messages.SchemaMessages.*;
+import static org.opends.server.schema.SchemaConstants.*;
 
 import java.util.Collection;
 import java.util.Collections;
+
+import org.opends.messages.Message;
 import org.opends.server.api.EqualityMatchingRule;
 import org.opends.server.core.DirectoryServer;
-import org.opends.server.protocols.asn1.ASN1OctetString;
+import org.opends.server.loggers.ErrorLogger;
+import org.opends.server.types.ByteSequence;
 import org.opends.server.types.ByteString;
 import org.opends.server.types.DirectoryException;
 import org.opends.server.types.ResultCode;
 
-import static org.opends.messages.SchemaMessages.*;
-import static org.opends.server.schema.SchemaConstants.*;
-import org.opends.server.loggers.ErrorLogger;
 
 
 /**
@@ -65,6 +65,7 @@
   /**
    * {@inheritDoc}
    */
+  @Override
   public Collection<String> getAllNames()
   {
     return Collections.singleton(getName());
@@ -78,6 +79,7 @@
    * @return  The common name for this matching rule, or <CODE>null</CODE> if
    * it does not have a name.
    */
+  @Override
   public String getName()
   {
     return EMR_INTEGER_NAME;
@@ -90,6 +92,7 @@
    *
    * @return  The OID for this matching rule.
    */
+  @Override
   public String getOID()
   {
     return EMR_INTEGER_OID;
@@ -103,6 +106,7 @@
    * @return  The description for this matching rule, or <CODE>null</CODE> if
    *          there is none.
    */
+  @Override
   public String getDescription()
   {
     // There is no standard description for this matching rule.
@@ -117,6 +121,7 @@
    *
    * @return  The OID of the syntax with which this matching rule is associated.
    */
+  @Override
   public String getSyntaxOID()
   {
     return SYNTAX_INTEGER_OID;
@@ -135,18 +140,17 @@
    * @throws  DirectoryException  If the provided value is invalid according to
    *                              the associated attribute syntax.
    */
-  public ByteString normalizeValue(ByteString value)
+  @Override
+  public ByteString normalizeValue(ByteSequence value)
          throws DirectoryException
   {
-    byte[] valueBytes = value.value();
-
-    int length = valueBytes.length;
+    int length = value.length();
     StringBuilder buffer = new StringBuilder(length);
 
     boolean logged = false;
     for (int i=0; i < length; i++)
     {
-      switch (valueBytes[i])
+      switch (value.byteAt(i))
       {
         case '0':
           switch (buffer.length())
@@ -160,7 +164,7 @@
               else
               {
                 Message message = WARN_ATTR_SYNTAX_INTEGER_INITIAL_ZERO.get(
-                        value.stringValue());
+                        value.toString());
 
                 switch (DirectoryServer.getSyntaxEnforcementPolicy())
                 {
@@ -182,7 +186,7 @@
               if (buffer.charAt(0) == '-')
               {
                 Message message = WARN_ATTR_SYNTAX_INTEGER_INITIAL_ZERO.get(
-                        value.stringValue());
+                        value.toString());
 
                 switch (DirectoryServer.getSyntaxEnforcementPolicy())
                 {
@@ -245,7 +249,7 @@
           else
           {
             Message message = WARN_ATTR_SYNTAX_INTEGER_MISPLACED_DASH.get(
-                    value.stringValue());
+                    value.toString());
 
             switch (DirectoryServer.getSyntaxEnforcementPolicy())
             {
@@ -264,8 +268,8 @@
           break;
         default:
           Message message = WARN_ATTR_SYNTAX_INTEGER_INVALID_CHARACTER.get(
-                  value.stringValue(),
-                  ((char) valueBytes[i]), i);
+                  value.toString(),
+                  ((char) value.byteAt(i)), i);
           switch (DirectoryServer.getSyntaxEnforcementPolicy())
           {
             case REJECT:
@@ -285,7 +289,7 @@
     if (buffer.length() == 0)
     {
       Message message = WARN_ATTR_SYNTAX_INTEGER_EMPTY_VALUE.get(
-              value.stringValue());
+              value.toString());
 
       switch (DirectoryServer.getSyntaxEnforcementPolicy())
       {
@@ -311,7 +315,7 @@
     else if ((buffer.length() == 1) && (buffer.charAt(0) == '-'))
     {
       Message message = WARN_ATTR_SYNTAX_INTEGER_DASH_NEEDS_VALUE.get(
-              value.stringValue());
+              value.toString());
       switch (DirectoryServer.getSyntaxEnforcementPolicy())
       {
         case REJECT:
@@ -334,26 +338,7 @@
       }
     }
 
-    return new ASN1OctetString(buffer.toString());
-  }
-
-
-
-  /**
-   * Indicates whether the two provided normalized values are equal to each
-   * other.
-   *
-   * @param  value1  The normalized form of the first value to compare.
-   * @param  value2  The normalized form of the second value to compare.
-   *
-   * @return  <CODE>true</CODE> if the provided values are equal, or
-   *          <CODE>false</CODE> if not.
-   */
-  public boolean areEqual(ByteString value1, ByteString value2)
-  {
-    // Since the values are already normalized, we just need to compare the
-    // associated byte arrays.
-    return Arrays.equals(value1.value(), value2.value());
+    return ByteString.valueOf(buffer.toString());
   }
 }
 
diff --git a/opends/src/server/org/opends/server/schema/IntegerFirstComponentEqualityMatchingRule.java b/opends/src/server/org/opends/server/schema/IntegerFirstComponentEqualityMatchingRule.java
index 901ff63..7fc5c62 100644
--- a/opends/src/server/org/opends/server/schema/IntegerFirstComponentEqualityMatchingRule.java
+++ b/opends/src/server/org/opends/server/schema/IntegerFirstComponentEqualityMatchingRule.java
@@ -25,26 +25,27 @@
  *      Copyright 2006-2008 Sun Microsystems, Inc.
  */
 package org.opends.server.schema;
-import java.util.Collection;
-import java.util.Collections;
-import org.opends.messages.Message;
 
 
 
-import org.opends.server.api.EqualityMatchingRule;
-import org.opends.server.protocols.asn1.ASN1OctetString;
-import org.opends.server.types.AttributeValue;
-import org.opends.server.types.ByteString;
-import org.opends.server.types.DirectoryException;
-import org.opends.server.types.ResultCode;
-
-import static org.opends.server.loggers.debug.DebugLogger.*;
-import org.opends.server.loggers.debug.DebugTracer;
-import org.opends.server.types.DebugLogLevel;
 import static org.opends.messages.SchemaMessages.*;
+import static org.opends.server.loggers.debug.DebugLogger.*;
 import static org.opends.server.schema.SchemaConstants.*;
 import static org.opends.server.util.StaticUtils.*;
 
+import java.util.Collection;
+import java.util.Collections;
+
+import org.opends.messages.Message;
+import org.opends.server.api.EqualityMatchingRule;
+import org.opends.server.loggers.debug.DebugTracer;
+import org.opends.server.types.ByteSequence;
+import org.opends.server.types.ByteString;
+import org.opends.server.types.DebugLogLevel;
+import org.opends.server.types.DirectoryException;
+import org.opends.server.types.ResultCode;
+import org.opends.server.util.ServerConstants;
+
 
 
 /**
@@ -79,6 +80,7 @@
   /**
    * {@inheritDoc}
    */
+  @Override
   public Collection<String> getAllNames()
   {
     return Collections.singleton(getName());
@@ -92,6 +94,7 @@
    * @return  The common name for this matching rule, or <CODE>null</CODE> if
    * it does not have a name.
    */
+  @Override
   public String getName()
   {
     return EMR_INTEGER_FIRST_COMPONENT_NAME;
@@ -104,6 +107,7 @@
    *
    * @return  The OID for this matching rule.
    */
+  @Override
   public String getOID()
   {
     return EMR_INTEGER_FIRST_COMPONENT_OID;
@@ -117,6 +121,7 @@
    * @return  The description for this matching rule, or <CODE>null</CODE> if
    *          there is none.
    */
+  @Override
   public String getDescription()
   {
     // There is no standard description for this matching rule.
@@ -131,6 +136,7 @@
    *
    * @return  The OID of the syntax with which this matching rule is associated.
    */
+  @Override
   public String getSyntaxOID()
   {
     return SYNTAX_INTEGER_OID;
@@ -149,25 +155,26 @@
    * @throws  DirectoryException  If the provided value is invalid according to
    *                              the associated attribute syntax.
    */
-  public ByteString normalizeValue(ByteString value)
+  @Override
+  public ByteString normalizeValue(ByteSequence value)
          throws DirectoryException
   {
     StringBuilder buffer = new StringBuilder();
-    toLowerCase(value.value(), buffer, true);
+    toLowerCase(value, buffer, true);
 
     int bufferLength = buffer.length();
     if (bufferLength == 0)
     {
-      if (value.value().length > 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 ASN1OctetString(" ");
+        return ServerConstants.SINGLE_SPACE_VALUE;
       }
       else
       {
         // The value is empty, so it is already normalized.
-        return new ASN1OctetString();
+        return ByteString.empty();
       }
     }
 
@@ -184,7 +191,7 @@
       }
     }
 
-    return new ASN1OctetString(buffer.toString());
+    return ByteString.valueOf(buffer.toString());
   }
 
 
@@ -199,12 +206,13 @@
    * @return  <CODE>true</CODE> if the provided values are equal, or
    *          <CODE>false</CODE> if not.
    */
-  public boolean areEqual(ByteString value1, ByteString value2)
+  @Override
+  public boolean areEqual(ByteSequence value1, ByteSequence value2)
   {
     try
     {
-      int intValue1 = extractIntValue(value1.stringValue());
-      int intValue2 = extractIntValue(value2.stringValue());
+      int intValue1 = extractIntValue(value1.toString());
+      int intValue2 = extractIntValue(value2.toString());
 
       return (intValue1 == intValue2);
     }
@@ -235,7 +243,8 @@
    *
    * @return  The hash code generated for the provided attribute value.
    */
-  public int generateHashCode(AttributeValue attributeValue)
+  @Override
+  public int generateHashCode(ByteSequence attributeValue)
   {
     // In this case, we'll always return the same value because the matching
     // isn't based on the entire value.
@@ -282,9 +291,8 @@
       }
     }
 
-    char c;
     int  pos = 1;
-    while ((pos < valueLength) && ((c = valueString.charAt(pos)) == ' '))
+    while ((pos < valueLength) && ((valueString.charAt(pos)) == ' '))
     {
       pos++;
     }
@@ -301,7 +309,7 @@
     // The current position must be the start position for the value.  Keep
     // reading until we find the next space.
     int startPos = pos++;
-    while ((pos < valueLength) && ((c = valueString.charAt(pos)) != ' '))
+    while ((pos < valueLength) && ((valueString.charAt(pos)) != ' '))
     {
       pos++;
     }
diff --git a/opends/src/server/org/opends/server/schema/IntegerOrderingMatchingRule.java b/opends/src/server/org/opends/server/schema/IntegerOrderingMatchingRule.java
index 917f858..a05e469 100644
--- a/opends/src/server/org/opends/server/schema/IntegerOrderingMatchingRule.java
+++ b/opends/src/server/org/opends/server/schema/IntegerOrderingMatchingRule.java
@@ -26,22 +26,23 @@
  */
 package org.opends.server.schema;
 
-import java.util.Collections;
+
+
+import static org.opends.messages.SchemaMessages.*;
+import static org.opends.server.loggers.ErrorLogger.*;
+import static org.opends.server.schema.SchemaConstants.*;
+
 import java.util.Collection;
+import java.util.Collections;
+
 import org.opends.messages.Message;
-
-
-
 import org.opends.server.api.OrderingMatchingRule;
 import org.opends.server.core.DirectoryServer;
-import org.opends.server.protocols.asn1.ASN1OctetString;
+import org.opends.server.types.ByteSequence;
 import org.opends.server.types.ByteString;
 import org.opends.server.types.DirectoryException;
 import org.opends.server.types.ResultCode;
 
-import static org.opends.server.loggers.ErrorLogger.*;
-import static org.opends.messages.SchemaMessages.*;
-import static org.opends.server.schema.SchemaConstants.*;
 
 
 /**
@@ -74,6 +75,7 @@
   /**
    * {@inheritDoc}
    */
+  @Override
   public Collection<String> getAllNames()
   {
     return Collections.singleton(getName());
@@ -87,6 +89,7 @@
    * @return  The common name for this matching rule, or <CODE>null</CODE> if
    * it does not have a name.
    */
+  @Override
   public String getName()
   {
     return OMR_INTEGER_NAME;
@@ -99,6 +102,7 @@
    *
    * @return  The OID for this matching rule.
    */
+  @Override
   public String getOID()
   {
     return OMR_INTEGER_OID;
@@ -112,6 +116,7 @@
    * @return  The description for this matching rule, or <CODE>null</CODE> if
    *          there is none.
    */
+  @Override
   public String getDescription()
   {
     // There is no standard description for this matching rule.
@@ -126,6 +131,7 @@
    *
    * @return  The OID of the syntax with which this matching rule is associated.
    */
+  @Override
   public String getSyntaxOID()
   {
     return SYNTAX_INTEGER_OID;
@@ -144,18 +150,17 @@
    * @throws  DirectoryException  If the provided value is invalid according to
    *                              the associated attribute syntax.
    */
-  public ByteString normalizeValue(ByteString value)
+  @Override
+  public ByteString normalizeValue(ByteSequence value)
          throws DirectoryException
   {
-    byte[] valueBytes = value.value();
-
-    int length = valueBytes.length;
+    int length = value.length();
     StringBuilder buffer = new StringBuilder(length);
 
     boolean logged = false;
     for (int i=0; i < length; i++)
     {
-      switch (valueBytes[i])
+      switch (value.byteAt(i))
       {
         case '0':
           switch (buffer.length())
@@ -170,7 +175,7 @@
               {
 
                 Message message = WARN_ATTR_SYNTAX_INTEGER_INITIAL_ZERO.get(
-                        value.stringValue());
+                        value.toString());
 
                 switch (DirectoryServer.getSyntaxEnforcementPolicy())
                 {
@@ -193,7 +198,7 @@
               {
 
                 Message message = WARN_ATTR_SYNTAX_INTEGER_INITIAL_ZERO.get(
-                        value.stringValue());
+                        value.toString());
 
                 switch (DirectoryServer.getSyntaxEnforcementPolicy())
                 {
@@ -257,7 +262,7 @@
           else
           {
             Message message = WARN_ATTR_SYNTAX_INTEGER_MISPLACED_DASH.get(
-                    value.stringValue());
+                    value.toString());
 
             switch (DirectoryServer.getSyntaxEnforcementPolicy())
             {
@@ -277,8 +282,8 @@
           break;
         default:
           Message message = WARN_ATTR_SYNTAX_INTEGER_INVALID_CHARACTER.get(
-                  value.stringValue(),
-                  ((char) valueBytes[i]), i);
+                  value.toString(),
+                  ((char) value.byteAt(i)), i);
           switch (DirectoryServer.getSyntaxEnforcementPolicy())
           {
             case REJECT:
@@ -299,7 +304,7 @@
     if (buffer.length() == 0)
     {
       Message message = WARN_ATTR_SYNTAX_INTEGER_EMPTY_VALUE.get(
-              value.stringValue());
+              value.toString());
 
       switch (DirectoryServer.getSyntaxEnforcementPolicy())
       {
@@ -326,7 +331,7 @@
     else if ((buffer.length() == 1) && (buffer.charAt(0) == '-'))
     {
       Message message = WARN_ATTR_SYNTAX_INTEGER_DASH_NEEDS_VALUE.get(
-              value.stringValue());
+              value.toString());
 
       switch (DirectoryServer.getSyntaxEnforcementPolicy())
       {
@@ -351,7 +356,7 @@
       }
     }
 
-    return new ASN1OctetString(buffer.toString());
+    return ByteString.valueOf(buffer.toString());
   }
 
 
@@ -369,9 +374,108 @@
    *          ascending order, or zero if there is no difference between the
    *          values with regard to ordering.
    */
-  public int compareValues(ByteString value1, ByteString value2)
+  @Override
+  public int compareValues(ByteSequence value1, ByteSequence value2)
   {
-    return compare(value1.value(), value2.value());
+    int b1Length = value1.length();
+    int b2Length = value2.length();
+
+
+    // A length of zero should be considered a value of zero.
+    if (b1Length == 0)
+    {
+      if (b2Length == 0)
+      {
+        return 0;
+      }
+      else if (value2.byteAt(0) == '-')
+      {
+        return 1;
+      }
+      else
+      {
+        return -1;
+      }
+    }
+    else if (b2Length == 0)
+    {
+      if (value1.byteAt(0) == '-')
+      {
+        return -1;
+      }
+      else
+      {
+        return 1;
+      }
+    }
+
+
+    // Starting with a dash should be an indicator of a negative value.
+    if (value1.byteAt(0) == '-')
+    {
+      if (value2.byteAt(0) == '-')
+      {
+        if (b1Length > b2Length)
+        {
+          return -1;
+        }
+        else if (b2Length > b1Length)
+        {
+          return 1;
+        }
+        else
+        {
+          for (int i=1; i < b1Length; i++)
+          {
+            if (value1.byteAt(i) > value2.byteAt(i))
+            {
+              return -1;
+            }
+            else if (value1.byteAt(i) < value2.byteAt(i))
+            {
+              return 1;
+            }
+          }
+
+          return 0;
+        }
+      }
+      else
+      {
+        return -1;
+      }
+    }
+    else if (value2.byteAt(0) == '-')
+    {
+      return 1;
+    }
+
+
+    // They are both positive, so see which one's bigger.
+    if (b1Length > b2Length)
+    {
+      return 1;
+    }
+    else if (b2Length > b1Length)
+    {
+      return -1;
+    }
+    else
+    {
+      for (int i=0; i < b1Length; i++)
+      {
+        if (value1.byteAt(i) > value2.byteAt(i))
+        {
+          return 1;
+        }
+        else if (value1.byteAt(i) < value2.byteAt(i))
+        {
+          return -1;
+        }
+      }
+
+      return 0;
+    }
   }
 
 
diff --git a/opends/src/server/org/opends/server/schema/IntegerSyntax.java b/opends/src/server/org/opends/server/schema/IntegerSyntax.java
index 5d99577..ffe0877 100644
--- a/opends/src/server/org/opends/server/schema/IntegerSyntax.java
+++ b/opends/src/server/org/opends/server/schema/IntegerSyntax.java
@@ -38,12 +38,9 @@
 import org.opends.server.api.SubstringMatchingRule;
 import org.opends.server.config.ConfigException;
 import org.opends.server.core.DirectoryServer;
-import org.opends.server.types.AttributeValue;
-import org.opends.server.types.ByteString;
-import org.opends.server.types.DirectoryException;
 
 
-import org.opends.server.types.ResultCode;
+import org.opends.server.types.*;
 
 import static org.opends.server.loggers.ErrorLogger.*;
 import static org.opends.messages.SchemaMessages.*;
@@ -84,12 +81,12 @@
       ByteString nvalue = value.getNormalizedValue();
       try
       {
-        return Integer.valueOf(nvalue.stringValue());
+        return Integer.valueOf(nvalue.toString());
       }
       catch (NumberFormatException e)
       {
         Message message =
-            WARN_ATTR_SYNTAX_ILLEGAL_INTEGER.get(nvalue.stringValue());
+            WARN_ATTR_SYNTAX_ILLEGAL_INTEGER.get(nvalue.toString());
         throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX,
             message);
       }
@@ -253,10 +250,10 @@
    * @return  <CODE>true</CODE> if the provided value is acceptable for use with
    *          this syntax, or <CODE>false</CODE> if not.
    */
-  public boolean valueIsAcceptable(ByteString value,
+  public boolean valueIsAcceptable(ByteSequence value,
                                    MessageBuilder invalidReason)
   {
-    String valueString = value.stringValue();
+    String valueString = value.toString();
     int    length      = valueString.length();
 
     if (length == 0)
diff --git a/opends/src/server/org/opends/server/schema/JPEGSyntax.java b/opends/src/server/org/opends/server/schema/JPEGSyntax.java
index d9e56c5..4e20310 100644
--- a/opends/src/server/org/opends/server/schema/JPEGSyntax.java
+++ b/opends/src/server/org/opends/server/schema/JPEGSyntax.java
@@ -36,8 +36,7 @@
 import org.opends.server.api.SubstringMatchingRule;
 import org.opends.server.config.ConfigException;
 import org.opends.server.core.DirectoryServer;
-import org.opends.server.types.ByteString;
-
+import org.opends.server.types.ByteSequence;
 
 
 import static org.opends.server.loggers.ErrorLogger.*;
@@ -220,7 +219,7 @@
    * @return  <CODE>true</CODE> if the provided value is acceptable for use with
    *          this syntax, or <CODE>false</CODE> if not.
    */
-  public boolean valueIsAcceptable(ByteString value,
+  public boolean valueIsAcceptable(ByteSequence value,
                                    MessageBuilder invalidReason)
   {
     // All values will be acceptable for the JPEG syntax.
diff --git a/opends/src/server/org/opends/server/schema/LDAPSyntaxDescriptionSyntax.java b/opends/src/server/org/opends/server/schema/LDAPSyntaxDescriptionSyntax.java
index ae0f217..d36b900 100644
--- a/opends/src/server/org/opends/server/schema/LDAPSyntaxDescriptionSyntax.java
+++ b/opends/src/server/org/opends/server/schema/LDAPSyntaxDescriptionSyntax.java
@@ -37,16 +37,12 @@
 import org.opends.server.api.SubstringMatchingRule;
 import org.opends.server.config.ConfigException;
 import org.opends.server.core.DirectoryServer;
-import org.opends.server.types.ByteString;
-import org.opends.server.types.DirectoryException;
 
 
-import org.opends.server.types.ResultCode;
-
 import static org.opends.server.loggers.debug.DebugLogger.*;
 import org.opends.server.loggers.debug.DebugTracer;
 import static org.opends.server.loggers.ErrorLogger.*;
-import org.opends.server.types.DebugLogLevel;
+import org.opends.server.types.*;
 import static org.opends.messages.SchemaMessages.*;
 import org.opends.messages.MessageBuilder;
 import static org.opends.server.schema.SchemaConstants.*;
@@ -96,6 +92,7 @@
   /**
    * {@inheritDoc}
    */
+  @Override
   public void initializeSyntax(AttributeSyntaxCfg configuration)
          throws ConfigException
   {
@@ -131,6 +128,7 @@
    *
    * @return  The common name for this attribute syntax.
    */
+  @Override
   public String getSyntaxName()
   {
     return SYNTAX_LDAP_SYNTAX_NAME;
@@ -143,6 +141,7 @@
    *
    * @return  The OID for this attribute syntax.
    */
+  @Override
   public String getOID()
   {
     return SYNTAX_LDAP_SYNTAX_OID;
@@ -155,6 +154,7 @@
    *
    * @return  A description for this attribute syntax.
    */
+  @Override
   public String getDescription()
   {
     return SYNTAX_LDAP_SYNTAX_DESCRIPTION;
@@ -170,6 +170,7 @@
    *          attributes with this syntax, or <CODE>null</CODE> if equality
    *          matches will not be allowed for this type by default.
    */
+  @Override
   public EqualityMatchingRule getEqualityMatchingRule()
   {
     return defaultEqualityMatchingRule;
@@ -185,6 +186,7 @@
    *          attributes with this syntax, or <CODE>null</CODE> if ordering
    *          matches will not be allowed for this type by default.
    */
+  @Override
   public OrderingMatchingRule getOrderingMatchingRule()
   {
     return defaultOrderingMatchingRule;
@@ -200,6 +202,7 @@
    *          attributes with this syntax, or <CODE>null</CODE> if substring
    *          matches will not be allowed for this type by default.
    */
+  @Override
   public SubstringMatchingRule getSubstringMatchingRule()
   {
     return defaultSubstringMatchingRule;
@@ -215,6 +218,7 @@
    *          attributes with this syntax, or <CODE>null</CODE> if approximate
    *          matches will not be allowed for this type by default.
    */
+  @Override
   public ApproximateMatchingRule getApproximateMatchingRule()
   {
     // There is no approximate matching rule by default.
@@ -235,12 +239,13 @@
    * @return  <CODE>true</CODE> if the provided value is acceptable for use with
    *          this syntax, or <CODE>false</CODE> if not.
    */
-  public boolean valueIsAcceptable(ByteString value,
+  @Override
+  public boolean valueIsAcceptable(ByteSequence value,
                                    MessageBuilder invalidReason)
   {
     // Get string representations of the provided value using the provided form
     // and with all lowercase characters.
-    String valueStr = value.stringValue();
+    String valueStr = value.toString();
     String lowerStr = toLowerCase(valueStr);
 
 
@@ -292,11 +297,6 @@
     }
 
 
-    // The next set of characters must be the OID.  Strictly speaking, this
-    // should only be a numeric OID, but we'll also allow for the
-    // "attrname-oid" case as well.  Look at the first character to figure out
-    // which we will be using.
-    int oidStartPos = pos;
     if (isDigit(c))
     {
       // This must be a numeric OID.  In that case, we will accept only digits
@@ -358,17 +358,12 @@
 
     // If we're at the end of the value, then it isn't a valid attribute type
     // description.  Otherwise, parse out the OID.
-    String oid;
     if (pos >= length)
     {
       invalidReason.append(ERR_ATTR_SYNTAX_ATTRSYNTAX_TRUNCATED_VALUE.get(
               valueStr));
       return false;
     }
-    else
-    {
-      oid = lowerStr.substring(oidStartPos, pos);
-    }
 
 
     // Skip over the space(s) after the OID.
@@ -724,6 +719,7 @@
   /**
    * {@inheritDoc}
    */
+  @Override
   public boolean isBinary()
   {
     return false;
diff --git a/opends/src/server/org/opends/server/schema/MatchingRuleSyntax.java b/opends/src/server/org/opends/server/schema/MatchingRuleSyntax.java
index 7d64204..2384026 100644
--- a/opends/src/server/org/opends/server/schema/MatchingRuleSyntax.java
+++ b/opends/src/server/org/opends/server/schema/MatchingRuleSyntax.java
@@ -40,13 +40,9 @@
 import org.opends.server.api.SubstringMatchingRule;
 import org.opends.server.config.ConfigException;
 import org.opends.server.core.DirectoryServer;
-import org.opends.server.types.ByteString;
-import org.opends.server.types.DirectoryException;
 
 
-import org.opends.server.types.ResultCode;
-
-import org.opends.server.types.DebugLogLevel;
+import org.opends.server.types.*;
 import static org.opends.server.loggers.ErrorLogger.*;
 import static org.opends.server.loggers.debug.DebugLogger.*;
 import org.opends.server.loggers.debug.DebugTracer;
@@ -99,6 +95,7 @@
   /**
    * {@inheritDoc}
    */
+  @Override
   public void initializeSyntax(AttributeSyntaxCfg configuration)
          throws ConfigException
   {
@@ -134,6 +131,7 @@
    *
    * @return  The common name for this attribute syntax.
    */
+  @Override
   public String getSyntaxName()
   {
     return SYNTAX_MATCHING_RULE_NAME;
@@ -146,6 +144,7 @@
    *
    * @return  The OID for this attribute syntax.
    */
+  @Override
   public String getOID()
   {
     return SYNTAX_MATCHING_RULE_OID;
@@ -158,6 +157,7 @@
    *
    * @return  A description for this attribute syntax.
    */
+  @Override
   public String getDescription()
   {
     return SYNTAX_MATCHING_RULE_DESCRIPTION;
@@ -173,6 +173,7 @@
    *          attributes with this syntax, or <CODE>null</CODE> if equality
    *          matches will not be allowed for this type by default.
    */
+  @Override
   public EqualityMatchingRule getEqualityMatchingRule()
   {
     return defaultEqualityMatchingRule;
@@ -188,6 +189,7 @@
    *          attributes with this syntax, or <CODE>null</CODE> if ordering
    *          matches will not be allowed for this type by default.
    */
+  @Override
   public OrderingMatchingRule getOrderingMatchingRule()
   {
     return defaultOrderingMatchingRule;
@@ -203,6 +205,7 @@
    *          attributes with this syntax, or <CODE>null</CODE> if substring
    *          matches will not be allowed for this type by default.
    */
+  @Override
   public SubstringMatchingRule getSubstringMatchingRule()
   {
     return defaultSubstringMatchingRule;
@@ -218,6 +221,7 @@
    *          attributes with this syntax, or <CODE>null</CODE> if approximate
    *          matches will not be allowed for this type by default.
    */
+  @Override
   public ApproximateMatchingRule getApproximateMatchingRule()
   {
     // There is no approximate matching rule by default.
@@ -238,12 +242,13 @@
    * @return  <CODE>true</CODE> if the provided value is acceptable for use with
    *          this syntax, or <CODE>false</CODE> if not.
    */
-  public boolean valueIsAcceptable(ByteString value,
+  @Override
+  public boolean valueIsAcceptable(ByteSequence value,
                                    MessageBuilder invalidReason)
   {
     // Get string representations of the provided value using the provided form
     // and with all lowercase characters.
-    String valueStr = value.stringValue();
+    String valueStr = value.toString();
     String lowerStr = toLowerCase(valueStr);
 
 
@@ -294,11 +299,6 @@
     }
 
 
-    // The next set of characters must be the OID.  Strictly speaking, this
-    // should only be a numeric OID, but we'll also allow for the
-    // "ocname-oid" case as well.  Look at the first character to figure out
-    // which we will be using.
-    int oidStartPos = pos;
     if (isDigit(c))
     {
       // This must be a numeric OID.  In that case, we will accept only digits
@@ -362,17 +362,12 @@
 
     // If we're at the end of the value, then it isn't a valid matching rule
     // description.  Otherwise, parse out the OID.
-    String oid;
     if (pos >= length)
     {
 
       invalidReason.append(ERR_ATTR_SYNTAX_MR_TRUNCATED_VALUE.get(valueStr));
       return false;
     }
-    else
-    {
-      oid = lowerStr.substring(oidStartPos, (pos-1));
-    }
 
 
     // Skip over the space(s) after the OID.
@@ -1150,6 +1145,7 @@
   /**
    * {@inheritDoc}
    */
+  @Override
   public boolean isBinary()
   {
     return false;
diff --git a/opends/src/server/org/opends/server/schema/MatchingRuleUseSyntax.java b/opends/src/server/org/opends/server/schema/MatchingRuleUseSyntax.java
index 1043fc0..1fbb240 100644
--- a/opends/src/server/org/opends/server/schema/MatchingRuleUseSyntax.java
+++ b/opends/src/server/org/opends/server/schema/MatchingRuleUseSyntax.java
@@ -43,17 +43,10 @@
 import org.opends.server.api.SubstringMatchingRule;
 import org.opends.server.config.ConfigException;
 import org.opends.server.core.DirectoryServer;
-import org.opends.server.types.AttributeType;
-import org.opends.server.types.ByteString;
-import org.opends.server.types.DirectoryException;
-import org.opends.server.types.InitializationException;
-import org.opends.server.types.MatchingRuleUse;
-import org.opends.server.types.ResultCode;
-import org.opends.server.types.Schema;
 
 import static org.opends.server.loggers.debug.DebugLogger.*;
 import org.opends.server.loggers.debug.DebugTracer;
-import org.opends.server.types.DebugLogLevel;
+import org.opends.server.types.*;
 import static org.opends.messages.SchemaMessages.*;
 import org.opends.messages.MessageBuilder;
 import static org.opends.server.schema.SchemaConstants.*;
@@ -211,7 +204,7 @@
   /**
    * {@inheritDoc}
    */
-  public boolean valueIsAcceptable(ByteString value,
+  public boolean valueIsAcceptable(ByteSequence value,
                                    MessageBuilder invalidReason)
   {
     // We'll use the decodeMatchingRuleUse method to determine if the value is
@@ -258,14 +251,14 @@
    * @throws  DirectoryException  If the provided value cannot be decoded as a
    *                              matching rule use definition.
    */
-  public static MatchingRuleUse decodeMatchingRuleUse(ByteString value,
+  public static MatchingRuleUse decodeMatchingRuleUse(ByteSequence value,
                                      Schema schema,
                                      boolean allowUnknownElements)
          throws DirectoryException
   {
     // Get string representations of the provided value using the provided form
     // and with all lowercase characters.
-    String valueStr = value.stringValue();
+    String valueStr = value.toString();
     String lowerStr = toLowerCase(valueStr);
 
 
@@ -636,7 +629,7 @@
     }
 
 
-    return new MatchingRuleUse(value.stringValue(), matchingRule, names,
+    return new MatchingRuleUse(value.toString(), matchingRule, names,
                                description, isObsolete, attributes,
                                extraProperties);
   }
diff --git a/opends/src/server/org/opends/server/schema/NameAndOptionalUIDSyntax.java b/opends/src/server/org/opends/server/schema/NameAndOptionalUIDSyntax.java
index ef4cfb1..cf52ef1 100644
--- a/opends/src/server/org/opends/server/schema/NameAndOptionalUIDSyntax.java
+++ b/opends/src/server/org/opends/server/schema/NameAndOptionalUIDSyntax.java
@@ -36,7 +36,6 @@
 import org.opends.server.api.SubstringMatchingRule;
 import org.opends.server.config.ConfigException;
 import org.opends.server.core.DirectoryServer;
-import org.opends.server.types.ByteString;
 import org.opends.server.types.DN;
 
 
@@ -45,6 +44,7 @@
 import org.opends.server.loggers.debug.DebugTracer;
 import static org.opends.server.loggers.ErrorLogger.*;
 import org.opends.server.types.DebugLogLevel;
+import org.opends.server.types.ByteSequence;
 import static org.opends.messages.SchemaMessages.*;
 import org.opends.messages.MessageBuilder;
 import static org.opends.server.schema.SchemaConstants.*;
@@ -222,10 +222,10 @@
    * @return  <CODE>true</CODE> if the provided value is acceptable for use with
    *          this syntax, or <CODE>false</CODE> if not.
    */
-  public boolean valueIsAcceptable(ByteString value,
+  public boolean valueIsAcceptable(ByteSequence value,
                                    MessageBuilder invalidReason)
   {
-    String valueString = value.stringValue().trim();
+    String valueString = value.toString().trim();
     int    valueLength = valueString.length();
 
 
diff --git a/opends/src/server/org/opends/server/schema/NameFormSyntax.java b/opends/src/server/org/opends/server/schema/NameFormSyntax.java
index 2abd70b..916bc9e 100644
--- a/opends/src/server/org/opends/server/schema/NameFormSyntax.java
+++ b/opends/src/server/org/opends/server/schema/NameFormSyntax.java
@@ -42,19 +42,10 @@
 import org.opends.server.api.SubstringMatchingRule;
 import org.opends.server.config.ConfigException;
 import org.opends.server.core.DirectoryServer;
-import org.opends.server.types.AttributeType;
-import org.opends.server.types.ByteString;
-import org.opends.server.types.DirectoryException;
-import org.opends.server.types.InitializationException;
-import org.opends.server.types.NameForm;
-import org.opends.server.types.ObjectClass;
-import org.opends.server.types.ObjectClassType;
-import org.opends.server.types.ResultCode;
-import org.opends.server.types.Schema;
 
 import static org.opends.server.loggers.debug.DebugLogger.*;
 import org.opends.server.loggers.debug.DebugTracer;
-import org.opends.server.types.DebugLogLevel;
+import org.opends.server.types.*;
 import static org.opends.messages.SchemaMessages.*;
 import org.opends.messages.MessageBuilder;
 import static org.opends.server.schema.SchemaConstants.*;
@@ -211,7 +202,7 @@
   /**
    * {@inheritDoc}
    */
-  public boolean valueIsAcceptable(ByteString value,
+  public boolean valueIsAcceptable(ByteSequence value,
                                    MessageBuilder invalidReason)
   {
     // We'll use the decodeNameForm method to determine if the value is
@@ -258,13 +249,13 @@
    * @throws  DirectoryException  If the provided value cannot be decoded as an
    *                              name form definition.
    */
-  public static NameForm decodeNameForm(ByteString value, Schema schema,
+  public static NameForm decodeNameForm(ByteSequence value, Schema schema,
                                         boolean allowUnknownElements)
          throws DirectoryException
   {
     // Get string representations of the provided value using the provided form
     // and with all lowercase characters.
-    String valueStr = value.stringValue();
+    String valueStr = value.toString();
     String lowerStr = toLowerCase(valueStr);
 
 
@@ -754,7 +745,7 @@
     }
 
 
-    return new NameForm(value.stringValue(), names, oid, description,
+    return new NameForm(value.toString(), names, oid, description,
                         isObsolete, structuralClass, requiredAttributes,
                         optionalAttributes, extraProperties);
   }
diff --git a/opends/src/server/org/opends/server/schema/NumericStringEqualityMatchingRule.java b/opends/src/server/org/opends/server/schema/NumericStringEqualityMatchingRule.java
index 2f46dd6..cc18603 100644
--- a/opends/src/server/org/opends/server/schema/NumericStringEqualityMatchingRule.java
+++ b/opends/src/server/org/opends/server/schema/NumericStringEqualityMatchingRule.java
@@ -25,25 +25,25 @@
  *      Copyright 2006-2008 Sun Microsystems, Inc.
  */
 package org.opends.server.schema;
-import org.opends.messages.Message;
 
 
 
-import java.util.Arrays;
-
-import java.util.Collection;
-import java.util.Collections;
-import org.opends.server.api.EqualityMatchingRule;
-import org.opends.server.core.DirectoryServer;
-import org.opends.server.protocols.asn1.ASN1OctetString;
-import org.opends.server.types.ByteString;
-import org.opends.server.types.DirectoryException;
-import org.opends.server.types.ResultCode;
-
 import static org.opends.messages.SchemaMessages.*;
 import static org.opends.server.schema.SchemaConstants.*;
 import static org.opends.server.util.StaticUtils.*;
+
+import java.util.Collection;
+import java.util.Collections;
+
+import org.opends.messages.Message;
+import org.opends.server.api.EqualityMatchingRule;
+import org.opends.server.core.DirectoryServer;
 import org.opends.server.loggers.ErrorLogger;
+import org.opends.server.types.ByteSequence;
+import org.opends.server.types.ByteString;
+import org.opends.server.types.DirectoryException;
+import org.opends.server.types.ResultCode;
+
 
 
 /**
@@ -67,6 +67,7 @@
   /**
    * {@inheritDoc}
    */
+  @Override
   public Collection<String> getAllNames()
   {
     return Collections.singleton(getName());
@@ -80,6 +81,7 @@
    * @return  The common name for this matching rule, or <CODE>null</CODE> if
    * it does not have a name.
    */
+  @Override
   public String getName()
   {
     return EMR_NUMERIC_STRING_NAME;
@@ -92,6 +94,7 @@
    *
    * @return  The OID for this matching rule.
    */
+  @Override
   public String getOID()
   {
     return EMR_NUMERIC_STRING_OID;
@@ -105,6 +108,7 @@
    * @return  The description for this matching rule, or <CODE>null</CODE> if
    *          there is none.
    */
+  @Override
   public String getDescription()
   {
     // There is no standard description for this matching rule.
@@ -119,6 +123,7 @@
    *
    * @return  The OID of the syntax with which this matching rule is associated.
    */
+  @Override
   public String getSyntaxOID()
   {
     return SYNTAX_NUMERIC_STRING_OID;
@@ -137,10 +142,11 @@
    * @throws  DirectoryException  If the provided value is invalid according to
    *                              the associated attribute syntax.
    */
-  public ByteString normalizeValue(ByteString value)
+  @Override
+  public ByteString normalizeValue(ByteSequence value)
          throws DirectoryException
   {
-    String        valueString = value.stringValue();
+    String        valueString = value.toString();
     int           valueLength = valueString.length();
     StringBuilder valueBuffer = new StringBuilder(valueLength);
 
@@ -174,26 +180,7 @@
       }
     }
 
-    return new ASN1OctetString(getBytes(valueBuffer.toString()));
-  }
-
-
-
-  /**
-   * Indicates whether the two provided normalized values are equal to each
-   * other.
-   *
-   * @param  value1  The normalized form of the first value to compare.
-   * @param  value2  The normalized form of the second value to compare.
-   *
-   * @return  <CODE>true</CODE> if the provided values are equal, or
-   *          <CODE>false</CODE> if not.
-   */
-  public boolean areEqual(ByteString value1, ByteString value2)
-  {
-    // Since the values are already normalized, we just need to compare the
-    // associated byte arrays.
-    return Arrays.equals(value1.value(), value2.value());
+    return ByteString.valueOf(valueBuffer.toString());
   }
 }
 
diff --git a/opends/src/server/org/opends/server/schema/NumericStringOrderingMatchingRule.java b/opends/src/server/org/opends/server/schema/NumericStringOrderingMatchingRule.java
index 54a82ac..6134cfb 100644
--- a/opends/src/server/org/opends/server/schema/NumericStringOrderingMatchingRule.java
+++ b/opends/src/server/org/opends/server/schema/NumericStringOrderingMatchingRule.java
@@ -25,23 +25,26 @@
  *      Copyright 2006-2008 Sun Microsystems, Inc.
  */
 package org.opends.server.schema;
-import java.util.Collection;
-import java.util.Collections;
-import org.opends.messages.Message;
 
 
 
-import org.opends.server.api.OrderingMatchingRule;
-import org.opends.server.core.DirectoryServer;
-import org.opends.server.protocols.asn1.ASN1OctetString;
-import org.opends.server.types.ByteString;
-import org.opends.server.types.DirectoryException;
-import org.opends.server.types.ResultCode;
-
 import static org.opends.messages.SchemaMessages.*;
 import static org.opends.server.schema.SchemaConstants.*;
 import static org.opends.server.util.StaticUtils.*;
+
+import java.util.Collection;
+import java.util.Collections;
+
+import org.opends.messages.Message;
+import org.opends.server.api.OrderingMatchingRule;
+import org.opends.server.core.DirectoryServer;
 import org.opends.server.loggers.ErrorLogger;
+import org.opends.server.types.ByteSequence;
+import org.opends.server.types.ByteString;
+import org.opends.server.types.DirectoryException;
+import org.opends.server.types.ResultCode;
+import org.opends.server.util.StaticUtils;
+
 
 
 /**
@@ -74,6 +77,7 @@
   /**
    * {@inheritDoc}
    */
+  @Override
   public Collection<String> getAllNames()
   {
     return Collections.singleton(getName());
@@ -87,6 +91,7 @@
    * @return  The common name for this matching rule, or <CODE>null</CODE> if
    * it does not have a name.
    */
+  @Override
   public String getName()
   {
     return OMR_NUMERIC_STRING_NAME;
@@ -99,6 +104,7 @@
    *
    * @return  The OID for this matching rule.
    */
+  @Override
   public String getOID()
   {
     return OMR_NUMERIC_STRING_OID;
@@ -112,6 +118,7 @@
    * @return  The description for this matching rule, or <CODE>null</CODE> if
    *          there is none.
    */
+  @Override
   public String getDescription()
   {
     // There is no standard description for this matching rule.
@@ -126,6 +133,7 @@
    *
    * @return  The OID of the syntax with which this matching rule is associated.
    */
+  @Override
   public String getSyntaxOID()
   {
     return SYNTAX_NUMERIC_STRING_OID;
@@ -144,10 +152,11 @@
    * @throws  DirectoryException  If the provided value is invalid according to
    *                              the associated attribute syntax.
    */
-  public ByteString normalizeValue(ByteString value)
+  @Override
+  public ByteString normalizeValue(ByteSequence value)
          throws DirectoryException
   {
-    String        valueString = value.stringValue();
+    String        valueString = value.toString();
     int           valueLength = valueString.length();
     StringBuilder valueBuffer = new StringBuilder(valueLength);
 
@@ -181,7 +190,7 @@
       }
     }
 
-    return new ASN1OctetString(getBytes(valueBuffer.toString()));
+    return ByteString.valueOf(valueBuffer.toString());
   }
 
 
@@ -199,9 +208,10 @@
    *          ascending order, or zero if there is no difference between the
    *          values with regard to ordering.
    */
-  public int compareValues(ByteString value1, ByteString value2)
+  @Override
+  public int compareValues(ByteSequence value1, ByteSequence value2)
   {
-    return compare(value1.value(), value2.value());
+    return StaticUtils.compare(value1, value2);
   }
 
 
@@ -221,36 +231,7 @@
    */
   public int compare(byte[] b1, byte[] b2)
   {
-    int minLength = Math.min(b1.length, b2.length);
-
-    for (int i=0; i < minLength; i++)
-    {
-      if (b1[i] == b2[i])
-      {
-        continue;
-      }
-      else if (b1[i] < b2[i])
-      {
-        return -1;
-      }
-      else if (b1[i] > b2[i])
-      {
-        return 1;
-      }
-    }
-
-    if (b1.length == b2.length)
-    {
-      return 0;
-    }
-    else if (b1.length < b2.length)
-    {
-      return -1;
-    }
-    else
-    {
-      return 1;
-    }
+    return StaticUtils.compare(b1, b2);
   }
 }
 
diff --git a/opends/src/server/org/opends/server/schema/NumericStringSubstringMatchingRule.java b/opends/src/server/org/opends/server/schema/NumericStringSubstringMatchingRule.java
index 652825f..3e1ad01 100644
--- a/opends/src/server/org/opends/server/schema/NumericStringSubstringMatchingRule.java
+++ b/opends/src/server/org/opends/server/schema/NumericStringSubstringMatchingRule.java
@@ -22,29 +22,28 @@
  * CDDL HEADER END
  *
  *
- *      Copyright 2006-2008 Sun Microsystems, Inc.
+ *      Copyright 2006-2009 Sun Microsystems, Inc.
  */
 package org.opends.server.schema;
 
-import java.util.Collections;
-import java.util.Collection;
-import org.opends.messages.Message;
 
 
-
-import java.util.List;
-
-import org.opends.server.api.SubstringMatchingRule;
-import org.opends.server.core.DirectoryServer;
-import org.opends.server.protocols.asn1.ASN1OctetString;
-import org.opends.server.types.ByteString;
-import org.opends.server.types.DirectoryException;
-import org.opends.server.types.ResultCode;
-
 import static org.opends.messages.SchemaMessages.*;
 import static org.opends.server.schema.SchemaConstants.*;
 import static org.opends.server.util.StaticUtils.*;
+
+import java.util.Collection;
+import java.util.Collections;
+
+import org.opends.messages.Message;
+import org.opends.server.api.SubstringMatchingRule;
+import org.opends.server.core.DirectoryServer;
 import org.opends.server.loggers.ErrorLogger;
+import org.opends.server.types.ByteSequence;
+import org.opends.server.types.ByteString;
+import org.opends.server.types.DirectoryException;
+import org.opends.server.types.ResultCode;
+
 
 
 /**
@@ -67,6 +66,7 @@
   /**
    * {@inheritDoc}
    */
+  @Override
   public Collection<String> getAllNames()
   {
     return Collections.singleton(getName());
@@ -80,6 +80,7 @@
    * @return  The common name for this matching rule, or <CODE>null</CODE> if
    * it does not have a name.
    */
+  @Override
   public String getName()
   {
     return SMR_NUMERIC_STRING_NAME;
@@ -92,6 +93,7 @@
    *
    * @return  The OID for this matching rule.
    */
+  @Override
   public String getOID()
   {
     return SMR_NUMERIC_STRING_OID;
@@ -105,6 +107,7 @@
    * @return  The description for this matching rule, or <CODE>null</CODE> if
    *          there is none.
    */
+  @Override
   public String getDescription()
   {
     // There is no standard description for this matching rule.
@@ -119,6 +122,7 @@
    *
    * @return  The OID of the syntax with which this matching rule is associated.
    */
+  @Override
   public String getSyntaxOID()
   {
     return SYNTAX_SUBSTRING_ASSERTION_OID;
@@ -137,10 +141,11 @@
    * @throws  DirectoryException  If the provided value is invalid according to
    *                              the associated attribute syntax.
    */
-  public ByteString normalizeValue(ByteString value)
+  @Override
+  public ByteString normalizeValue(ByteSequence value)
          throws DirectoryException
   {
-    String        valueString = value.stringValue();
+    String        valueString = value.toString();
     int           valueLength = valueString.length();
     StringBuilder valueBuffer = new StringBuilder(valueLength);
 
@@ -174,7 +179,7 @@
       }
     }
 
-    return new ASN1OctetString(getBytes(valueBuffer.toString()));
+    return ByteString.valueOf(valueBuffer.toString());
   }
 
 
@@ -190,10 +195,11 @@
    * @throws  DirectoryException  If the provided value fragment is not
    *                              acceptable according to the associated syntax.
    */
-  public ByteString normalizeSubstring(ByteString substring)
+  @Override
+  public ByteString normalizeSubstring(ByteSequence substring)
          throws DirectoryException
   {
-    String        valueString = substring.stringValue();
+    String        valueString = substring.toString();
     int           valueLength = valueString.length();
     StringBuilder valueBuffer = new StringBuilder(valueLength);
 
@@ -227,126 +233,7 @@
       }
     }
 
-    return new ASN1OctetString(getBytes(valueBuffer.toString()));
-  }
-
-
-
-  /**
-   * Determines whether the provided value matches the given substring filter
-   * components.  Note that any of the substring filter components may be
-   * <CODE>null</CODE> but at least one of them must be non-<CODE>null</CODE>.
-   *
-   * @param  value           The normalized value against which to compare the
-   *                         substring components.
-   * @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  <CODE>true</CODE> if the provided value does match the given
-   *          substring components, or <CODE>false</CODE> if not.
-   */
-  public boolean valueMatchesSubstring(ByteString value, ByteString subInitial,
-                                       List<ByteString> subAnyElements,
-                                       ByteString subFinal)
-  {
-    byte[] valueBytes = value.value();
-    int valueLength = valueBytes.length;
-
-    int pos = 0;
-    if (subInitial != null)
-    {
-      byte[] initialBytes = subInitial.value();
-      int initialLength = initialBytes.length;
-      if (initialLength > valueLength)
-      {
-        return false;
-      }
-
-      for (; pos < initialLength; pos++)
-      {
-        if (initialBytes[pos] != valueBytes[pos])
-        {
-          return false;
-        }
-      }
-    }
-
-
-    if ((subAnyElements != null) && (! subAnyElements.isEmpty()))
-    {
-      for (ByteString element : subAnyElements)
-      {
-        byte[] anyBytes = element.value();
-        int anyLength = anyBytes.length;
-
-        int end = valueLength - anyLength;
-        boolean match = false;
-        if (anyLength == 0)
-        {
-          // empty element is not considered as unmatching
-          match = true;
-          continue;
-        }
-        for (; pos <= end; pos++)
-        {
-          if (anyBytes[0] == valueBytes[pos])
-          {
-            boolean subMatch = true;
-            for (int i=1; i < anyLength; i++)
-            {
-              if (anyBytes[i] != valueBytes[pos+i])
-              {
-                subMatch = false;
-                break;
-              }
-            }
-
-            if (subMatch)
-            {
-              match = subMatch;
-              break;
-            }
-          }
-        }
-
-        if (match)
-        {
-          pos += anyLength;
-        }
-        else
-        {
-          return false;
-        }
-      }
-    }
-
-
-    if (subFinal != null)
-    {
-      byte[] finalBytes = subFinal.value();
-      int finalLength = finalBytes.length;
-
-      if ((valueLength - finalLength) < pos)
-      {
-        return false;
-      }
-
-      pos = valueLength - finalLength;
-      for (int i=0; i < finalLength; i++,pos++)
-      {
-        if (finalBytes[i] != valueBytes[pos])
-        {
-          return false;
-        }
-      }
-    }
-
-
-    return true;
+    return ByteString.valueOf(valueBuffer.toString());
   }
 }
 
diff --git a/opends/src/server/org/opends/server/schema/NumericStringSyntax.java b/opends/src/server/org/opends/server/schema/NumericStringSyntax.java
index b731dee..98a0b29 100644
--- a/opends/src/server/org/opends/server/schema/NumericStringSyntax.java
+++ b/opends/src/server/org/opends/server/schema/NumericStringSyntax.java
@@ -36,8 +36,7 @@
 import org.opends.server.api.SubstringMatchingRule;
 import org.opends.server.config.ConfigException;
 import org.opends.server.core.DirectoryServer;
-import org.opends.server.types.ByteString;
-
+import org.opends.server.types.ByteSequence;
 
 
 import static org.opends.server.loggers.ErrorLogger.*;
@@ -221,10 +220,10 @@
    * @return  <CODE>true</CODE> if the provided value is acceptable for use with
    *          this syntax, or <CODE>false</CODE> if not.
    */
-  public boolean valueIsAcceptable(ByteString value,
+  public boolean valueIsAcceptable(ByteSequence value,
                                    MessageBuilder invalidReason)
   {
-    String valueString = value.stringValue();
+    String valueString = value.toString();
     int    length      = valueString.length();
 
 
diff --git a/opends/src/server/org/opends/server/schema/OIDSyntax.java b/opends/src/server/org/opends/server/schema/OIDSyntax.java
index 98d7840..b26acaf 100644
--- a/opends/src/server/org/opends/server/schema/OIDSyntax.java
+++ b/opends/src/server/org/opends/server/schema/OIDSyntax.java
@@ -36,8 +36,7 @@
 import org.opends.server.api.SubstringMatchingRule;
 import org.opends.server.config.ConfigException;
 import org.opends.server.core.DirectoryServer;
-import org.opends.server.types.ByteString;
-
+import org.opends.server.types.ByteSequence;
 
 
 import static org.opends.server.loggers.ErrorLogger.*;
@@ -210,10 +209,10 @@
    * @return  <CODE>true</CODE> if the provided value is acceptable for use with
    *          this syntax, or <CODE>false</CODE> if not.
    */
-  public boolean valueIsAcceptable(ByteString value,
+  public boolean valueIsAcceptable(ByteSequence value,
                                    MessageBuilder invalidReason)
   {
-    String lowerValue = toLowerCase(value.stringValue());
+    String lowerValue = toLowerCase(value.toString());
     return isValidSchemaElement(lowerValue, 0, lowerValue.length(),
             invalidReason);
   }
diff --git a/opends/src/server/org/opends/server/schema/ObjectClassSyntax.java b/opends/src/server/org/opends/server/schema/ObjectClassSyntax.java
index 10c2f5a..22d1e39 100644
--- a/opends/src/server/org/opends/server/schema/ObjectClassSyntax.java
+++ b/opends/src/server/org/opends/server/schema/ObjectClassSyntax.java
@@ -44,18 +44,10 @@
 import org.opends.server.api.SubstringMatchingRule;
 import org.opends.server.config.ConfigException;
 import org.opends.server.core.DirectoryServer;
-import org.opends.server.types.AttributeType;
-import org.opends.server.types.ByteString;
-import org.opends.server.types.DirectoryException;
-import org.opends.server.types.InitializationException;
-import org.opends.server.types.ObjectClass;
-import org.opends.server.types.ObjectClassType;
-import org.opends.server.types.ResultCode;
-import org.opends.server.types.Schema;
 
 import static org.opends.server.loggers.debug.DebugLogger.*;
 import org.opends.server.loggers.debug.DebugTracer;
-import org.opends.server.types.DebugLogLevel;
+import org.opends.server.types.*;
 import static org.opends.messages.SchemaMessages.*;
 import org.opends.messages.MessageBuilder;
 import static org.opends.server.schema.SchemaConstants.*;
@@ -213,7 +205,7 @@
   /**
    * {@inheritDoc}
    */
-  public boolean valueIsAcceptable(ByteString value,
+  public boolean valueIsAcceptable(ByteSequence value,
                                    MessageBuilder invalidReason)
   {
     // We'll use the decodeObjectClass method to determine if the value is
@@ -260,13 +252,13 @@
    * @throws  DirectoryException  If the provided value cannot be decoded as an
    *                              objectclass definition.
    */
-  public static ObjectClass decodeObjectClass(ByteString value, Schema schema,
+  public static ObjectClass decodeObjectClass(ByteSequence value, Schema schema,
                                               boolean allowUnknownElements)
          throws DirectoryException
   {
     // Get string representations of the provided value using the provided form
     // and with all lowercase characters.
-    String valueStr = value.stringValue();
+    String valueStr = value.toString();
     String lowerStr = toLowerCase(valueStr);
 
 
@@ -836,7 +828,7 @@
 
 
 
-    return new ObjectClass(value.stringValue(), primaryName, names, oid,
+    return new ObjectClass(value.toString(), primaryName, names, oid,
                            description, superiorClass, requiredAttributes,
                            optionalAttributes, objectClassType, isObsolete,
                            extraProperties);
diff --git a/opends/src/server/org/opends/server/schema/ObjectIdentifierEqualityMatchingRule.java b/opends/src/server/org/opends/server/schema/ObjectIdentifierEqualityMatchingRule.java
index 5bd1c0f..eb6fe98 100644
--- a/opends/src/server/org/opends/server/schema/ObjectIdentifierEqualityMatchingRule.java
+++ b/opends/src/server/org/opends/server/schema/ObjectIdentifierEqualityMatchingRule.java
@@ -25,29 +25,30 @@
  *      Copyright 2006-2008 Sun Microsystems, Inc.
  */
 package org.opends.server.schema;
+
+
+
+import static org.opends.messages.SchemaMessages.*;
+import static org.opends.server.schema.SchemaConstants.*;
+import static org.opends.server.util.StaticUtils.*;
+
+import java.util.Collection;
+import java.util.Collections;
+
 import org.opends.messages.Message;
 import org.opends.messages.MessageBuilder;
-
-
-import java.util.Arrays;
-
-import java.util.Collections;
-import java.util.Collection;
 import org.opends.server.api.EqualityMatchingRule;
 import org.opends.server.api.MatchingRule;
 import org.opends.server.core.DirectoryServer;
-import org.opends.server.protocols.asn1.ASN1OctetString;
-import org.opends.server.types. AttributeType;
+import org.opends.server.loggers.ErrorLogger;
+import org.opends.server.types.AttributeType;
+import org.opends.server.types.ByteSequence;
 import org.opends.server.types.ByteString;
 import org.opends.server.types.DirectoryException;
 import org.opends.server.types.NameForm;
 import org.opends.server.types.ObjectClass;
 import org.opends.server.types.ResultCode;
 
-import static org.opends.messages.SchemaMessages.*;
-import static org.opends.server.schema.SchemaConstants.*;
-import static org.opends.server.util.StaticUtils.*;
-import org.opends.server.loggers.ErrorLogger;
 
 
 /**
@@ -71,6 +72,7 @@
   /**
    * {@inheritDoc}
    */
+  @Override
   public Collection<String> getAllNames()
   {
     return Collections.singleton(getName());
@@ -84,6 +86,7 @@
    * @return  The common name for this matching rule, or <CODE>null</CODE> if
    * it does not have a name.
    */
+  @Override
   public String getName()
   {
     return EMR_OID_NAME;
@@ -96,6 +99,7 @@
    *
    * @return  The OID for this matching rule.
    */
+  @Override
   public String getOID()
   {
     return EMR_OID_OID;
@@ -109,6 +113,7 @@
    * @return  The description for this matching rule, or <CODE>null</CODE> if
    *          there is none.
    */
+  @Override
   public String getDescription()
   {
     // There is no standard description for this matching rule.
@@ -123,6 +128,7 @@
    *
    * @return  The OID of the syntax with which this matching rule is associated.
    */
+  @Override
   public String getSyntaxOID()
   {
     return SYNTAX_OID_OID;
@@ -141,11 +147,12 @@
    * @throws  DirectoryException  If the provided value is invalid according to
    *                              the associated attribute syntax.
    */
-  public ByteString normalizeValue(ByteString value)
+  @Override
+  public ByteString normalizeValue(ByteSequence value)
          throws DirectoryException
   {
     StringBuilder buffer = new StringBuilder();
-    toLowerCase(value.value(), buffer, true);
+    toLowerCase(value, buffer, true);
     String lowerValue = buffer.toString();
 
     // Normalize OIDs into schema names, and secondary schema names into
@@ -188,7 +195,7 @@
 
     if (schemaName != null)
     {
-      return new ASN1OctetString(toLowerCase(schemaName));
+      return ByteString.valueOf(toLowerCase(schemaName));
     }
 
     // There were no schema matches so we must check the syntax.
@@ -199,7 +206,7 @@
         if (isValidSchemaElement(lowerValue, 0, lowerValue.length(),
                                 invalidReason))
         {
-          return new ASN1OctetString(lowerValue);
+          return ByteString.valueOf(lowerValue);
         }
         else
         {
@@ -219,10 +226,10 @@
           ErrorLogger.logError(message);
         }
 
-        return new ASN1OctetString(lowerValue);
+        return ByteString.valueOf(lowerValue);
 
       default:
-        return new ASN1OctetString(lowerValue);
+        return ByteString.valueOf(lowerValue);
     }
   }
 
@@ -238,10 +245,11 @@
    * @return  <CODE>true</CODE> if the provided values are equal, or
    *          <CODE>false</CODE> if not.
    */
-  public boolean areEqual(ByteString value1, ByteString value2)
+  @Override
+  public boolean areEqual(ByteSequence value1, ByteSequence value2)
   {
     // First, compare the normalized values to see if they are the same.
-    if (Arrays.equals(value1.value(), value2.value()))
+    if (value1.equals(value2))
     {
       return true;
     }
diff --git a/opends/src/server/org/opends/server/schema/ObjectIdentifierFirstComponentEqualityMatchingRule.java b/opends/src/server/org/opends/server/schema/ObjectIdentifierFirstComponentEqualityMatchingRule.java
index 6b845d3..71d90b5 100644
--- a/opends/src/server/org/opends/server/schema/ObjectIdentifierFirstComponentEqualityMatchingRule.java
+++ b/opends/src/server/org/opends/server/schema/ObjectIdentifierFirstComponentEqualityMatchingRule.java
@@ -28,22 +28,23 @@
 
 
 
+import static org.opends.server.schema.SchemaConstants.*;
+import static org.opends.server.util.StaticUtils.*;
+
 import java.util.Collection;
 import java.util.Collections;
+
 import org.opends.server.api.AttributeSyntax;
 import org.opends.server.api.EqualityMatchingRule;
 import org.opends.server.api.MatchingRule;
 import org.opends.server.core.DirectoryServer;
-import org.opends.server.protocols.asn1.ASN1OctetString;
 import org.opends.server.types.AttributeType;
-import org.opends.server.types.AttributeValue;
+import org.opends.server.types.ByteSequence;
 import org.opends.server.types.ByteString;
 import org.opends.server.types.DirectoryException;
 import org.opends.server.types.NameForm;
 import org.opends.server.types.ObjectClass;
-
-import static org.opends.server.schema.SchemaConstants.*;
-import static org.opends.server.util.StaticUtils.*;
+import org.opends.server.util.ServerConstants;
 
 
 
@@ -71,6 +72,7 @@
   /**
    * {@inheritDoc}
    */
+  @Override
   public Collection<String> getAllNames()
   {
     return Collections.singleton(getName());
@@ -84,6 +86,7 @@
    * @return  The common name for this matching rule, or <CODE>null</CODE> if
    * it does not have a name.
    */
+  @Override
   public String getName()
   {
     return EMR_OID_FIRST_COMPONENT_NAME;
@@ -96,6 +99,7 @@
    *
    * @return  The OID for this matching rule.
    */
+  @Override
   public String getOID()
   {
     return EMR_OID_FIRST_COMPONENT_OID;
@@ -109,6 +113,7 @@
    * @return  The description for this matching rule, or <CODE>null</CODE> if
    *          there is none.
    */
+  @Override
   public String getDescription()
   {
     // There is no standard description for this matching rule.
@@ -123,6 +128,7 @@
    *
    * @return  The OID of the syntax with which this matching rule is associated.
    */
+  @Override
   public String getSyntaxOID()
   {
     return SYNTAX_OID_OID;
@@ -141,25 +147,26 @@
    * @throws  DirectoryException  If the provided value is invalid according to
    *                              the associated attribute syntax.
    */
-  public ByteString normalizeValue(ByteString value)
+  @Override
+  public ByteString normalizeValue(ByteSequence value)
          throws DirectoryException
   {
     StringBuilder buffer = new StringBuilder();
-    toLowerCase(value.value(), buffer, true);
+    toLowerCase(value, buffer, true);
 
     int bufferLength = buffer.length();
     if (bufferLength == 0)
     {
-      if (value.value().length > 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 ASN1OctetString(" ");
+        return ServerConstants.SINGLE_SPACE_VALUE;
       }
       else
       {
         // The value is empty, so it is already normalized.
-        return new ASN1OctetString();
+        return ByteString.empty();
       }
     }
 
@@ -176,7 +183,7 @@
       }
     }
 
-    return new ASN1OctetString(buffer.toString());
+    return ByteString.valueOf(buffer.toString());
   }
 
 
@@ -191,12 +198,13 @@
    * @return  <CODE>true</CODE> if the provided values are equal, or
    *          <CODE>false</CODE> if not.
    */
-  public boolean areEqual(ByteString value1, ByteString value2)
+  @Override
+  public boolean areEqual(ByteSequence value1, ByteSequence value2)
   {
     // For this purpose, the first value will be considered the attribute value,
     // and the second the assertion value.  The attribute value must start with
     // an open parenthesis, followed by one or more spaces.
-    String value1String = value1.stringValue();
+    String value1String = value1.toString();
     int    value1Length = value1String.length();
 
     if ((value1Length == 0) || (value1String.charAt(0) != '('))
@@ -206,9 +214,8 @@
       return false;
     }
 
-    char c;
     int  pos = 1;
-    while ((pos < value1Length) && ((c = value1String.charAt(pos)) == ' '))
+    while ((pos < value1Length) && ((value1String.charAt(pos)) == ' '))
     {
       pos++;
     }
@@ -223,7 +230,7 @@
     // The current position must be the start position for the value.  Keep
     // reading until we find the next space.
     int startPos = pos++;
-    while ((pos < value1Length) && ((c = value1String.charAt(pos)) != ' '))
+    while ((pos < value1Length) && ((value1String.charAt(pos)) != ' '))
     {
       pos++;
     }
@@ -239,7 +246,7 @@
     // equal to the string representation of the second value, then we have a
     // match.
     String oid          = value1String.substring(startPos, pos);
-    String value2String = value2.stringValue();
+    String value2String = value2.toString();
     if (oid.equals(value2String))
     {
       return true;
@@ -347,7 +354,8 @@
    *                         code.
    *
    * @return  The hash code generated for the provided attribute value.*/
-  public int generateHashCode(AttributeValue attributeValue)
+  @Override
+  public int generateHashCode(ByteSequence attributeValue)
   {
     // In this case, we'll always return the same value because the matching
     // isn't based on the entire value.
diff --git a/opends/src/server/org/opends/server/schema/OctetStringEqualityMatchingRule.java b/opends/src/server/org/opends/server/schema/OctetStringEqualityMatchingRule.java
index 54a3f15..781b12b 100644
--- a/opends/src/server/org/opends/server/schema/OctetStringEqualityMatchingRule.java
+++ b/opends/src/server/org/opends/server/schema/OctetStringEqualityMatchingRule.java
@@ -28,17 +28,16 @@
 
 
 
-import java.util.Arrays;
+import static org.opends.server.schema.SchemaConstants.*;
 
 import java.util.Collection;
 import java.util.Collections;
+
 import org.opends.server.api.EqualityMatchingRule;
-import org.opends.server.protocols.asn1.ASN1OctetString;
+import org.opends.server.types.ByteSequence;
 import org.opends.server.types.ByteString;
 import org.opends.server.types.DirectoryException;
 
-import static org.opends.server.schema.SchemaConstants.*;
-
 
 
 /**
@@ -62,6 +61,7 @@
   /**
    * {@inheritDoc}
    */
+  @Override
   public Collection<String> getAllNames()
   {
     return Collections.singleton(getName());
@@ -75,6 +75,7 @@
    * @return  The common name for this matching rule, or <CODE>null</CODE> if
    * it does not have a name.
    */
+  @Override
   public String getName()
   {
     return EMR_OCTET_STRING_NAME;
@@ -87,6 +88,7 @@
    *
    * @return  The OID for this matching rule.
    */
+  @Override
   public String getOID()
   {
     return EMR_OCTET_STRING_OID;
@@ -100,6 +102,7 @@
    * @return  The description for this matching rule, or <CODE>null</CODE> if
    *          there is none.
    */
+  @Override
   public String getDescription()
   {
     // There is no standard description for this matching rule.
@@ -114,6 +117,7 @@
    *
    * @return  The OID of the syntax with which this matching rule is associated.
    */
+  @Override
   public String getSyntaxOID()
   {
     return SYNTAX_OCTET_STRING_OID;
@@ -132,29 +136,11 @@
    * @throws  DirectoryException  If the provided value is invalid according to
    *                              the associated attribute syntax.
    */
-  public ByteString normalizeValue(ByteString value)
+  @Override
+  public ByteString normalizeValue(ByteSequence value)
          throws DirectoryException
   {
-    return new ASN1OctetString(value.value());
-  }
-
-
-
-  /**
-   * Indicates whether the two provided normalized values are equal to each
-   * other.
-   *
-   * @param  value1  The normalized form of the first value to compare.
-   * @param  value2  The normalized form of the second value to compare.
-   *
-   * @return  <CODE>true</CODE> if the provided values are equal, or
-   *          <CODE>false</CODE> if not.
-   */
-  public boolean areEqual(ByteString value1, ByteString value2)
-  {
-    // Since the values are already normalized, we just need to compare the
-    // associated byte arrays.
-    return Arrays.equals(value1.value(), value2.value());
+    return value.toByteString();
   }
 }
 
diff --git a/opends/src/server/org/opends/server/schema/OctetStringOrderingMatchingRule.java b/opends/src/server/org/opends/server/schema/OctetStringOrderingMatchingRule.java
index a6b3a69..7f02b59 100644
--- a/opends/src/server/org/opends/server/schema/OctetStringOrderingMatchingRule.java
+++ b/opends/src/server/org/opends/server/schema/OctetStringOrderingMatchingRule.java
@@ -28,16 +28,17 @@
 
 
 
+import static org.opends.server.schema.SchemaConstants.*;
+
 import java.util.Collection;
 import java.util.Collections;
+
 import org.opends.server.api.OrderingMatchingRule;
-import org.opends.server.protocols.asn1.ASN1OctetString;
+import org.opends.server.types.ByteSequence;
 import org.opends.server.types.ByteString;
 import org.opends.server.types.DirectoryException;
 import org.opends.server.util.StaticUtils;
 
-import static org.opends.server.schema.SchemaConstants.*;
-
 
 
 /**
@@ -71,6 +72,7 @@
   /**
    * {@inheritDoc}
    */
+  @Override
   public Collection<String> getAllNames()
   {
     return Collections.singleton(getName());
@@ -84,6 +86,7 @@
    * @return  The common name for this matching rule, or <CODE>null</CODE> if
    * it does not have a name.
    */
+  @Override
   public String getName()
   {
     return OMR_OCTET_STRING_NAME;
@@ -96,6 +99,7 @@
    *
    * @return  The OID for this matching rule.
    */
+  @Override
   public String getOID()
   {
     return OMR_OCTET_STRING_OID;
@@ -109,6 +113,7 @@
    * @return  The description for this matching rule, or <CODE>null</CODE> if
    *          there is none.
    */
+  @Override
   public String getDescription()
   {
     // There is no standard description for this matching rule.
@@ -123,6 +128,7 @@
    *
    * @return  The OID of the syntax with which this matching rule is associated.
    */
+  @Override
   public String getSyntaxOID()
   {
     return SYNTAX_OCTET_STRING_OID;
@@ -141,10 +147,11 @@
    * @throws  DirectoryException  If the provided value is invalid according to
    *                              the associated attribute syntax.
    */
-  public ByteString normalizeValue(ByteString value)
+  @Override
+  public ByteString normalizeValue(ByteSequence value)
          throws DirectoryException
   {
-    return new ASN1OctetString(value.value());
+    return value.toByteString();
   }
 
 
@@ -162,9 +169,10 @@
    *          ascending order, or zero if there is no difference between the
    *          values with regard to ordering.
    */
-  public int compareValues(ByteString value1, ByteString value2)
+  @Override
+  public int compareValues(ByteSequence value1, ByteSequence value2)
   {
-    return compare(value1.value(), value2.value());
+    return StaticUtils.compare(value1, value2);
   }
 
 
diff --git a/opends/src/server/org/opends/server/schema/OctetStringSubstringMatchingRule.java b/opends/src/server/org/opends/server/schema/OctetStringSubstringMatchingRule.java
index 177a9bc..c9e7790 100644
--- a/opends/src/server/org/opends/server/schema/OctetStringSubstringMatchingRule.java
+++ b/opends/src/server/org/opends/server/schema/OctetStringSubstringMatchingRule.java
@@ -22,23 +22,22 @@
  * CDDL HEADER END
  *
  *
- *      Copyright 2006-2008 Sun Microsystems, Inc.
+ *      Copyright 2006-2009 Sun Microsystems, Inc.
  */
 package org.opends.server.schema;
 
 
 
+import static org.opends.server.schema.SchemaConstants.*;
+
 import java.util.Collection;
 import java.util.Collections;
-import java.util.List;
 
 import org.opends.server.api.SubstringMatchingRule;
-import org.opends.server.protocols.asn1.ASN1OctetString;
+import org.opends.server.types.ByteSequence;
 import org.opends.server.types.ByteString;
 import org.opends.server.types.DirectoryException;
 
-import static org.opends.server.schema.SchemaConstants.*;
-
 
 
 /**
@@ -62,6 +61,7 @@
   /**
    * {@inheritDoc}
    */
+  @Override
   public Collection<String> getAllNames()
   {
     return Collections.singleton(getName());
@@ -75,6 +75,7 @@
    * @return  The common name for this matching rule, or <CODE>null</CODE> if
    * it does not have a name.
    */
+  @Override
   public String getName()
   {
     return SMR_OCTET_STRING_NAME;
@@ -87,6 +88,7 @@
    *
    * @return  The OID for this matching rule.
    */
+  @Override
   public String getOID()
   {
     return SMR_OCTET_STRING_OID;
@@ -100,6 +102,7 @@
    * @return  The description for this matching rule, or <CODE>null</CODE> if
    *          there is none.
    */
+  @Override
   public String getDescription()
   {
     // There is no standard description for this matching rule.
@@ -114,6 +117,7 @@
    *
    * @return  The OID of the syntax with which this matching rule is associated.
    */
+  @Override
   public String getSyntaxOID()
   {
     return SYNTAX_SUBSTRING_ASSERTION_OID;
@@ -132,10 +136,11 @@
    * @throws  DirectoryException  If the provided value is invalid according to
    *                              the associated attribute syntax.
    */
-  public ByteString normalizeValue(ByteString value)
+  @Override
+  public ByteString normalizeValue(ByteSequence value)
          throws DirectoryException
   {
-    return new ASN1OctetString(value.value());
+    return value.toByteString();
   }
 
 
@@ -151,124 +156,12 @@
    * @throws  DirectoryException  If the provided value fragment is not
    *                              acceptable according to the associated syntax.
    */
-  public ByteString normalizeSubstring(ByteString substring)
+  @Override
+  public ByteString normalizeSubstring(ByteSequence substring)
          throws DirectoryException
   {
     // This is exactly the same as normalizing a full value.
-    return new ASN1OctetString(substring.value());
-  }
-
-
-
-  /**
-   * Determines whether the provided value matches the given substring filter
-   * components.  Note that any of the substring filter components may be
-   * <CODE>null</CODE> but at least one of them must be non-<CODE>null</CODE>.
-   *
-   * @param  value           The normalized value against which to compare the
-   *                         substring components.
-   * @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  <CODE>true</CODE> if the provided value does match the given
-   *          substring components, or <CODE>false</CODE> if not.
-   */
-  public boolean valueMatchesSubstring(ByteString value, ByteString subInitial,
-                                       List<ByteString> subAnyElements,
-                                       ByteString subFinal)
-  {
-    byte[] valueBytes = value.value();
-    int valueLength = valueBytes.length;
-
-    int pos = 0;
-    if (subInitial != null)
-    {
-      byte[] initialBytes = subInitial.value();
-      int initialLength = initialBytes.length;
-      if (initialLength > valueLength)
-      {
-        return false;
-      }
-
-      for (; pos < initialLength; pos++)
-      {
-        if (initialBytes[pos] != valueBytes[pos])
-        {
-          return false;
-        }
-      }
-    }
-
-
-    if ((subAnyElements != null) && (! subAnyElements.isEmpty()))
-    {
-      for (ByteString element : subAnyElements)
-      {
-        byte[] anyBytes = element.value();
-        int anyLength = anyBytes.length;
-
-        int end = valueLength - anyLength;
-        boolean match = false;
-        for (; pos <= end; pos++)
-        {
-          if (anyBytes[0] == valueBytes[pos])
-          {
-            boolean subMatch = true;
-            for (int i=1; i < anyLength; i++)
-            {
-              if (anyBytes[i] != valueBytes[pos+i])
-              {
-                subMatch = false;
-                break;
-              }
-            }
-
-            if (subMatch)
-            {
-              match = subMatch;
-              break;
-            }
-          }
-        }
-
-        if (match)
-        {
-          pos += anyLength;
-        }
-        else
-        {
-          return false;
-        }
-      }
-    }
-
-
-    if (subFinal != null)
-    {
-      byte[] finalBytes = subFinal.value();
-      int finalLength = finalBytes.length;
-
-      if ((valueLength - finalLength) < pos)
-      {
-        return false;
-      }
-
-      pos = valueLength - finalLength;
-      for (int i=0; i < finalLength; i++,pos++)
-      {
-        if (finalBytes[i] != valueBytes[pos])
-        {
-          return false;
-        }
-      }
-    }
-
-
-    return true;
+    return substring.toByteString();
   }
 }
 
diff --git a/opends/src/server/org/opends/server/schema/OctetStringSyntax.java b/opends/src/server/org/opends/server/schema/OctetStringSyntax.java
index 7d78f41..5fcbc01 100644
--- a/opends/src/server/org/opends/server/schema/OctetStringSyntax.java
+++ b/opends/src/server/org/opends/server/schema/OctetStringSyntax.java
@@ -36,8 +36,7 @@
 import org.opends.server.api.SubstringMatchingRule;
 import org.opends.server.config.ConfigException;
 import org.opends.server.core.DirectoryServer;
-import org.opends.server.types.ByteString;
-
+import org.opends.server.types.ByteSequence;
 
 
 import static org.opends.server.loggers.ErrorLogger.*;
@@ -220,7 +219,7 @@
    * @return  <CODE>true</CODE> if the provided value is acceptable for use with
    *          this syntax, or <CODE>false</CODE> if not.
    */
-  public boolean valueIsAcceptable(ByteString value,
+  public boolean valueIsAcceptable(ByteSequence value,
                                    MessageBuilder invalidReason)
   {
     // All values will be acceptable for the octet string syntax.
diff --git a/opends/src/server/org/opends/server/schema/OtherMailboxSyntax.java b/opends/src/server/org/opends/server/schema/OtherMailboxSyntax.java
index 25e413a..015212a 100644
--- a/opends/src/server/org/opends/server/schema/OtherMailboxSyntax.java
+++ b/opends/src/server/org/opends/server/schema/OtherMailboxSyntax.java
@@ -36,8 +36,7 @@
 import org.opends.server.api.SubstringMatchingRule;
 import org.opends.server.config.ConfigException;
 import org.opends.server.core.DirectoryServer;
-import org.opends.server.types.ByteString;
-
+import org.opends.server.types.ByteSequence;
 
 
 import static org.opends.server.loggers.ErrorLogger.*;
@@ -211,7 +210,7 @@
    * @return  <CODE>true</CODE> if the provided value is acceptable for use with
    *          this syntax, or <CODE>false</CODE> if not.
    */
-  public boolean valueIsAcceptable(ByteString value,
+  public boolean valueIsAcceptable(ByteSequence value,
                                    MessageBuilder invalidReason)
   {
     // Check to see if the provided value was null.  If so, then that's not
@@ -226,7 +225,7 @@
 
     // Get the value as a string and determine its length.  If it is empty, then
     // that's not acceptable.
-    String valueString = value.stringValue();
+    String valueString = value.toString();
     int    valueLength = valueString.length();
     if (valueLength == 0)
     {
diff --git a/opends/src/server/org/opends/server/schema/PostalAddressSyntax.java b/opends/src/server/org/opends/server/schema/PostalAddressSyntax.java
index 08d2f01..e9a130a 100644
--- a/opends/src/server/org/opends/server/schema/PostalAddressSyntax.java
+++ b/opends/src/server/org/opends/server/schema/PostalAddressSyntax.java
@@ -36,8 +36,7 @@
 import org.opends.server.api.SubstringMatchingRule;
 import org.opends.server.config.ConfigException;
 import org.opends.server.core.DirectoryServer;
-import org.opends.server.types.ByteString;
-
+import org.opends.server.types.ByteSequence;
 
 
 import static org.opends.server.loggers.ErrorLogger.*;
@@ -212,7 +211,7 @@
    * @return  <CODE>true</CODE> if the provided value is acceptable for use with
    *          this syntax, or <CODE>false</CODE> if not.
    */
-  public boolean valueIsAcceptable(ByteString value,
+  public boolean valueIsAcceptable(ByteSequence value,
                                    MessageBuilder invalidReason)
   {
     // We'll allow any value.
diff --git a/opends/src/server/org/opends/server/schema/PresentationAddressEqualityMatchingRule.java b/opends/src/server/org/opends/server/schema/PresentationAddressEqualityMatchingRule.java
index 954aa96..be4c8af 100644
--- a/opends/src/server/org/opends/server/schema/PresentationAddressEqualityMatchingRule.java
+++ b/opends/src/server/org/opends/server/schema/PresentationAddressEqualityMatchingRule.java
@@ -28,17 +28,17 @@
 
 
 
-import java.util.Arrays;
+import static org.opends.server.schema.SchemaConstants.*;
+import static org.opends.server.util.StaticUtils.*;
 
 import java.util.Collection;
 import java.util.Collections;
+
 import org.opends.server.api.EqualityMatchingRule;
-import org.opends.server.protocols.asn1.ASN1OctetString;
+import org.opends.server.types.ByteSequence;
 import org.opends.server.types.ByteString;
 import org.opends.server.types.DirectoryException;
-
-import static org.opends.server.schema.SchemaConstants.*;
-import static org.opends.server.util.StaticUtils.*;
+import org.opends.server.util.ServerConstants;
 
 
 
@@ -64,6 +64,7 @@
 /**
    * {@inheritDoc}
    */
+  @Override
   public Collection<String> getAllNames()
   {
     return Collections.singleton(getName());
@@ -77,6 +78,7 @@
    * @return  The common name for this matching rule, or <CODE>null</CODE> if
    * it does not have a name.
    */
+  @Override
   public String getName()
   {
     return EMR_PRESENTATION_ADDRESS_NAME;
@@ -89,6 +91,7 @@
    *
    * @return  The OID for this matching rule.
    */
+  @Override
   public String getOID()
   {
     return EMR_PRESENTATION_ADDRESS_OID;
@@ -102,6 +105,7 @@
    * @return  The description for this matching rule, or <CODE>null</CODE> if
    *          there is none.
    */
+  @Override
   public String getDescription()
   {
     // There is no standard description for this matching rule.
@@ -116,6 +120,7 @@
    *
    * @return  The OID of the syntax with which this matching rule is associated.
    */
+  @Override
   public String getSyntaxOID()
   {
     return SYNTAX_PRESENTATION_ADDRESS_OID;
@@ -134,25 +139,26 @@
    * @throws  DirectoryException  If the provided value is invalid according to
    *                              the associated attribute syntax.
    */
-  public ByteString normalizeValue(ByteString value)
+  @Override
+  public ByteString normalizeValue(ByteSequence value)
          throws DirectoryException
   {
     StringBuilder buffer = new StringBuilder();
-    toLowerCase(value.value(), buffer, true);
+    toLowerCase(value, buffer, true);
 
     int bufferLength = buffer.length();
     if (bufferLength == 0)
     {
-      if (value.value().length > 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 ASN1OctetString(" ");
+        return ServerConstants.SINGLE_SPACE_VALUE;
       }
       else
       {
         // The value is empty, so it is already normalized.
-        return new ASN1OctetString();
+        return ByteString.empty();
       }
     }
 
@@ -169,26 +175,7 @@
       }
     }
 
-    return new ASN1OctetString(buffer.toString());
-  }
-
-
-
-  /**
-   * Indicates whether the two provided normalized values are equal to each
-   * other.
-   *
-   * @param  value1  The normalized form of the first value to compare.
-   * @param  value2  The normalized form of the second value to compare.
-   *
-   * @return  <CODE>true</CODE> if the provided values are equal, or
-   *          <CODE>false</CODE> if not.
-   */
-  public boolean areEqual(ByteString value1, ByteString value2)
-  {
-    // Since the values are already normalized, we just need to compare the
-    // associated byte arrays.
-    return Arrays.equals(value1.value(), value2.value());
+    return ByteString.valueOf(buffer.toString());
   }
 }
 
diff --git a/opends/src/server/org/opends/server/schema/PresentationAddressSyntax.java b/opends/src/server/org/opends/server/schema/PresentationAddressSyntax.java
index 6c4cfbe..f626378 100644
--- a/opends/src/server/org/opends/server/schema/PresentationAddressSyntax.java
+++ b/opends/src/server/org/opends/server/schema/PresentationAddressSyntax.java
@@ -36,8 +36,7 @@
 import org.opends.server.api.SubstringMatchingRule;
 import org.opends.server.config.ConfigException;
 import org.opends.server.core.DirectoryServer;
-import org.opends.server.types.ByteString;
-
+import org.opends.server.types.ByteSequence;
 
 
 import static org.opends.server.loggers.ErrorLogger.*;
@@ -230,7 +229,7 @@
    * @return  <CODE>true</CODE> if the provided value is acceptable for use with
    *          this syntax, or <CODE>false</CODE> if not.
    */
-  public boolean valueIsAcceptable(ByteString value,
+  public boolean valueIsAcceptable(ByteSequence value,
                                    MessageBuilder invalidReason)
   {
     // We will accept any value for this syntax.
diff --git a/opends/src/server/org/opends/server/schema/PrintableStringSyntax.java b/opends/src/server/org/opends/server/schema/PrintableStringSyntax.java
index 4afdd59..2de4831 100644
--- a/opends/src/server/org/opends/server/schema/PrintableStringSyntax.java
+++ b/opends/src/server/org/opends/server/schema/PrintableStringSyntax.java
@@ -36,8 +36,7 @@
 import org.opends.server.api.SubstringMatchingRule;
 import org.opends.server.config.ConfigException;
 import org.opends.server.core.DirectoryServer;
-import org.opends.server.types.ByteString;
-
+import org.opends.server.types.ByteSequence;
 
 
 import static org.opends.server.loggers.ErrorLogger.*;
@@ -232,7 +231,7 @@
    * @return  <CODE>true</CODE> if the provided value is acceptable for use with
    *          this syntax, or <CODE>false</CODE> if not.
    */
-  public boolean valueIsAcceptable(ByteString value,
+  public boolean valueIsAcceptable(ByteSequence value,
                                    MessageBuilder invalidReason)
   {
     // Check to see if the provided value was null.  If so, then that's not
@@ -247,7 +246,7 @@
 
     // Get the value as a string and determine its length.  If it is empty, then
     // that's not acceptable.
-    String valueString = value.stringValue();
+    String valueString = value.toString();
     int    valueLength = valueString.length();
     if (valueLength == 0)
     {
diff --git a/opends/src/server/org/opends/server/schema/ProtocolInformationEqualityMatchingRule.java b/opends/src/server/org/opends/server/schema/ProtocolInformationEqualityMatchingRule.java
index f778a1f..db69258 100644
--- a/opends/src/server/org/opends/server/schema/ProtocolInformationEqualityMatchingRule.java
+++ b/opends/src/server/org/opends/server/schema/ProtocolInformationEqualityMatchingRule.java
@@ -28,17 +28,17 @@
 
 
 
-import java.util.Arrays;
+import static org.opends.server.schema.SchemaConstants.*;
+import static org.opends.server.util.StaticUtils.*;
 
 import java.util.Collection;
 import java.util.Collections;
+
 import org.opends.server.api.EqualityMatchingRule;
-import org.opends.server.protocols.asn1.ASN1OctetString;
+import org.opends.server.types.ByteSequence;
 import org.opends.server.types.ByteString;
 import org.opends.server.types.DirectoryException;
-
-import static org.opends.server.schema.SchemaConstants.*;
-import static org.opends.server.util.StaticUtils.*;
+import org.opends.server.util.ServerConstants;
 
 
 
@@ -64,6 +64,7 @@
   /**
    * {@inheritDoc}
    */
+  @Override
   public Collection<String> getAllNames()
   {
     return Collections.singleton(getName());
@@ -77,6 +78,7 @@
    * @return  The common name for this matching rule, or <CODE>null</CODE> if
    * it does not have a name.
    */
+  @Override
   public String getName()
   {
     return EMR_PROTOCOL_INFORMATION_NAME;
@@ -89,6 +91,7 @@
    *
    * @return  The OID for this matching rule.
    */
+  @Override
   public String getOID()
   {
     return EMR_PROTOCOL_INFORMATION_OID;
@@ -102,6 +105,7 @@
    * @return  The description for this matching rule, or <CODE>null</CODE> if
    *          there is none.
    */
+  @Override
   public String getDescription()
   {
     // There is no standard description for this matching rule.
@@ -116,6 +120,7 @@
    *
    * @return  The OID of the syntax with which this matching rule is associated.
    */
+  @Override
   public String getSyntaxOID()
   {
     return SYNTAX_PROTOCOL_INFORMATION_OID;
@@ -134,25 +139,26 @@
    * @throws  DirectoryException  If the provided value is invalid according to
    *                              the associated attribute syntax.
    */
-  public ByteString normalizeValue(ByteString value)
+  @Override
+  public ByteString normalizeValue(ByteSequence value)
          throws DirectoryException
   {
     StringBuilder buffer = new StringBuilder();
-    toLowerCase(value.value(), buffer, true);
+    toLowerCase(value, buffer, true);
 
     int bufferLength = buffer.length();
     if (bufferLength == 0)
     {
-      if (value.value().length > 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 ASN1OctetString(" ");
+        return ServerConstants.SINGLE_SPACE_VALUE;
       }
       else
       {
         // The value is empty, so it is already normalized.
-        return new ASN1OctetString();
+        return ByteString.empty();
       }
     }
 
@@ -169,26 +175,7 @@
       }
     }
 
-    return new ASN1OctetString(buffer.toString());
-  }
-
-
-
-  /**
-   * Indicates whether the two provided normalized values are equal to each
-   * other.
-   *
-   * @param  value1  The normalized form of the first value to compare.
-   * @param  value2  The normalized form of the second value to compare.
-   *
-   * @return  <CODE>true</CODE> if the provided values are equal, or
-   *          <CODE>false</CODE> if not.
-   */
-  public boolean areEqual(ByteString value1, ByteString value2)
-  {
-    // Since the values are already normalized, we just need to compare the
-    // associated byte arrays.
-    return Arrays.equals(value1.value(), value2.value());
+    return ByteString.valueOf(buffer.toString());
   }
 }
 
diff --git a/opends/src/server/org/opends/server/schema/ProtocolInformationSyntax.java b/opends/src/server/org/opends/server/schema/ProtocolInformationSyntax.java
index 5c169d9..704f25e 100644
--- a/opends/src/server/org/opends/server/schema/ProtocolInformationSyntax.java
+++ b/opends/src/server/org/opends/server/schema/ProtocolInformationSyntax.java
@@ -36,8 +36,7 @@
 import org.opends.server.api.SubstringMatchingRule;
 import org.opends.server.config.ConfigException;
 import org.opends.server.core.DirectoryServer;
-import org.opends.server.types.ByteString;
-
+import org.opends.server.types.ByteSequence;
 
 
 import static org.opends.server.loggers.ErrorLogger.*;
@@ -230,7 +229,7 @@
    * @return  <CODE>true</CODE> if the provided value is acceptable for use with
    *          this syntax, or <CODE>false</CODE> if not.
    */
-  public boolean valueIsAcceptable(ByteString value,
+  public boolean valueIsAcceptable(ByteSequence value,
                                    MessageBuilder invalidReason)
   {
     // We will accept any value for this syntax.
diff --git a/opends/src/server/org/opends/server/schema/RFC3672SubtreeSpecificationSyntax.java b/opends/src/server/org/opends/server/schema/RFC3672SubtreeSpecificationSyntax.java
index 798ab11..3328aad 100644
--- a/opends/src/server/org/opends/server/schema/RFC3672SubtreeSpecificationSyntax.java
+++ b/opends/src/server/org/opends/server/schema/RFC3672SubtreeSpecificationSyntax.java
@@ -29,7 +29,6 @@
 import static org.opends.server.loggers.debug.DebugLogger.*;
 import org.opends.server.loggers.debug.DebugTracer;
 import static org.opends.server.loggers.ErrorLogger.logError;
-import org.opends.server.types.DebugLogLevel;
 import static org.opends.messages.SchemaMessages.*;
 import org.opends.messages.MessageBuilder;
 import static org.opends.server.schema.SchemaConstants.*;
@@ -44,11 +43,7 @@
 import org.opends.server.config.ConfigException;
 import org.opends.server.core.DirectoryServer;
 import org.opends.server.core.RFC3672SubtreeSpecification;
-import org.opends.server.types.AttributeValue;
-import org.opends.server.types.ByteString;
-import org.opends.server.types.DirectoryException;
-import org.opends.server.types.DN;
-
+import org.opends.server.types.*;
 
 
 /**
@@ -113,7 +108,7 @@
     public RFC3672SubtreeSpecification decode(AttributeValue value)
         throws DirectoryException {
       return RFC3672SubtreeSpecification.valueOf(rootDN, value
-          .getStringValue());
+          .getValue().toString());
     }
   }
 
@@ -254,12 +249,12 @@
    * @return <CODE>true</CODE> if the provided value is acceptable for
    *         use with this syntax, or <CODE>false</CODE> if not.
    */
-  public boolean valueIsAcceptable(ByteString value,
+  public boolean valueIsAcceptable(ByteSequence value,
                                    MessageBuilder invalidReason) {
 
     // Use the subtree specification code to make this determination.
     try {
-      RFC3672SubtreeSpecification.valueOf(DN.nullDN(), value.stringValue());
+      RFC3672SubtreeSpecification.valueOf(DN.nullDN(), value.toString());
 
       return true;
     } catch (DirectoryException e) {
diff --git a/opends/src/server/org/opends/server/schema/RelativeSubtreeSpecificationSyntax.java b/opends/src/server/org/opends/server/schema/RelativeSubtreeSpecificationSyntax.java
index c76a142..2442d14 100644
--- a/opends/src/server/org/opends/server/schema/RelativeSubtreeSpecificationSyntax.java
+++ b/opends/src/server/org/opends/server/schema/RelativeSubtreeSpecificationSyntax.java
@@ -28,7 +28,6 @@
 
 import static org.opends.server.loggers.debug.DebugLogger.*;
 import org.opends.server.loggers.debug.DebugTracer;
-import org.opends.server.types.DebugLogLevel;
 import static org.opends.server.loggers.ErrorLogger.logError;
 import static org.opends.messages.SchemaMessages.*;
 import org.opends.messages.MessageBuilder;
@@ -44,11 +43,7 @@
 import org.opends.server.config.ConfigException;
 import org.opends.server.core.DirectoryServer;
 import org.opends.server.core.RelativeSubtreeSpecification;
-import org.opends.server.types.AttributeValue;
-import org.opends.server.types.ByteString;
-import org.opends.server.types.DirectoryException;
-import org.opends.server.types.DN;
-
+import org.opends.server.types.*;
 
 
 /**
@@ -116,7 +111,7 @@
     public RelativeSubtreeSpecification decode(AttributeValue value)
         throws DirectoryException {
       return RelativeSubtreeSpecification.valueOf(rootDN, value
-          .getStringValue());
+          .getValue().toString());
     }
   }
 
@@ -257,12 +252,12 @@
    * @return <CODE>true</CODE> if the provided value is acceptable for
    *         use with this syntax, or <CODE>false</CODE> if not.
    */
-  public boolean valueIsAcceptable(ByteString value,
+  public boolean valueIsAcceptable(ByteSequence value,
                                    MessageBuilder invalidReason) {
 
     // Use the subtree specification code to make this determination.
     try {
-      RelativeSubtreeSpecification.valueOf(DN.nullDN(), value.stringValue());
+      RelativeSubtreeSpecification.valueOf(DN.nullDN(), value.toString());
 
       return true;
     } catch (DirectoryException e) {
diff --git a/opends/src/server/org/opends/server/schema/SubstringAssertionSyntax.java b/opends/src/server/org/opends/server/schema/SubstringAssertionSyntax.java
index 77ee54e..792685d 100644
--- a/opends/src/server/org/opends/server/schema/SubstringAssertionSyntax.java
+++ b/opends/src/server/org/opends/server/schema/SubstringAssertionSyntax.java
@@ -36,8 +36,7 @@
 import org.opends.server.api.SubstringMatchingRule;
 import org.opends.server.config.ConfigException;
 import org.opends.server.core.DirectoryServer;
-import org.opends.server.types.ByteString;
-
+import org.opends.server.types.ByteSequence;
 
 
 import static org.opends.server.loggers.ErrorLogger.*;
@@ -221,14 +220,14 @@
    * @return  <CODE>true</CODE> if the provided value is acceptable for use with
    *          this syntax, or <CODE>false</CODE> if not.
    */
-  public boolean valueIsAcceptable(ByteString value,
+  public boolean valueIsAcceptable(ByteSequence value,
                                    MessageBuilder 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.
-    String valueString = value.stringValue();
+    String valueString = value.toString();
     int    valueLength = valueString.length();
     if (valueLength == 0)
     {
diff --git a/opends/src/server/org/opends/server/schema/SupportedAlgorithmSyntax.java b/opends/src/server/org/opends/server/schema/SupportedAlgorithmSyntax.java
index d36097f..16902ad 100644
--- a/opends/src/server/org/opends/server/schema/SupportedAlgorithmSyntax.java
+++ b/opends/src/server/org/opends/server/schema/SupportedAlgorithmSyntax.java
@@ -36,8 +36,7 @@
 import org.opends.server.api.SubstringMatchingRule;
 import org.opends.server.config.ConfigException;
 import org.opends.server.core.DirectoryServer;
-import org.opends.server.types.ByteString;
-
+import org.opends.server.types.ByteSequence;
 
 
 import static org.opends.server.loggers.ErrorLogger.*;
@@ -221,7 +220,7 @@
    * @return  <CODE>true</CODE> if the provided value is acceptable for use with
    *          this syntax, or <CODE>false</CODE> if not.
    */
-  public boolean valueIsAcceptable(ByteString value,
+  public boolean valueIsAcceptable(ByteSequence value,
                                    MessageBuilder invalidReason)
   {
     // All values will be acceptable for the supported algorithm syntax.
diff --git a/opends/src/server/org/opends/server/schema/TelephoneNumberEqualityMatchingRule.java b/opends/src/server/org/opends/server/schema/TelephoneNumberEqualityMatchingRule.java
index de40bfa..5e683e4 100644
--- a/opends/src/server/org/opends/server/schema/TelephoneNumberEqualityMatchingRule.java
+++ b/opends/src/server/org/opends/server/schema/TelephoneNumberEqualityMatchingRule.java
@@ -28,18 +28,17 @@
 
 
 
-import java.util.Arrays;
+import static org.opends.server.schema.SchemaConstants.*;
+import static org.opends.server.util.StaticUtils.*;
 
 import java.util.Collection;
 import java.util.Collections;
+
 import org.opends.server.api.EqualityMatchingRule;
-import org.opends.server.protocols.asn1.ASN1OctetString;
+import org.opends.server.types.ByteSequence;
 import org.opends.server.types.ByteString;
 import org.opends.server.types.DirectoryException;
 
-import static org.opends.server.schema.SchemaConstants.*;
-import static org.opends.server.util.StaticUtils.*;
-
 
 
 /**
@@ -64,6 +63,7 @@
   /**
    * {@inheritDoc}
    */
+  @Override
   public Collection<String> getAllNames()
   {
     return Collections.singleton(getName());
@@ -77,6 +77,7 @@
    * @return  The common name for this matching rule, or <CODE>null</CODE> if
    * it does not have a name.
    */
+  @Override
   public String getName()
   {
     return EMR_TELEPHONE_NAME;
@@ -89,6 +90,7 @@
    *
    * @return  The OID for this matching rule.
    */
+  @Override
   public String getOID()
   {
     return EMR_TELEPHONE_OID;
@@ -102,6 +104,7 @@
    * @return  The description for this matching rule, or <CODE>null</CODE> if
    *          there is none.
    */
+  @Override
   public String getDescription()
   {
     // There is no standard description for this matching rule.
@@ -116,6 +119,7 @@
    *
    * @return  The OID of the syntax with which this matching rule is associated.
    */
+  @Override
   public String getSyntaxOID()
   {
     return SYNTAX_TELEPHONE_OID;
@@ -134,10 +138,11 @@
    * @throws  DirectoryException  If the provided value is invalid according to
    *                              the associated attribute syntax.
    */
-  public ByteString normalizeValue(ByteString value)
+  @Override
+  public ByteString normalizeValue(ByteSequence value)
          throws DirectoryException
   {
-    String valueString = value.stringValue();
+    String valueString = value.toString();
     int    valueLength = valueString.length();
     StringBuilder buffer = new StringBuilder(valueLength);
 
@@ -154,26 +159,7 @@
     }
 
 
-    return new ASN1OctetString(buffer.toString());
-  }
-
-
-
-  /**
-   * Indicates whether the two provided normalized values are equal to each
-   * other.
-   *
-   * @param  value1  The normalized form of the first value to compare.
-   * @param  value2  The normalized form of the second value to compare.
-   *
-   * @return  <CODE>true</CODE> if the provided values are equal, or
-   *          <CODE>false</CODE> if not.
-   */
-  public boolean areEqual(ByteString value1, ByteString value2)
-  {
-    // Since the values are already normalized, we just need to compare the
-    // associated byte arrays.
-    return Arrays.equals(value1.value(), value2.value());
+    return ByteString.valueOf(buffer.toString());
   }
 }
 
diff --git a/opends/src/server/org/opends/server/schema/TelephoneNumberSubstringMatchingRule.java b/opends/src/server/org/opends/server/schema/TelephoneNumberSubstringMatchingRule.java
index b790751..955eddc 100644
--- a/opends/src/server/org/opends/server/schema/TelephoneNumberSubstringMatchingRule.java
+++ b/opends/src/server/org/opends/server/schema/TelephoneNumberSubstringMatchingRule.java
@@ -22,24 +22,23 @@
  * CDDL HEADER END
  *
  *
- *      Copyright 2006-2008 Sun Microsystems, Inc.
+ *      Copyright 2006-2009 Sun Microsystems, Inc.
  */
 package org.opends.server.schema;
 
 
 
-import java.util.Collection;
-import java.util.Collections;
-import java.util.List;
-
-import org.opends.server.api.SubstringMatchingRule;
-import org.opends.server.protocols.asn1.ASN1OctetString;
-import org.opends.server.types.ByteString;
-import org.opends.server.types.DirectoryException;
-
 import static org.opends.server.schema.SchemaConstants.*;
 import static org.opends.server.util.StaticUtils.*;
 
+import java.util.Collection;
+import java.util.Collections;
+
+import org.opends.server.api.SubstringMatchingRule;
+import org.opends.server.types.ByteSequence;
+import org.opends.server.types.ByteString;
+import org.opends.server.types.DirectoryException;
+
 
 
 /**
@@ -65,6 +64,7 @@
   /**
    * {@inheritDoc}
    */
+  @Override
   public Collection<String> getAllNames()
   {
     return Collections.singleton(getName());
@@ -78,6 +78,7 @@
    * @return  The common name for this matching rule, or <CODE>null</CODE> if
    * it does not have a name.
    */
+  @Override
   public String getName()
   {
     return SMR_TELEPHONE_NAME;
@@ -90,6 +91,7 @@
    *
    * @return  The OID for this matching rule.
    */
+  @Override
   public String getOID()
   {
     return SMR_TELEPHONE_OID;
@@ -103,6 +105,7 @@
    * @return  The description for this matching rule, or <CODE>null</CODE> if
    *          there is none.
    */
+  @Override
   public String getDescription()
   {
     // There is no standard description for this matching rule.
@@ -117,6 +120,7 @@
    *
    * @return  The OID of the syntax with which this matching rule is associated.
    */
+  @Override
   public String getSyntaxOID()
   {
     return SYNTAX_SUBSTRING_ASSERTION_OID;
@@ -135,10 +139,11 @@
    * @throws  DirectoryException  If the provided value is invalid according to
    *                              the associated attribute syntax.
    */
-  public ByteString normalizeValue(ByteString value)
+  @Override
+  public ByteString normalizeValue(ByteSequence value)
          throws DirectoryException
   {
-    String valueString = value.stringValue();
+    String valueString = value.toString();
     int    valueLength = valueString.length();
     StringBuilder buffer = new StringBuilder(valueLength);
 
@@ -155,7 +160,7 @@
     }
 
 
-    return new ASN1OctetString(buffer.toString());
+    return ByteString.valueOf(buffer.toString());
   }
 
 
@@ -171,125 +176,13 @@
    * @throws  DirectoryException  If the provided value fragment is not
    *                              acceptable according to the associated syntax.
    */
-  public ByteString normalizeSubstring(ByteString substring)
+  @Override
+  public ByteString normalizeSubstring(ByteSequence substring)
          throws DirectoryException
   {
     // In this case, the logic used to normalize a substring is identical to the
     // logic used to normalize a full value.
     return normalizeValue(substring);
   }
-
-
-
-  /**
-   * Determines whether the provided value matches the given substring filter
-   * components.  Note that any of the substring filter components may be
-   * <CODE>null</CODE> but at least one of them must be non-<CODE>null</CODE>.
-   *
-   * @param  value           The normalized value against which to compare the
-   *                         substring components.
-   * @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  <CODE>true</CODE> if the provided value does match the given
-   *          substring components, or <CODE>false</CODE> if not.
-   */
-  public boolean valueMatchesSubstring(ByteString value, ByteString subInitial,
-                                       List<ByteString> subAnyElements,
-                                       ByteString subFinal)
-  {
-    byte[] valueBytes = value.value();
-    int valueLength = valueBytes.length;
-
-    int pos = 0;
-    if (subInitial != null)
-    {
-      byte[] initialBytes = subInitial.value();
-      int initialLength = initialBytes.length;
-      if (initialLength > valueLength)
-      {
-        return false;
-      }
-
-      for (; pos < initialLength; pos++)
-      {
-        if (initialBytes[pos] != valueBytes[pos])
-        {
-          return false;
-        }
-      }
-    }
-
-
-    if ((subAnyElements != null) && (! subAnyElements.isEmpty()))
-    {
-      for (ByteString element : subAnyElements)
-      {
-        byte[] anyBytes = element.value();
-        int anyLength = anyBytes.length;
-
-        int end = valueLength - anyLength;
-        boolean match = false;
-        for (; pos <= end; pos++)
-        {
-          if (anyBytes[0] == valueBytes[pos])
-          {
-            boolean subMatch = true;
-            for (int i=1; i < anyLength; i++)
-            {
-              if (anyBytes[i] != valueBytes[pos+i])
-              {
-                subMatch = false;
-                break;
-              }
-            }
-
-            if (subMatch)
-            {
-              match = subMatch;
-              break;
-            }
-          }
-        }
-
-        if (match)
-        {
-          pos += anyLength;
-        }
-        else
-        {
-          return false;
-        }
-      }
-    }
-
-
-    if (subFinal != null)
-    {
-      byte[] finalBytes = subFinal.value();
-      int finalLength = finalBytes.length;
-
-      if ((valueLength - finalLength) < pos)
-      {
-        return false;
-      }
-
-      pos = valueLength - finalLength;
-      for (int i=0; i < finalLength; i++,pos++)
-      {
-        if (finalBytes[i] != valueBytes[pos])
-        {
-          return false;
-        }
-      }
-    }
-
-
-    return true;
-  }
 }
 
diff --git a/opends/src/server/org/opends/server/schema/TelephoneNumberSyntax.java b/opends/src/server/org/opends/server/schema/TelephoneNumberSyntax.java
index b5db7a6..47a2446 100644
--- a/opends/src/server/org/opends/server/schema/TelephoneNumberSyntax.java
+++ b/opends/src/server/org/opends/server/schema/TelephoneNumberSyntax.java
@@ -40,11 +40,11 @@
 import org.opends.server.api.SubstringMatchingRule;
 import org.opends.server.config.ConfigException;
 import org.opends.server.core.DirectoryServer;
-import org.opends.server.types.ByteString;
 import org.opends.server.types.ConfigChangeResult;
 
 
 import org.opends.server.types.ResultCode;
+import org.opends.server.types.ByteSequence;
 
 import static org.opends.server.loggers.ErrorLogger.*;
 import static org.opends.messages.SchemaMessages.*;
@@ -251,13 +251,13 @@
    * @return  <CODE>true</CODE> if the provided value is acceptable for use with
    *          this syntax, or <CODE>false</CODE> if not.
    */
-  public boolean valueIsAcceptable(ByteString value,
+  public boolean valueIsAcceptable(ByteSequence value,
                                    MessageBuilder invalidReason)
   {
     // No matter what, the value can't be empty or null.
     String valueStr;
     if ((value == null) ||
-        ((valueStr = value.stringValue().trim()).length() == 0))
+        ((valueStr = value.toString().trim()).length() == 0))
     {
       invalidReason.append(ERR_ATTR_SYNTAX_TELEPHONE_EMPTY.get());
       return false;
diff --git a/opends/src/server/org/opends/server/schema/TeletexTerminalIdentifierSyntax.java b/opends/src/server/org/opends/server/schema/TeletexTerminalIdentifierSyntax.java
index 40fb5dd..b877652 100644
--- a/opends/src/server/org/opends/server/schema/TeletexTerminalIdentifierSyntax.java
+++ b/opends/src/server/org/opends/server/schema/TeletexTerminalIdentifierSyntax.java
@@ -38,8 +38,7 @@
 import org.opends.server.api.SubstringMatchingRule;
 import org.opends.server.config.ConfigException;
 import org.opends.server.core.DirectoryServer;
-import org.opends.server.types.ByteString;
-
+import org.opends.server.types.ByteSequence;
 
 
 import static org.opends.server.loggers.ErrorLogger.*;
@@ -252,11 +251,11 @@
    * @return  <CODE>true</CODE> if the provided value is acceptable for use with
    *          this syntax, or <CODE>false</CODE> if not.
    */
-  public boolean valueIsAcceptable(ByteString value,
+  public boolean valueIsAcceptable(ByteSequence value,
                                    MessageBuilder invalidReason)
   {
     // Get a lowercase string representation of the value and find its length.
-    String valueString = value.stringValue();
+    String valueString = value.toString();
     int    valueLength = valueString.length();
 
 
diff --git a/opends/src/server/org/opends/server/schema/TelexNumberSyntax.java b/opends/src/server/org/opends/server/schema/TelexNumberSyntax.java
index 3007731..0b93028 100644
--- a/opends/src/server/org/opends/server/schema/TelexNumberSyntax.java
+++ b/opends/src/server/org/opends/server/schema/TelexNumberSyntax.java
@@ -36,8 +36,7 @@
 import org.opends.server.api.SubstringMatchingRule;
 import org.opends.server.config.ConfigException;
 import org.opends.server.core.DirectoryServer;
-import org.opends.server.types.ByteString;
-
+import org.opends.server.types.ByteSequence;
 
 
 import static org.opends.server.loggers.ErrorLogger.*;
@@ -220,11 +219,11 @@
    * @return  <CODE>true</CODE> if the provided value is acceptable for use with
    *          this syntax, or <CODE>false</CODE> if not.
    */
-  public boolean valueIsAcceptable(ByteString value,
+  public boolean valueIsAcceptable(ByteSequence value,
                                    MessageBuilder invalidReason)
   {
     // Get a string representation of the value and find its length.
-    String valueString = value.stringValue();
+    String valueString = value.toString();
     int    valueLength = valueString.length();
 
     if (valueLength < 5)
diff --git a/opends/src/server/org/opends/server/schema/UTCTimeSyntax.java b/opends/src/server/org/opends/server/schema/UTCTimeSyntax.java
index cd5547e..55c7d08 100644
--- a/opends/src/server/org/opends/server/schema/UTCTimeSyntax.java
+++ b/opends/src/server/org/opends/server/schema/UTCTimeSyntax.java
@@ -43,12 +43,7 @@
 import org.opends.server.config.ConfigException;
 import org.opends.server.core.DirectoryServer;
 import org.opends.server.loggers.debug.DebugTracer;
-import org.opends.server.protocols.asn1.ASN1OctetString;
-import org.opends.server.types.AttributeValue;
-import org.opends.server.types.ByteString;
-import org.opends.server.types.DebugLogLevel;
-import org.opends.server.types.DirectoryException;
-import org.opends.server.types.ResultCode;
+import org.opends.server.types.*;
 
 import static org.opends.messages.SchemaMessages.*;
 import static org.opends.server.loggers.debug.DebugLogger.*;
@@ -273,12 +268,12 @@
    * @return  <CODE>true</CODE> if the provided value is acceptable for use with
    *          this syntax, or <CODE>false</CODE> if not.
    */
-  public boolean valueIsAcceptable(ByteString value,
+  public boolean valueIsAcceptable(ByteSequence value,
                                    MessageBuilder invalidReason)
   {
     // Get the value as a string and verify that it is at least long enough for
     // "YYYYMMDDhhmmZ", which is the shortest allowed value.
-    String valueString = value.stringValue().toUpperCase();
+    String valueString = value.toString().toUpperCase();
     int    length      = valueString.length();
     if (length < 11)
     {
@@ -846,8 +841,8 @@
       valueString = dateFormat.format(d);
     }
 
-    return new AttributeValue(new ASN1OctetString(valueString),
-                              new ASN1OctetString(valueString));
+    return AttributeValues.create(ByteString.valueOf(valueString),
+        ByteString.valueOf(valueString));
   }
 
 
@@ -868,7 +863,7 @@
   public static Date decodeUTCTimeValue(ByteString normalizedValue)
          throws DirectoryException
   {
-    String valueString = normalizedValue.stringValue();
+    String valueString = normalizedValue.toString();
     try
     {
       synchronized (dateFormatLock)
diff --git a/opends/src/server/org/opends/server/schema/UUIDEqualityMatchingRule.java b/opends/src/server/org/opends/server/schema/UUIDEqualityMatchingRule.java
index 05ea4e5..0baa1b8 100644
--- a/opends/src/server/org/opends/server/schema/UUIDEqualityMatchingRule.java
+++ b/opends/src/server/org/opends/server/schema/UUIDEqualityMatchingRule.java
@@ -28,23 +28,21 @@
 
 
 
-import java.util.Arrays;
+import static org.opends.messages.SchemaMessages.*;
+import static org.opends.server.loggers.ErrorLogger.*;
+import static org.opends.server.schema.SchemaConstants.*;
 
 import java.util.Collection;
 import java.util.Collections;
+
+import org.opends.messages.Message;
 import org.opends.server.api.EqualityMatchingRule;
 import org.opends.server.core.DirectoryServer;
-
-import org.opends.server.protocols.asn1.ASN1OctetString;
+import org.opends.server.types.ByteSequence;
 import org.opends.server.types.ByteString;
 import org.opends.server.types.DirectoryException;
 import org.opends.server.types.ResultCode;
 
-import static org.opends.server.loggers.ErrorLogger.*;
-import static org.opends.messages.SchemaMessages.*;
-import org.opends.messages.Message;
-import static org.opends.server.schema.SchemaConstants.*;
-
 
 
 /**
@@ -67,6 +65,7 @@
   /**
    * {@inheritDoc}
    */
+  @Override
   public Collection<String> getAllNames()
   {
     return Collections.singleton(getName());
@@ -80,6 +79,7 @@
    * @return  The common name for this matching rule, or <CODE>null</CODE> if
    * it does not have a name.
    */
+  @Override
   public String getName()
   {
     return EMR_UUID_NAME;
@@ -92,6 +92,7 @@
    *
    * @return  The OID for this matching rule.
    */
+  @Override
   public String getOID()
   {
     return EMR_UUID_OID;
@@ -105,6 +106,7 @@
    * @return  The description for this matching rule, or <CODE>null</CODE> if
    *          there is none.
    */
+  @Override
   public String getDescription()
   {
     // There is no standard description for this matching rule.
@@ -119,6 +121,7 @@
    *
    * @return  The OID of the syntax with which this matching rule is associated.
    */
+  @Override
   public String getSyntaxOID()
   {
     return SYNTAX_UUID_OID;
@@ -137,14 +140,14 @@
    * @throws  DirectoryException  If the provided value is invalid according to
    *                              the associated attribute syntax.
    */
-  public ByteString normalizeValue(ByteString value)
+  @Override
+  public ByteString normalizeValue(ByteSequence value)
          throws DirectoryException
   {
-    byte[] valueBytes = value.value();
-    if (valueBytes.length != 36)
+    if (value.length() != 36)
     {
       Message message = WARN_ATTR_SYNTAX_UUID_INVALID_LENGTH.get(
-              value.stringValue(), valueBytes.length);
+              value.toString(), value.length());
       switch (DirectoryServer.getSyntaxEnforcementPolicy())
       {
         case REJECT:
@@ -152,28 +155,29 @@
                                        message);
         case WARN:
           logError(message);
-          return new ASN1OctetString(valueBytes);
+          return value.toByteString();
         default:
-          return new ASN1OctetString(valueBytes);
+          return value.toByteString();
       }
     }
 
-    byte[] normBytes = new byte[36];
-    System.arraycopy(valueBytes, 0, normBytes, 0, 36);
+    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 (normBytes[i] != '-')
+          if (c != '-')
           {
             Message message = WARN_ATTR_SYNTAX_UUID_EXPECTED_DASH.get(
-                    value.stringValue(), i, String.valueOf(normBytes[i]));
+                    value.toString(), i, String.valueOf(c));
             switch (DirectoryServer.getSyntaxEnforcementPolicy())
             {
               case REJECT:
@@ -182,14 +186,15 @@
               case WARN:
                 logError(
                         message);
-                return new ASN1OctetString(valueBytes);
+                return value.toByteString();
               default:
-                return new ASN1OctetString(valueBytes);
+                return value.toByteString();
             }
           }
+          builder.append(c);
           break;
         default:
-          switch (normBytes[i])
+          switch (c)
           {
             case '0':
             case '1':
@@ -208,28 +213,29 @@
             case 'e':
             case 'f':
               // These are all fine.
+              builder.append(c);
               break;
             case 'A':
-              normBytes[i] = 'a';
+              builder.append('a');
               break;
             case 'B':
-              normBytes[i] = 'b';
+              builder.append('b');
               break;
             case 'C':
-              normBytes[i] = 'c';
+              builder.append('c');
               break;
             case 'D':
-              normBytes[i] = 'd';
+              builder.append('d');
               break;
             case 'E':
-              normBytes[i] = 'e';
+              builder.append('e');
               break;
             case 'F':
-              normBytes[i] = 'f';
+              builder.append('f');
               break;
             default:
               Message message = WARN_ATTR_SYNTAX_UUID_EXPECTED_HEX.get(
-                      value.stringValue(), i, String.valueOf(normBytes[i]));
+                      value.toString(), i, String.valueOf(value.byteAt(i)));
               switch (DirectoryServer.getSyntaxEnforcementPolicy())
               {
                 case REJECT:
@@ -238,34 +244,15 @@
                 case WARN:
                   logError(
                           message);
-                  return new ASN1OctetString(valueBytes);
+                  return value.toByteString();
                 default:
-                  return new ASN1OctetString(valueBytes);
+                  return value.toByteString();
               }
           }
       }
     }
 
-    return new ASN1OctetString(normBytes);
-  }
-
-
-
-  /**
-   * Indicates whether the two provided normalized values are equal to each
-   * other.
-   *
-   * @param  value1  The normalized form of the first value to compare.
-   * @param  value2  The normalized form of the second value to compare.
-   *
-   * @return  <CODE>true</CODE> if the provided values are equal, or
-   *          <CODE>false</CODE> if not.
-   */
-  public boolean areEqual(ByteString value1, ByteString value2)
-  {
-    // Since the values are already normalized, we just need to compare the
-    // associated byte arrays.
-    return Arrays.equals(value1.value(), value2.value());
+    return ByteString.valueOf(builder.toString());
   }
 }
 
diff --git a/opends/src/server/org/opends/server/schema/UUIDOrderingMatchingRule.java b/opends/src/server/org/opends/server/schema/UUIDOrderingMatchingRule.java
index d83427c..543b70e 100644
--- a/opends/src/server/org/opends/server/schema/UUIDOrderingMatchingRule.java
+++ b/opends/src/server/org/opends/server/schema/UUIDOrderingMatchingRule.java
@@ -26,22 +26,24 @@
  */
 package org.opends.server.schema;
 
-import java.util.Collections;
-import java.util.Collection;
-import org.opends.messages.Message;
 
 
-
-import org.opends.server.api.OrderingMatchingRule;
-import org.opends.server.core.DirectoryServer;
-import org.opends.server.protocols.asn1.ASN1OctetString;
-import org.opends.server.types.ByteString;
-import org.opends.server.types.DirectoryException;
-import org.opends.server.types.ResultCode;
-
 import static org.opends.messages.SchemaMessages.*;
 import static org.opends.server.schema.SchemaConstants.*;
+
+import java.util.Collection;
+import java.util.Collections;
+
+import org.opends.messages.Message;
+import org.opends.server.api.OrderingMatchingRule;
+import org.opends.server.core.DirectoryServer;
 import org.opends.server.loggers.ErrorLogger;
+import org.opends.server.types.ByteSequence;
+import org.opends.server.types.ByteString;
+import org.opends.server.types.DirectoryException;
+import org.opends.server.types.ResultCode;
+import org.opends.server.util.StaticUtils;
+
 
 
 /**
@@ -74,6 +76,7 @@
   /**
    * {@inheritDoc}
    */
+  @Override
   public Collection<String> getAllNames()
   {
     return Collections.singleton(getName());
@@ -87,6 +90,7 @@
    * @return  The common name for this matching rule, or <CODE>null</CODE> if
    * it does not have a name.
    */
+  @Override
   public String getName()
   {
     return OMR_UUID_NAME;
@@ -99,6 +103,7 @@
    *
    * @return  The OID for this matching rule.
    */
+  @Override
   public String getOID()
   {
     return OMR_UUID_OID;
@@ -112,6 +117,7 @@
    * @return  The description for this matching rule, or <CODE>null</CODE> if
    *          there is none.
    */
+  @Override
   public String getDescription()
   {
     // There is no standard description for this matching rule.
@@ -126,6 +132,7 @@
    *
    * @return  The OID of the syntax with which this matching rule is associated.
    */
+  @Override
   public String getSyntaxOID()
   {
     return SYNTAX_UUID_OID;
@@ -144,14 +151,14 @@
    * @throws  DirectoryException  If the provided value is invalid according to
    *                              the associated attribute syntax.
    */
-  public ByteString normalizeValue(ByteString value)
+  @Override
+  public ByteString normalizeValue(ByteSequence value)
          throws DirectoryException
   {
-    byte[] valueBytes = value.value();
-    if (valueBytes.length != 36)
+    if (value.length() != 36)
     {
       Message message = WARN_ATTR_SYNTAX_UUID_INVALID_LENGTH.get(
-              value.stringValue(), valueBytes.length);
+              value.toString(), value.length());
       switch (DirectoryServer.getSyntaxEnforcementPolicy())
       {
         case REJECT:
@@ -159,28 +166,29 @@
                                        message);
         case WARN:
           ErrorLogger.logError(message);
-          return new ASN1OctetString(valueBytes);
+          return value.toByteString();
         default:
-          return new ASN1OctetString(valueBytes);
+          return value.toByteString();
       }
     }
 
-    byte[] normBytes = new byte[36];
-    System.arraycopy(valueBytes, 0, normBytes, 0, 36);
+    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 (normBytes[i] != '-')
+          if (c != '-')
           {
             Message message = WARN_ATTR_SYNTAX_UUID_EXPECTED_DASH.get(
-                    value.stringValue(), i, String.valueOf(normBytes[i]));
+                    value.toString(), i, String.valueOf(c));
             switch (DirectoryServer.getSyntaxEnforcementPolicy())
             {
               case REJECT:
@@ -188,14 +196,15 @@
                                ResultCode.INVALID_ATTRIBUTE_SYNTAX, message);
               case WARN:
                 ErrorLogger.logError(message);
-                return new ASN1OctetString(valueBytes);
+                return value.toByteString();
               default:
-                return new ASN1OctetString(valueBytes);
+                return value.toByteString();
             }
           }
+          builder.append(c);
           break;
         default:
-          switch (normBytes[i])
+          switch (c)
           {
             case '0':
             case '1':
@@ -214,28 +223,29 @@
             case 'e':
             case 'f':
               // These are all fine.
+              builder.append(c);
               break;
             case 'A':
-              normBytes[i] = 'a';
+              builder.append('a');
               break;
             case 'B':
-              normBytes[i] = 'b';
+              builder.append('b');
               break;
             case 'C':
-              normBytes[i] = 'c';
+              builder.append('c');
               break;
             case 'D':
-              normBytes[i] = 'd';
+              builder.append('d');
               break;
             case 'E':
-              normBytes[i] = 'e';
+              builder.append('e');
               break;
             case 'F':
-              normBytes[i] = 'f';
+              builder.append('f');
               break;
             default:
               Message message = WARN_ATTR_SYNTAX_UUID_EXPECTED_HEX.get(
-                      value.stringValue(), i, String.valueOf(normBytes[i]));
+                      value.toString(), i, String.valueOf(c));
               switch (DirectoryServer.getSyntaxEnforcementPolicy())
               {
                 case REJECT:
@@ -243,15 +253,15 @@
                                  ResultCode.INVALID_ATTRIBUTE_SYNTAX, message);
                 case WARN:
                   ErrorLogger.logError(message);
-                  return new ASN1OctetString(valueBytes);
+                  return value.toByteString();
                 default:
-                  return new ASN1OctetString(valueBytes);
+                  return value.toByteString();
               }
           }
       }
     }
 
-    return new ASN1OctetString(normBytes);
+    return ByteString.valueOf(builder.toString());
   }
 
 
@@ -269,9 +279,10 @@
    *          ascending order, or zero if there is no difference between the
    *          values with regard to ordering.
    */
-  public int compareValues(ByteString value1, ByteString value2)
+  @Override
+  public int compareValues(ByteSequence value1, ByteSequence value2)
   {
-    return compare(value1.value(), value2.value());
+    return StaticUtils.compare(value1, value2);
   }
 
 
@@ -291,36 +302,7 @@
    */
   public int compare(byte[] b1, byte[] b2)
   {
-    int minLength = Math.min(b1.length, b2.length);
-
-    for (int i=0; i < minLength; i++)
-    {
-      if (b1[i] == b2[i])
-      {
-        continue;
-      }
-      else if (b1[i] < b2[i])
-      {
-        return -1;
-      }
-      else if (b1[i] > b2[i])
-      {
-        return 1;
-      }
-    }
-
-    if (b1.length == b2.length)
-    {
-      return 0;
-    }
-    else if (b1.length < b2.length)
-    {
-      return -1;
-    }
-    else
-    {
-      return 1;
-    }
+    return StaticUtils.compare(b1, b2);
   }
 }
 
diff --git a/opends/src/server/org/opends/server/schema/UUIDSyntax.java b/opends/src/server/org/opends/server/schema/UUIDSyntax.java
index 87d4a1b..4bf49ba 100644
--- a/opends/src/server/org/opends/server/schema/UUIDSyntax.java
+++ b/opends/src/server/org/opends/server/schema/UUIDSyntax.java
@@ -36,8 +36,7 @@
 import org.opends.server.api.SubstringMatchingRule;
 import org.opends.server.config.ConfigException;
 import org.opends.server.core.DirectoryServer;
-import org.opends.server.types.ByteString;
-
+import org.opends.server.types.ByteSequence;
 
 
 import static org.opends.server.loggers.ErrorLogger.*;
@@ -209,14 +208,14 @@
    * @return  <CODE>true</CODE> if the provided value is acceptable for use with
    *          this syntax, or <CODE>false</CODE> if not.
    */
-  public boolean valueIsAcceptable(ByteString value,
+  public boolean valueIsAcceptable(ByteSequence value,
                                    MessageBuilder 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.
-    String valueString = value.stringValue();
+    String valueString = value.toString();
     if (valueString.length() != 36)
     {
 
diff --git a/opends/src/server/org/opends/server/schema/UniqueMemberEqualityMatchingRule.java b/opends/src/server/org/opends/server/schema/UniqueMemberEqualityMatchingRule.java
index 669ca5f..a9ad8e3 100644
--- a/opends/src/server/org/opends/server/schema/UniqueMemberEqualityMatchingRule.java
+++ b/opends/src/server/org/opends/server/schema/UniqueMemberEqualityMatchingRule.java
@@ -25,29 +25,28 @@
  *      Copyright 2006-2008 Sun Microsystems, Inc.
  */
 package org.opends.server.schema;
-import org.opends.messages.Message;
 
 
 
-import java.util.Arrays;
+import static org.opends.messages.SchemaMessages.*;
+import static org.opends.server.loggers.debug.DebugLogger.*;
+import static org.opends.server.schema.SchemaConstants.*;
+import static org.opends.server.util.StaticUtils.*;
 
 import java.util.Collection;
 import java.util.Collections;
+
+import org.opends.messages.Message;
 import org.opends.server.api.EqualityMatchingRule;
 import org.opends.server.core.DirectoryServer;
-import org.opends.server.protocols.asn1.ASN1OctetString;
-import org.opends.server.types.ByteString;
-import org.opends.server.types.DirectoryException;
-import org.opends.server.types.DN;
-import org.opends.server.types.ResultCode;
-
-import static org.opends.server.loggers.debug.DebugLogger.*;
-import org.opends.server.loggers.debug.DebugTracer;
 import org.opends.server.loggers.ErrorLogger;
+import org.opends.server.loggers.debug.DebugTracer;
+import org.opends.server.types.ByteSequence;
+import org.opends.server.types.ByteString;
+import org.opends.server.types.DN;
 import org.opends.server.types.DebugLogLevel;
-import static org.opends.messages.SchemaMessages.*;
-import static org.opends.server.schema.SchemaConstants.*;
-import static org.opends.server.util.StaticUtils.*;
+import org.opends.server.types.DirectoryException;
+import org.opends.server.types.ResultCode;
 
 
 
@@ -80,6 +79,7 @@
   /**
    * {@inheritDoc}
    */
+  @Override
   public Collection<String> getAllNames()
   {
     return Collections.singleton(getName());
@@ -93,6 +93,7 @@
    * @return  The common name for this matching rule, or <CODE>null</CODE> if
    * it does not have a name.
    */
+  @Override
   public String getName()
   {
     return EMR_UNIQUE_MEMBER_NAME;
@@ -105,6 +106,7 @@
    *
    * @return  The OID for this matching rule.
    */
+  @Override
   public String getOID()
   {
     return EMR_UNIQUE_MEMBER_OID;
@@ -118,6 +120,7 @@
    * @return  The description for this matching rule, or <CODE>null</CODE> if
    *          there is none.
    */
+  @Override
   public String getDescription()
   {
     // There is no standard description for this matching rule.
@@ -132,6 +135,7 @@
    *
    * @return  The OID of the syntax with which this matching rule is associated.
    */
+  @Override
   public String getSyntaxOID()
   {
     return SYNTAX_NAME_AND_OPTIONAL_UID_OID;
@@ -150,10 +154,11 @@
    * @throws  DirectoryException  If the provided value is invalid according to
    *                              the associated attribute syntax.
    */
-  public ByteString normalizeValue(ByteString value)
+  @Override
+  public ByteString normalizeValue(ByteSequence value)
          throws DirectoryException
   {
-    String valueString = value.stringValue().trim();
+    String valueString = value.toString().trim();
     int    valueLength = valueString.length();
 
 
@@ -252,26 +257,7 @@
       valueBuffer.append("'B");
     }
 
-    return new ASN1OctetString(valueBuffer.toString());
-  }
-
-
-
-  /**
-   * Indicates whether the two provided normalized values are equal to each
-   * other.
-   *
-   * @param  value1  The normalized form of the first value to compare.
-   * @param  value2  The normalized form of the second value to compare.
-   *
-   * @return  <CODE>true</CODE> if the provided values are equal, or
-   *          <CODE>false</CODE> if not.
-   */
-  public boolean areEqual(ByteString value1, ByteString value2)
-  {
-    // Since the values are already normalized, we just need to compare the
-    // associated byte arrays.
-    return Arrays.equals(value1.value(), value2.value());
+    return ByteString.valueOf(valueBuffer.toString());
   }
 }
 
diff --git a/opends/src/server/org/opends/server/schema/UserPasswordEqualityMatchingRule.java b/opends/src/server/org/opends/server/schema/UserPasswordEqualityMatchingRule.java
index 61ba9dc..de1337f 100644
--- a/opends/src/server/org/opends/server/schema/UserPasswordEqualityMatchingRule.java
+++ b/opends/src/server/org/opends/server/schema/UserPasswordEqualityMatchingRule.java
@@ -28,23 +28,21 @@
 
 
 
-import java.util.Arrays;
+import static org.opends.server.loggers.debug.DebugLogger.*;
+import static org.opends.server.schema.SchemaConstants.*;
 
-import java.util.Collections;
 import java.util.Collection;
+import java.util.Collections;
+
 import org.opends.server.api.EqualityMatchingRule;
 import org.opends.server.api.PasswordStorageScheme;
 import org.opends.server.core.DirectoryServer;
-import org.opends.server.protocols.asn1.ASN1OctetString;
-import org.opends.server.types.AttributeValue;
+import org.opends.server.loggers.debug.DebugTracer;
+import org.opends.server.types.ByteSequence;
 import org.opends.server.types.ByteString;
 import org.opends.server.types.ConditionResult;
-import org.opends.server.types.DirectoryException;
-
-import static org.opends.server.loggers.debug.DebugLogger.*;
-import org.opends.server.loggers.debug.DebugTracer;
 import org.opends.server.types.DebugLogLevel;
-import static org.opends.server.schema.SchemaConstants.*;
+import org.opends.server.types.DirectoryException;
 
 
 
@@ -75,6 +73,7 @@
   /**
    * {@inheritDoc}
    */
+  @Override
   public Collection<String> getAllNames()
   {
     return Collections.singleton(getName());
@@ -88,6 +87,7 @@
    * @return  The common name for this matching rule, or <CODE>null</CODE> if
    * it does not have a name.
    */
+  @Override
   public String getName()
   {
     return EMR_USER_PASSWORD_NAME;
@@ -100,6 +100,7 @@
    *
    * @return  The OID for this matching rule.
    */
+  @Override
   public String getOID()
   {
     return EMR_USER_PASSWORD_OID;
@@ -113,6 +114,7 @@
    * @return  The description for this matching rule, or <CODE>null</CODE> if
    *          there is none.
    */
+  @Override
   public String getDescription()
   {
     // There is no standard description for this matching rule.
@@ -127,6 +129,7 @@
    *
    * @return  The OID of the syntax with which this matching rule is associated.
    */
+  @Override
   public String getSyntaxOID()
   {
     return SYNTAX_USER_PASSWORD_OID;
@@ -145,39 +148,15 @@
    * @throws  DirectoryException  If the provided value is invalid according to
    *                              the associated attribute syntax.
    */
-  public ByteString normalizeValue(ByteString value)
+  @Override
+  public ByteString normalizeValue(ByteSequence value)
          throws DirectoryException
   {
-    // We will not alter the value in any way, but we'll create a new value
-    // just in case something else is using the underlying array.
-    byte[] currentValue = value.value();
-    byte[] newValue     = new byte[currentValue.length];
-    System.arraycopy(currentValue, 0, newValue, 0, currentValue.length);
-
-    return new ASN1OctetString(newValue);
+    // We will not alter the value in any way
+    return value.toByteString();
   }
 
 
-
-  /**
-   * Indicates whether the two provided normalized values are equal to each
-   * other.
-   *
-   * @param  value1  The normalized form of the first value to compare.
-   * @param  value2  The normalized form of the second value to compare.
-   *
-   * @return  <CODE>true</CODE> if the provided values are equal, or
-   *          <CODE>false</CODE> if not.
-   */
-  public boolean areEqual(ByteString value1, ByteString value2)
-  {
-    // Since the values are already normalized, we just need to compare the
-    // associated byte arrays.
-    return Arrays.equals(value1.value(), value2.value());
-  }
-
-
-
   /**
    * Indicates whether the provided attribute value should be considered a match
    * for the given assertion value.  This will only be used for the purpose of
@@ -193,8 +172,9 @@
    *          match for the provided assertion value, or <CODE>false</CODE> if
    *          not.
    */
-  public ConditionResult valuesMatch(ByteString attributeValue,
-                                     ByteString assertionValue)
+  @Override
+  public ConditionResult valuesMatch(ByteSequence attributeValue,
+                                     ByteSequence assertionValue)
   {
     // We must be able to decode the attribute value using the user password
     // syntax.
@@ -202,7 +182,7 @@
     try
     {
       userPWComponents =
-           UserPasswordSyntax.decodeUserPassword(attributeValue.stringValue());
+           UserPasswordSyntax.decodeUserPassword(attributeValue.toString());
     }
     catch (Exception e)
     {
@@ -228,7 +208,7 @@
 
     // We support the scheme, so make the determination.
     if (storageScheme.passwordMatches(assertionValue,
-                                      new ASN1OctetString(userPWComponents[1])))
+        ByteString.valueOf(userPWComponents[1])))
     {
       return ConditionResult.TRUE;
     }
@@ -254,7 +234,8 @@
    *
    * @return  The hash code generated for the provided attribute value.
    */
-  public int generateHashCode(AttributeValue attributeValue)
+  @Override
+  public int generateHashCode(ByteSequence attributeValue)
   {
     // Because of the variable encoding that may be used, we have no way of
     // comparing two user password values by hash code and therefore we'll
diff --git a/opends/src/server/org/opends/server/schema/UserPasswordExactEqualityMatchingRule.java b/opends/src/server/org/opends/server/schema/UserPasswordExactEqualityMatchingRule.java
index 7d8b870..11d9a42 100644
--- a/opends/src/server/org/opends/server/schema/UserPasswordExactEqualityMatchingRule.java
+++ b/opends/src/server/org/opends/server/schema/UserPasswordExactEqualityMatchingRule.java
@@ -28,16 +28,16 @@
 
 
 
-import java.util.Arrays;
+import static org.opends.server.schema.SchemaConstants.*;
 
-import java.util.Collections;
 import java.util.Collection;
+import java.util.Collections;
+
 import org.opends.server.api.EqualityMatchingRule;
-import org.opends.server.protocols.asn1.ASN1OctetString;
+import org.opends.server.types.ByteSequence;
 import org.opends.server.types.ByteString;
 import org.opends.server.types.DirectoryException;
-
-import static org.opends.server.schema.SchemaConstants.*;
+import org.opends.server.util.StaticUtils;
 
 
 
@@ -62,6 +62,7 @@
   /**
    * {@inheritDoc}
    */
+  @Override
   public Collection<String> getAllNames()
   {
     return Collections.singleton(getName());
@@ -75,6 +76,7 @@
    * @return  The common name for this matching rule, or <CODE>null</CODE> if
    * it does not have a name.
    */
+  @Override
   public String getName()
   {
     return EMR_USER_PASSWORD_EXACT_NAME;
@@ -87,6 +89,7 @@
    *
    * @return  The OID for this matching rule.
    */
+  @Override
   public String getOID()
   {
     return EMR_USER_PASSWORD_EXACT_OID;
@@ -100,6 +103,7 @@
    * @return  The description for this matching rule, or <CODE>null</CODE> if
    *          there is none.
    */
+  @Override
   public String getDescription()
   {
     // There is no standard description for this matching rule.
@@ -114,6 +118,7 @@
    *
    * @return  The OID of the syntax with which this matching rule is associated.
    */
+  @Override
   public String getSyntaxOID()
   {
     return SYNTAX_USER_PASSWORD_OID;
@@ -132,127 +137,24 @@
    * @throws  DirectoryException  If the provided value is invalid according to
    *                              the associated attribute syntax.
    */
-  public ByteString normalizeValue(ByteString value)
+  @Override
+  public ByteString normalizeValue(ByteSequence value)
          throws DirectoryException
   {
     // 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).
-    byte[] valueBytes = value.value();
-    byte[] newValueBytes = new byte[valueBytes.length];
-    System.arraycopy(valueBytes, 0, newValueBytes, 0, valueBytes.length);
 
     if (UserPasswordSyntax.isEncoded(value))
     {
-schemeLoop:
-      for (int i=1; i < newValueBytes.length; i++)
-      {
-        switch (newValueBytes[i])
-        {
-          case 'A':
-            newValueBytes[i] = 'a';
-            break;
-          case 'B':
-            newValueBytes[i] = 'b';
-            break;
-          case 'C':
-            newValueBytes[i] = 'c';
-            break;
-          case 'D':
-            newValueBytes[i] = 'd';
-            break;
-          case 'E':
-            newValueBytes[i] = 'e';
-            break;
-          case 'F':
-            newValueBytes[i] = 'f';
-            break;
-          case 'G':
-            newValueBytes[i] = 'g';
-            break;
-          case 'H':
-            newValueBytes[i] = 'h';
-            break;
-          case 'I':
-            newValueBytes[i] = 'i';
-            break;
-          case 'J':
-            newValueBytes[i] = 'j';
-            break;
-          case 'K':
-            newValueBytes[i] = 'k';
-            break;
-          case 'L':
-            newValueBytes[i] = 'l';
-            break;
-          case 'M':
-            newValueBytes[i] = 'm';
-            break;
-          case 'N':
-            newValueBytes[i] = 'n';
-            break;
-          case 'O':
-            newValueBytes[i] = 'o';
-            break;
-          case 'P':
-            newValueBytes[i] = 'p';
-            break;
-          case 'Q':
-            newValueBytes[i] = 'q';
-            break;
-          case 'R':
-            newValueBytes[i] = 'r';
-            break;
-          case 'S':
-            newValueBytes[i] = 's';
-            break;
-          case 'T':
-            newValueBytes[i] = 't';
-            break;
-          case 'U':
-            newValueBytes[i] = 'u';
-            break;
-          case 'V':
-            newValueBytes[i] = 'v';
-            break;
-          case 'W':
-            newValueBytes[i] = 'w';
-            break;
-          case 'X':
-            newValueBytes[i] = 'x';
-            break;
-          case 'Y':
-            newValueBytes[i] = 'y';
-            break;
-          case 'Z':
-            newValueBytes[i] = 'z';
-            break;
-          case '}':
-            break schemeLoop;
-        }
-      }
+      StringBuilder builder = new StringBuilder(value.length());
+      StaticUtils.toLowerCase(value, builder, false);
+      return ByteString.valueOf(builder.toString());
     }
-
-    return new ASN1OctetString(newValueBytes);
-  }
-
-
-
-  /**
-   * Indicates whether the two provided normalized values are equal to each
-   * other.
-   *
-   * @param  value1  The normalized form of the first value to compare.
-   * @param  value2  The normalized form of the second value to compare.
-   *
-   * @return  <CODE>true</CODE> if the provided values are equal, or
-   *          <CODE>false</CODE> if not.
-   */
-  public boolean areEqual(ByteString value1, ByteString value2)
-  {
-    // Since the values are already normalized, we just need to compare the
-    // associated byte arrays.
-    return Arrays.equals(value1.value(), value2.value());
+    else
+    {
+      return value.toByteString();
+    }
   }
 }
 
diff --git a/opends/src/server/org/opends/server/schema/UserPasswordSyntax.java b/opends/src/server/org/opends/server/schema/UserPasswordSyntax.java
index e69d4b7..5dc61ef 100644
--- a/opends/src/server/org/opends/server/schema/UserPasswordSyntax.java
+++ b/opends/src/server/org/opends/server/schema/UserPasswordSyntax.java
@@ -37,11 +37,9 @@
 import org.opends.server.api.SubstringMatchingRule;
 import org.opends.server.config.ConfigException;
 import org.opends.server.core.DirectoryServer;
-import org.opends.server.types.ByteString;
-import org.opends.server.types.DirectoryException;
 
 
-import org.opends.server.types.ResultCode;
+import org.opends.server.types.*;
 
 import static org.opends.server.loggers.ErrorLogger.*;
 import static org.opends.messages.SchemaMessages.*;
@@ -212,7 +210,7 @@
    * @return  <CODE>true</CODE> if the provided value is acceptable for use with
    *          this syntax, or <CODE>false</CODE> if not.
    */
-  public boolean valueIsAcceptable(ByteString value,
+  public boolean valueIsAcceptable(ByteSequence value,
                                    MessageBuilder invalidReason)
   {
     // We have to accept any value here because in many cases the value will not
@@ -291,18 +289,17 @@
    * @return  <CODE>true</CODE> if the value appears to be encoded using the
    *          user password syntax, or <CODE>false</CODE> if not.
    */
-  public static boolean isEncoded(ByteString value)
+  public static boolean isEncoded(ByteSequence value)
   {
     // If the value is null or empty, then it's not.
-    byte[] valueBytes;
-    if ((value == null) || ((valueBytes = value.value()).length == 0))
+    if ((value == null) || value.length() == 0)
     {
       return false;
     }
 
 
     // If the value doesn't start with an opening curly brace, then it's not.
-    if (valueBytes[0] != '{')
+    if (value.byteAt(0) != '{')
     {
       return false;
     }
@@ -311,9 +308,9 @@
     // 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 < valueBytes.length; i++)
+    for (int i=1; i < value.length(); i++)
     {
-      if (valueBytes[i] == '}')
+      if (value.byteAt(i) == '}')
       {
         closingBracePos = i;
         break;
@@ -327,7 +324,7 @@
 
 
     // The closing curly brace must not be the last character of the password.
-    if (closingBracePos == (valueBytes.length - 1))
+    if (closingBracePos == (value.length() - 1))
     {
       return false;
     }
diff --git a/opends/src/server/org/opends/server/schema/WordEqualityMatchingRule.java b/opends/src/server/org/opends/server/schema/WordEqualityMatchingRule.java
index 09b9572..5c08a0f 100644
--- a/opends/src/server/org/opends/server/schema/WordEqualityMatchingRule.java
+++ b/opends/src/server/org/opends/server/schema/WordEqualityMatchingRule.java
@@ -28,17 +28,18 @@
 
 
 
-import java.util.Collection;
-import java.util.Collections;
-import org.opends.server.api.EqualityMatchingRule;
-import org.opends.server.protocols.asn1.ASN1OctetString;
-import org.opends.server.types.AttributeValue;
-import org.opends.server.types.ByteString;
-import org.opends.server.types.DirectoryException;
-
 import static org.opends.server.schema.SchemaConstants.*;
 import static org.opends.server.util.StaticUtils.*;
 
+import java.util.Collection;
+import java.util.Collections;
+
+import org.opends.server.api.EqualityMatchingRule;
+import org.opends.server.types.ByteSequence;
+import org.opends.server.types.ByteString;
+import org.opends.server.types.DirectoryException;
+import org.opends.server.util.ServerConstants;
+
 
 
 /**
@@ -77,6 +78,7 @@
   /**
    * {@inheritDoc}
    */
+  @Override
   public Collection<String> getAllNames()
   {
     return Collections.singleton(getName());
@@ -90,6 +92,7 @@
    * @return  The common name for this matching rule, or <CODE>null</CODE> if
    * it does not have a name.
    */
+  @Override
   public String getName()
   {
     return EMR_WORD_NAME;
@@ -102,6 +105,7 @@
    *
    * @return  The OID for this matching rule.
    */
+  @Override
   public String getOID()
   {
     return EMR_WORD_OID;
@@ -115,6 +119,7 @@
    * @return  The description for this matching rule, or <CODE>null</CODE> if
    *          there is none.
    */
+  @Override
   public String getDescription()
   {
     // There is no standard description for this matching rule.
@@ -129,6 +134,7 @@
    *
    * @return  The OID of the syntax with which this matching rule is associated.
    */
+  @Override
   public String getSyntaxOID()
   {
     return SYNTAX_DIRECTORY_STRING_OID;
@@ -147,25 +153,26 @@
    * @throws  DirectoryException  If the provided value is invalid according to
    *                              the associated attribute syntax.
    */
-  public ByteString normalizeValue(ByteString value)
+  @Override
+  public ByteString normalizeValue(ByteSequence value)
          throws DirectoryException
   {
     StringBuilder buffer = new StringBuilder();
-    toLowerCase(value.value(), buffer, true);
+    toLowerCase(value, buffer, true);
 
     int bufferLength = buffer.length();
     if (bufferLength == 0)
     {
-      if (value.value().length > 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 ASN1OctetString(" ");
+        return ServerConstants.SINGLE_SPACE_VALUE;
       }
       else
       {
         // The value is empty, so it is already normalized.
-        return new ASN1OctetString();
+        return ByteString.empty();
       }
     }
 
@@ -182,7 +189,7 @@
       }
     }
 
-    return new ASN1OctetString(buffer.toString());
+    return ByteString.valueOf(buffer.toString());
   }
 
 
@@ -197,13 +204,14 @@
    * @return  <CODE>true</CODE> if the provided values are equal, or
    *          <CODE>false</CODE> if not.
    */
-  public boolean areEqual(ByteString value1, ByteString value2)
+  @Override
+  public boolean areEqual(ByteSequence value1, ByteSequence value2)
   {
     // For this purpose, the first value will be considered the attribute value,
     // and the second the assertion value.  See if the second value is contained
     // in the first.  If not, then it isn't a match.
-    String valueStr1 = value1.stringValue();
-    String valueStr2 = value2.stringValue();
+    String valueStr1 = value1.toString();
+    String valueStr2 = value2.toString();
     int pos = valueStr1.indexOf(valueStr2);
     if (pos < 0)
     {
@@ -280,7 +288,8 @@
    *                         code.
    *
    * @return  The hash code generated for the provided attribute value.*/
-  public int generateHashCode(AttributeValue attributeValue)
+  @Override
+  public int generateHashCode(ByteSequence attributeValue)
   {
     // In this case, we'll always return the same value because the matching
     // isn't based on the entire value.
diff --git a/opends/src/server/org/opends/server/tasks/AddSchemaFileTask.java b/opends/src/server/org/opends/server/tasks/AddSchemaFileTask.java
index 6c82691..970e558 100644
--- a/opends/src/server/org/opends/server/tasks/AddSchemaFileTask.java
+++ b/opends/src/server/org/opends/server/tasks/AddSchemaFileTask.java
@@ -43,21 +43,7 @@
 import org.opends.server.config.ConfigException;
 import org.opends.server.core.DirectoryServer;
 import org.opends.server.core.SchemaConfigManager;
-import org.opends.server.types.Attribute;
-import org.opends.server.types.AttributeBuilder;
-import org.opends.server.types.AttributeType;
-import org.opends.server.types.AttributeValue;
-import org.opends.server.types.DebugLogLevel;
-import org.opends.server.types.DirectoryException;
-import org.opends.server.types.DN;
-import org.opends.server.types.Entry;
-import org.opends.server.types.InitializationException;
-import org.opends.server.types.LockManager;
-import org.opends.server.types.Modification;
-import org.opends.server.types.Operation;
-import org.opends.server.types.Privilege;
-import org.opends.server.types.ResultCode;
-import org.opends.server.types.Schema;
+import org.opends.server.types.*;
 
 import static org.opends.server.config.ConfigConstants.*;
 import static org.opends.server.loggers.debug.DebugLogger.*;
@@ -136,7 +122,7 @@
     {
       for (AttributeValue v  : a)
       {
-        String filename = v.getStringValue();
+        String filename = v.getValue().toString();
         filesToAdd.add(filename);
 
         try
@@ -253,7 +239,7 @@
                 .getAttributeType(), a.getName());
             for (AttributeValue v : a)
             {
-              String s = v.getStringValue();
+              String s = v.getValue().toString();
               if (s.indexOf(SCHEMA_PROPERTY_FILENAME) < 0)
               {
                 if (s.endsWith(" )"))
@@ -268,7 +254,7 @@
                 }
               }
 
-              builder.add(new AttributeValue(a.getAttributeType(), s));
+              builder.add(AttributeValues.create(a.getAttributeType(), s));
             }
 
             mods.add(new Modification(m.getModificationType(), builder
diff --git a/opends/src/server/org/opends/server/tasks/BackupTask.java b/opends/src/server/org/opends/server/tasks/BackupTask.java
index 1547d06..9f28dcc 100644
--- a/opends/src/server/org/opends/server/tasks/BackupTask.java
+++ b/opends/src/server/org/opends/server/tasks/BackupTask.java
@@ -438,7 +438,7 @@
             Message message = ERR_BACKUPDB_CANNOT_BACKUP_IN_DIRECTORY.get(
                 b.getBackendID(),backupLocation.getPath(),
                 backupDir.getConfigEntryDN().getRDN().
-                getAttributeValue(0).getStringValue());
+                getAttributeValue(0).toString());
             logError(message);
             return false ;
           }
@@ -609,6 +609,7 @@
   /**
    * {@inheritDoc}
    */
+  @Override
   protected TaskState runTask()
   {
     if (!argumentsAreValid())
diff --git a/opends/src/server/org/opends/server/tasks/DisconnectClientTask.java b/opends/src/server/org/opends/server/tasks/DisconnectClientTask.java
index f39500e..9c472a6 100644
--- a/opends/src/server/org/opends/server/tasks/DisconnectClientTask.java
+++ b/opends/src/server/org/opends/server/tasks/DisconnectClientTask.java
@@ -113,13 +113,13 @@
         {
           try
           {
-            connectionID = Long.parseLong(v.getStringValue());
+            connectionID = Long.parseLong(v.getValue().toString());
             break connIDLoop;
           }
           catch (Exception e)
           {
             Message message =
-                ERR_TASK_DISCONNECT_INVALID_CONN_ID.get(v.getStringValue());
+               ERR_TASK_DISCONNECT_INVALID_CONN_ID.get(v.getValue().toString());
             throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX,
                                          message, e);
           }
@@ -149,7 +149,7 @@
       {
         for (AttributeValue v : a)
         {
-          String stringValue = toLowerCase(v.getStringValue());
+          String stringValue = toLowerCase(v.getValue().toString());
           if (stringValue.equals("true"))
           {
             notifyClient = true;
@@ -183,7 +183,7 @@
       {
         for (AttributeValue v : a)
         {
-          disconnectMessage = Message.raw(v.getStringValue());
+          disconnectMessage = Message.raw(v.getValue().toString());
           break disconnectMessageLoop;
         }
       }
diff --git a/opends/src/server/org/opends/server/tasks/ShutdownTask.java b/opends/src/server/org/opends/server/tasks/ShutdownTask.java
index 22bf607..24e0274 100644
--- a/opends/src/server/org/opends/server/tasks/ShutdownTask.java
+++ b/opends/src/server/org/opends/server/tasks/ShutdownTask.java
@@ -104,7 +104,7 @@
       if (!attr.isEmpty())
       {
         String valueString = attr.iterator().next()
-            .getStringValue();
+            .getValue().toString();
 
         shutdownMessage = INFO_TASK_SHUTDOWN_CUSTOM_MESSAGE.get(String
             .valueOf(taskEntry.getDN()), String.valueOf(valueString));
@@ -120,7 +120,7 @@
       if (!attr.isEmpty())
       {
         String valueString = toLowerCase(attr.iterator().next()
-            .getStringValue());
+            .getValue().toString());
 
         restart = (valueString.equals("true") || valueString.equals("yes")
             || valueString.equals("on") || valueString.equals("1"));
diff --git a/opends/src/server/org/opends/server/tasks/TaskUtils.java b/opends/src/server/org/opends/server/tasks/TaskUtils.java
index edd2bc4..188bafc 100644
--- a/opends/src/server/org/opends/server/tasks/TaskUtils.java
+++ b/opends/src/server/org/opends/server/tasks/TaskUtils.java
@@ -34,6 +34,7 @@
 import static org.opends.server.loggers.ErrorLogger.*;
 import static org.opends.server.loggers.debug.DebugLogger.*;
 import static org.opends.server.util.StaticUtils.*;
+import org.opends.server.util.ServerConstants;
 
 import java.util.ArrayList;
 import java.util.HashMap;
@@ -52,19 +53,10 @@
 import org.opends.server.core.DirectoryServer;
 import org.opends.server.core.ModifyOperation;
 import org.opends.server.loggers.debug.DebugTracer;
-import org.opends.server.protocols.asn1.ASN1OctetString;
 import org.opends.server.protocols.internal.InternalClientConnection;
 import org.opends.server.protocols.ldap.LDAPAttribute;
 import org.opends.server.protocols.ldap.LDAPModification;
-import org.opends.server.types.Attribute;
-import org.opends.server.types.AttributeValue;
-import org.opends.server.types.DN;
-import org.opends.server.types.DebugLogLevel;
-import org.opends.server.types.DirectoryException;
-import org.opends.server.types.ModificationType;
-import org.opends.server.types.RawModification;
-import org.opends.server.types.ResultCode;
-
+import org.opends.server.types.*;
 
 
 /**
@@ -262,8 +254,8 @@
                                    e.getMessageObject(), e);
     }
 
-    ArrayList<ASN1OctetString> valueList = new ArrayList<ASN1OctetString>(1);
-    valueList.add(new ASN1OctetString("TRUE"));
+    ArrayList<ByteString> valueList = new ArrayList<ByteString>(1);
+    valueList.add(ServerConstants.TRUE_VALUE);
     LDAPAttribute a = new LDAPAttribute(ATTR_BACKEND_ENABLED, valueList);
 
     LDAPModification m = new LDAPModification(ModificationType.REPLACE, a);
@@ -274,8 +266,8 @@
     InternalClientConnection conn =
          InternalClientConnection.getRootConnection();
     String backendDNString = configEntryDN.toString();
-    ASN1OctetString rawEntryDN =
-         new ASN1OctetString(backendDNString);
+    ByteString rawEntryDN =
+        ByteString.valueOf(backendDNString);
     ModifyOperation internalModify = conn.processModify(rawEntryDN, modList);
 
     ResultCode resultCode = internalModify.getResultCode();
@@ -312,8 +304,8 @@
                                    e.getMessageObject(), e);
     }
 
-    ArrayList<ASN1OctetString> valueList = new ArrayList<ASN1OctetString>(1);
-    valueList.add(new ASN1OctetString("FALSE"));
+    ArrayList<ByteString> valueList = new ArrayList<ByteString>(1);
+    valueList.add(ServerConstants.FALSE_VALUE);
     LDAPAttribute a = new LDAPAttribute(ATTR_BACKEND_ENABLED, valueList);
 
     LDAPModification m = new LDAPModification(ModificationType.REPLACE, a);
@@ -324,8 +316,8 @@
     InternalClientConnection conn =
          InternalClientConnection.getRootConnection();
     String backendDNString = configEntryDN.toString();
-    ASN1OctetString rawEntryDN =
-         new ASN1OctetString(backendDNString);
+    ByteString rawEntryDN =
+        ByteString.valueOf(backendDNString);
     ModifyOperation internalModify = conn.processModify(rawEntryDN, modList);
 
     ResultCode resultCode = internalModify.getResultCode();
@@ -362,7 +354,7 @@
     {
       for (AttributeValue v  : a)
       {
-        String valueString = toLowerCase(v.getStringValue());
+        String valueString = toLowerCase(v.getValue().toString());
         if (valueString.equals("true") || valueString.equals("yes") ||
             valueString.equals("on") || valueString.equals("1"))
         {
@@ -400,7 +392,7 @@
       {
         for (AttributeValue value : attr)
         {
-          valueStrings.add(value.getStringValue());
+          valueStrings.add(value.getValue().toString());
         }
       }
     }
@@ -427,7 +419,7 @@
     Attribute attr = attrList.get(0);
     if (!attr.isEmpty())
     {
-      valueString = attr.iterator().next().getStringValue();
+      valueString = attr.iterator().next().getValue().toString();
     }
     return valueString;
   }
@@ -453,7 +445,7 @@
       if (!attr.isEmpty())
       {
         String valueString = attr.iterator().next()
-            .getStringValue();
+            .getValue().toString();
         try
         {
           return Integer.parseInt(valueString);
diff --git a/opends/src/server/org/opends/server/tools/BackUpDB.java b/opends/src/server/org/opends/server/tools/BackUpDB.java
index fa9c78b..2a0416a 100644
--- a/opends/src/server/org/opends/server/tools/BackUpDB.java
+++ b/opends/src/server/org/opends/server/tools/BackUpDB.java
@@ -55,13 +55,7 @@
 import org.opends.server.loggers.debug.TextDebugLogPublisher;
 import org.opends.server.loggers.debug.DebugLogger;
 import static org.opends.server.loggers.ErrorLogger.*;
-import org.opends.server.types.BackupConfig;
-import org.opends.server.types.BackupDirectory;
-import org.opends.server.types.DirectoryException;
-import org.opends.server.types.DN;
-import org.opends.server.types.InitializationException;
-import org.opends.server.types.NullOutputStream;
-import org.opends.server.types.RawAttribute;
+import org.opends.server.types.*;
 import org.opends.server.util.args.ArgumentException;
 import org.opends.server.util.args.BooleanArgument;
 import org.opends.server.util.args.StringArgument;
@@ -74,7 +68,6 @@
 import org.opends.server.tools.tasks.TaskTool;
 import org.opends.server.admin.std.server.BackendCfg;
 import org.opends.server.tasks.BackupTask;
-import org.opends.server.protocols.asn1.ASN1OctetString;
 import org.opends.server.protocols.ldap.LDAPAttribute;
 
 
@@ -425,12 +418,12 @@
    */
   public void addTaskAttributes(List<RawAttribute> attributes)
   {
-    ArrayList<ASN1OctetString> values;
+    ArrayList<ByteString> values;
     if (backUpAll.getValue() != null &&
             !backUpAll.getValue().equals(
                     backUpAll.getDefaultValue())) {
-      values = new ArrayList<ASN1OctetString>(1);
-      values.add(new ASN1OctetString(backUpAll.getValue()));
+      values = new ArrayList<ByteString>(1);
+      values.add(ByteString.valueOf(backUpAll.getValue()));
       attributes.add(
               new LDAPAttribute(ATTR_TASK_BACKUP_ALL, values));
     }
@@ -438,8 +431,8 @@
     if (compress.getValue() != null &&
             !compress.getValue().equals(
                     compress.getDefaultValue())) {
-      values = new ArrayList<ASN1OctetString>(1);
-      values.add(new ASN1OctetString(compress.getValue()));
+      values = new ArrayList<ByteString>(1);
+      values.add(ByteString.valueOf(compress.getValue()));
       attributes.add(
               new LDAPAttribute(ATTR_TASK_BACKUP_COMPRESS, values));
     }
@@ -447,8 +440,8 @@
     if (encrypt.getValue() != null &&
             !encrypt.getValue().equals(
                     encrypt.getDefaultValue())) {
-      values = new ArrayList<ASN1OctetString>(1);
-      values.add(new ASN1OctetString(encrypt.getValue()));
+      values = new ArrayList<ByteString>(1);
+      values.add(ByteString.valueOf(encrypt.getValue()));
       attributes.add(
               new LDAPAttribute(ATTR_TASK_BACKUP_ENCRYPT, values));
     }
@@ -456,8 +449,8 @@
     if (hash.getValue() != null &&
             !hash.getValue().equals(
                     hash.getDefaultValue())) {
-      values = new ArrayList<ASN1OctetString>(1);
-      values.add(new ASN1OctetString(hash.getValue()));
+      values = new ArrayList<ByteString>(1);
+      values.add(ByteString.valueOf(hash.getValue()));
       attributes.add(
               new LDAPAttribute(ATTR_TASK_BACKUP_HASH, values));
     }
@@ -465,8 +458,8 @@
     if (incremental.getValue() != null &&
             !incremental.getValue().equals(
                     incremental.getDefaultValue())) {
-      values = new ArrayList<ASN1OctetString>(1);
-      values.add(new ASN1OctetString(incremental.getValue()));
+      values = new ArrayList<ByteString>(1);
+      values.add(ByteString.valueOf(incremental.getValue()));
       attributes.add(
               new LDAPAttribute(ATTR_TASK_BACKUP_INCREMENTAL, values));
     }
@@ -474,17 +467,17 @@
     if (signHash.getValue() != null &&
             !signHash.getValue().equals(
                     signHash.getDefaultValue())) {
-      values = new ArrayList<ASN1OctetString>(1);
-      values.add(new ASN1OctetString(signHash.getValue()));
+      values = new ArrayList<ByteString>(1);
+      values.add(ByteString.valueOf(signHash.getValue()));
       attributes.add(
               new LDAPAttribute(ATTR_TASK_BACKUP_SIGN_HASH, values));
     }
 
     List<String> backendIDs = backendID.getValues();
     if (backendIDs != null && backendIDs.size() > 0) {
-      values = new ArrayList<ASN1OctetString>(backendIDs.size());
+      values = new ArrayList<ByteString>(backendIDs.size());
       for (String s : backendIDs) {
-        values.add(new ASN1OctetString(s));
+        values.add(ByteString.valueOf(s));
       }
       attributes.add(
               new LDAPAttribute(ATTR_TASK_BACKUP_BACKEND_ID, values));
@@ -493,8 +486,8 @@
     if (backupIDString.getValue() != null &&
             !backupIDString.getValue().equals(
                     backupIDString.getDefaultValue())) {
-      values = new ArrayList<ASN1OctetString>(1);
-      values.add(new ASN1OctetString(backupIDString.getValue()));
+      values = new ArrayList<ByteString>(1);
+      values.add(ByteString.valueOf(backupIDString.getValue()));
       attributes.add(
               new LDAPAttribute(ATTR_BACKUP_ID, values));
     }
@@ -502,8 +495,8 @@
     if (backupDirectory.getValue() != null &&
             !backupDirectory.getValue().equals(
                     backupDirectory.getDefaultValue())) {
-      values = new ArrayList<ASN1OctetString>(1);
-      values.add(new ASN1OctetString(backupDirectory.getValue()));
+      values = new ArrayList<ByteString>(1);
+      values.add(ByteString.valueOf(backupDirectory.getValue()));
       attributes.add(
               new LDAPAttribute(ATTR_BACKUP_DIRECTORY_PATH, values));
     }
@@ -511,8 +504,8 @@
     if (incrementalBaseID.getValue() != null &&
             !incrementalBaseID.getValue().equals(
                     incrementalBaseID.getDefaultValue())) {
-      values = new ArrayList<ASN1OctetString>(1);
-      values.add(new ASN1OctetString(incrementalBaseID.getValue()));
+      values = new ArrayList<ByteString>(1);
+      values.add(ByteString.valueOf(incrementalBaseID.getValue()));
       attributes.add(
               new LDAPAttribute(ATTR_TASK_BACKUP_INCREMENTAL_BASE_ID, values));
     }
diff --git a/opends/src/server/org/opends/server/tools/ConsoleDebugLogPublisher.java b/opends/src/server/org/opends/server/tools/ConsoleDebugLogPublisher.java
new file mode 100644
index 0000000..bdb0ec9
--- /dev/null
+++ b/opends/src/server/org/opends/server/tools/ConsoleDebugLogPublisher.java
@@ -0,0 +1,474 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License").  You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE
+ * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
+ * add the following below this CDDL 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.server.tools;
+
+import org.opends.server.api.DebugLogPublisher;
+import org.opends.server.loggers.LogLevel;
+import org.opends.server.loggers.LogCategory;
+import org.opends.server.loggers.debug.TraceSettings;
+import org.opends.server.loggers.debug.DebugStackTraceFormatter;
+import org.opends.server.loggers.debug.DebugMessageFormatter;
+import org.opends.server.types.DebugLogCategory;
+import org.opends.server.types.DN;
+import org.opends.server.types.InitializationException;
+import org.opends.server.util.ServerConstants;
+import org.opends.server.util.StaticUtils;
+import org.opends.server.admin.std.server.DebugLogPublisherCfg;
+import org.opends.server.config.ConfigException;
+import com.sleepycat.je.*;
+
+import java.io.PrintStream;
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+
+/**
+ * The debug log publisher implementation that writes debug messages in a
+ * friendly for console output.
+ */
+public class ConsoleDebugLogPublisher extends DebugLogPublisher
+{
+  /**
+   * The print stream where tracing will be sent.
+   */
+  private PrintStream err;
+
+  /**
+   * The format used for trace timestamps.
+   */
+  private DateFormat dateFormat = new SimpleDateFormat("HH:mm:ss.SSS");
+
+  /**
+   * Constructs a new ConsoleDebugLogPublisher that writes debug messages
+   * to the given PrintStream.
+   * @param err The PrintStream to write messages to.
+   */
+  public ConsoleDebugLogPublisher(PrintStream err)
+  {
+    this.err = err;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  public void initializeDebugLogPublisher(DebugLogPublisherCfg config)
+      throws ConfigException, InitializationException {
+    // This pubisher is not configurable.
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  public void traceConstructor(LogLevel level,
+                               TraceSettings settings,
+                               String signature,
+                               String sourceLocation,
+                               Object[] args,
+                               StackTraceElement[] stackTrace)
+  {
+    LogCategory category = DebugLogCategory.CONSTRUCTOR;
+
+    String msg = "";
+    if(args != null)
+    {
+      msg = buildDefaultEntryMessage(signature, sourceLocation, args);
+    }
+
+    String stack = null;
+    if(stackTrace != null)
+    {
+      stack = DebugStackTraceFormatter.formatStackTrace(stackTrace,
+                                                      settings.getStackDepth());
+    }
+    publish(category, level, msg, stack);
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  public void traceMethodEntry(LogLevel level,
+                               TraceSettings settings,
+                               String signature,
+                               String sourceLocation,
+                               Object obj,
+                               Object[] args,
+                               StackTraceElement[] stackTrace)
+  {
+    LogCategory category = DebugLogCategory.ENTER;
+    String msg = "";
+    if(args != null)
+    {
+      msg = buildDefaultEntryMessage(signature, sourceLocation, args);
+    }
+
+    String stack = null;
+    if(stackTrace != null)
+    {
+      stack = DebugStackTraceFormatter.formatStackTrace(stackTrace,
+                                                      settings.getStackDepth());
+    }
+    publish(category, level, msg, stack);
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  public void traceStaticMethodEntry(LogLevel level,
+                                     TraceSettings settings,
+                                     String signature,
+                                     String sourceLocation,
+                                     Object[] args,
+                                     StackTraceElement[] stackTrace)
+  {
+    LogCategory category = DebugLogCategory.ENTER;
+    String msg = "";
+    if(args != null)
+    {
+      msg = buildDefaultEntryMessage(signature, sourceLocation, args);
+    }
+
+    String stack = null;
+    if(stackTrace != null)
+    {
+      stack = DebugStackTraceFormatter.formatStackTrace(stackTrace,
+                                                      settings.getStackDepth());
+    }
+    publish(category, level, msg, stack);
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  public void traceReturn(LogLevel level,
+                          TraceSettings settings,
+                          String signature,
+                          String sourceLocation,
+                          Object ret,
+                          StackTraceElement[] stackTrace)
+  {
+    LogCategory category = DebugLogCategory.EXIT;
+    String msg = "";
+    if(ret != null)
+    {
+      StringBuilder format = new StringBuilder();
+      format.append("returned={%s} ");
+      format.append(signature);
+      format.append("():");
+      format.append(sourceLocation);
+
+      msg = DebugMessageFormatter.format(format.toString(),
+                                         new Object[] {ret});
+    }
+
+    String stack = null;
+    if(stackTrace != null)
+    {
+      stack = DebugStackTraceFormatter.formatStackTrace(stackTrace,
+                                                      settings.getStackDepth());
+    }
+    publish(category, level,  msg, stack);
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  public void traceThrown(LogLevel level,
+                          TraceSettings settings,
+                          String signature,
+                          String sourceLocation,
+                          Throwable ex,
+                          StackTraceElement[] stackTrace)
+  {
+    LogCategory category = DebugLogCategory.THROWN;
+
+    StringBuilder format = new StringBuilder();
+    format.append("thrown={%s} ");
+    format.append(signature);
+    format.append("():");
+    format.append(sourceLocation);
+
+    String msg = DebugMessageFormatter.format(format.toString(),
+                                              new Object[] {ex});
+
+    String stack = null;
+    if(stackTrace != null)
+    {
+      stack = DebugStackTraceFormatter.formatStackTrace(ex,
+                                                       settings.getStackDepth(),
+                                                     settings.isIncludeCause());
+    }
+    publish(category, level, msg, stack);
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  public void traceMessage(LogLevel level,
+                           TraceSettings settings,
+                           String signature,
+                           String sourceLocation,
+                           String msg,
+                           StackTraceElement[] stackTrace)
+  {
+    LogCategory category = DebugLogCategory.MESSAGE;
+
+    String stack = null;
+    if(stackTrace != null)
+    {
+      stack = DebugStackTraceFormatter.formatStackTrace(stackTrace,
+                                                      settings.getStackDepth());
+    }
+    publish(category, level, msg, stack);
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  public void traceCaught(LogLevel level,
+                          TraceSettings settings,
+                          String signature,
+                          String sourceLocation,
+                          Throwable ex,
+                          StackTraceElement[] stackTrace)
+  {
+    LogCategory category = DebugLogCategory.CAUGHT;
+
+    StringBuilder format = new StringBuilder();
+    format.append("caught={%s} ");
+    format.append(signature);
+    format.append("():");
+    format.append(sourceLocation);
+
+    String msg = DebugMessageFormatter.format("caught={%s}",
+                                              new Object[] {ex});
+
+    String stack = null;
+    if(stackTrace != null)
+    {
+      stack = DebugStackTraceFormatter.formatStackTrace(ex,
+                                                       settings.getStackDepth(),
+                                                     settings.isIncludeCause());
+    }
+    publish(category, level, msg, stack);
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  public void traceJEAccess(LogLevel level,
+                            TraceSettings settings,
+                            String signature,
+                            String sourceLocation,
+                            OperationStatus status,
+                            Database database, Transaction txn,
+                            DatabaseEntry key, DatabaseEntry data,
+                            StackTraceElement[] stackTrace)
+  {
+    LogCategory category = DebugLogCategory.DATABASE_ACCESS;
+
+    // Build the string that is common to category DATABASE_ACCESS.
+    StringBuilder builder = new StringBuilder();
+    builder.append(" (");
+    builder.append(status.toString());
+    builder.append(")");
+    builder.append(" db=");
+    try
+    {
+      builder.append(database.getDatabaseName());
+    }
+    catch(DatabaseException de)
+    {
+      builder.append(de.toString());
+    }
+    if (txn != null)
+    {
+      builder.append(" txnid=");
+      try
+      {
+        builder.append(txn.getId());
+      }
+      catch(DatabaseException de)
+      {
+        builder.append(de.toString());
+      }
+    }
+    else
+    {
+      builder.append(" txnid=none");
+    }
+
+    builder.append(ServerConstants.EOL);
+    if(key != null)
+    {
+      builder.append("key:");
+      builder.append(ServerConstants.EOL);
+      StaticUtils.byteArrayToHexPlusAscii(builder, key.getData(), 4);
+    }
+
+    // If the operation was successful we log the same common information
+    // plus the data
+    if (status == OperationStatus.SUCCESS && data != null)
+    {
+
+      builder.append("data(len=");
+      builder.append(data.getSize());
+      builder.append("):");
+      builder.append(ServerConstants.EOL);
+      StaticUtils.byteArrayToHexPlusAscii(builder, data.getData(), 4);
+
+    }
+
+    String stack = null;
+    if(stackTrace != null)
+    {
+      stack = DebugStackTraceFormatter.formatStackTrace(stackTrace,
+                                                      settings.getStackDepth());
+    }
+    publish(category, level, builder.toString(), stack);
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  public void traceData(LogLevel level,
+                        TraceSettings settings,
+                        String signature,
+                        String sourceLocation,
+                        byte[] data,
+                        StackTraceElement[] stackTrace)
+  {
+    LogCategory category = DebugLogCategory.DATA;
+    if(data != null)
+    {
+      StringBuilder builder = new StringBuilder();
+      builder.append(ServerConstants.EOL);
+      builder.append("data(len=");
+      builder.append(data.length);
+      builder.append("):");
+      builder.append(ServerConstants.EOL);
+      StaticUtils.byteArrayToHexPlusAscii(builder, data, 4);
+
+    String stack = null;
+    if(stackTrace != null)
+    {
+      stack = DebugStackTraceFormatter.formatStackTrace(stackTrace,
+                                                      settings.getStackDepth());
+    }
+    publish(category, level, builder.toString(), stack);
+    }
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  public void traceProtocolElement(LogLevel level,
+                                   TraceSettings settings,
+                                   String signature,
+                                   String sourceLocation,
+                                   String decodedForm,
+                                   StackTraceElement[] stackTrace)
+  {
+    LogCategory category = DebugLogCategory.PROTOCOL;
+
+    String stack = null;
+    if(stackTrace != null)
+    {
+      stack = DebugStackTraceFormatter.formatStackTrace(stackTrace,
+                                                      settings.getStackDepth());
+    }
+    publish(category, level, decodedForm, stack);
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  public void close()
+  {
+    // Nothing to do.
+  }
+
+
+  // Publishes a record, optionally performing some "special" work:
+  // - injecting a stack trace into the message
+  private void publish(LogCategory category, LogLevel level, String msg,
+                       String stack)
+  {
+    StringBuilder buf = new StringBuilder();
+    // Emit the timestamp.
+    buf.append(dateFormat.format(System.currentTimeMillis()));
+    buf.append(" ");
+
+    // Emit debug category.
+    buf.append(category);
+    buf.append(" ");
+
+    // Emit the debug level.
+    buf.append(level);
+    buf.append(" ");
+
+    // Emit message.
+    buf.append(msg);
+    buf.append(ServerConstants.EOL);
+
+    // Emit Stack Trace.
+    if(stack != null)
+    {
+      buf.append("\nStack Trace:\n");
+      buf.append(stack);
+    }
+
+    err.print(buf);
+  }
+
+  private String buildDefaultEntryMessage(String signature,
+                                          String sourceLocation, Object[] args)
+  {
+    StringBuilder format = new StringBuilder();
+    format.append(signature);
+    format.append("(");
+    for (int i = 0; i < args.length; i++)
+    {
+      if (i != 0) format.append(", ");
+      format.append("arg");
+      format.append(i + 1);
+      format.append("={%s}");
+    }
+    format.append("):");
+    format.append(sourceLocation);
+
+    return DebugMessageFormatter.format(format.toString(), args);
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  public DN getDN()
+  {
+    // There is no configuration DN associated with this publisher.
+    return DN.NULL_DN;
+  }
+
+}
diff --git a/opends/src/server/org/opends/server/tools/DBTest.java b/opends/src/server/org/opends/server/tools/DBTest.java
index fa221dd..76cb1ec 100644
--- a/opends/src/server/org/opends/server/tools/DBTest.java
+++ b/opends/src/server/org/opends/server/tools/DBTest.java
@@ -45,13 +45,12 @@
 import org.opends.server.extensions.ConfigFileHandler;
 import org.opends.server.core.DirectoryServer;
 import org.opends.server.core.LockFileManager;
+import org.opends.server.core.CoreConfigManager;
 import org.opends.server.config.ConfigException;
 import org.opends.server.api.Backend;
 import org.opends.server.admin.std.server.BackendCfg;
 import org.opends.server.admin.std.server.LocalDBBackendCfg;
 import org.opends.server.backends.jeb.*;
-import org.opends.server.protocols.asn1.ASN1OctetString;
-import org.opends.server.protocols.asn1.ASN1Element;
 
 import java.io.*;
 import java.util.*;
@@ -442,6 +441,64 @@
         printMessage(message);
         return 1;
       }
+
+
+
+      // Initialize the Directory Server core configuration.
+      try
+      {
+        CoreConfigManager coreConfigManager = new CoreConfigManager();
+        coreConfigManager.initializeCoreConfig();
+      }
+      catch (ConfigException ce)
+      {
+        Message message = ERR_CANNOT_INITIALIZE_CORE_CONFIG.get(
+                ce.getMessage());
+        printMessage(message);
+        return 1;
+      }
+      catch (InitializationException ie)
+      {
+        Message message = ERR_CANNOT_INITIALIZE_CORE_CONFIG.get(
+                ie.getMessage());
+        printMessage(message);
+        return 1;
+      }
+      catch (Exception e)
+      {
+        Message message = ERR_CANNOT_INITIALIZE_CORE_CONFIG.get(
+                getExceptionMessage(e));
+        printMessage(message);
+        return 1;
+      }
+
+
+      // Initialize the Directory Server crypto manager.
+      try
+      {
+        directoryServer.initializeCryptoManager();
+      }
+      catch (ConfigException ce)
+      {
+        Message message = ERR_CANNOT_INITIALIZE_CRYPTO_MANAGER.get(
+                ce.getMessage());
+        printMessage(message);
+        return 1;
+      }
+      catch (InitializationException ie)
+      {
+        Message message = ERR_CANNOT_INITIALIZE_CRYPTO_MANAGER.get(
+                ie.getMessage());
+        printMessage(message);
+        return 1;
+      }
+      catch (Exception e)
+      {
+        Message message = ERR_CANNOT_INITIALIZE_CRYPTO_MANAGER.get(
+                getExceptionMessage(e));
+        printMessage(message);
+        return 1;
+      }
     }
 
     // Make sure that we have a sub-command.
@@ -1162,17 +1219,15 @@
               else if(databaseContainer instanceof VLVIndex)
               {
                 // Encode the value as a size/value pair
-                byte[] vBytes =
-                    new ASN1OctetString(minKeyValue.getValue()).value();
-                byte[] vLength = ASN1Element.encodeLength(vBytes.length);
-                start = new byte[vBytes.length + vLength.length];
-                System.arraycopy(vLength, 0, start, 0, vLength.length);
-                System.arraycopy(vBytes, 0, start, vLength.length,
-                                 vBytes.length);
+                byte[] vBytes = StaticUtils.getBytes(minKeyValue.getValue());
+                ByteStringBuilder builder = new ByteStringBuilder();
+                builder.appendBERLength(vBytes.length);
+                builder.append(vBytes);
+                start = builder.toByteArray();
               }
               else
               {
-                start = new ASN1OctetString(minKeyValue.getValue()).value();
+                start = StaticUtils.getBytes(minKeyValue.getValue());
               }
             }
           }
@@ -1213,17 +1268,15 @@
               else if(databaseContainer instanceof VLVIndex)
               {
                 // Encode the value as a size/value pair
-                byte[] vBytes =
-                    new ASN1OctetString(maxKeyValue.getValue()).value();
-                byte[] vLength = ASN1Element.encodeLength(vBytes.length);
-                end = new byte[vBytes.length + vLength.length];
-                System.arraycopy(vLength, 0, end, 0, vLength.length);
-                System.arraycopy(vBytes, 0, end, vLength.length,
-                                 vBytes.length);
+                byte[] vBytes = StaticUtils.getBytes(maxKeyValue.getValue());
+                ByteStringBuilder builder = new ByteStringBuilder();
+                builder.appendBERLength(vBytes.length);
+                builder.append(vBytes);
+                start = builder.toByteArray();
               }
               else
               {
-                end = new ASN1OctetString(maxKeyValue.getValue()).value();
+                end = StaticUtils.getBytes(maxKeyValue.getValue());
               }
             }
           }
@@ -1311,8 +1364,8 @@
             {
               try
               {
-                formatedKey = DN.decode(new ASN1OctetString(
-                    key.getData())).toNormalizedString();
+                formatedKey = DN.decode(ByteString.wrap(key.getData())).
+                    toNormalizedString();
                 keyLabel = INFO_LABEL_DBTEST_ENTRY_DN.get();
               }
               catch(Exception e)
@@ -1333,8 +1386,9 @@
               try
               {
                 formatedData = System.getProperty("line.separator") +
-                    JebFormat.entryFromDatabase(data.getData(),
-                         ec.getRootContainer().getCompressedSchema()).
+                    ID2Entry.entryFromDatabase(
+                        ByteString.wrap(data.getData()),
+                        ec.getRootContainer().getCompressedSchema()).
                               toLDIFString();
                 dataLabel = INFO_LABEL_DBTEST_ENTRY.get();
               }
@@ -1349,7 +1403,7 @@
             {
               try
               {
-                formatedKey = DN.decode(new ASN1OctetString(
+                formatedKey = DN.decode(ByteString.wrap(
                     key.getData())).toNormalizedString();
                 keyLabel = INFO_LABEL_DBTEST_ENTRY_DN.get();
               }
@@ -1359,12 +1413,12 @@
                     ERR_DBTEST_DECODE_FAIL.get(getExceptionMessage(e));
                 printMessage(message);
               }
-              formatedData = new ASN1OctetString(key.getData()).stringValue();
+              formatedData = new String(key.getData());
               dataLabel = INFO_LABEL_DBTEST_URI.get();
             }
             else if(databaseContainer instanceof Index)
             {
-              formatedKey = new ASN1OctetString(key.getData()).stringValue();
+              formatedKey = new String(key.getData());
               keyLabel = INFO_LABEL_DBTEST_INDEX_VALUE.get();
 
               EntryIDSet idSet = new EntryIDSet(key.getData(),
@@ -1434,8 +1488,7 @@
                   }
                   else
                   {
-                    builder.append(
-                        new ASN1OctetString(valueBytes).stringValue());
+                    builder.append(new String(valueBytes));
                   }
                   builder.append(" ");
                   pos += valueLength;
@@ -1469,21 +1522,20 @@
                   for(int j = 0; j < sortKeys.length; j++)
                   {
                     SortKey sortKey = index.sortOrder.getSortKeys()[j];
-                    byte[] value = svs.getValue(i * sortKeys.length + j);
+                    ByteString value = svs.getValue(i * sortKeys.length + j);
                     builder.append(sortKey.getAttributeType().getNameOrOID());
                     builder.append(": ");
                     if(value == null)
                     {
                       builder.append("NULL");
                     }
-                    else if(value.length == 0)
+                    else if(value.length() == 0)
                     {
                       builder.append("SIZE-EXCEEDED");
                     }
                     else
                     {
-                      builder.append(
-                          new ASN1OctetString(value).stringValue());
+                      builder.append(value.toString());
                     }
                     builder.append(" ");
                   }
diff --git a/opends/src/server/org/opends/server/tools/EncodePassword.java b/opends/src/server/org/opends/server/tools/EncodePassword.java
index 3d60136..69a21e6 100644
--- a/opends/src/server/org/opends/server/tools/EncodePassword.java
+++ b/opends/src/server/org/opends/server/tools/EncodePassword.java
@@ -25,10 +25,17 @@
  *      Copyright 2006-2008 Sun Microsystems, Inc.
  */
 package org.opends.server.tools;
-import org.opends.messages.Message;
 
 
 
+import static org.opends.messages.ConfigMessages.*;
+import static org.opends.messages.ToolMessages.*;
+import static org.opends.server.loggers.ErrorLogger.*;
+import static org.opends.server.loggers.debug.DebugLogger.*;
+import static org.opends.server.tools.ToolConstants.*;
+import static org.opends.server.util.ServerConstants.*;
+import static org.opends.server.util.StaticUtils.*;
+
 import java.io.OutputStream;
 import java.io.PrintStream;
 import java.util.ArrayList;
@@ -36,6 +43,7 @@
 import java.util.HashSet;
 import java.util.concurrent.ConcurrentHashMap;
 
+import org.opends.messages.Message;
 import org.opends.server.admin.server.ServerManagementContext;
 import org.opends.server.admin.std.server.BackendCfg;
 import org.opends.server.admin.std.server.LDIFBackendCfg;
@@ -52,7 +60,7 @@
 import org.opends.server.core.PasswordStorageSchemeConfigManager;
 import org.opends.server.crypto.CryptoManagerSync;
 import org.opends.server.extensions.ConfigFileHandler;
-import org.opends.server.protocols.asn1.ASN1OctetString;
+import org.opends.server.loggers.debug.DebugTracer;
 import org.opends.server.protocols.ldap.LDAPResultCode;
 import org.opends.server.schema.AuthPasswordSyntax;
 import org.opends.server.schema.UserPasswordSyntax;
@@ -68,16 +76,6 @@
 import org.opends.server.util.args.BooleanArgument;
 import org.opends.server.util.args.FileBasedArgument;
 import org.opends.server.util.args.StringArgument;
-import static org.opends.server.loggers.ErrorLogger.logError;
-import static org.opends.server.loggers.debug.DebugLogger.*;
-
-import org.opends.server.loggers.debug.DebugTracer;
-import static org.opends.messages.ConfigMessages.*;
-
-import static org.opends.messages.ToolMessages.*;
-import static org.opends.server.util.ServerConstants.*;
-import static org.opends.server.util.StaticUtils.*;
-import static org.opends.server.tools.ToolConstants.*;
 
 
 
@@ -330,16 +328,16 @@
     // If we are not going to just list the storage schemes, then the clear-text
     // password must have been provided.  If we're going to encode a password,
     // then the scheme must have also been provided.
-    ASN1OctetString clearPW = null;
+    ByteString clearPW = null;
     if (! listSchemes.isPresent())
     {
       if (clearPassword.hasValue())
       {
-        clearPW = new ASN1OctetString(clearPassword.getValue());
+        clearPW = ByteString.valueOf(clearPassword.getValue());
       }
       else if (clearPasswordFile.hasValue())
       {
-        clearPW = new ASN1OctetString(clearPasswordFile.getValue());
+        clearPW = ByteString.valueOf(clearPasswordFile.getValue());
       }
       else
       {
@@ -370,12 +368,12 @@
     if (encodedPassword.hasValue())
     {
       compareMode = true;
-      encodedPW = new ASN1OctetString(encodedPassword.getValue());
+      encodedPW = ByteString.valueOf(encodedPassword.getValue());
     }
     else if (encodedPasswordFile.hasValue())
     {
       compareMode = true;
-      encodedPW = new ASN1OctetString(encodedPasswordFile.getValue());
+      encodedPW = ByteString.valueOf(encodedPasswordFile.getValue());
     }
     else
     {
@@ -391,8 +389,8 @@
     {
       try
       {
-        directoryServer.bootstrapClient();
-        directoryServer.initializeJMX();
+        DirectoryServer.bootstrapClient();
+        DirectoryServer.initializeJMX();
       }
       catch (Exception e)
       {
@@ -595,7 +593,7 @@
         try
         {
           StringBuilder[] authPWElements =
-               AuthPasswordSyntax.decodeAuthPassword(encodedPW.stringValue());
+               AuthPasswordSyntax.decodeAuthPassword(encodedPW.toString());
           scheme    = authPWElements[0].toString();
           authInfo  = authPWElements[1].toString();
           authValue = authPWElements[2].toString();
@@ -664,7 +662,7 @@
           try
           {
             String[] userPWElements =
-                 UserPasswordSyntax.decodeUserPassword(encodedPW.stringValue());
+                 UserPasswordSyntax.decodeUserPassword(encodedPW.toString());
             encodedPWString = userPWElements[1];
 
             storageScheme =
@@ -704,7 +702,7 @@
           encodedPWString = encodedPW.toString();
 
           String scheme = toLowerCase(schemeName.getValue());
-          storageScheme = directoryServer.getPasswordStorageScheme(scheme);
+          storageScheme = DirectoryServer.getPasswordStorageScheme(scheme);
           if (storageScheme == null)
           {
             Message message = ERR_ENCPW_NO_SUCH_SCHEME.get(scheme);
@@ -714,7 +712,7 @@
         }
 
         if (storageScheme.passwordMatches(clearPW,
-                                          new ASN1OctetString(encodedPWString)))
+            ByteString.valueOf(encodedPWString)))
         {
           Message message = INFO_ENCPW_PASSWORDS_MATCH.get();
           out.println(message);
@@ -778,7 +776,7 @@
           encodedPW = storageScheme.encodeAuthPassword(clearPW);
 
           Message message = ERR_ENCPW_ENCODED_PASSWORD.get(
-                  encodedPW.stringValue());
+                  encodedPW.toString());
           out.println(message);
         }
         catch (DirectoryException de)
@@ -801,7 +799,7 @@
           encodedPW = storageScheme.encodePasswordWithScheme(clearPW);
 
           Message message =
-                  ERR_ENCPW_ENCODED_PASSWORD.get(encodedPW.stringValue());
+                  ERR_ENCPW_ENCODED_PASSWORD.get(encodedPW.toString());
           out.println(message);
         }
         catch (DirectoryException de)
diff --git a/opends/src/server/org/opends/server/tools/ExportLDIF.java b/opends/src/server/org/opends/server/tools/ExportLDIF.java
index bc6c706..debea69 100644
--- a/opends/src/server/org/opends/server/tools/ExportLDIF.java
+++ b/opends/src/server/org/opends/server/tools/ExportLDIF.java
@@ -47,15 +47,7 @@
 import org.opends.server.loggers.ErrorLogger;
 import org.opends.server.loggers.debug.TextDebugLogPublisher;
 import org.opends.server.loggers.debug.DebugLogger;
-import org.opends.server.types.AttributeType;
-import org.opends.server.types.DirectoryException;
-import org.opends.server.types.DN;
-import org.opends.server.types.ExistingFileBehavior;
-import org.opends.server.types.InitializationException;
-import org.opends.server.types.LDIFExportConfig;
-import org.opends.server.types.NullOutputStream;
-import org.opends.server.types.SearchFilter;
-import org.opends.server.types.RawAttribute;
+import org.opends.server.types.*;
 import org.opends.server.util.args.ArgumentException;
 import org.opends.server.util.args.BooleanArgument;
 import org.opends.server.util.args.IntegerArgument;
@@ -71,7 +63,6 @@
 import org.opends.server.tools.tasks.TaskTool;
 import org.opends.server.admin.std.server.BackendCfg;
 import org.opends.server.protocols.ldap.LDAPAttribute;
-import org.opends.server.protocols.asn1.ASN1OctetString;
 import org.opends.server.tasks.ExportTask;
 
 
@@ -359,12 +350,12 @@
     //
     // Required attributes
     //
-    ArrayList<ASN1OctetString> values = new ArrayList<ASN1OctetString>(1);
-    values.add(new ASN1OctetString(ldifFile.getValue()));
+    ArrayList<ByteString> values = new ArrayList<ByteString>(1);
+    values.add(ByteString.valueOf(ldifFile.getValue()));
     attributes.add(new LDAPAttribute(ATTR_TASK_EXPORT_LDIF_FILE, values));
 
-    values = new ArrayList<ASN1OctetString>(1);
-    values.add(new ASN1OctetString(backendID.getValue()));
+    values = new ArrayList<ByteString>(1);
+    values.add(ByteString.valueOf(backendID.getValue()));
     attributes.add(new LDAPAttribute(ATTR_TASK_EXPORT_BACKEND_ID, values));
 
     //
@@ -372,39 +363,39 @@
     //
     if (appendToLDIF.getValue() != null &&
             !appendToLDIF.getValue().equals(appendToLDIF.getDefaultValue())) {
-      values = new ArrayList<ASN1OctetString>(1);
-      values.add(new ASN1OctetString(appendToLDIF.getValue()));
+      values = new ArrayList<ByteString>(1);
+      values.add(ByteString.valueOf(appendToLDIF.getValue()));
       attributes.add(
               new LDAPAttribute(ATTR_TASK_EXPORT_APPEND_TO_LDIF, values));
     }
 
     if (compressLDIF.getValue() != null &&
             !compressLDIF.getValue().equals(compressLDIF.getDefaultValue())) {
-      values = new ArrayList<ASN1OctetString>(1);
-      values.add(new ASN1OctetString(compressLDIF.getValue()));
+      values = new ArrayList<ByteString>(1);
+      values.add(ByteString.valueOf(compressLDIF.getValue()));
       attributes.add(new LDAPAttribute(ATTR_TASK_EXPORT_COMPRESS_LDIF, values));
     }
 
     if (encryptLDIF.getValue() != null &&
             !encryptLDIF.getValue().equals(encryptLDIF.getDefaultValue())) {
-      values = new ArrayList<ASN1OctetString>(1);
-      values.add(new ASN1OctetString(encryptLDIF.getValue()));
+      values = new ArrayList<ByteString>(1);
+      values.add(ByteString.valueOf(encryptLDIF.getValue()));
       attributes.add(new LDAPAttribute(ATTR_TASK_EXPORT_ENCRYPT_LDIF, values));
     }
 
     if (signHash.getValue() != null &&
             !signHash.getValue().equals(signHash.getDefaultValue())) {
-      values = new ArrayList<ASN1OctetString>(1);
-      values.add(new ASN1OctetString(signHash.getValue()));
+      values = new ArrayList<ByteString>(1);
+      values.add(ByteString.valueOf(signHash.getValue()));
       attributes.add(
               new LDAPAttribute(ATTR_TASK_EXPORT_SIGN_HASH, values));
     }
 
     List<String> includeAttributes = includeAttributeStrings.getValues();
     if (includeAttributes != null && includeAttributes.size() > 0) {
-      values = new ArrayList<ASN1OctetString>(includeAttributes.size());
+      values = new ArrayList<ByteString>(includeAttributes.size());
       for (String includeAttribute : includeAttributes) {
-        values.add(new ASN1OctetString(includeAttribute));
+        values.add(ByteString.valueOf(includeAttribute));
       }
       attributes.add(
               new LDAPAttribute(ATTR_TASK_EXPORT_INCLUDE_ATTRIBUTE, values));
@@ -412,9 +403,9 @@
 
     List<String> excludeAttributes = excludeAttributeStrings.getValues();
     if (excludeAttributes != null && excludeAttributes.size() > 0) {
-      values = new ArrayList<ASN1OctetString>(excludeAttributes.size());
+      values = new ArrayList<ByteString>(excludeAttributes.size());
       for (String excludeAttribute : excludeAttributes) {
-        values.add(new ASN1OctetString(excludeAttribute));
+        values.add(ByteString.valueOf(excludeAttribute));
       }
       attributes.add(
               new LDAPAttribute(ATTR_TASK_EXPORT_EXCLUDE_ATTRIBUTE, values));
@@ -422,9 +413,9 @@
 
     List<String> includeFilters = includeFilterStrings.getValues();
     if (includeFilters != null && includeFilters.size() > 0) {
-      values = new ArrayList<ASN1OctetString>(includeFilters.size());
+      values = new ArrayList<ByteString>(includeFilters.size());
       for (String includeFilter : includeFilters) {
-        values.add(new ASN1OctetString(includeFilter));
+        values.add(ByteString.valueOf(includeFilter));
       }
       attributes.add(
               new LDAPAttribute(ATTR_TASK_EXPORT_INCLUDE_FILTER, values));
@@ -432,9 +423,9 @@
 
     List<String> excludeFilters = excludeFilterStrings.getValues();
     if (excludeFilters != null && excludeFilters.size() > 0) {
-      values = new ArrayList<ASN1OctetString>(excludeFilters.size());
+      values = new ArrayList<ByteString>(excludeFilters.size());
       for (String excludeFilter : excludeFilters) {
-        values.add(new ASN1OctetString(excludeFilter));
+        values.add(ByteString.valueOf(excludeFilter));
       }
       attributes.add(
               new LDAPAttribute(ATTR_TASK_EXPORT_EXCLUDE_FILTER, values));
@@ -442,9 +433,9 @@
 
     List<String> includeBranches = includeBranchStrings.getValues();
     if (includeBranches != null && includeBranches.size() > 0) {
-      values = new ArrayList<ASN1OctetString>(includeBranches.size());
+      values = new ArrayList<ByteString>(includeBranches.size());
       for (String includeBranche : includeBranches) {
-        values.add(new ASN1OctetString(includeBranche));
+        values.add(ByteString.valueOf(includeBranche));
       }
       attributes.add(
               new LDAPAttribute(ATTR_TASK_EXPORT_INCLUDE_BRANCH, values));
@@ -452,9 +443,9 @@
 
     List<String> excludeBranches = excludeBranchStrings.getValues();
     if (excludeBranches != null && excludeBranches.size() > 0) {
-      values = new ArrayList<ASN1OctetString>(excludeBranches.size());
+      values = new ArrayList<ByteString>(excludeBranches.size());
       for (String excludeBranche : excludeBranches) {
-        values.add(new ASN1OctetString(excludeBranche));
+        values.add(ByteString.valueOf(excludeBranche));
       }
       attributes.add(
               new LDAPAttribute(ATTR_TASK_EXPORT_EXCLUDE_BRANCH, values));
@@ -462,16 +453,16 @@
 
     if (wrapColumn.getValue() != null &&
             !wrapColumn.getValue().equals(wrapColumn.getDefaultValue())) {
-      values = new ArrayList<ASN1OctetString>(1);
-      values.add(new ASN1OctetString(wrapColumn.getValue()));
+      values = new ArrayList<ByteString>(1);
+      values.add(ByteString.valueOf(wrapColumn.getValue()));
       attributes.add(
               new LDAPAttribute(ATTR_TASK_EXPORT_WRAP_COLUMN, values));
     }
 
     if (excludeOperationalAttrs.isPresent())
     {
-      values = new ArrayList<ASN1OctetString>(1);
-      values.add(new ASN1OctetString("false"));
+      values = new ArrayList<ByteString>(1);
+      values.add(ByteString.valueOf("false"));
       attributes.add(
           new LDAPAttribute(ATTR_TASK_EXPORT_INCLUDE_OPERATIONAL_ATTRIBUTES,
               values));
diff --git a/opends/src/server/org/opends/server/tools/ImportLDIF.java b/opends/src/server/org/opends/server/tools/ImportLDIF.java
index f54160c..d4f8859 100644
--- a/opends/src/server/org/opends/server/tools/ImportLDIF.java
+++ b/opends/src/server/org/opends/server/tools/ImportLDIF.java
@@ -59,12 +59,12 @@
 import org.opends.server.loggers.TextWriter;
 import org.opends.server.loggers.debug.DebugLogger;
 import org.opends.server.loggers.debug.TextDebugLogPublisher;
-import org.opends.server.protocols.asn1.ASN1OctetString;
 import org.opends.server.protocols.ldap.LDAPAttribute;
 import org.opends.server.tasks.ImportTask;
 import org.opends.server.tools.makeldif.TemplateFile;
 import org.opends.server.tools.tasks.TaskTool;
 import org.opends.server.types.AttributeType;
+import org.opends.server.types.ByteString;
 import org.opends.server.types.DN;
 import org.opends.server.types.DirectoryException;
 import org.opends.server.types.ExistingFileBehavior;
@@ -81,6 +81,7 @@
 import org.opends.server.util.args.StringArgument;
 
 
+
 /**
  * This program provides a utility that may be used to import the contents of an
  * LDIF file into a Directory Server backend.  This will be a process that is
@@ -476,15 +477,15 @@
     //
     // Required attributes
     //
-    ArrayList<ASN1OctetString> values;
+    ArrayList<ByteString> values;
 
     List<String> fileList = ldifFiles.getValues();
     if ((fileList != null) && (fileList.size() > 0))
     {
       if (fileList != null && fileList.size() > 0) {
-        values = new ArrayList<ASN1OctetString>(fileList.size());
+        values = new ArrayList<ByteString>(fileList.size());
         for (String file : fileList) {
-          values.add(new ASN1OctetString(file));
+          values.add(ByteString.valueOf(file));
         }
         attributes.add(new LDAPAttribute(ATTR_IMPORT_LDIF_FILE, values));
       }
@@ -493,16 +494,16 @@
     String templateFileValue = templateFile.getValue();
     if (templateFileValue != null)
     {
-      values = new ArrayList<ASN1OctetString>(1);
-      values.add(new ASN1OctetString(templateFileValue));
+      values = new ArrayList<ByteString>(1);
+      values.add(ByteString.valueOf(templateFileValue));
       attributes.add(new LDAPAttribute(ATTR_IMPORT_TEMPLATE_FILE, values));
     }
 
     String randomSeedValue = randomSeed.getValue();
     if (randomSeedValue != null)
     {
-      values = new ArrayList<ASN1OctetString>(1);
-      values.add(new ASN1OctetString(randomSeedValue));
+      values = new ArrayList<ByteString>(1);
+      values.add(ByteString.valueOf(randomSeedValue));
       attributes.add(new LDAPAttribute(ATTR_IMPORT_RANDOM_SEED, values));
     }
 
@@ -511,77 +512,77 @@
     //
     if (append.getValue() != null &&
             !append.getValue().equals(append.getDefaultValue())) {
-      values = new ArrayList<ASN1OctetString>(1);
-      values.add(new ASN1OctetString(append.getValue()));
+      values = new ArrayList<ByteString>(1);
+      values.add(ByteString.valueOf(append.getValue()));
       attributes.add(new LDAPAttribute(ATTR_IMPORT_APPEND, values));
     }
 
     if (replaceExisting.getValue() != null &&
             !replaceExisting.getValue().equals(
                     replaceExisting.getDefaultValue())) {
-      values = new ArrayList<ASN1OctetString>(1);
-      values.add(new ASN1OctetString(replaceExisting.getValue()));
+      values = new ArrayList<ByteString>(1);
+      values.add(ByteString.valueOf(replaceExisting.getValue()));
       attributes.add(new LDAPAttribute(ATTR_IMPORT_REPLACE_EXISTING, values));
     }
 
     if (backendID.getValue() != null &&
             !backendID.getValue().equals(
                     backendID.getDefaultValue())) {
-      values = new ArrayList<ASN1OctetString>(1);
-      values.add(new ASN1OctetString(backendID.getValue()));
+      values = new ArrayList<ByteString>(1);
+      values.add(ByteString.valueOf(backendID.getValue()));
       attributes.add(new LDAPAttribute(ATTR_IMPORT_BACKEND_ID, values));
     }
 
     List<String> includeAttributes = includeAttributeStrings.getValues();
     if (includeAttributes != null && includeAttributes.size() > 0) {
-      values = new ArrayList<ASN1OctetString>(includeAttributes.size());
+      values = new ArrayList<ByteString>(includeAttributes.size());
       for (String includeAttribute : includeAttributes) {
-        values.add(new ASN1OctetString(includeAttribute));
+        values.add(ByteString.valueOf(includeAttribute));
       }
       attributes.add(new LDAPAttribute(ATTR_IMPORT_INCLUDE_ATTRIBUTE, values));
     }
 
     List<String> excludeAttributes = excludeAttributeStrings.getValues();
     if (excludeAttributes != null && excludeAttributes.size() > 0) {
-      values = new ArrayList<ASN1OctetString>(excludeAttributes.size());
+      values = new ArrayList<ByteString>(excludeAttributes.size());
       for (String excludeAttribute : excludeAttributes) {
-        values.add(new ASN1OctetString(excludeAttribute));
+        values.add(ByteString.valueOf(excludeAttribute));
       }
       attributes.add(new LDAPAttribute(ATTR_IMPORT_EXCLUDE_ATTRIBUTE, values));
     }
 
     List<String> includeFilters = includeFilterStrings.getValues();
     if (includeFilters != null && includeFilters.size() > 0) {
-      values = new ArrayList<ASN1OctetString>(includeFilters.size());
+      values = new ArrayList<ByteString>(includeFilters.size());
       for (String includeFilter : includeFilters) {
-        values.add(new ASN1OctetString(includeFilter));
+        values.add(ByteString.valueOf(includeFilter));
       }
       attributes.add(new LDAPAttribute(ATTR_IMPORT_INCLUDE_FILTER, values));
     }
 
     List<String> excludeFilters = excludeFilterStrings.getValues();
     if (excludeFilters != null && excludeFilters.size() > 0) {
-      values = new ArrayList<ASN1OctetString>(excludeFilters.size());
+      values = new ArrayList<ByteString>(excludeFilters.size());
       for (String excludeFilter : excludeFilters) {
-        values.add(new ASN1OctetString(excludeFilter));
+        values.add(ByteString.valueOf(excludeFilter));
       }
       attributes.add(new LDAPAttribute(ATTR_IMPORT_EXCLUDE_FILTER, values));
     }
 
     List<String> includeBranches = includeBranchStrings.getValues();
     if (includeBranches != null && includeBranches.size() > 0) {
-      values = new ArrayList<ASN1OctetString>(includeBranches.size());
+      values = new ArrayList<ByteString>(includeBranches.size());
       for (String includeBranche : includeBranches) {
-        values.add(new ASN1OctetString(includeBranche));
+        values.add(ByteString.valueOf(includeBranche));
       }
       attributes.add(new LDAPAttribute(ATTR_IMPORT_INCLUDE_BRANCH, values));
     }
 
     List<String> excludeBranches = excludeBranchStrings.getValues();
     if (excludeBranches != null && excludeBranches.size() > 0) {
-      values = new ArrayList<ASN1OctetString>(excludeBranches.size());
+      values = new ArrayList<ByteString>(excludeBranches.size());
       for (String excludeBranch : excludeBranches) {
-        values.add(new ASN1OctetString(excludeBranch));
+        values.add(ByteString.valueOf(excludeBranch));
       }
       attributes.add(new LDAPAttribute(ATTR_IMPORT_EXCLUDE_BRANCH, values));
     }
@@ -589,32 +590,32 @@
     if (rejectFile.getValue() != null &&
             !rejectFile.getValue().equals(
                     rejectFile.getDefaultValue())) {
-      values = new ArrayList<ASN1OctetString>(1);
-      values.add(new ASN1OctetString(rejectFile.getValue()));
+      values = new ArrayList<ByteString>(1);
+      values.add(ByteString.valueOf(rejectFile.getValue()));
       attributes.add(new LDAPAttribute(ATTR_IMPORT_REJECT_FILE, values));
     }
 
     if (skipFile.getValue() != null &&
             !skipFile.getValue().equals(
                     skipFile.getDefaultValue())) {
-      values = new ArrayList<ASN1OctetString>(1);
-      values.add(new ASN1OctetString(skipFile.getValue()));
+      values = new ArrayList<ByteString>(1);
+      values.add(ByteString.valueOf(skipFile.getValue()));
       attributes.add(new LDAPAttribute(ATTR_IMPORT_SKIP_FILE, values));
     }
 
     if (overwrite.getValue() != null &&
             !overwrite.getValue().equals(
                     overwrite.getDefaultValue())) {
-      values = new ArrayList<ASN1OctetString>(1);
-      values.add(new ASN1OctetString(overwrite.getValue()));
+      values = new ArrayList<ByteString>(1);
+      values.add(ByteString.valueOf(overwrite.getValue()));
       attributes.add(new LDAPAttribute(ATTR_IMPORT_OVERWRITE, values));
     }
 
     if (skipSchemaValidation.getValue() != null &&
             !skipSchemaValidation.getValue().equals(
                     skipSchemaValidation.getDefaultValue())) {
-      values = new ArrayList<ASN1OctetString>(1);
-      values.add(new ASN1OctetString(skipSchemaValidation.getValue()));
+      values = new ArrayList<ByteString>(1);
+      values.add(ByteString.valueOf(skipSchemaValidation.getValue()));
       attributes.add(
               new LDAPAttribute(ATTR_IMPORT_SKIP_SCHEMA_VALIDATION, values));
     }
@@ -622,8 +623,8 @@
     if (isCompressed.getValue() != null &&
             !isCompressed.getValue().equals(
                     isCompressed.getDefaultValue())) {
-      values = new ArrayList<ASN1OctetString>(1);
-      values.add(new ASN1OctetString(isCompressed.getValue()));
+      values = new ArrayList<ByteString>(1);
+      values.add(ByteString.valueOf(isCompressed.getValue()));
       attributes.add(
               new LDAPAttribute(ATTR_IMPORT_IS_COMPRESSED, values));
     }
@@ -631,8 +632,8 @@
     if (isEncrypted.getValue() != null &&
             !isEncrypted.getValue().equals(
                     isEncrypted.getDefaultValue())) {
-      values = new ArrayList<ASN1OctetString>(1);
-      values.add(new ASN1OctetString(isEncrypted.getValue()));
+      values = new ArrayList<ByteString>(1);
+      values.add(ByteString.valueOf(isEncrypted.getValue()));
       attributes.add(
               new LDAPAttribute(ATTR_IMPORT_IS_ENCRYPTED, values));
     }
@@ -640,8 +641,8 @@
     if (clearBackend.getValue() != null &&
             !clearBackend.getValue().equals(
                     clearBackend.getDefaultValue())) {
-      values = new ArrayList<ASN1OctetString>(1);
-      values.add(new ASN1OctetString(clearBackend.getValue()));
+      values = new ArrayList<ByteString>(1);
+      values.add(ByteString.valueOf(clearBackend.getValue()));
       attributes.add(
               new LDAPAttribute(ATTR_IMPORT_CLEAR_BACKEND, values));
     }
diff --git a/opends/src/server/org/opends/server/tools/LDAPAuthenticationHandler.java b/opends/src/server/org/opends/server/tools/LDAPAuthenticationHandler.java
index a24bec3..1dabcd2 100644
--- a/opends/src/server/org/opends/server/tools/LDAPAuthenticationHandler.java
+++ b/opends/src/server/org/opends/server/tools/LDAPAuthenticationHandler.java
@@ -37,7 +37,6 @@
 import java.security.MessageDigest;
 import java.security.PrivilegedExceptionAction;
 import java.security.SecureRandom;
-import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.HashMap;
 import java.util.Iterator;
@@ -58,15 +57,16 @@
 import javax.security.sasl.SaslClient;
 
 import org.opends.server.protocols.asn1.ASN1Exception;
-import org.opends.server.protocols.asn1.ASN1OctetString;
 import org.opends.server.protocols.ldap.BindRequestProtocolOp;
 import org.opends.server.protocols.ldap.BindResponseProtocolOp;
 import org.opends.server.protocols.ldap.ExtendedRequestProtocolOp;
 import org.opends.server.protocols.ldap.ExtendedResponseProtocolOp;
-import org.opends.server.protocols.ldap.LDAPControl;
 import org.opends.server.protocols.ldap.LDAPMessage;
 import org.opends.server.protocols.ldap.LDAPResultCode;
 import org.opends.server.types.LDAPException;
+import org.opends.server.types.Control;
+import org.opends.server.types.ByteString;
+import org.opends.server.types.ByteSequence;
 import org.opends.server.util.Base64;
 import org.opends.server.util.PasswordReader;
 
@@ -100,7 +100,7 @@
        implements PrivilegedExceptionAction<Object>, CallbackHandler
 {
   // The bind DN for GSSAPI authentication.
-  private ASN1OctetString gssapiBindDN;
+  private ByteSequence gssapiBindDN;
 
   // The LDAP reader that will be used to read data from the server.
   private LDAPReader reader;
@@ -276,10 +276,10 @@
    * @throws  LDAPException  If the bind fails or some other server-side problem
    *                         occurs during processing.
    */
-  public String doSimpleBind(int ldapVersion, ASN1OctetString bindDN,
-                             ASN1OctetString bindPassword,
-                             ArrayList<LDAPControl> requestControls,
-                             ArrayList<LDAPControl> responseControls)
+  public String doSimpleBind(int ldapVersion, ByteSequence bindDN,
+                             ByteSequence bindPassword,
+                             List<Control> requestControls,
+                             List<Control> responseControls)
          throws ClientException, LDAPException
   {
     // See if we need to prompt the user for the password.
@@ -287,21 +287,21 @@
     {
       if (bindDN == null)
       {
-        bindPassword = new ASN1OctetString();
+        bindPassword = ByteString.empty();
       }
       else
       {
         System.out.print(INFO_LDAPAUTH_PASSWORD_PROMPT.get(
-                bindDN.stringValue()));
+                bindDN.toString()));
         System.out.flush();
         char[] pwChars = PasswordReader.readPassword();
         if (pwChars == null)
         {
-          bindPassword = new ASN1OctetString();
+          bindPassword = ByteString.empty();
         }
         else
         {
-          bindPassword = new ASN1OctetString(getBytes(pwChars));
+          bindPassword = ByteString.wrap(getBytes(pwChars));
           Arrays.fill(pwChars, '\u0000');
         }
       }
@@ -311,13 +311,14 @@
     // Make sure that critical elements aren't null.
     if (bindDN == null)
     {
-      bindDN = new ASN1OctetString();
+      bindDN = ByteString.empty();
     }
 
 
     // Create the bind request and send it to the server.
     BindRequestProtocolOp bindRequest =
-         new BindRequestProtocolOp(bindDN, ldapVersion, bindPassword);
+         new BindRequestProtocolOp(bindDN.toByteString(), ldapVersion,
+             bindPassword.toByteString());
     LDAPMessage bindRequestMessage =
          new LDAPMessage(nextMessageID.getAndIncrement(), bindRequest,
                          requestControls);
@@ -387,7 +388,7 @@
 
     // See if there are any controls in the response.  If so, then add them to
     // the response controls list.
-    ArrayList<LDAPControl> respControls = responseMessage.getControls();
+    List<Control> respControls = responseMessage.getControls();
     if ((respControls != null) && (! respControls.isEmpty()))
     {
       responseControls.addAll(respControls);
@@ -482,17 +483,17 @@
    * @throws  LDAPException  If the bind fails or some other server-side problem
    *                         occurs during processing.
    */
-  public String doSASLBind(ASN1OctetString bindDN, ASN1OctetString bindPassword,
+  public String doSASLBind(ByteSequence bindDN, ByteSequence bindPassword,
                            String mechanism,
                            Map<String,List<String>> saslProperties,
-                           ArrayList<LDAPControl> requestControls,
-                           ArrayList<LDAPControl> responseControls)
+                           List<Control> requestControls,
+                           List<Control> responseControls)
          throws ClientException, LDAPException
   {
     // Make sure that critical elements aren't null.
     if (bindDN == null)
     {
-      bindDN = new ASN1OctetString();
+      bindDN = ByteString.empty();
     }
 
     if ((mechanism == null) || (mechanism.length() == 0))
@@ -569,10 +570,10 @@
    * @throws  LDAPException  If the bind fails or some other server-side problem
    *                         occurs during processing.
    */
-  public String doSASLAnonymous(ASN1OctetString bindDN,
+  public String doSASLAnonymous(ByteSequence bindDN,
                      Map<String,List<String>> saslProperties,
-                     ArrayList<LDAPControl> requestControls,
-                     ArrayList<LDAPControl> responseControls)
+                     List<Control> requestControls,
+                     List<Control> responseControls)
          throws ClientException, LDAPException
   {
     String trace = null;
@@ -620,19 +621,19 @@
 
 
     // Construct the bind request and send it to the server.
-    ASN1OctetString saslCredentials;
+    ByteString saslCredentials;
     if (trace == null)
     {
       saslCredentials = null;
     }
     else
     {
-      saslCredentials = new ASN1OctetString(trace);
+      saslCredentials = ByteString.valueOf(trace);
     }
 
     BindRequestProtocolOp bindRequest =
-         new BindRequestProtocolOp(bindDN, SASL_MECHANISM_ANONYMOUS,
-                                   saslCredentials);
+         new BindRequestProtocolOp(bindDN.toByteString(),
+             SASL_MECHANISM_ANONYMOUS, saslCredentials);
     LDAPMessage requestMessage =
          new LDAPMessage(nextMessageID.getAndIncrement(), bindRequest,
                          requestControls);
@@ -702,7 +703,7 @@
 
     // See if there are any controls in the response.  If so, then add them to
     // the response controls list.
-    ArrayList<LDAPControl> respControls = responseMessage.getControls();
+    List<Control> respControls = responseMessage.getControls();
     if ((respControls != null) && (! respControls.isEmpty()))
     {
       responseControls.addAll(respControls);
@@ -813,11 +814,11 @@
    * @throws  LDAPException  If the bind fails or some other server-side problem
    *                         occurs during processing.
    */
-  public String doSASLCRAMMD5(ASN1OctetString bindDN,
-                     ASN1OctetString bindPassword,
+  public String doSASLCRAMMD5(ByteSequence bindDN,
+                     ByteSequence bindPassword,
                      Map<String,List<String>> saslProperties,
-                     ArrayList<LDAPControl> requestControls,
-                     ArrayList<LDAPControl> responseControls)
+                     List<Control> requestControls,
+                     List<Control> responseControls)
          throws ClientException, LDAPException
   {
     String authID  = null;
@@ -883,11 +884,11 @@
       char[] pwChars = PasswordReader.readPassword();
       if (pwChars == null)
       {
-        bindPassword = new ASN1OctetString();
+        bindPassword = ByteString.empty();
       }
       else
       {
-        bindPassword = new ASN1OctetString(getBytes(pwChars));
+        bindPassword = ByteString.wrap(getBytes(pwChars));
         Arrays.fill(pwChars, '\u0000');
       }
     }
@@ -897,7 +898,8 @@
     // we'll simply indicate that we want to use CRAM-MD5 so the server will
     // send us the challenge.
     BindRequestProtocolOp bindRequest1 =
-         new BindRequestProtocolOp(bindDN, SASL_MECHANISM_CRAM_MD5, null);
+         new BindRequestProtocolOp(bindDN.toByteString(),
+             SASL_MECHANISM_CRAM_MD5, null);
     // FIXME -- Should we include request controls in both stages or just the
     // second stage?
     LDAPMessage requestMessage1 =
@@ -1026,7 +1028,7 @@
 
     // Make sure that the bind response contains SASL credentials with the
     // challenge to use for the next stage of the bind.
-    ASN1OctetString serverChallenge = bindResponse1.getServerSASLCredentials();
+    ByteString serverChallenge = bindResponse1.getServerSASLCredentials();
     if (serverChallenge == null)
     {
       Message message = ERR_LDAPAUTH_NO_CRAMMD5_SERVER_CREDENTIALS.get();
@@ -1044,8 +1046,8 @@
 
     // Create and send the second bind request to the server.
     BindRequestProtocolOp bindRequest2 =
-         new BindRequestProtocolOp(bindDN, SASL_MECHANISM_CRAM_MD5,
-                                   new ASN1OctetString(buffer.toString()));
+         new BindRequestProtocolOp(bindDN.toByteString(),
+             SASL_MECHANISM_CRAM_MD5, ByteString.valueOf(buffer.toString()));
     LDAPMessage requestMessage2 =
          new LDAPMessage(nextMessageID.getAndIncrement(), bindRequest2,
                          requestControls);
@@ -1115,7 +1117,7 @@
 
     // See if there are any controls in the response.  If so, then add them to
     // the response controls list.
-    ArrayList<LDAPControl> respControls = responseMessage2.getControls();
+    List<Control> respControls = responseMessage2.getControls();
     if ((respControls != null) && (! respControls.isEmpty()))
     {
       responseControls.addAll(respControls);
@@ -1193,8 +1195,8 @@
    * @throws  ClientException  If a problem occurs while attempting to perform
    *                           the necessary initialization.
    */
-  private String generateCRAMMD5Digest(ASN1OctetString password,
-                                       ASN1OctetString challenge)
+  private String generateCRAMMD5Digest(ByteSequence password,
+                                       ByteSequence challenge)
           throws ClientException
   {
     // Perform the necessary initialization if it hasn't been done yet.
@@ -1223,13 +1225,13 @@
 
 
     // Get the byte arrays backing the password and challenge.
-    byte[] p = password.value();
-    byte[] c = challenge.value();
+    byte[] p = password.toByteArray();
+    byte[] c = challenge.toByteArray();
 
 
     // If the password is longer than the HMAC-MD5 block length, then use an
     // MD5 digest of the password rather than the password itself.
-    if (p.length > HMAC_MD5_BLOCK_LENGTH)
+    if (password.length() > HMAC_MD5_BLOCK_LENGTH)
     {
       p = md5Digest.digest(p);
     }
@@ -1321,11 +1323,11 @@
    * @throws  LDAPException  If the bind fails or some other server-side problem
    *                         occurs during processing.
    */
-  public String doSASLDigestMD5(ASN1OctetString bindDN,
-                     ASN1OctetString bindPassword,
+  public String doSASLDigestMD5(ByteSequence bindDN,
+                     ByteSequence bindPassword,
                      Map<String,List<String>> saslProperties,
-                     ArrayList<LDAPControl> requestControls,
-                     ArrayList<LDAPControl> responseControls)
+                     List<Control> requestControls,
+                     List<Control> responseControls)
          throws ClientException, LDAPException
   {
     String  authID               = null;
@@ -1480,11 +1482,11 @@
       char[] pwChars = PasswordReader.readPassword();
       if (pwChars == null)
       {
-        bindPassword = new ASN1OctetString();
+        bindPassword = ByteString.empty();
       }
       else
       {
-        bindPassword = new ASN1OctetString(getBytes(pwChars));
+        bindPassword = ByteString.wrap(getBytes(pwChars));
         Arrays.fill(pwChars, '\u0000');
       }
     }
@@ -1494,7 +1496,8 @@
     // we'll simply indicate that we want to use DIGEST-MD5 so the server will
     // send us the challenge.
     BindRequestProtocolOp bindRequest1 =
-         new BindRequestProtocolOp(bindDN, SASL_MECHANISM_DIGEST_MD5, null);
+         new BindRequestProtocolOp(bindDN.toByteString(),
+             SASL_MECHANISM_DIGEST_MD5, null);
     // FIXME -- Should we include request controls in both stages or just the
     // second stage?
     LDAPMessage requestMessage1 =
@@ -1623,7 +1626,7 @@
 
     // Make sure that the bind response contains SASL credentials with the
     // information to use for the next stage of the bind.
-    ASN1OctetString serverCredentials =
+    ByteString serverCredentials =
          bindResponse1.getServerSASLCredentials();
     if (serverCredentials == null)
     {
@@ -1636,7 +1639,7 @@
     // particular, look at the realm, the nonce, the QoP modes, and the charset.
     // We'll only care about the realm if none was provided in the SASL
     // properties and only one was provided in the server SASL credentials.
-    String  credString = serverCredentials.stringValue();
+    String  credString = serverCredentials.toString();
     String  lowerCreds = toLowerCase(credString);
     String  nonce      = null;
     boolean useUTF8    = false;
@@ -1751,7 +1754,7 @@
     try
     {
       responseDigest = generateDigestMD5Response(authID, authzID,
-                                                 bindPassword.value(), realm,
+                                                 bindPassword, realm,
                                                  nonce, cnonce, nonceCount,
                                                  digestURI, qop, charset);
     }
@@ -1809,8 +1812,9 @@
 
     // Generate and send the second bind request.
     BindRequestProtocolOp bindRequest2 =
-         new BindRequestProtocolOp(bindDN, SASL_MECHANISM_DIGEST_MD5,
-                                   new ASN1OctetString(credBuffer.toString()));
+         new BindRequestProtocolOp(bindDN.toByteString(),
+             SASL_MECHANISM_DIGEST_MD5,
+             ByteString.valueOf(credBuffer.toString()));
     LDAPMessage requestMessage2 =
          new LDAPMessage(nextMessageID.getAndIncrement(), bindRequest2,
                          requestControls);
@@ -1880,7 +1884,7 @@
 
     // See if there are any controls in the response.  If so, then add them to
     // the response controls list.
-    ArrayList<LDAPControl> respControls = responseMessage2.getControls();
+    List<Control> respControls = responseMessage2.getControls();
     if ((respControls != null) && (! respControls.isEmpty()))
     {
       responseControls.addAll(respControls);
@@ -1941,14 +1945,14 @@
 
     // Make sure that the bind response included server SASL credentials with
     // the appropriate rspauth value.
-    ASN1OctetString rspAuthCreds = bindResponse2.getServerSASLCredentials();
+    ByteString rspAuthCreds = bindResponse2.getServerSASLCredentials();
     if (rspAuthCreds == null)
     {
       Message message = ERR_LDAPAUTH_DIGESTMD5_NO_RSPAUTH_CREDS.get();
       throw new LDAPException(LDAPResultCode.PROTOCOL_ERROR, message);
     }
 
-    String credStr = toLowerCase(rspAuthCreds.stringValue());
+    String credStr = toLowerCase(rspAuthCreds.toString());
     if (! credStr.startsWith("rspauth="))
     {
       Message message = ERR_LDAPAUTH_DIGESTMD5_NO_RSPAUTH_CREDS.get();
@@ -1972,7 +1976,7 @@
     try
     {
       clientRspAuth =
-           generateDigestMD5RspAuth(authID, authzID, bindPassword.value(),
+           generateDigestMD5RspAuth(authID, authzID, bindPassword,
                                     realm, nonce, cnonce, nonceCount, digestURI,
                                     qop, charset);
     }
@@ -2195,7 +2199,7 @@
    *                                        invalid for some reason.
    */
   private String generateDigestMD5Response(String authID, String authzID,
-                                           byte[] password, String realm,
+                                           ByteSequence password, String realm,
                                            String nonce, String cnonce,
                                            String nonceCount, String digestURI,
                                            String qop, String charset)
@@ -2226,9 +2230,9 @@
     a1String1.append(':');
 
     byte[] a1Bytes1a = a1String1.toString().getBytes(charset);
-    byte[] a1Bytes1  = new byte[a1Bytes1a.length + password.length];
+    byte[] a1Bytes1  = new byte[a1Bytes1a.length + password.length()];
     System.arraycopy(a1Bytes1a, 0, a1Bytes1, 0, a1Bytes1a.length);
-    System.arraycopy(password, 0, a1Bytes1, a1Bytes1a.length, password.length);
+    password.copyTo(a1Bytes1, a1Bytes1a.length);
     byte[] urpHash = md5Digest.digest(a1Bytes1);
 
 
@@ -2308,7 +2312,7 @@
    *                                        invalid for some reason.
    */
   public byte[] generateDigestMD5RspAuth(String authID, String authzID,
-                                         byte[] password, String realm,
+                                         ByteSequence password, String realm,
                                          String nonce, String cnonce,
                                          String nonceCount, String digestURI,
                                          String qop, String charset)
@@ -2322,10 +2326,9 @@
     a1String1.append(':');
 
     byte[] a1Bytes1a = a1String1.toString().getBytes(charset);
-    byte[] a1Bytes1  = new byte[a1Bytes1a.length + password.length];
+    byte[] a1Bytes1  = new byte[a1Bytes1a.length + password.length()];
     System.arraycopy(a1Bytes1a, 0, a1Bytes1, 0, a1Bytes1a.length);
-    System.arraycopy(password, 0, a1Bytes1, a1Bytes1a.length,
-                     password.length);
+    password.copyTo(a1Bytes1, a1Bytes1a.length);
     byte[] urpHash = md5Digest.digest(a1Bytes1);
 
 
@@ -2460,10 +2463,10 @@
    * @throws  LDAPException  If the bind fails or some other server-side problem
    *                         occurs during processing.
    */
-  public String doSASLExternal(ASN1OctetString bindDN,
+  public String doSASLExternal(ByteSequence bindDN,
                      Map<String,List<String>> saslProperties,
-                     ArrayList<LDAPControl> requestControls,
-                     ArrayList<LDAPControl> responseControls)
+                     List<Control> requestControls,
+                     List<Control> responseControls)
          throws ClientException, LDAPException
   {
     // Make sure that no SASL properties were provided.
@@ -2478,7 +2481,8 @@
 
     // Construct the bind request and send it to the server.
     BindRequestProtocolOp bindRequest =
-         new BindRequestProtocolOp(bindDN, SASL_MECHANISM_EXTERNAL, null);
+         new BindRequestProtocolOp(bindDN.toByteString(),
+             SASL_MECHANISM_EXTERNAL, null);
     LDAPMessage requestMessage =
          new LDAPMessage(nextMessageID.getAndIncrement(), bindRequest,
                          requestControls);
@@ -2548,7 +2552,7 @@
 
     // See if there are any controls in the response.  If so, then add them to
     // the response controls list.
-    ArrayList<LDAPControl> respControls = responseMessage.getControls();
+    List<Control> respControls = responseMessage.getControls();
     if ((respControls != null) && (! respControls.isEmpty()))
     {
       responseControls.addAll(respControls);
@@ -2656,11 +2660,11 @@
    * @throws  LDAPException  If the bind fails or some other server-side problem
    *                         occurs during processing.
    */
-  public String doSASLGSSAPI(ASN1OctetString bindDN,
-                     ASN1OctetString bindPassword,
+  public String doSASLGSSAPI(ByteSequence bindDN,
+                     ByteSequence bindPassword,
                      Map<String,List<String>> saslProperties,
-                     ArrayList<LDAPControl> requestControls,
-                     ArrayList<LDAPControl> responseControls)
+                     List<Control> requestControls,
+                     List<Control> responseControls)
          throws ClientException, LDAPException
   {
     String kdc     = null;
@@ -2677,7 +2681,7 @@
     }
     else
     {
-      gssapiAuthPW = bindPassword.stringValue().toCharArray();
+      gssapiAuthPW = bindPassword.toString().toCharArray();
     }
 
 
@@ -2975,11 +2979,11 @@
    * @throws  LDAPException  If the bind fails or some other server-side problem
    *                         occurs during processing.
    */
-  public String doSASLPlain(ASN1OctetString bindDN,
-                     ASN1OctetString bindPassword,
+  public String doSASLPlain(ByteSequence bindDN,
+                     ByteSequence bindPassword,
                      Map<String,List<String>> saslProperties,
-                     ArrayList<LDAPControl> requestControls,
-                     ArrayList<LDAPControl> responseControls)
+                     List<Control> requestControls,
+                     List<Control> responseControls)
          throws ClientException, LDAPException
   {
     String authID  = null;
@@ -3062,11 +3066,11 @@
       char[] pwChars = PasswordReader.readPassword();
       if (pwChars == null)
       {
-        bindPassword = new ASN1OctetString();
+        bindPassword = ByteString.empty();
       }
       else
       {
-        bindPassword = new ASN1OctetString(getBytes(pwChars));
+        bindPassword = ByteString.wrap(getBytes(pwChars));
         Arrays.fill(pwChars, '\u0000');
       }
     }
@@ -3081,12 +3085,12 @@
     credBuffer.append('\u0000');
     credBuffer.append(authID);
     credBuffer.append('\u0000');
-    credBuffer.append(bindPassword.stringValue());
+    credBuffer.append(bindPassword.toString());
 
-    ASN1OctetString saslCredentials =
-         new ASN1OctetString(credBuffer.toString());
+    ByteString saslCredentials =
+        ByteString.valueOf(credBuffer.toString());
     BindRequestProtocolOp bindRequest =
-         new BindRequestProtocolOp(bindDN, SASL_MECHANISM_PLAIN,
+         new BindRequestProtocolOp(bindDN.toByteString(), SASL_MECHANISM_PLAIN,
                                 saslCredentials);
     LDAPMessage requestMessage =
          new LDAPMessage(nextMessageID.getAndIncrement(), bindRequest,
@@ -3157,7 +3161,7 @@
 
     // See if there are any controls in the response.  If so, then add them to
     // the response controls list.
-    ArrayList<LDAPControl> respControls = responseMessage.getControls();
+    List<Control> respControls = responseMessage.getControls();
     if ((respControls != null) && (! respControls.isEmpty()))
     {
       responseControls.addAll(respControls);
@@ -3294,13 +3298,13 @@
 
 
       // Get the SASL credentials to include in the initial bind request.
-      ASN1OctetString saslCredentials;
+      ByteString saslCredentials;
       if (saslClient.hasInitialResponse())
       {
         try
         {
           byte[] credBytes = saslClient.evaluateChallenge(new byte[0]);
-          saslCredentials = new ASN1OctetString(credBytes);
+          saslCredentials = ByteString.wrap(credBytes);
         }
         catch (Exception e)
         {
@@ -3318,8 +3322,8 @@
 
 
       BindRequestProtocolOp bindRequest =
-           new BindRequestProtocolOp(gssapiBindDN, SASL_MECHANISM_GSSAPI,
-                                     saslCredentials);
+           new BindRequestProtocolOp(gssapiBindDN.toByteString(),
+               SASL_MECHANISM_GSSAPI, saslCredentials);
       // FIXME -- Add controls here?
       LDAPMessage requestMessage =
            new LDAPMessage(nextMessageID.getAndIncrement(), bindRequest);
@@ -3436,13 +3440,13 @@
         {
           // We should be done after this, but we still need to look for and
           // handle the server SASL credentials.
-          ASN1OctetString serverSASLCredentials =
+          ByteString serverSASLCredentials =
                bindResponse.getServerSASLCredentials();
           if (serverSASLCredentials != null)
           {
             try
             {
-              saslClient.evaluateChallenge(serverSASLCredentials.value());
+              saslClient.evaluateChallenge(serverSASLCredentials.toByteArray());
             }
             catch (Exception e)
             {
@@ -3469,7 +3473,7 @@
         else if (resultCode == LDAPResultCode.SASL_BIND_IN_PROGRESS)
         {
           // Read the response and process the server SASL credentials.
-          ASN1OctetString serverSASLCredentials =
+          ByteString serverSASLCredentials =
                bindResponse.getServerSASLCredentials();
           byte[] credBytes;
           try
@@ -3480,8 +3484,8 @@
             }
             else
             {
-              credBytes =
-                   saslClient.evaluateChallenge(serverSASLCredentials.value());
+              credBytes = saslClient.evaluateChallenge(
+                  serverSASLCredentials.toByteArray());
             }
           }
           catch (Exception e)
@@ -3495,8 +3499,8 @@
 
           // Send the next bind in the sequence to the server.
           bindRequest =
-               new BindRequestProtocolOp(gssapiBindDN, SASL_MECHANISM_GSSAPI,
-                                         new ASN1OctetString(credBytes));
+               new BindRequestProtocolOp(gssapiBindDN.toByteString(),
+                   SASL_MECHANISM_GSSAPI, ByteString.wrap(credBytes));
           // FIXME -- Add controls here?
           requestMessage =
                new LDAPMessage(nextMessageID.getAndIncrement(), bindRequest);
@@ -3700,7 +3704,7 @@
    * @throws  LDAPException  If a server-side problem occurs during the request
    *                         processing.
    */
-  public ASN1OctetString requestAuthorizationIdentity()
+  public ByteString requestAuthorizationIdentity()
          throws ClientException, LDAPException
   {
     // Construct the extended request and send it to the server.
@@ -3810,14 +3814,13 @@
 
 
     // Get the authorization ID (if there is one) and return it to the caller.
-    ASN1OctetString authzID = extendedResponse.getValue();
-    if ((authzID == null) || (authzID.value() == null) ||
-        (authzID.value().length == 0))
+    ByteString authzID = extendedResponse.getValue();
+    if ((authzID == null) || (authzID.length() == 0))
     {
       return null;
     }
 
-    String valueString = authzID.stringValue();
+    String valueString = authzID.toString();
     if ((valueString == null) || (valueString.length() == 0) ||
         valueString.equalsIgnoreCase("dn:"))
     {
diff --git a/opends/src/server/org/opends/server/tools/LDAPCompare.java b/opends/src/server/org/opends/server/tools/LDAPCompare.java
index e352177..5117e2e 100644
--- a/opends/src/server/org/opends/server/tools/LDAPCompare.java
+++ b/opends/src/server/org/opends/server/tools/LDAPCompare.java
@@ -40,16 +40,12 @@
 import java.util.concurrent.atomic.AtomicInteger;
 
 import org.opends.server.protocols.asn1.ASN1Exception;
-import org.opends.server.protocols.asn1.ASN1OctetString;
 import org.opends.server.protocols.ldap.CompareRequestProtocolOp;
 import org.opends.server.protocols.ldap.CompareResponseProtocolOp;
-import org.opends.server.protocols.ldap.LDAPControl;
 import org.opends.server.protocols.ldap.LDAPFilter;
 import org.opends.server.protocols.ldap.LDAPMessage;
 import org.opends.server.protocols.ldap.ProtocolOp;
-import org.opends.server.types.NullOutputStream;
-import org.opends.server.types.DebugLogLevel;
-import org.opends.server.types.LDAPException;
+import org.opends.server.types.*;
 import org.opends.server.util.Base64;
 import org.opends.server.util.EmbeddedUtils;
 import org.opends.server.util.PasswordReader;
@@ -67,6 +63,7 @@
 import static org.opends.server.util.ServerConstants.*;
 import static org.opends.server.util.StaticUtils.*;
 import static org.opends.server.tools.ToolConstants.*;
+import org.opends.server.controls.LDAPAssertionRequestControl;
 
 
 /**
@@ -191,9 +188,9 @@
                               LDAPCompareOptions compareOptions)
           throws IOException, LDAPException
   {
-    ArrayList<LDAPControl> controls = compareOptions.getControls();
-    ASN1OctetString dnOctetStr = new ASN1OctetString(line);
-    ASN1OctetString attrValOctetStr = new ASN1OctetString(attributeVal);
+    ArrayList<Control> controls = compareOptions.getControls();
+    ByteString dnOctetStr = ByteString.valueOf(line);
+    ByteString attrValOctetStr = ByteString.wrap(attributeVal);
 
     ProtocolOp protocolOp = new CompareRequestProtocolOp(dnOctetStr,
                                      attributeType, attrValOctetStr);
@@ -816,7 +813,7 @@
     {
       for (String ctrlString : controlStr.getValues())
       {
-        LDAPControl ctrl = LDAPToolUtils.getControl(ctrlString, err);
+        Control ctrl = LDAPToolUtils.getControl(ctrlString, err);
         if(ctrl == null)
         {
           Message message = ERR_TOOL_INVALID_CONTROL_STRING.get(ctrlString);
@@ -836,9 +833,8 @@
       {
         filter = LDAPFilter.decode(filterString);
 
-        LDAPControl assertionControl =
-             new LDAPControl(OID_LDAP_ASSERTION, true,
-                             new ASN1OctetString(filter.encode().encode()));
+        Control assertionControl =
+            new LDAPAssertionRequestControl(true, filter);
         compareOptions.getControls().add(assertionControl);
       }
       catch (LDAPException le)
diff --git a/opends/src/server/org/opends/server/tools/LDAPConnection.java b/opends/src/server/org/opends/server/tools/LDAPConnection.java
index 26ec6b3..e8d39fe 100644
--- a/opends/src/server/org/opends/server/tools/LDAPConnection.java
+++ b/opends/src/server/org/opends/server/tools/LDAPConnection.java
@@ -22,7 +22,7 @@
  * CDDL HEADER END
  *
  *
- *      Copyright 2008 Sun Microsystems, Inc.
+ *      Copyright 2009 Sun Microsystems, Inc.
  */
 package org.opends.server.tools;
 import org.opends.messages.Message;
@@ -35,11 +35,7 @@
 import java.util.ArrayList;
 import java.util.concurrent.atomic.AtomicInteger;
 
-import org.opends.server.controls.PasswordExpiringControl;
-import org.opends.server.controls.PasswordPolicyErrorType;
-import org.opends.server.controls.PasswordPolicyResponseControl;
-import org.opends.server.controls.PasswordPolicyWarningType;
-import org.opends.server.protocols.asn1.ASN1OctetString;
+import org.opends.server.controls.*;
 import org.opends.server.protocols.ldap.ExtendedRequestProtocolOp;
 import org.opends.server.protocols.ldap.ExtendedResponseProtocolOp;
 import org.opends.server.protocols.ldap.LDAPControl;
@@ -47,10 +43,14 @@
 import org.opends.server.protocols.ldap.UnbindRequestProtocolOp;
 import org.opends.server.types.Control;
 import org.opends.server.types.DebugLogLevel;
+import org.opends.server.types.DirectoryException;
+import org.opends.server.types.ByteString;
 import org.opends.server.types.LDAPException;
 
 import static org.opends.server.loggers.debug.DebugLogger.*;
 import org.opends.server.loggers.debug.DebugTracer;
+import org.opends.server.loggers.debug.DebugLogger;
+import org.opends.server.loggers.debug.TraceSettings;
 import static org.opends.messages.CoreMessages.
                    INFO_RESULT_CLIENT_SIDE_CONNECT_ERROR;
 import static org.opends.messages.ToolMessages.*;
@@ -155,18 +155,24 @@
     Socket socket;
     Socket startTLSSocket = null;
     int resultCode;
-    ArrayList<LDAPControl> requestControls = new ArrayList<LDAPControl> ();
-    ArrayList<LDAPControl> responseControls = new ArrayList<LDAPControl> ();
+    ArrayList<Control> requestControls = new ArrayList<Control> ();
+    ArrayList<Control> responseControls = new ArrayList<Control> ();
 
-    VerboseTracer tracer =
-         new VerboseTracer(connectionOptions.isVerbose(), err);
+    if(connectionOptions.isVerbose())
+    {
+      ConsoleDebugLogPublisher publisher = new ConsoleDebugLogPublisher(err);
+      publisher.addTraceSettings(null,
+          new TraceSettings(DebugLogLevel.VERBOSE));
+      DebugLogger.addDebugLogPublisher(publisher);
+    }
+
     if(connectionOptions.useStartTLS())
     {
       try
       {
         startTLSSocket = new Socket(hostName, portNumber);
-        ldapWriter = new LDAPWriter(startTLSSocket, tracer);
-        ldapReader = new LDAPReader(startTLSSocket, tracer);
+        ldapWriter = new LDAPWriter(startTLSSocket);
+        ldapReader = new LDAPReader(startTLSSocket);
       } catch(UnknownHostException uhe)
       {
         Message msg = INFO_RESULT_CLIENT_SIDE_CONNECT_ERROR.get();
@@ -235,8 +241,8 @@
       {
         socket = new Socket(hostName, portNumber);
       }
-      ldapWriter = new LDAPWriter(socket, tracer);
-      ldapReader = new LDAPReader(socket, tracer);
+      ldapWriter = new LDAPWriter(socket);
+      ldapReader = new LDAPReader(socket);
     } catch(UnknownHostException uhe)
     {
       Message msg = INFO_RESULT_CLIENT_SIDE_CONNECT_ERROR.get();
@@ -285,34 +291,43 @@
          ldapReader, ldapWriter, hostName, nextMessageID);
     try
     {
-      ASN1OctetString bindPW;
-      if (bindPassword == null)
+      ByteString bindDNBytes;
+      if(bindDN == null)
       {
-        bindPW = null;
+        bindDNBytes = ByteString.empty();
       }
       else
       {
-        bindPW = new ASN1OctetString(bindPassword);
+        bindDNBytes = ByteString.valueOf(bindDN);
+      }
+
+      ByteString bindPW;
+      if (bindPassword == null)
+      {
+        bindPW =  ByteString.empty();
+      }
+      else
+      {
+        bindPW = ByteString.valueOf(bindPassword);
       }
 
       String result = null;
       if (connectionOptions.useSASLExternal())
       {
-        result = handler.doSASLExternal(new ASN1OctetString(bindDN),
+        result = handler.doSASLExternal(bindDNBytes,
                                         connectionOptions.getSASLProperties(),
                                         requestControls, responseControls);
       }
       else if (connectionOptions.getSASLMechanism() != null)
       {
-            result = handler.doSASLBind(new ASN1OctetString(bindDN), bindPW,
+            result = handler.doSASLBind(bindDNBytes, bindPW,
             connectionOptions.getSASLMechanism(),
             connectionOptions.getSASLProperties(),
             requestControls, responseControls);
       }
       else if(bindDN != null)
       {
-              result = handler.doSimpleBind(versionNumber,
-                  new ASN1OctetString(bindDN), bindPW,
+              result = handler.doSimpleBind(versionNumber, bindDNBytes, bindPW,
               requestControls, responseControls);
       }
       if(result != null)
@@ -320,18 +335,27 @@
         out.println(result);
       }
 
-      for (LDAPControl c : responseControls)
+      for (Control c : responseControls)
       {
         if (c.getOID().equals(OID_AUTHZID_RESPONSE))
         {
-          ASN1OctetString controlValue = c.getValue();
-          if (controlValue != null)
+          AuthorizationIdentityResponseControl control;
+          if (c instanceof LDAPControl)
           {
-
-            Message message =
-                    INFO_BIND_AUTHZID_RETURNED.get(controlValue.stringValue());
-            out.println(message);
+            // We have to decode this control.
+            control = AuthorizationIdentityResponseControl.DECODER.decode(c
+                .isCritical(), ((LDAPControl) c).getValue());
           }
+          else
+          {
+            // Control should already have been decoded.
+            control = (AuthorizationIdentityResponseControl)c;
+          }
+
+          Message message =
+              INFO_BIND_AUTHZID_RETURNED.get(
+                  control.getAuthorizationID());
+          out.println(message);
         }
         else if (c.getOID().equals(OID_NS_PASSWORD_EXPIRED))
         {
@@ -341,12 +365,20 @@
         }
         else if (c.getOID().equals(OID_NS_PASSWORD_EXPIRING))
         {
-          PasswordExpiringControl expiringControl =
-               PasswordExpiringControl.decodeControl(new Control(c.getOID(),
-                                                                 c.isCritical(),
-                                                                 c.getValue()));
+          PasswordExpiringControl control;
+          if(c instanceof LDAPControl)
+          {
+            // We have to decode this control.
+            control = PasswordExpiringControl.DECODER.decode(c.isCritical(),
+                ((LDAPControl) c).getValue());
+          }
+          else
+          {
+            // Control should already have been decoded.
+            control = (PasswordExpiringControl)c;
+          }
           Message timeString =
-               secondsToTimeString(expiringControl.getSecondsUntilExpiration());
+               secondsToTimeString(control.getSecondsUntilExpiration());
 
 
           Message message = INFO_BIND_PASSWORD_EXPIRING.get(timeString);
@@ -354,9 +386,17 @@
         }
         else if (c.getOID().equals(OID_PASSWORD_POLICY_CONTROL))
         {
-          PasswordPolicyResponseControl pwPolicyControl =
-               PasswordPolicyResponseControl.decodeControl(new Control(
-                    c.getOID(), c.isCritical(), c.getValue()));
+          PasswordPolicyResponseControl pwPolicyControl;
+          if(c instanceof LDAPControl)
+          {
+            pwPolicyControl = PasswordPolicyResponseControl.DECODER.decode(c
+                .isCritical(), ((LDAPControl) c).getValue());
+          }
+          else
+          {
+            pwPolicyControl = (PasswordPolicyResponseControl)c;
+          }
+
 
           PasswordPolicyErrorType errorType = pwPolicyControl.getErrorType();
           if (errorType != null)
@@ -413,13 +453,17 @@
       }
       throw new LDAPConnectionException(ce.getMessageObject(), ce.getExitCode(),
                                         null, ce);
-    } catch (LDAPException le)
+    } catch (LDAPException le) {
+        throw new LDAPConnectionException(le.getMessageObject(),
+                le.getResultCode(),
+                le.getErrorMessage(),
+                le.getMatchedDN(),
+                le.getCause());
+    } catch (DirectoryException de)
     {
-      throw new LDAPConnectionException(le.getMessageObject(),
-                                        le.getResultCode(),
-                                        le.getErrorMessage(),
-                                        le.getMatchedDN(),
-                                        le.getCause());
+      throw new LDAPConnectionException(de.getMessageObject(), de
+          .getResultCode().getIntValue(), null, de.getMatchedDN(), de
+          .getCause());
     } catch(Exception ex)
     {
       if (debugEnabled())
diff --git a/opends/src/server/org/opends/server/tools/LDAPDelete.java b/opends/src/server/org/opends/server/tools/LDAPDelete.java
index bb49189..ea0ae3e 100644
--- a/opends/src/server/org/opends/server/tools/LDAPDelete.java
+++ b/opends/src/server/org/opends/server/tools/LDAPDelete.java
@@ -39,15 +39,11 @@
 import java.util.concurrent.atomic.AtomicInteger;
 
 import org.opends.server.protocols.asn1.ASN1Exception;
-import org.opends.server.protocols.asn1.ASN1OctetString;
 import org.opends.server.protocols.ldap.DeleteRequestProtocolOp;
 import org.opends.server.protocols.ldap.DeleteResponseProtocolOp;
-import org.opends.server.protocols.ldap.LDAPControl;
 import org.opends.server.protocols.ldap.LDAPMessage;
 import org.opends.server.protocols.ldap.ProtocolOp;
-import org.opends.server.types.NullOutputStream;
-import org.opends.server.types.DebugLogLevel;
-import org.opends.server.types.LDAPException;
+import org.opends.server.types.*;
 import org.opends.server.util.EmbeddedUtils;
 import org.opends.server.util.PasswordReader;
 import org.opends.server.util.args.ArgumentException;
@@ -58,6 +54,8 @@
 import org.opends.server.util.args.StringArgument;
 
 import static org.opends.server.loggers.debug.DebugLogger.*;
+
+import org.opends.server.controls.SubtreeDeleteControl;
 import org.opends.server.loggers.debug.DebugTracer;
 import static org.opends.messages.ToolMessages.*;
 import static org.opends.server.protocols.ldap.LDAPResultCode.*;
@@ -85,13 +83,13 @@
 
 
   // The message ID counter to use for requests.
-  private AtomicInteger nextMessageID;
+  private final AtomicInteger nextMessageID;
 
   // The print stream to use for standard error.
-  private PrintStream err;
+  private final PrintStream err;
 
   // The print stream to use for standard output.
-  private PrintStream out;
+  private final PrintStream out;
 
 
 
@@ -177,9 +175,9 @@
                              LDAPDeleteOptions deleteOptions)
           throws IOException, LDAPException
   {
-    ArrayList<LDAPControl> controls = deleteOptions.getControls();
+    ArrayList<Control> controls = deleteOptions.getControls();
     ProtocolOp protocolOp = null;
-    ASN1OctetString asn1OctetStr = new ASN1OctetString(line);
+    ByteString asn1OctetStr = ByteString.valueOf(line);
 
     protocolOp = new DeleteRequestProtocolOp(asn1OctetStr);
 
@@ -702,7 +700,7 @@
     {
       for (String ctrlString : controlStr.getValues())
       {
-        LDAPControl ctrl = LDAPToolUtils.getControl(ctrlString, err);
+        Control ctrl = LDAPToolUtils.getControl(ctrlString, err);
         if(ctrl == null)
         {
           Message message = ERR_TOOL_INVALID_CONTROL_STRING.get(ctrlString);
@@ -716,7 +714,7 @@
 
     if(deleteOptions.getDeleteSubtree())
     {
-      LDAPControl control = new LDAPControl(OID_SUBTREE_DELETE_CONTROL);
+      Control control = new SubtreeDeleteControl(false);
       deleteOptions.getControls().add(control);
     }
 
diff --git a/opends/src/server/org/opends/server/tools/LDAPModify.java b/opends/src/server/org/opends/server/tools/LDAPModify.java
index 44eb914..7768f61 100644
--- a/opends/src/server/org/opends/server/tools/LDAPModify.java
+++ b/opends/src/server/org/opends/server/tools/LDAPModify.java
@@ -32,16 +32,10 @@
 import java.io.IOException;
 import java.io.OutputStream;
 import java.io.PrintStream;
-import java.util.ArrayList;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.StringTokenizer;
+import java.util.*;
 import java.util.concurrent.atomic.AtomicInteger;
 
-import org.opends.server.protocols.asn1.ASN1Element;
 import org.opends.server.protocols.asn1.ASN1Exception;
-import org.opends.server.protocols.asn1.ASN1OctetString;
-import org.opends.server.protocols.asn1.ASN1Sequence;
 import org.opends.server.protocols.ldap.AddRequestProtocolOp;
 import org.opends.server.protocols.ldap.AddResponseProtocolOp;
 import org.opends.server.protocols.ldap.DeleteRequestProtocolOp;
@@ -54,16 +48,8 @@
 import org.opends.server.protocols.ldap.ModifyResponseProtocolOp;
 import org.opends.server.protocols.ldap.ModifyDNRequestProtocolOp;
 import org.opends.server.protocols.ldap.ModifyDNResponseProtocolOp;
-import org.opends.server.protocols.ldap.SearchResultEntryProtocolOp;
 import org.opends.server.protocols.ldap.ProtocolOp;
-import org.opends.server.types.Attribute;
-import org.opends.server.types.DebugLogLevel;
-import org.opends.server.types.DN;
-import org.opends.server.types.LDAPException;
-import org.opends.server.types.LDIFImportConfig;
-import org.opends.server.types.NullOutputStream;
-import org.opends.server.types.RawAttribute;
-import org.opends.server.types.RawModification;
+import org.opends.server.types.*;
 import org.opends.server.util.AddChangeRecordEntry;
 import org.opends.server.util.ChangeRecordEntry;
 import org.opends.server.util.EmbeddedUtils;
@@ -86,6 +72,8 @@
 import static org.opends.server.util.ServerConstants.*;
 import static org.opends.server.util.StaticUtils.*;
 import static org.opends.server.tools.ToolConstants.*;
+import org.opends.server.controls.*;
+import org.opends.server.plugins.ChangeNumberControlPlugin;
 
 
 
@@ -161,7 +149,7 @@
                              LDAPModifyOptions modifyOptions)
          throws IOException, LDAPException
   {
-    ArrayList<LDAPControl> controls = modifyOptions.getControls();
+    ArrayList<Control> controls = modifyOptions.getControls();
     LDIFReader reader;
 
     // Create an LDIF import configuration to do this and then get the reader.
@@ -279,11 +267,10 @@
       }
 
       ProtocolOp protocolOp = null;
-      ASN1OctetString asn1OctetStr =
-           new ASN1OctetString(entry.getDN().toString());
+      ByteString asn1OctetStr =
+          ByteString.valueOf(entry.getDN().toString());
 
       String operationType = "";
-      int msgID = 0;
       switch(entry.getChangeOperationType())
       {
         case ADD:
@@ -298,13 +285,13 @@
           }
           protocolOp = new AddRequestProtocolOp(asn1OctetStr, attributes);
           out.println(INFO_PROCESSING_OPERATION.get(
-                  operationType, String.valueOf(asn1OctetStr)));
+                  operationType, asn1OctetStr.toString()));
           break;
         case DELETE:
           operationType = "DELETE";
           protocolOp = new DeleteRequestProtocolOp(asn1OctetStr);
           out.println(INFO_PROCESSING_OPERATION.get(
-                  operationType, String.valueOf(asn1OctetStr)));
+                  operationType, asn1OctetStr.toString()));
           break;
         case MODIFY:
           operationType = "MODIFY";
@@ -313,7 +300,7 @@
             new ArrayList<RawModification>(modEntry.getModifications());
           protocolOp = new ModifyRequestProtocolOp(asn1OctetStr, mods);
           out.println(INFO_PROCESSING_OPERATION.get(
-                  operationType, String.valueOf(asn1OctetStr)));
+                  operationType, asn1OctetStr.toString()));
           break;
         case MODIFY_DN:
           operationType = "MODIFY DN";
@@ -322,19 +309,19 @@
           if(modDNEntry.getNewSuperiorDN() != null)
           {
             protocolOp = new ModifyDNRequestProtocolOp(asn1OctetStr,
-                 new ASN1OctetString(modDNEntry.getNewRDN().toString()),
+                ByteString.valueOf(modDNEntry.getNewRDN().toString()),
                  modDNEntry.deleteOldRDN(),
-                 new ASN1OctetString(
+                ByteString.valueOf(
                           modDNEntry.getNewSuperiorDN().toString()));
           } else
           {
             protocolOp = new ModifyDNRequestProtocolOp(asn1OctetStr,
-                 new ASN1OctetString(modDNEntry.getNewRDN().toString()),
+                ByteString.valueOf(modDNEntry.getNewRDN().toString()),
                  modDNEntry.deleteOldRDN());
           }
 
           out.println(INFO_PROCESSING_OPERATION.get(
-                  operationType, String.valueOf(asn1OctetStr)));
+                  operationType, asn1OctetStr.toString()));
           break;
         default:
           break;
@@ -424,7 +411,7 @@
         } else
         {
           Message msg = INFO_OPERATION_SUCCESSFUL.get(
-                  operationType, String.valueOf(asn1OctetStr));
+                  operationType, asn1OctetStr.toString());
           out.println(msg);
 
           if (errorMessage != null)
@@ -439,102 +426,91 @@
         }
 
 
-        for (LDAPControl c : responseMessage.getControls())
+        for (Control c : responseMessage.getControls())
         {
           String oid = c.getOID();
           if (oid.equals(OID_LDAP_READENTRY_PREREAD))
           {
-            ASN1OctetString controlValue = c.getValue();
-            if (controlValue == null)
-            {
-
-              err.println(wrapText(
-                      ERR_LDAPMODIFY_PREREAD_NO_VALUE.get(),
-                      MAX_LINE_WIDTH));
-              continue;
-            }
-
-            SearchResultEntryProtocolOp searchEntry;
+            SearchResultEntry searchEntry;
             try
             {
-              byte[] valueBytes = controlValue.value();
-              ASN1Element valueElement = ASN1Element.decode(valueBytes);
-              searchEntry =
-                   SearchResultEntryProtocolOp.decodeSearchEntry(valueElement);
+              LDAPPreReadResponseControl prrc;
+              if(c instanceof LDAPControl)
+              {
+                // Control needs to be decoded
+                prrc = LDAPPreReadResponseControl.DECODER.decode(
+                    c.isCritical(), ((LDAPControl) c).getValue());
+
+              }
+              else
+              {
+                prrc = (LDAPPreReadResponseControl)c;
+              }
+              searchEntry = prrc.getSearchEntry();
             }
-            catch (ASN1Exception ae)
+            catch (DirectoryException de)
             {
 
               err.println(wrapText(
-                      ERR_LDAPMODIFY_PREREAD_CANNOT_DECODE_VALUE.get(
-                              ae.getMessage()),
-                      MAX_LINE_WIDTH));
-              continue;
-            }
-            catch (LDAPException le)
-            {
-
-              err.println(wrapText(
-                      ERR_LDAPMODIFY_PREREAD_CANNOT_DECODE_VALUE.get(
-                              le.getMessage()),
+                  ERR_LDAPMODIFY_PREREAD_CANNOT_DECODE_VALUE.get(
+                              de.getMessage()),
                       MAX_LINE_WIDTH));
               continue;
             }
 
             StringBuilder buffer = new StringBuilder();
-            searchEntry.toLDIF(buffer, 78);
+            searchEntry.toString(buffer, 78);
             out.println(INFO_LDAPMODIFY_PREREAD_ENTRY.get());
             out.println(buffer);
           }
           else if (oid.equals(OID_LDAP_READENTRY_POSTREAD))
           {
-            ASN1OctetString controlValue = c.getValue();
-            if (controlValue == null)
-            {
-
-              err.println(wrapText(
-                      ERR_LDAPMODIFY_POSTREAD_NO_VALUE.get(),
-                      MAX_LINE_WIDTH));
-              continue;
-            }
-
-            SearchResultEntryProtocolOp searchEntry;
+            SearchResultEntry searchEntry;
             try
             {
-              byte[] valueBytes = controlValue.value();
-              ASN1Element valueElement = ASN1Element.decode(valueBytes);
-              searchEntry =
-                   SearchResultEntryProtocolOp.decodeSearchEntry(valueElement);
+              LDAPPostReadResponseControl pprc;
+              if (c instanceof LDAPControl)
+              {
+                // Control needs to be decoded
+                pprc = LDAPPostReadResponseControl.DECODER.decode(c
+                    .isCritical(), ((LDAPControl) c).getValue());
+
+              }
+              else
+              {
+                pprc = (LDAPPostReadResponseControl)c;
+              }
+              searchEntry = pprc.getSearchEntry();
             }
-            catch (ASN1Exception ae)
+            catch (DirectoryException de)
             {
 
               err.println(wrapText(
                       ERR_LDAPMODIFY_POSTREAD_CANNOT_DECODE_VALUE.get(
-                              ae.getMessage()),
-                      MAX_LINE_WIDTH));
-              continue;
-            }
-            catch (LDAPException le)
-            {
-
-              err.println(wrapText(
-                      ERR_LDAPMODIFY_POSTREAD_CANNOT_DECODE_VALUE.get(
-                              le.getMessage()),
+                              de.getMessage()),
                       MAX_LINE_WIDTH));
               continue;
             }
 
             StringBuilder buffer = new StringBuilder();
-            searchEntry.toLDIF(buffer, 78);
+            searchEntry.toString(buffer, 78);
             out.println(INFO_LDAPMODIFY_POSTREAD_ENTRY.get());
             out.println(buffer);
           }
           else if (oid.equals(OID_CSN_CONTROL))
           {
-            ASN1OctetString controlValue = c.getValue();
-            out.println(INFO_CHANGE_NUMBER_CONTROL_RESULT.get(operationType,
-                String.valueOf(controlValue)));
+            if(c instanceof LDAPControl)
+            {
+              // Don't really need to decode since its just an octet string.
+              out.println(INFO_CHANGE_NUMBER_CONTROL_RESULT.get(operationType,
+                  ((LDAPControl)c).getValue().toString()));
+            }
+            else
+            {
+              out.println(INFO_CHANGE_NUMBER_CONTROL_RESULT.get(operationType,
+                  ((ChangeNumberControlPlugin.ChangeNumberControl)c).
+                      getChangeNumber().toString()));
+            }
           }
         }
       }
@@ -1052,7 +1028,7 @@
     {
       for (String ctrlString : controlStr.getValues())
       {
-        LDAPControl ctrl = LDAPToolUtils.getControl(ctrlString, err);
+        Control ctrl = LDAPToolUtils.getControl(ctrlString, err);
         if(ctrl == null)
         {
           Message message = ERR_TOOL_INVALID_CONTROL_STRING.get(ctrlString);
@@ -1066,10 +1042,9 @@
 
     if (proxyAuthzID.isPresent())
     {
-      ASN1OctetString proxyValue = new ASN1OctetString(proxyAuthzID.getValue());
-
-      LDAPControl proxyControl =
-        new LDAPControl(OID_PROXIED_AUTH_V2, true, proxyValue);
+      Control proxyControl =
+          new ProxiedAuthV2Control(true,
+              ByteString.valueOf(proxyAuthzID.getValue()));
       modifyOptions.getControls().add(proxyControl);
     }
 
@@ -1081,9 +1056,8 @@
       {
         filter = LDAPFilter.decode(filterString);
 
-        LDAPControl assertionControl =
-             new LDAPControl(OID_LDAP_ASSERTION, true,
-                             new ASN1OctetString(filter.encode().encode()));
+        Control assertionControl =
+            new LDAPAssertionRequestControl(true, filter);
         modifyOptions.getControls().add(assertionControl);
       }
       catch (LDAPException le)
@@ -1098,36 +1072,30 @@
     if (preReadAttributes.isPresent())
     {
       String valueStr = preReadAttributes.getValue();
-      ArrayList<ASN1Element> attrElements = new ArrayList<ASN1Element>();
+      Set<String> attrElements = new LinkedHashSet<String>();
 
       StringTokenizer tokenizer = new StringTokenizer(valueStr, ", ");
       while (tokenizer.hasMoreTokens())
       {
-        attrElements.add(new ASN1OctetString(tokenizer.nextToken()));
+        attrElements.add(tokenizer.nextToken());
       }
 
-      ASN1OctetString controlValue =
-           new ASN1OctetString(new ASN1Sequence(attrElements).encode());
-      LDAPControl c = new LDAPControl(OID_LDAP_READENTRY_PREREAD, true,
-                                      controlValue);
+      Control c = new LDAPPreReadRequestControl(true, attrElements);
       modifyOptions.getControls().add(c);
     }
 
     if (postReadAttributes.isPresent())
     {
       String valueStr = postReadAttributes.getValue();
-      ArrayList<ASN1Element> attrElements = new ArrayList<ASN1Element>();
+      Set<String> attrElements = new LinkedHashSet<String>();
 
       StringTokenizer tokenizer = new StringTokenizer(valueStr, ", ");
       while (tokenizer.hasMoreTokens())
       {
-        attrElements.add(new ASN1OctetString(tokenizer.nextToken()));
+        attrElements.add(tokenizer.nextToken());
       }
 
-      ASN1OctetString controlValue =
-           new ASN1OctetString(new ASN1Sequence(attrElements).encode());
-      LDAPControl c = new LDAPControl(OID_LDAP_READENTRY_POSTREAD, true,
-                                      controlValue);
+      Control c = new LDAPPostReadRequestControl(true, attrElements);
       modifyOptions.getControls().add(c);
     }
 
diff --git a/opends/src/server/org/opends/server/tools/LDAPPasswordModify.java b/opends/src/server/org/opends/server/tools/LDAPPasswordModify.java
index 7c9a795..9ee5d04 100644
--- a/opends/src/server/org/opends/server/tools/LDAPPasswordModify.java
+++ b/opends/src/server/org/opends/server/tools/LDAPPasswordModify.java
@@ -32,22 +32,20 @@
 import java.io.OutputStream;
 import java.io.PrintStream;
 import java.util.ArrayList;
+import java.util.List;
 import java.util.concurrent.atomic.AtomicInteger;
 
 import org.opends.server.controls.PasswordPolicyErrorType;
 import org.opends.server.controls.PasswordPolicyResponseControl;
 import org.opends.server.controls.PasswordPolicyWarningType;
-import org.opends.server.protocols.asn1.ASN1Element;
-import org.opends.server.protocols.asn1.ASN1OctetString;
-import org.opends.server.protocols.asn1.ASN1Sequence;
+import org.opends.server.protocols.asn1.*;
 import org.opends.server.protocols.ldap.ExtendedRequestProtocolOp;
 import org.opends.server.protocols.ldap.ExtendedResponseProtocolOp;
 import org.opends.server.protocols.ldap.LDAPControl;
 import org.opends.server.protocols.ldap.LDAPMessage;
 import org.opends.server.protocols.ldap.LDAPResultCode;
 import org.opends.server.protocols.ldap.UnbindRequestProtocolOp;
-import org.opends.server.types.DN;
-import org.opends.server.types.NullOutputStream;
+import org.opends.server.types.*;
 import org.opends.server.util.EmbeddedUtils;
 import org.opends.server.util.args.ArgumentException;
 import org.opends.server.util.args.ArgumentParser;
@@ -565,7 +563,7 @@
 
 
     // If a control string was provided, then decode the requested controls.
-    ArrayList<LDAPControl> controls = new ArrayList<LDAPControl>();
+    ArrayList<Control> controls = new ArrayList<Control>();
     if(controlStr.isPresent())
     {
       for (String ctrlString : controlStr.getValues())
@@ -680,51 +678,58 @@
 
 
     // Construct the password modify request.
-    ArrayList<ASN1Element> requestElements = new ArrayList<ASN1Element>(3);
+    ByteStringBuilder builder = new ByteStringBuilder();
+    ASN1Writer asn1Writer = ASN1.getWriter(builder);
+
+    try
+    {
+    asn1Writer.writeStartSequence();
     if (authzID.isPresent())
     {
-      requestElements.add(new ASN1OctetString(TYPE_PASSWORD_MODIFY_USER_ID,
-                                              authzID.getValue()));
+      asn1Writer.writeOctetString(TYPE_PASSWORD_MODIFY_USER_ID,
+          authzID.getValue());
     }
     else if (provideDNForAuthzID.isPresent())
     {
-      requestElements.add(new ASN1OctetString(TYPE_PASSWORD_MODIFY_USER_ID,
-                                              "dn:" + dn));
+      asn1Writer.writeOctetString(TYPE_PASSWORD_MODIFY_USER_ID, "dn:" + dn);
     }
 
     if (currentPW.isPresent())
     {
-      requestElements.add(new ASN1OctetString(TYPE_PASSWORD_MODIFY_OLD_PASSWORD,
-                                              currentPW.getValue()));
+      asn1Writer.writeOctetString(TYPE_PASSWORD_MODIFY_OLD_PASSWORD,
+                                              currentPW.getValue());
     }
     else if (currentPWFile.isPresent())
     {
-      requestElements.add(new ASN1OctetString(TYPE_PASSWORD_MODIFY_OLD_PASSWORD,
-                                              currentPWFile.getValue()));
+      asn1Writer.writeOctetString(TYPE_PASSWORD_MODIFY_OLD_PASSWORD,
+                                              currentPWFile.getValue());
     }
     else if (provideDNForAuthzID.isPresent())
     {
-      requestElements.add(new ASN1OctetString(TYPE_PASSWORD_MODIFY_OLD_PASSWORD,
-                                              pw));
+      asn1Writer.writeOctetString(TYPE_PASSWORD_MODIFY_OLD_PASSWORD,
+                                              pw);
     }
 
     if (newPW.isPresent())
     {
-      requestElements.add(new ASN1OctetString(TYPE_PASSWORD_MODIFY_NEW_PASSWORD,
-                                              newPW.getValue()));
+      asn1Writer.writeOctetString(TYPE_PASSWORD_MODIFY_NEW_PASSWORD,
+                                              newPW.getValue());
     }
     else if (newPWFile.isPresent())
     {
-      requestElements.add(new ASN1OctetString(TYPE_PASSWORD_MODIFY_NEW_PASSWORD,
-                                              newPWFile.getValue()));
+      asn1Writer.writeOctetString(TYPE_PASSWORD_MODIFY_NEW_PASSWORD,
+                                              newPWFile.getValue());
     }
-
-    ASN1OctetString requestValue =
-         new ASN1OctetString(new ASN1Sequence(requestElements).encode());
+    asn1Writer.writeEndSequence();
+    }
+    catch(Exception e)
+    {
+      err.println(e);
+    }
 
     ExtendedRequestProtocolOp extendedRequest =
          new ExtendedRequestProtocolOp(OID_PASSWORD_MODIFY_REQUEST,
-                                       requestValue);
+                                       builder.toByteString());
     LDAPMessage requestMessage =
          new LDAPMessage(nextMessageID.getAndIncrement(), extendedRequest,
                          controls);
@@ -847,17 +852,18 @@
 
     // See if the response included any controls that we recognize, and if so
     // then handle them.
-    ArrayList<LDAPControl> responseControls = responseMessage.getControls();
+    List<Control> responseControls = responseMessage.getControls();
     if (responseControls != null)
     {
-      for (LDAPControl c : responseControls)
+      for (Control c : responseControls)
       {
         if (c.getOID().equals(OID_PASSWORD_POLICY_CONTROL))
         {
           try
           {
             PasswordPolicyResponseControl pwPolicyControl =
-                 PasswordPolicyResponseControl.decodeControl(c.getControl());
+              PasswordPolicyResponseControl.DECODER
+                .decode(c.isCritical(), ((LDAPControl) c).getValue());
 
             PasswordPolicyWarningType pwPolicyWarningType =
                  pwPolicyControl.getWarningType();
@@ -890,28 +896,29 @@
 
 
     // See if the response included a generated password.
-    ASN1OctetString responseValue = extendedResponse.getValue();
+    ByteString responseValue = extendedResponse.getValue();
     if (responseValue != null)
     {
       try
       {
-        ASN1Sequence responseSequence =
-             ASN1Sequence.decodeAsSequence(responseValue.value());
-        for (ASN1Element e : responseSequence.elements())
+        ASN1Reader asn1Reader = ASN1.getReader(responseValue);
+        asn1Reader.readStartSequence();
+        while(asn1Reader.hasNextElement())
         {
-          if (e.getType() == TYPE_PASSWORD_MODIFY_GENERATED_PASSWORD)
+          if (asn1Reader.peekType() == TYPE_PASSWORD_MODIFY_GENERATED_PASSWORD)
           {
             Message message = INFO_LDAPPWMOD_GENERATED_PASSWORD.get(
-                    e.decodeAsOctetString().stringValue());
+                    asn1Reader.readOctetStringAsString());
             out.println(wrapText(message, MAX_LINE_WIDTH));
           }
           else
           {
             Message message = ERR_LDAPPWMOD_UNRECOGNIZED_VALUE_TYPE.get(
-                    byteToHex(e.getType()));
+                    asn1Reader.readOctetStringAsString());
             err.println(wrapText(message, MAX_LINE_WIDTH));
           }
         }
+        asn1Reader.readEndSequence();
       }
       catch (Exception e)
       {
diff --git a/opends/src/server/org/opends/server/tools/LDAPReader.java b/opends/src/server/org/opends/server/tools/LDAPReader.java
index 5730e30..761cd83 100644
--- a/opends/src/server/org/opends/server/tools/LDAPReader.java
+++ b/opends/src/server/org/opends/server/tools/LDAPReader.java
@@ -22,17 +22,21 @@
  * CDDL HEADER END
  *
  *
- *      Copyright 2008 Sun Microsystems, Inc.
+ *      Copyright 2009 Sun Microsystems, Inc.
  */
 
 package org.opends.server.tools;
 
-import org.opends.server.protocols.asn1.ASN1Reader;
-import org.opends.server.protocols.asn1.ASN1Element;
-import org.opends.server.protocols.asn1.ASN1Exception;
-import org.opends.server.protocols.asn1.ASN1Sequence;
+import org.opends.server.protocols.asn1.*;
 import org.opends.server.protocols.ldap.LDAPMessage;
 import org.opends.server.types.LDAPException;
+import org.opends.server.types.DebugLogLevel;
+import org.opends.server.types.RecordingInputStream;
+import org.opends.server.types.ByteString;
+import static org.opends.server.loggers.debug.DebugLogger.debugEnabled;
+import static org.opends.server.loggers.debug.DebugLogger.getTracer;
+import org.opends.server.loggers.debug.DebugTracer;
+import org.opends.server.util.ServerConstants;
 
 import java.io.IOException;
 import java.net.Socket;
@@ -43,23 +47,14 @@
  */
 public class LDAPReader
 {
-  private ASN1Reader asn1Reader;
-  private VerboseTracer tracer;
-
   /**
-   * Creates a new LDAP reader that will read messages from the provided
-   * socket.
-   *
-   * @param  socket  The socket from which to read the LDAP messages.
-   *
-   * @throws  IOException  If a problem occurs while attempting to obtain an
-   *                       ASN.1 reader for the socket.
+   * The tracer object for the debug logger.
    */
-  public LDAPReader(Socket socket)
-       throws IOException
-  {
-    this(socket, null);
-  }
+  private static final DebugTracer TRACER = getTracer();
+
+  private Socket socket;
+  private ASN1Reader asn1Reader;
+  private RecordingInputStream debugInputStream;
 
   /**
    * Creates a new LDAP reader that will read messages from the provided
@@ -67,16 +62,15 @@
    *
    * @param  socket   The socket from which to read the LDAP messages.
    *
-   * @param  tracer   Specifies a tracer to be used for tracing messages read.
-   *
    * @throws  IOException  If a problem occurs while attempting to obtain an
    *                       input stream for the socket.
    */
-  public LDAPReader(Socket socket, VerboseTracer tracer)
+  public LDAPReader(Socket socket)
        throws IOException
   {
-    this.asn1Reader = new ASN1Reader(socket);
-    this.tracer = tracer;
+    this.socket = socket;
+    this.debugInputStream = new RecordingInputStream(socket.getInputStream());
+    this.asn1Reader = ASN1.getReader(debugInputStream);
   }
 
   /**
@@ -97,17 +91,31 @@
   public LDAPMessage readMessage()
        throws IOException, ASN1Exception, LDAPException
   {
-    ASN1Element element = asn1Reader.readElement();
-    if (element == null)
+    debugInputStream.setRecordingEnabled(debugEnabled());
+
+    if(!asn1Reader.hasNextElement())
     {
+      // EOF was reached...
       return null;
     }
 
-    ASN1Sequence sequence = ASN1Sequence.decodeAsSequence(element);
-    LDAPMessage message = LDAPMessage.decode(sequence);
-    if (tracer != null)
+    LDAPMessage message =
+        org.opends.server.protocols.ldap.LDAPReader.readMessage(asn1Reader);
+
+    if(debugInputStream.isRecordingEnabled())
     {
-      tracer.traceIncomingMessage(message, sequence);
+      ByteString bytesRead = debugInputStream.getRecordedBytes();
+      debugInputStream.clearRecordedBytes();
+
+      StringBuilder builder = new StringBuilder();
+      builder.append("bytes read from wire(len=");
+      builder.append(bytesRead.length());
+      builder.append("):");
+      builder.append(ServerConstants.EOL);
+      bytesRead.toHexPlusAscii(builder, 4);
+
+      TRACER.debugProtocolElement(DebugLogLevel.VERBOSE, builder.toString());
+      TRACER.debugProtocolElement(DebugLogLevel.VERBOSE, message.toString());
     }
 
     return message;
@@ -118,18 +126,31 @@
    */
   public void close()
   {
-    asn1Reader.close();
+    try
+    {
+      asn1Reader.close();
+    }
+    catch (Exception e)
+    {
+      if (debugEnabled())
+      {
+        TRACER.debugCaught(DebugLogLevel.ERROR, e);
+      }
+    }
+
+    if (socket != null)
+    {
+      try
+      {
+        socket.close();
+      }
+      catch (Exception e)
+      {
+        if (debugEnabled())
+        {
+          TRACER.debugCaught(DebugLogLevel.ERROR, e);
+        }
+      }
+    }
   }
-
-  /**
-   * Get the underlying ASN1 reader.
-   *
-   * @return  The underlying ASN1 reader.
-   */
-  public ASN1Reader getASN1Reader()
-  {
-    return asn1Reader;
-  }
-
-
 }
diff --git a/opends/src/server/org/opends/server/tools/LDAPSearch.java b/opends/src/server/org/opends/server/tools/LDAPSearch.java
index 0654882..ec98581 100644
--- a/opends/src/server/org/opends/server/tools/LDAPSearch.java
+++ b/opends/src/server/org/opends/server/tools/LDAPSearch.java
@@ -22,7 +22,7 @@
  * CDDL HEADER END
  *
  *
- *      Copyright 2006-2008 Sun Microsystems, Inc.
+ *      Copyright 2006-2009 Sun Microsystems, Inc.
  */
 package org.opends.server.tools;
 import org.opends.messages.Message;
@@ -32,24 +32,10 @@
 import java.io.IOException;
 import java.io.OutputStream;
 import java.io.PrintStream;
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.LinkedHashSet;
-import java.util.LinkedList;
-import java.util.StringTokenizer;
+import java.util.*;
 import java.util.concurrent.atomic.AtomicInteger;
 
-import org.opends.server.controls.AccountUsableResponseControl;
-import org.opends.server.controls.EntryChangeNotificationControl;
-import org.opends.server.controls.MatchedValuesControl;
-import org.opends.server.controls.MatchedValuesFilter;
-import org.opends.server.controls.PagedResultsControl;
-import org.opends.server.controls.PersistentSearchChangeType;
-import org.opends.server.controls.PersistentSearchControl;
-import org.opends.server.controls.ServerSideSortRequestControl;
-import org.opends.server.controls.ServerSideSortResponseControl;
-import org.opends.server.controls.VLVRequestControl;
-import org.opends.server.controls.VLVResponseControl;
+import org.opends.server.controls.*;
 import org.opends.server.util.Base64;
 import org.opends.server.util.EmbeddedUtils;
 import org.opends.server.util.PasswordReader;
@@ -59,10 +45,7 @@
 import org.opends.server.util.args.FileBasedArgument;
 import org.opends.server.util.args.IntegerArgument;
 import org.opends.server.util.args.StringArgument;
-import org.opends.server.protocols.asn1.ASN1Element;
 import org.opends.server.protocols.asn1.ASN1Exception;
-import org.opends.server.protocols.asn1.ASN1OctetString;
-import org.opends.server.protocols.asn1.ASN1Sequence;
 import org.opends.server.protocols.ldap.LDAPAttribute;
 import org.opends.server.protocols.ldap.LDAPControl;
 import org.opends.server.protocols.ldap.LDAPFilter;
@@ -84,8 +67,6 @@
 import static org.opends.server.tools.ToolConstants.*;
 
 
-
-
 /**
  * This class provides a tool that can be used to issue search requests to the
  * Directory Server.
@@ -105,7 +86,7 @@
 
 
   // The set of response controls for the search.
-  private ArrayList<LDAPControl> responseControls;
+  private List<Control> responseControls;
 
   // The message ID counter to use for requests.
   private AtomicInteger nextMessageID;
@@ -131,7 +112,7 @@
     this.nextMessageID = nextMessageID;
     this.out           = out;
     this.err           = err;
-    responseControls   = new ArrayList<LDAPControl>();
+    responseControls   = new ArrayList<Control>();
   }
 
 
@@ -165,7 +146,7 @@
 
     for (LDAPFilter filter: filters)
     {
-      ASN1OctetString asn1OctetStr = new ASN1OctetString(baseDN);
+      ByteString asn1OctetStr = ByteString.valueOf(baseDN);
 
       SearchRequestProtocolOp protocolOp =
         new SearchRequestProtocolOp(asn1OctetStr,
@@ -200,15 +181,15 @@
             switch(opType)
             {
               case OP_TYPE_SEARCH_RESULT_ENTRY:
-                for (LDAPControl c : responseControls)
+                for (Control c : responseControls)
                 {
                   if (c.getOID().equals(OID_ENTRY_CHANGE_NOTIFICATION))
                   {
                     try
                     {
                       EntryChangeNotificationControl ecn =
-                           EntryChangeNotificationControl.decodeControl(
-                                c.getControl());
+                        EntryChangeNotificationControl.DECODER
+                        .decode(c.isCritical(), ((LDAPControl) c).getValue());
 
                       out.println(INFO_LDAPSEARCH_PSEARCH_CHANGE_TYPE.get(
                               ecn.getChangeType().toString()));
@@ -226,8 +207,8 @@
                     try
                     {
                       AccountUsableResponseControl acrc =
-                           AccountUsableResponseControl.decodeControl(
-                                c.getControl());
+                        AccountUsableResponseControl.DECODER
+                        .decode(c.isCritical(), ((LDAPControl) c).getValue());
 
                       out.println(INFO_LDAPSEARCH_ACCTUSABLE_HEADER.get());
                       if (acrc.isUsable())
@@ -315,15 +296,15 @@
                 errorMessage = searchOp.getErrorMessage();
                 matchedDN = searchOp.getMatchedDN();
 
-                for (LDAPControl c : responseMessage.getControls())
+                for (Control c : responseMessage.getControls())
                 {
                   if (c.getOID().equals(OID_SERVER_SIDE_SORT_RESPONSE_CONTROL))
                   {
                     try
                     {
                       ServerSideSortResponseControl sortResponse =
-                           ServerSideSortResponseControl.decodeControl(
-                                c.getControl());
+                        ServerSideSortResponseControl.DECODER
+                        .decode(c.isCritical(), ((LDAPControl) c).getValue());
                       int rc = sortResponse.getResultCode();
                       if (rc != LDAPResultCode.SUCCESS)
                       {
@@ -345,7 +326,8 @@
                     try
                     {
                       VLVResponseControl vlvResponse =
-                           VLVResponseControl.decodeControl(c.getControl());
+                          VLVResponseControl.DECODER.decode(c.isCritical(),
+                              ((LDAPControl) c).getValue());
                       int rc = vlvResponse.getVLVResultCode();
                       if (rc == LDAPResultCode.SUCCESS)
                       {
@@ -493,19 +475,19 @@
           buffer.append(EOL);
       } else
       {
-        for (ASN1OctetString v : a.getValues())
+        for (ByteString v : a.getValues())
         {
           String valueString;
-          if (needsBase64Encoding(v.value()))
+          if (needsBase64Encoding(v))
           {
-            valueString = Base64.encode(v.value());
+            valueString = Base64.encode(v);
             buffer.append(name);
             buffer.append(":: ");
 
             colsRemaining = wrapColumn - nameLength - 3;
           } else
           {
-            valueString = v.stringValue();
+            valueString = v.toString();
             buffer.append(name);
             buffer.append(": ");
 
@@ -557,7 +539,7 @@
    * @return  The set of response controls included in the last search result
    *          done message.
    */
-  public ArrayList<LDAPControl> getResponseControls()
+  public List<Control> getResponseControls()
   {
     return responseControls;
   }
@@ -1273,7 +1255,7 @@
     {
       for (String ctrlString : controlStr.getValues())
       {
-        LDAPControl ctrl = LDAPToolUtils.getControl(ctrlString, err);
+        Control ctrl = LDAPToolUtils.getControl(ctrlString, err);
         if(ctrl == null)
         {
           Message message = ERR_TOOL_INVALID_CONTROL_STRING.get(ctrlString);
@@ -1293,31 +1275,17 @@
         err.println(argParser.getUsage());
         return 1;
       }
-      ASN1OctetString v=null;
-      ASN1OctetString effectiveRightsUserVal =
-              new ASN1OctetString(authzID);
-      ASN1Sequence sequence=null;
-      ArrayList<ASN1Element> attrElements =
-              new ArrayList<ASN1Element>();
-      for(String a : effectiveRightsAttrs.getValues())
-        attrElements.add(new ASN1OctetString(a));
-      ASN1Sequence attrSeq=new ASN1Sequence(attrElements);
-      ArrayList<ASN1Element> elements = new ArrayList<ASN1Element>(2);
-      elements.add(effectiveRightsUserVal);
-      elements.add(attrSeq);
-      sequence= new ASN1Sequence(elements);
-      LDAPControl effectiveRightsControl =
-              new LDAPControl(OID_GET_EFFECTIVE_RIGHTS, false,
-                      new ASN1OctetString(sequence.encode()));
+      Control effectiveRightsControl =
+          new GetEffectiveRightsRequestControl(false, authzID.substring(3),
+              effectiveRightsAttrs.getValues());
       searchOptions.getControls().add(effectiveRightsControl);
     }
 
     if (proxyAuthzID.isPresent())
     {
-      ASN1OctetString proxyValue = new ASN1OctetString(proxyAuthzID.getValue());
-
-      LDAPControl proxyControl =
-        new LDAPControl(OID_PROXIED_AUTH_V2, true, proxyValue);
+      Control proxyControl =
+          new ProxiedAuthV2Control(true,
+              ByteString.valueOf(proxyAuthzID.getValue()));
       searchOptions.getControls().add(proxyControl);
     }
 
@@ -1441,7 +1409,7 @@
 
       PersistentSearchControl psearchControl =
            new PersistentSearchControl(changeTypes, changesOnly, returnECs);
-      searchOptions.getControls().add(new LDAPControl(psearchControl));
+      searchOptions.getControls().add(psearchControl);
     }
 
     if (assertionFilter.isPresent())
@@ -1454,9 +1422,8 @@
 
         // FIXME -- Change this to the correct OID when the official one is
         //          assigned.
-        LDAPControl assertionControl =
-             new LDAPControl(OID_LDAP_ASSERTION, true,
-                             new ASN1OctetString(filter.encode().encode()));
+        Control assertionControl =
+            new LDAPAssertionRequestControl(true, filter);
         searchOptions.getControls().add(assertionControl);
       }
       catch (LDAPException le)
@@ -1490,7 +1457,7 @@
       }
 
       MatchedValuesControl mvc = new MatchedValuesControl(true, mvFilters);
-      searchOptions.getControls().add(new LDAPControl(mvc));
+      searchOptions.getControls().add(mvc);
     }
 
     if (sortOrder.isPresent())
@@ -1498,8 +1465,7 @@
       try
       {
         searchOptions.getControls().add(
-             new LDAPControl(new ServerSideSortRequestControl(
-                                      sortOrder.getValue())));
+            new ServerSideSortRequestControl(sortOrder.getValue()));
       }
       catch (LDAPException le)
       {
@@ -1530,11 +1496,9 @@
         {
           int beforeCount = Integer.parseInt(tokenizer.nextToken());
           int afterCount  = Integer.parseInt(tokenizer.nextToken());
-          ASN1OctetString assertionValue =
-               new ASN1OctetString(tokenizer.nextToken());
+          ByteString assertionValue = ByteString.valueOf(tokenizer.nextToken());
           searchOptions.getControls().add(
-               new LDAPControl(new VLVRequestControl(beforeCount, afterCount,
-                                                     assertionValue)));
+              new VLVRequestControl(beforeCount, afterCount, assertionValue));
         }
         catch (Exception e)
         {
@@ -1552,8 +1516,8 @@
           int offset       = Integer.parseInt(tokenizer.nextToken());
           int contentCount = Integer.parseInt(tokenizer.nextToken());
           searchOptions.getControls().add(
-               new LDAPControl(new VLVRequestControl(beforeCount, afterCount,
-                                                     offset, contentCount)));
+              new VLVRequestControl(beforeCount, afterCount, offset,
+                  contentCount));
         }
         catch (Exception e)
         {
@@ -1725,16 +1689,15 @@
         }
 
         int pageSize = simplePageSize.getIntValue();
-        ASN1OctetString cookieValue = new ASN1OctetString();
-        ArrayList<LDAPControl> origControls = searchOptions.getControls();
+        ByteString cookieValue = null;
+        ArrayList<Control> origControls = searchOptions.getControls();
 
         while (true)
         {
-          ArrayList<LDAPControl> newControls =
-               new ArrayList<LDAPControl>(origControls.size()+1);
+          ArrayList<Control> newControls =
+               new ArrayList<Control>(origControls.size()+1);
           newControls.addAll(origControls);
-          newControls.add(new LDAPControl(
-               new PagedResultsControl(true, pageSize, cookieValue)));
+          newControls.add(new PagedResultsControl(true, pageSize, cookieValue));
           searchOptions.setControls(newControls);
 
           ldapSearch = new LDAPSearch(nextMessageID, out, err);
@@ -1743,27 +1706,27 @@
                                                       searchOptions,
                                                       wrapColumn);
 
-          ArrayList<LDAPControl> responseControls =
+          List<Control> responseControls =
                ldapSearch.getResponseControls();
           boolean responseFound = false;
-          for (LDAPControl c  :responseControls)
+          for (Control c : responseControls)
           {
             if (c.getOID().equals(OID_PAGED_RESULTS_CONTROL))
             {
               try
               {
-                PagedResultsControl control =
-                     new PagedResultsControl(c.isCritical(), c.getValue());
+                PagedResultsControl control = PagedResultsControl.DECODER
+                    .decode(c.isCritical(), ((LDAPControl) c).getValue());
                 responseFound = true;
                 cookieValue = control.getCookie();
                 break;
               }
-              catch (LDAPException le)
+              catch (DirectoryException de)
               {
                 Message message =
-                    ERR_PAGED_RESULTS_CANNOT_DECODE.get(le.getMessage());
+                    ERR_PAGED_RESULTS_CANNOT_DECODE.get(de.getMessage());
                 throw new LDAPException(
-                        CLIENT_SIDE_DECODING_ERROR, message, le);
+                        CLIENT_SIDE_DECODING_ERROR, message, de);
               }
             }
           }
@@ -1773,7 +1736,7 @@
             Message message = ERR_PAGED_RESULTS_RESPONSE_NOT_FOUND.get();
             throw new LDAPException(CLIENT_SIDE_CONTROL_NOT_FOUND, message);
           }
-          else if (cookieValue.value().length == 0)
+          else if (cookieValue.length() == 0)
           {
             break;
           }
diff --git a/opends/src/server/org/opends/server/tools/LDAPToolOptions.java b/opends/src/server/org/opends/server/tools/LDAPToolOptions.java
index 51b03ec..763f99f 100644
--- a/opends/src/server/org/opends/server/tools/LDAPToolOptions.java
+++ b/opends/src/server/org/opends/server/tools/LDAPToolOptions.java
@@ -27,9 +27,7 @@
 package org.opends.server.tools;
 
 import java.util.ArrayList;
-import org.opends.server.protocols.ldap.LDAPControl;
-
-
+import org.opends.server.types.Control;
 
 
 /**
@@ -43,7 +41,7 @@
   private boolean verbose = false;
   private boolean continueOnError = false;
   private String encoding = System.getProperty("file.encoding");
-  private ArrayList<LDAPControl> controls = new ArrayList<LDAPControl>();
+  private ArrayList<Control> controls = new ArrayList<Control>();
 
   /**
    * Creates a the tool options instance.
@@ -128,7 +126,7 @@
    *
    * @return  The controls to apply to the operation.
    */
-  public ArrayList<LDAPControl> getControls()
+  public ArrayList<Control> getControls()
   {
     return controls;
   }
@@ -138,7 +136,7 @@
    *
    * @param  controls  The set of controls to apply to the operation.
    */
-  public void setControls(ArrayList<LDAPControl> controls)
+  public void setControls(ArrayList<Control> controls)
   {
     this.controls = controls;
   }
diff --git a/opends/src/server/org/opends/server/tools/LDAPToolUtils.java b/opends/src/server/org/opends/server/tools/LDAPToolUtils.java
index dc0ba70..519b4c3 100644
--- a/opends/src/server/org/opends/server/tools/LDAPToolUtils.java
+++ b/opends/src/server/org/opends/server/tools/LDAPToolUtils.java
@@ -32,10 +32,10 @@
 import java.io.IOException;
 import java.io.PrintStream;
 
-import org.opends.server.protocols.asn1.ASN1OctetString;
 import org.opends.server.protocols.ldap.LDAPControl;
 import org.opends.server.protocols.ldap.LDAPResultCode;
 import org.opends.server.types.DN;
+import org.opends.server.types.ByteString;
 
 import static org.opends.messages.ToolMessages.*;
 import static org.opends.server.util.ServerConstants.*;
@@ -68,7 +68,7 @@
     LDAPControl control = null;
     String controlOID = null;
     boolean controlCriticality = false;
-    ASN1OctetString controlValue = null;
+    ByteString controlValue = null;
 
     int idx = argString.indexOf(":");
 
@@ -170,7 +170,7 @@
     if(valString.charAt(0) == ':')
     {
       controlValue =
-           new ASN1OctetString(valString.substring(1, valString.length()));
+          ByteString.valueOf(valString.substring(1, valString.length()));
     } else if(valString.charAt(0) == '<')
     {
       // Read data from the file.
@@ -178,7 +178,7 @@
       try
       {
         byte[] val = readBytesFromFile(filePath, err);
-        controlValue = new ASN1OctetString(val);
+        controlValue = ByteString.wrap(val);
       }
       catch (Exception e)
       {
@@ -186,7 +186,7 @@
       }
     } else
     {
-      controlValue = new ASN1OctetString(valString);
+      controlValue = ByteString.valueOf(valString);
     }
 
     control = new LDAPControl(controlOID, controlCriticality, controlValue);
diff --git a/opends/src/server/org/opends/server/tools/LDAPWriter.java b/opends/src/server/org/opends/server/tools/LDAPWriter.java
index 7835bea..7293dfb 100644
--- a/opends/src/server/org/opends/server/tools/LDAPWriter.java
+++ b/opends/src/server/org/opends/server/tools/LDAPWriter.java
@@ -22,14 +22,21 @@
  * CDDL HEADER END
  *
  *
- *      Copyright 2008 Sun Microsystems, Inc.
+ *      Copyright 2009 Sun Microsystems, Inc.
  */
 
 package org.opends.server.tools;
 
 import org.opends.server.protocols.asn1.ASN1Writer;
-import org.opends.server.protocols.asn1.ASN1Element;
+import org.opends.server.protocols.asn1.ASN1;
 import org.opends.server.protocols.ldap.LDAPMessage;
+import static org.opends.server.loggers.debug.DebugLogger.debugEnabled;
+import static org.opends.server.loggers.debug.DebugLogger.getTracer;
+import org.opends.server.loggers.debug.DebugTracer;
+import org.opends.server.types.DebugLogLevel;
+import org.opends.server.types.RecordingOutputStream;
+import org.opends.server.types.ByteString;
+import org.opends.server.util.ServerConstants;
 
 import java.net.Socket;
 import java.io.IOException;
@@ -40,23 +47,14 @@
  */
 public class LDAPWriter
 {
-  ASN1Writer asn1Writer;
-  VerboseTracer tracer;
-
   /**
-   * Creates a new LDAP writer that will write messages to the provided
-   * socket.
-   *
-   * @param  socket  The socket to use to write LDAP messages.
-   *
-   * @throws  IOException  If a problem occurs while attempting to obtain an
-   *                       ASN.1 reader for the socket.
+   * The tracer object for the debug logger.
    */
-  public LDAPWriter(Socket socket)
-       throws IOException
-  {
-    this(socket, null);
-  }
+  private static final DebugTracer TRACER = getTracer();
+
+  Socket socket;
+  ASN1Writer asn1Writer;
+  private RecordingOutputStream debugOutputStream;
 
 
   /**
@@ -65,16 +63,16 @@
    *
    * @param  socket  The socket to use to write LDAP messages.
    *
-   * @param  tracer  Specifies a tracer to be used for tracing messages written.
-   *
    * @throws  IOException  If a problem occurs while attempting to obtain an
    *                       output stream for the socket.
    */
-  public LDAPWriter(Socket socket, VerboseTracer tracer)
+  public LDAPWriter(Socket socket)
        throws IOException
   {
-    this.asn1Writer = new ASN1Writer(socket);
-    this.tracer = tracer;
+    this.socket = socket;
+    this.debugOutputStream =
+        new RecordingOutputStream(socket.getOutputStream());
+    this.asn1Writer = ASN1.getWriter(debugOutputStream);
   }
 
   /**
@@ -88,12 +86,28 @@
   public void writeMessage(LDAPMessage message)
        throws IOException
   {
-    ASN1Element element = message.encode();
-    if (tracer != null)
+    if(debugEnabled())
     {
-      tracer.traceOutgoingMessage(message, element);
+      TRACER.debugProtocolElement(DebugLogLevel.VERBOSE, message.toString());
+      debugOutputStream.setRecordingEnabled(true);
     }
-    asn1Writer.writeElement(element);
+
+    message.write(asn1Writer);
+
+    if(debugOutputStream.isRecordingEnabled())
+    {
+      ByteString bytesRead = debugOutputStream.getRecordedBytes();
+      debugOutputStream.clearRecordedBytes();
+
+      StringBuilder builder = new StringBuilder();
+      builder.append("bytes written to wire(len=");
+      builder.append(bytesRead.length());
+      builder.append("):");
+      builder.append(ServerConstants.EOL);
+      bytesRead.toHexPlusAscii(builder, 4);
+
+      TRACER.debugProtocolElement(DebugLogLevel.VERBOSE, builder.toString());
+    }
   }
 
   /**
@@ -101,17 +115,32 @@
    */
   public void close()
   {
-    asn1Writer.close();
-  }
+    try
+    {
+      asn1Writer.close();
+    }
+    catch (Exception e)
+    {
+      if (debugEnabled())
+      {
+        TRACER.debugCaught(DebugLogLevel.ERROR, e);
+      }
+    }
 
-  /**
-   * Get the underlying ASN1 writer.
-   *
-   * @return  The underlying ASN1 writer.
-   */
-  public ASN1Writer getASN1Writer()
-  {
-    return asn1Writer;
-  }
 
+    if (socket != null)
+    {
+      try
+      {
+        socket.close();
+      }
+      catch (Exception e)
+      {
+        if (debugEnabled())
+        {
+          TRACER.debugCaught(DebugLogLevel.ERROR, e);
+        }
+      }
+    }
+  }
 }
diff --git a/opends/src/server/org/opends/server/tools/LDIFDiff.java b/opends/src/server/org/opends/server/tools/LDIFDiff.java
index a5ca4ec..0c4764c 100644
--- a/opends/src/server/org/opends/server/tools/LDIFDiff.java
+++ b/opends/src/server/org/opends/server/tools/LDIFDiff.java
@@ -44,20 +44,7 @@
 import org.opends.server.core.DirectoryServer;
 import org.opends.server.extensions.ConfigFileHandler;
 import org.opends.server.protocols.ldap.LDAPResultCode;
-import org.opends.server.types.Attribute;
-import org.opends.server.types.AttributeBuilder;
-import org.opends.server.types.AttributeType;
-import org.opends.server.types.AttributeValue;
-import org.opends.server.types.DN;
-import org.opends.server.types.DirectoryException;
-import org.opends.server.types.Entry;
-import org.opends.server.types.ExistingFileBehavior;
-import org.opends.server.types.LDIFImportConfig;
-import org.opends.server.types.LDIFExportConfig;
-import org.opends.server.types.Modification;
-import org.opends.server.types.ModificationType;
-import org.opends.server.types.NullOutputStream;
-import org.opends.server.types.ObjectClass;
+import org.opends.server.types.*;
 import org.opends.server.util.LDIFReader;
 import org.opends.server.util.LDIFWriter;
 import org.opends.server.util.args.ArgumentException;
@@ -824,7 +811,7 @@
       AttributeBuilder builder = new AttributeBuilder(attrType);
       for (ObjectClass oc : sourceClasses)
       {
-        builder.add(new AttributeValue(attrType, oc.getNameOrOID()));
+        builder.add(AttributeValues.create(attrType, oc.getNameOrOID()));
       }
 
       modifications.add(new Modification(ModificationType.DELETE, builder
@@ -838,7 +825,7 @@
       AttributeBuilder builder = new AttributeBuilder(attrType);
       for (ObjectClass oc : targetClasses)
       {
-        builder.add(new AttributeValue(attrType, oc.getNameOrOID()));
+        builder.add(AttributeValues.create(attrType, oc.getNameOrOID()));
       }
 
       modifications.add(new Modification(ModificationType.ADD, builder
diff --git a/opends/src/server/org/opends/server/tools/LDIFModify.java b/opends/src/server/org/opends/server/tools/LDIFModify.java
index 63edb09..07648a9 100644
--- a/opends/src/server/org/opends/server/tools/LDIFModify.java
+++ b/opends/src/server/org/opends/server/tools/LDIFModify.java
@@ -332,7 +332,7 @@
         {
           for (AttributeValue v : a)
           {
-            String stringValue = v.getStringValue();
+            String stringValue = v.getValue().toString();
             String lowerValue  = toLowerCase(stringValue);
             ObjectClass oc = DirectoryServer.getObjectClass(lowerValue, true);
             objectClasses.put(oc, stringValue);
diff --git a/opends/src/server/org/opends/server/tools/ManageAccount.java b/opends/src/server/org/opends/server/tools/ManageAccount.java
index 73dca13..10cb1c0 100644
--- a/opends/src/server/org/opends/server/tools/ManageAccount.java
+++ b/opends/src/server/org/opends/server/tools/ManageAccount.java
@@ -32,20 +32,21 @@
 
 import java.io.OutputStream;
 import java.io.PrintStream;
+import java.io.IOException;
 import java.util.ArrayList;
 import java.util.LinkedList;
 import java.util.HashSet;
 import java.util.concurrent.atomic.AtomicInteger;
 
 import javax.net.ssl.SSLException;
-import org.opends.server.protocols.asn1.ASN1Element;
-import org.opends.server.protocols.asn1.ASN1OctetString;
-import org.opends.server.protocols.asn1.ASN1Sequence;
+
+import org.opends.server.protocols.asn1.*;
 import org.opends.server.protocols.ldap.ExtendedRequestProtocolOp;
 import org.opends.server.protocols.ldap.ExtendedResponseProtocolOp;
 import org.opends.server.protocols.ldap.LDAPMessage;
 import org.opends.server.protocols.ldap.LDAPResultCode;
 import org.opends.server.types.NullOutputStream;
+import org.opends.server.types.ByteStringBuilder;
 import org.opends.server.util.args.Argument;
 import org.opends.server.util.args.ArgumentException;
 import org.opends.server.util.args.BooleanArgument;
@@ -569,28 +570,35 @@
 
     try
     {
-      // Use the subcommand provided to figure out how to encode the request.
-      ArrayList<ASN1Element> opElements = new ArrayList<ASN1Element>(1);
-      result = processSubcommand(opElements);
-      if (result != LDAPResultCode.SUCCESS)
+      ByteStringBuilder builder = new ByteStringBuilder();
+      ASN1Writer writer = ASN1.getWriter(builder);
+
+      try
       {
-        return result;
+        writer.writeStartSequence();
+        writer.writeOctetString(targetDNString);
+
+        // Use the subcommand provided to figure out how to encode the request.
+        writer.writeStartSequence();
+        result = processSubcommand(writer);
+        if (result != LDAPResultCode.SUCCESS)
+        {
+          return result;
+        }
+        writer.writeEndSequence();
+
+        writer.writeEndSequence();
+      }
+      catch(Exception e)
+      {
+        // TODO: Better message
+        err.println(e);
       }
 
 
-      // Generate the extended request and send it to the server.
-      ArrayList<ASN1Element> valueElements = new ArrayList<ASN1Element>(2);
-      valueElements.add(new ASN1OctetString(targetDNString));
-      if (! opElements.isEmpty())
-      {
-        valueElements.add(new ASN1Sequence(opElements));
-      }
-      ASN1OctetString requestValue =
-           new ASN1OctetString(new ASN1Sequence(valueElements).encode());
-
       ExtendedRequestProtocolOp extendedRequest =
            new ExtendedRequestProtocolOp(OID_PASSWORD_POLICY_STATE_EXTOP,
-                                         requestValue);
+                                         builder.toByteString());
 
       LDAPMessage requestMessage =
            new LDAPMessage(nextMessageID.getAndIncrement(), extendedRequest);
@@ -609,7 +617,6 @@
 
 
       // Read the response from the server.
-      ArrayList<ASN1Element> responseOpElements;
       try
       {
         LDAPMessage responseMessage = ldapReader.readMessage();
@@ -635,169 +642,174 @@
           return resultCode;
         }
 
-        ASN1Sequence valueSequence =
-             ASN1Sequence.decodeAsSequence(extendedResponse.getValue().value());
-        responseOpElements =
-             valueSequence.elements().get(1).decodeAsSequence().elements();
+        ASN1Reader reader = ASN1.getReader(extendedResponse.getValue());
+        reader.readStartSequence();
+
+        // Skip the target user DN element
+        reader.skipElement();
+        reader.readStartSequence();
+
+        while(reader.hasNextElement())
+        {
+          // Get the response value and parse its individual elements.
+          int opType;
+          ArrayList<String> opValues;
+
+          try
+          {
+            reader.readStartSequence();
+            opType = (int)reader.readInteger();
+            opValues = new ArrayList<String>();
+            if (reader.hasNextElement())
+            {
+              reader.readStartSequence();
+              while(reader.hasNextElement())
+              {
+                opValues.add(reader.readOctetStringAsString());
+              }
+              reader.readEndSequence();
+            }
+            reader.readEndSequence();
+          }
+          catch (Exception e)
+          {
+            Message message = ERR_PWPSTATE_CANNOT_DECODE_RESPONSE_OP.get(
+                getExceptionMessage(e));
+            err.println(wrapText(message, MAX_LINE_WIDTH));
+            continue;
+          }
+
+          switch (opType)
+          {
+            case OP_GET_PASSWORD_POLICY_DN:
+              Message message = INFO_PWPSTATE_LABEL_PASSWORD_POLICY_DN.get();
+              printLabelAndValues(message, opValues);
+              break;
+
+            case OP_GET_ACCOUNT_DISABLED_STATE:
+              message = INFO_PWPSTATE_LABEL_ACCOUNT_DISABLED_STATE.get();
+              printLabelAndValues(message, opValues);
+              break;
+
+            case OP_GET_ACCOUNT_EXPIRATION_TIME:
+              message = INFO_PWPSTATE_LABEL_ACCOUNT_EXPIRATION_TIME.get();
+              printLabelAndValues(message, opValues);
+              break;
+
+            case OP_GET_SECONDS_UNTIL_ACCOUNT_EXPIRATION:
+              message =
+                  INFO_PWPSTATE_LABEL_SECONDS_UNTIL_ACCOUNT_EXPIRATION.get();
+              printLabelAndValues(message, opValues);
+              break;
+
+            case OP_GET_PASSWORD_CHANGED_TIME:
+              message = INFO_PWPSTATE_LABEL_PASSWORD_CHANGED_TIME.get();
+              printLabelAndValues(message, opValues);
+              break;
+
+            case OP_GET_PASSWORD_EXPIRATION_WARNED_TIME:
+              message =
+                  INFO_PWPSTATE_LABEL_PASSWORD_EXPIRATION_WARNED_TIME.get();
+              printLabelAndValues(message, opValues);
+              break;
+
+            case OP_GET_SECONDS_UNTIL_PASSWORD_EXPIRATION:
+              message =
+                  INFO_PWPSTATE_LABEL_SECONDS_UNTIL_PASSWORD_EXPIRATION.get();
+              printLabelAndValues(message, opValues);
+              break;
+
+            case OP_GET_SECONDS_UNTIL_PASSWORD_EXPIRATION_WARNING:
+              message =
+                  INFO_PWPSTATE_LABEL_SECONDS_UNTIL_PASSWORD_EXPIRATION_WARNING
+                      .get();
+              printLabelAndValues(message, opValues);
+              break;
+
+            case OP_GET_AUTHENTICATION_FAILURE_TIMES:
+              message = INFO_PWPSTATE_LABEL_AUTH_FAILURE_TIMES.get();
+              printLabelAndValues(message, opValues);
+              break;
+
+            case OP_GET_SECONDS_UNTIL_AUTHENTICATION_FAILURE_UNLOCK:
+              message =
+                  INFO_PWPSTATE_LABEL_SECONDS_UNTIL_AUTH_FAILURE_UNLOCK.get();
+              printLabelAndValues(message, opValues);
+              break;
+
+            case OP_GET_REMAINING_AUTHENTICATION_FAILURE_COUNT:
+              message = INFO_PWPSTATE_LABEL_REMAINING_AUTH_FAILURE_COUNT.get();
+              printLabelAndValues(message, opValues);
+              break;
+
+            case OP_GET_LAST_LOGIN_TIME:
+              message = INFO_PWPSTATE_LABEL_LAST_LOGIN_TIME.get();
+              printLabelAndValues(message, opValues);
+              break;
+
+            case OP_GET_SECONDS_UNTIL_IDLE_LOCKOUT:
+              message = INFO_PWPSTATE_LABEL_SECONDS_UNTIL_IDLE_LOCKOUT.get();
+              printLabelAndValues(message, opValues);
+              break;
+
+            case OP_GET_PASSWORD_RESET_STATE:
+              message = INFO_PWPSTATE_LABEL_PASSWORD_RESET_STATE.get();
+              printLabelAndValues(message, opValues);
+              break;
+
+            case OP_GET_SECONDS_UNTIL_PASSWORD_RESET_LOCKOUT:
+              message =
+                  INFO_PWPSTATE_LABEL_SECONDS_UNTIL_PASSWORD_RESET_LOCKOUT
+                      .get();
+              printLabelAndValues(message, opValues);
+              break;
+
+            case OP_GET_GRACE_LOGIN_USE_TIMES:
+              message = INFO_PWPSTATE_LABEL_GRACE_LOGIN_USE_TIMES.get();
+              printLabelAndValues(message, opValues);
+              break;
+
+            case OP_GET_REMAINING_GRACE_LOGIN_COUNT:
+              message = INFO_PWPSTATE_LABEL_REMAINING_GRACE_LOGIN_COUNT.get();
+              printLabelAndValues(message, opValues);
+              break;
+
+            case OP_GET_PASSWORD_CHANGED_BY_REQUIRED_TIME:
+              message =
+                  INFO_PWPSTATE_LABEL_PASSWORD_CHANGED_BY_REQUIRED_TIME.get();
+              printLabelAndValues(message, opValues);
+              break;
+
+            case OP_GET_SECONDS_UNTIL_REQUIRED_CHANGE_TIME:
+              message =
+                  INFO_PWPSTATE_LABEL_SECONDS_UNTIL_REQUIRED_CHANGE_TIME
+                      .get();
+              printLabelAndValues(message, opValues);
+              break;
+
+            case OP_GET_PASSWORD_HISTORY:
+              message = INFO_PWPSTATE_LABEL_PASSWORD_HISTORY.get();
+              printLabelAndValues(message, opValues);
+              break;
+
+            default:
+              message = ERR_PWPSTATE_INVALID_RESPONSE_OP_TYPE.get(
+                  String.valueOf(opType));
+              err.println(wrapText(message, MAX_LINE_WIDTH));
+              break;
+          }
+        }
+        reader.readEndSequence();
+        reader.readEndSequence();
       }
       catch (Exception e)
       {
         Message message = ERR_PWPSTATE_CANNOT_DECODE_RESPONSE_MESSAGE.get(
-                getExceptionMessage(e));
+            getExceptionMessage(e));
         err.println(wrapText(message, MAX_LINE_WIDTH));
         return LDAPResultCode.CLIENT_SIDE_SERVER_DOWN;
       }
 
-
-      // Get the response value and parse its individual elements.
-      for (ASN1Element opElement : responseOpElements)
-      {
-        int opType;
-        ArrayList<String> opValues;
-
-        try
-        {
-          ASN1Sequence opSequence = opElement.decodeAsSequence();
-          ArrayList<ASN1Element> elements = opSequence.elements();
-          opType = elements.get(0).decodeAsEnumerated().intValue();
-          opValues = new ArrayList<String>();
-          if (elements.size() == 2)
-          {
-            for (ASN1Element e : elements.get(1).decodeAsSequence().elements())
-            {
-              opValues.add(e.decodeAsOctetString().stringValue());
-            }
-          }
-        }
-        catch (Exception e)
-        {
-          Message message = ERR_PWPSTATE_CANNOT_DECODE_RESPONSE_OP.get(
-                  getExceptionMessage(e));
-          err.println(wrapText(message, MAX_LINE_WIDTH));
-          continue;
-        }
-
-        switch (opType)
-        {
-          case OP_GET_PASSWORD_POLICY_DN:
-            Message message = INFO_PWPSTATE_LABEL_PASSWORD_POLICY_DN.get();
-            printLabelAndValues(message, opValues);
-            break;
-
-          case OP_GET_ACCOUNT_DISABLED_STATE:
-            message = INFO_PWPSTATE_LABEL_ACCOUNT_DISABLED_STATE.get();
-            printLabelAndValues(message, opValues);
-            break;
-
-          case OP_GET_ACCOUNT_EXPIRATION_TIME:
-            message = INFO_PWPSTATE_LABEL_ACCOUNT_EXPIRATION_TIME.get();
-            printLabelAndValues(message, opValues);
-            break;
-
-          case OP_GET_SECONDS_UNTIL_ACCOUNT_EXPIRATION:
-            message =
-                    INFO_PWPSTATE_LABEL_SECONDS_UNTIL_ACCOUNT_EXPIRATION.get();
-            printLabelAndValues(message, opValues);
-            break;
-
-          case OP_GET_PASSWORD_CHANGED_TIME:
-            message = INFO_PWPSTATE_LABEL_PASSWORD_CHANGED_TIME.get();
-            printLabelAndValues(message, opValues);
-            break;
-
-          case OP_GET_PASSWORD_EXPIRATION_WARNED_TIME:
-            message = INFO_PWPSTATE_LABEL_PASSWORD_EXPIRATION_WARNED_TIME.get();
-            printLabelAndValues(message, opValues);
-            break;
-
-          case OP_GET_SECONDS_UNTIL_PASSWORD_EXPIRATION:
-            message =
-                    INFO_PWPSTATE_LABEL_SECONDS_UNTIL_PASSWORD_EXPIRATION.get();
-            printLabelAndValues(message, opValues);
-            break;
-
-          case OP_GET_SECONDS_UNTIL_PASSWORD_EXPIRATION_WARNING:
-            message =
-                  INFO_PWPSTATE_LABEL_SECONDS_UNTIL_PASSWORD_EXPIRATION_WARNING
-                          .get();
-            printLabelAndValues(message, opValues);
-            break;
-
-          case OP_GET_AUTHENTICATION_FAILURE_TIMES:
-            message = INFO_PWPSTATE_LABEL_AUTH_FAILURE_TIMES.get();
-            printLabelAndValues(message, opValues);
-            break;
-
-          case OP_GET_SECONDS_UNTIL_AUTHENTICATION_FAILURE_UNLOCK:
-            message =
-                    INFO_PWPSTATE_LABEL_SECONDS_UNTIL_AUTH_FAILURE_UNLOCK.get();
-            printLabelAndValues(message, opValues);
-            break;
-
-          case OP_GET_REMAINING_AUTHENTICATION_FAILURE_COUNT:
-            message = INFO_PWPSTATE_LABEL_REMAINING_AUTH_FAILURE_COUNT.get();
-            printLabelAndValues(message, opValues);
-            break;
-
-          case OP_GET_LAST_LOGIN_TIME:
-            message = INFO_PWPSTATE_LABEL_LAST_LOGIN_TIME.get();
-            printLabelAndValues(message, opValues);
-            break;
-
-          case OP_GET_SECONDS_UNTIL_IDLE_LOCKOUT:
-            message = INFO_PWPSTATE_LABEL_SECONDS_UNTIL_IDLE_LOCKOUT.get();
-            printLabelAndValues(message, opValues);
-            break;
-
-          case OP_GET_PASSWORD_RESET_STATE:
-            message = INFO_PWPSTATE_LABEL_PASSWORD_RESET_STATE.get();
-            printLabelAndValues(message, opValues);
-            break;
-
-          case OP_GET_SECONDS_UNTIL_PASSWORD_RESET_LOCKOUT:
-            message =
-                    INFO_PWPSTATE_LABEL_SECONDS_UNTIL_PASSWORD_RESET_LOCKOUT
-                            .get();
-            printLabelAndValues(message, opValues);
-            break;
-
-          case OP_GET_GRACE_LOGIN_USE_TIMES:
-            message = INFO_PWPSTATE_LABEL_GRACE_LOGIN_USE_TIMES.get();
-            printLabelAndValues(message, opValues);
-            break;
-
-          case OP_GET_REMAINING_GRACE_LOGIN_COUNT:
-            message = INFO_PWPSTATE_LABEL_REMAINING_GRACE_LOGIN_COUNT.get();
-            printLabelAndValues(message, opValues);
-            break;
-
-          case OP_GET_PASSWORD_CHANGED_BY_REQUIRED_TIME:
-            message =
-                    INFO_PWPSTATE_LABEL_PASSWORD_CHANGED_BY_REQUIRED_TIME.get();
-            printLabelAndValues(message, opValues);
-            break;
-
-          case OP_GET_SECONDS_UNTIL_REQUIRED_CHANGE_TIME:
-            message =
-                    INFO_PWPSTATE_LABEL_SECONDS_UNTIL_REQUIRED_CHANGE_TIME
-                            .get();
-            printLabelAndValues(message, opValues);
-            break;
-
-          case OP_GET_PASSWORD_HISTORY:
-            message = INFO_PWPSTATE_LABEL_PASSWORD_HISTORY.get();
-            printLabelAndValues(message, opValues);
-            break;
-
-          default:
-            message = ERR_PWPSTATE_INVALID_RESPONSE_OP_TYPE.get(
-                    String.valueOf(opType));
-            err.println(wrapText(message, MAX_LINE_WIDTH));
-            break;
-        }
-      }
-
-
       // If we've gotten here, then everything completed successfully.
       return 0;
     }
@@ -1382,15 +1394,14 @@
 
 
   /**
-   * Processes the subcommand from the provided argument parser and appends the
-   * appropriate operation elements to the given list.
+   * Processes the subcommand from the provided argument parser and writes the
+   * appropriate operation elements to the given writer.
    *
-   * @param  opElements  A list into which the operation elements shouold be
-   *                     placed.
+   * @param  writer The ASN.1 writer used to write the operation elements.
    *
    * @return  A result code indicating the results of the processing.
    */
-  private static int processSubcommand(ArrayList<ASN1Element> opElements)
+  private static int processSubcommand(ASN1Writer writer) throws IOException
   {
     SubCommand subCommand = argParser.getSubCommand();
     if (subCommand == null)
@@ -1408,11 +1419,11 @@
     }
     else if (subCommandName.equals(SC_GET_PASSWORD_POLICY_DN))
     {
-      opElements.add(encode(OP_GET_PASSWORD_POLICY_DN, NO_VALUE));
+      encode(writer, OP_GET_PASSWORD_POLICY_DN, NO_VALUE);
     }
     else if (subCommandName.equals(SC_GET_ACCOUNT_DISABLED_STATE))
     {
-      opElements.add(encode(OP_GET_ACCOUNT_DISABLED_STATE, NO_VALUE));
+      encode(writer, OP_GET_ACCOUNT_DISABLED_STATE, NO_VALUE);
     }
     else if (subCommandName.equals(SC_SET_ACCOUNT_DISABLED_STATE))
     {
@@ -1422,11 +1433,11 @@
         String valueStr = a.getValue();
         if (isTrueValue(valueStr))
         {
-          opElements.add(encode(OP_SET_ACCOUNT_DISABLED_STATE, "true"));
+          encode(writer, OP_SET_ACCOUNT_DISABLED_STATE, "true");
         }
         else if (isFalseValue(valueStr))
         {
-          opElements.add(encode(OP_SET_ACCOUNT_DISABLED_STATE, "false"));
+          encode(writer, OP_SET_ACCOUNT_DISABLED_STATE, "false");
         }
         else
         {
@@ -1444,101 +1455,101 @@
     }
     else if (subCommandName.equals(SC_CLEAR_ACCOUNT_DISABLED_STATE))
     {
-      opElements.add(encode(OP_CLEAR_ACCOUNT_DISABLED_STATE, NO_VALUE));
+      encode(writer, OP_CLEAR_ACCOUNT_DISABLED_STATE, NO_VALUE);
     }
     else if (subCommandName.equals(SC_GET_ACCOUNT_EXPIRATION_TIME))
     {
-      opElements.add(encode(OP_GET_ACCOUNT_EXPIRATION_TIME, NO_VALUE));
+      encode(writer, OP_GET_ACCOUNT_EXPIRATION_TIME, NO_VALUE);
     }
     else if (subCommandName.equals(SC_SET_ACCOUNT_EXPIRATION_TIME))
     {
       Argument a = subCommand.getArgumentForName(ARG_OP_VALUE);
       if ((a != null) && a.isPresent())
       {
-        opElements.add(encode(OP_SET_ACCOUNT_EXPIRATION_TIME, a.getValue()));
+        encode(writer, OP_SET_ACCOUNT_EXPIRATION_TIME, a.getValue());
       }
       else
       {
-        opElements.add(encode(OP_SET_ACCOUNT_EXPIRATION_TIME, NO_VALUE));
+        encode(writer, OP_SET_ACCOUNT_EXPIRATION_TIME, NO_VALUE);
       }
     }
     else if (subCommandName.equals(SC_CLEAR_ACCOUNT_EXPIRATION_TIME))
     {
-      opElements.add(encode(OP_CLEAR_ACCOUNT_EXPIRATION_TIME, NO_VALUE));
+      encode(writer, OP_CLEAR_ACCOUNT_EXPIRATION_TIME, NO_VALUE);
     }
     else if (subCommandName.equals(SC_GET_SECONDS_UNTIL_ACCOUNT_EXPIRATION))
     {
-      opElements.add(encode(OP_GET_SECONDS_UNTIL_ACCOUNT_EXPIRATION, NO_VALUE));
+      encode(writer, OP_GET_SECONDS_UNTIL_ACCOUNT_EXPIRATION, NO_VALUE);
     }
     else if (subCommandName.equals(SC_GET_PASSWORD_CHANGED_TIME))
     {
-      opElements.add(encode(OP_GET_PASSWORD_CHANGED_TIME, NO_VALUE));
+      encode(writer, OP_GET_PASSWORD_CHANGED_TIME, NO_VALUE);
     }
     else if (subCommandName.equals(SC_SET_PASSWORD_CHANGED_TIME))
     {
       Argument a = subCommand.getArgumentForName(ARG_OP_VALUE);
       if ((a != null) && a.isPresent())
       {
-        opElements.add(encode(OP_SET_PASSWORD_CHANGED_TIME, a.getValue()));
+        encode(writer, OP_SET_PASSWORD_CHANGED_TIME, a.getValue());
       }
       else
       {
-        opElements.add(encode(OP_SET_PASSWORD_CHANGED_TIME, NO_VALUE));
+        encode(writer, OP_SET_PASSWORD_CHANGED_TIME, NO_VALUE);
       }
     }
     else if (subCommandName.equals(SC_CLEAR_PASSWORD_CHANGED_TIME))
     {
-      opElements.add(encode(OP_CLEAR_PASSWORD_CHANGED_TIME, NO_VALUE));
+      encode(writer, OP_CLEAR_PASSWORD_CHANGED_TIME, NO_VALUE);
     }
     else if(subCommandName.equals(SC_GET_PASSWORD_EXP_WARNED_TIME))
     {
-      opElements.add(encode(OP_GET_PASSWORD_EXPIRATION_WARNED_TIME, NO_VALUE));
+      encode(writer, OP_GET_PASSWORD_EXPIRATION_WARNED_TIME, NO_VALUE);
     }
     else if(subCommandName.equals(SC_SET_PASSWORD_EXP_WARNED_TIME))
     {
       Argument a = subCommand.getArgumentForName(ARG_OP_VALUE);
       if ((a != null) && a.isPresent())
       {
-        opElements.add(encode(OP_SET_PASSWORD_EXPIRATION_WARNED_TIME,
-                              a.getValue()));
+        encode(writer, OP_SET_PASSWORD_EXPIRATION_WARNED_TIME,
+                              a.getValue());
       }
       else
       {
-        opElements.add(encode(OP_SET_PASSWORD_EXPIRATION_WARNED_TIME,
-                              NO_VALUE));
+        encode(writer, OP_SET_PASSWORD_EXPIRATION_WARNED_TIME,
+                              NO_VALUE);
       }
     }
     else if(subCommandName.equals(SC_CLEAR_PASSWORD_EXP_WARNED_TIME))
     {
-      opElements.add(encode(OP_CLEAR_PASSWORD_EXPIRATION_WARNED_TIME,
-                            NO_VALUE));
+      encode(writer, OP_CLEAR_PASSWORD_EXPIRATION_WARNED_TIME,
+                            NO_VALUE);
     }
     else if(subCommandName.equals(SC_GET_SECONDS_UNTIL_PASSWORD_EXPIRATION))
     {
-      opElements.add(encode(OP_GET_SECONDS_UNTIL_PASSWORD_EXPIRATION,
-                            NO_VALUE));
+      encode(writer, OP_GET_SECONDS_UNTIL_PASSWORD_EXPIRATION,
+                            NO_VALUE);
     }
     else if(subCommandName.equals(
                  SC_GET_SECONDS_UNTIL_PASSWORD_EXPIRATION_WARNING))
     {
-      opElements.add(encode(OP_GET_SECONDS_UNTIL_PASSWORD_EXPIRATION_WARNING,
-                            NO_VALUE));
+      encode(writer, OP_GET_SECONDS_UNTIL_PASSWORD_EXPIRATION_WARNING,
+                            NO_VALUE);
     }
     else if(subCommandName.equals(SC_GET_AUTHENTICATION_FAILURE_TIMES))
     {
-      opElements.add(encode(OP_GET_AUTHENTICATION_FAILURE_TIMES, NO_VALUE));
+      encode(writer, OP_GET_AUTHENTICATION_FAILURE_TIMES, NO_VALUE);
     }
     else if(subCommandName.equals(SC_ADD_AUTHENTICATION_FAILURE_TIME))
     {
       Argument a = subCommand.getArgumentForName(ARG_OP_VALUE);
       if ((a != null) && a.isPresent())
       {
-        opElements.add(encode(OP_ADD_AUTHENTICATION_FAILURE_TIME,
-                              a.getValue()));
+        encode(writer, OP_ADD_AUTHENTICATION_FAILURE_TIME,
+                              a.getValue());
       }
       else
       {
-        opElements.add(encode(OP_ADD_AUTHENTICATION_FAILURE_TIME, NO_VALUE));
+        encode(writer, OP_ADD_AUTHENTICATION_FAILURE_TIME, NO_VALUE);
       }
     }
     else if(subCommandName.equals(SC_SET_AUTHENTICATION_FAILURE_TIMES))
@@ -1550,56 +1561,56 @@
         String[] values = new String[valueList.size()];
         valueList.toArray(values);
 
-        opElements.add(encode(OP_SET_AUTHENTICATION_FAILURE_TIMES, values));
+        encode(writer, OP_SET_AUTHENTICATION_FAILURE_TIMES, values);
       }
       else
       {
-        opElements.add(encode(OP_SET_AUTHENTICATION_FAILURE_TIMES, NO_VALUE));
+        encode(writer, OP_SET_AUTHENTICATION_FAILURE_TIMES, NO_VALUE);
       }
     }
     else if(subCommandName.equals(SC_CLEAR_AUTHENTICATION_FAILURE_TIMES))
     {
-      opElements.add(encode(OP_CLEAR_AUTHENTICATION_FAILURE_TIMES, NO_VALUE));
+      encode(writer, OP_CLEAR_AUTHENTICATION_FAILURE_TIMES, NO_VALUE);
     }
     else if(subCommandName.equals(
                  SC_GET_SECONDS_UNTIL_AUTHENTICATION_FAILURE_UNLOCK))
     {
-      opElements.add(encode(OP_GET_SECONDS_UNTIL_AUTHENTICATION_FAILURE_UNLOCK,
-                            NO_VALUE));
+      encode(writer, OP_GET_SECONDS_UNTIL_AUTHENTICATION_FAILURE_UNLOCK,
+                            NO_VALUE);
     }
     else if(subCommandName.equals(
                  SC_GET_REMAINING_AUTHENTICATION_FAILURE_COUNT))
     {
-      opElements.add(encode(OP_GET_REMAINING_AUTHENTICATION_FAILURE_COUNT,
-                            NO_VALUE));
+      encode(writer, OP_GET_REMAINING_AUTHENTICATION_FAILURE_COUNT,
+                            NO_VALUE);
     }
     else if(subCommandName.equals(SC_GET_LAST_LOGIN_TIME))
     {
-      opElements.add(encode(OP_GET_LAST_LOGIN_TIME, NO_VALUE));
+      encode(writer, OP_GET_LAST_LOGIN_TIME, NO_VALUE);
     }
     else if(subCommandName.equals(SC_SET_LAST_LOGIN_TIME))
     {
       Argument a = subCommand.getArgumentForName(ARG_OP_VALUE);
       if ((a != null) && a.isPresent())
       {
-        opElements.add(encode(OP_SET_LAST_LOGIN_TIME, a.getValue()));
+        encode(writer, OP_SET_LAST_LOGIN_TIME, a.getValue());
       }
       else
       {
-        opElements.add(encode(OP_SET_LAST_LOGIN_TIME, NO_VALUE));
+        encode(writer, OP_SET_LAST_LOGIN_TIME, NO_VALUE);
       }
     }
     else if(subCommandName.equals(SC_CLEAR_LAST_LOGIN_TIME))
     {
-      opElements.add(encode(OP_CLEAR_LAST_LOGIN_TIME, NO_VALUE));
+      encode(writer, OP_CLEAR_LAST_LOGIN_TIME, NO_VALUE);
     }
     else if(subCommandName.equals(SC_GET_SECONDS_UNTIL_IDLE_LOCKOUT))
     {
-      opElements.add(encode(OP_GET_SECONDS_UNTIL_IDLE_LOCKOUT, NO_VALUE));
+      encode(writer, OP_GET_SECONDS_UNTIL_IDLE_LOCKOUT, NO_VALUE);
     }
     else if(subCommandName.equals(SC_GET_PASSWORD_RESET_STATE))
     {
-      opElements.add(encode(OP_GET_PASSWORD_RESET_STATE, NO_VALUE));
+      encode(writer, OP_GET_PASSWORD_RESET_STATE, NO_VALUE);
     }
     else if(subCommandName.equals(SC_SET_PASSWORD_RESET_STATE))
     {
@@ -1609,11 +1620,11 @@
         String valueStr = a.getValue();
         if (isTrueValue(valueStr))
         {
-          opElements.add(encode(OP_SET_PASSWORD_RESET_STATE, "true"));
+          encode(writer, OP_SET_PASSWORD_RESET_STATE, "true");
         }
         else if (isFalseValue(valueStr))
         {
-          opElements.add(encode(OP_SET_PASSWORD_RESET_STATE, "false"));
+          encode(writer, OP_SET_PASSWORD_RESET_STATE, "false");
         }
         else
         {
@@ -1631,27 +1642,27 @@
     }
     else if(subCommandName.equals(SC_CLEAR_PASSWORD_RESET_STATE))
     {
-      opElements.add(encode(OP_GET_PASSWORD_RESET_STATE, NO_VALUE));
+      encode(writer, OP_GET_PASSWORD_RESET_STATE, NO_VALUE);
     }
     else if(subCommandName.equals(SC_GET_SECONDS_UNTIL_PASSWORD_RESET_LOCKOUT))
     {
-      opElements.add(encode(OP_GET_SECONDS_UNTIL_PASSWORD_RESET_LOCKOUT,
-                            NO_VALUE));
+      encode(writer, OP_GET_SECONDS_UNTIL_PASSWORD_RESET_LOCKOUT,
+                            NO_VALUE);
     }
     else if(subCommandName.equals(SC_GET_GRACE_LOGIN_USE_TIMES))
     {
-      opElements.add(encode(OP_GET_GRACE_LOGIN_USE_TIMES, NO_VALUE));
+      encode(writer, OP_GET_GRACE_LOGIN_USE_TIMES, NO_VALUE);
     }
     else if(subCommandName.equals(SC_ADD_GRACE_LOGIN_USE_TIME))
     {
       Argument a = subCommand.getArgumentForName(ARG_OP_VALUE);
       if ((a != null) && a.isPresent())
       {
-        opElements.add(encode(OP_ADD_GRACE_LOGIN_USE_TIME, a.getValue()));
+        encode(writer, OP_ADD_GRACE_LOGIN_USE_TIME, a.getValue());
       }
       else
       {
-        opElements.add(encode(OP_ADD_GRACE_LOGIN_USE_TIME, NO_VALUE));
+        encode(writer, OP_ADD_GRACE_LOGIN_USE_TIME, NO_VALUE);
       }
     }
     else if(subCommandName.equals(SC_SET_GRACE_LOGIN_USE_TIMES))
@@ -1663,57 +1674,57 @@
         String[] values = new String[valueList.size()];
         valueList.toArray(values);
 
-        opElements.add(encode(OP_SET_GRACE_LOGIN_USE_TIMES, values));
+        encode(writer, OP_SET_GRACE_LOGIN_USE_TIMES, values);
       }
       else
       {
-        opElements.add(encode(OP_SET_GRACE_LOGIN_USE_TIMES, NO_VALUE));
+        encode(writer, OP_SET_GRACE_LOGIN_USE_TIMES, NO_VALUE);
       }
     }
     else if(subCommandName.equals(SC_CLEAR_GRACE_LOGIN_USE_TIMES))
     {
-      opElements.add(encode(OP_CLEAR_GRACE_LOGIN_USE_TIMES, NO_VALUE));
+      encode(writer, OP_CLEAR_GRACE_LOGIN_USE_TIMES, NO_VALUE);
     }
     else if(subCommandName.equals(SC_GET_REMAINING_GRACE_LOGIN_COUNT))
     {
-      opElements.add(encode(OP_GET_REMAINING_GRACE_LOGIN_COUNT, NO_VALUE));
+      encode(writer, OP_GET_REMAINING_GRACE_LOGIN_COUNT, NO_VALUE);
     }
     else if(subCommandName.equals(SC_GET_PASSWORD_CHANGED_BY_REQUIRED_TIME))
     {
-      opElements.add(encode(OP_GET_PASSWORD_CHANGED_BY_REQUIRED_TIME,
-                            NO_VALUE));
+      encode(writer, OP_GET_PASSWORD_CHANGED_BY_REQUIRED_TIME,
+                            NO_VALUE);
     }
     else if(subCommandName.equals(SC_SET_PASSWORD_CHANGED_BY_REQUIRED_TIME))
     {
       Argument a = subCommand.getArgumentForName(ARG_OP_VALUE);
       if ((a != null) && a.isPresent())
       {
-        opElements.add(encode(OP_SET_PASSWORD_CHANGED_BY_REQUIRED_TIME,
-                              a.getValue()));
+        encode(writer, OP_SET_PASSWORD_CHANGED_BY_REQUIRED_TIME,
+                              a.getValue());
       }
       else
       {
-        opElements.add(encode(OP_SET_PASSWORD_CHANGED_BY_REQUIRED_TIME,
-                              NO_VALUE));
+        encode(writer, OP_SET_PASSWORD_CHANGED_BY_REQUIRED_TIME,
+                              NO_VALUE);
       }
     }
     else if(subCommandName.equals(SC_CLEAR_PASSWORD_CHANGED_BY_REQUIRED_TIME))
     {
-      opElements.add(encode(OP_CLEAR_PASSWORD_CHANGED_BY_REQUIRED_TIME,
-                            NO_VALUE));
+      encode(writer, OP_CLEAR_PASSWORD_CHANGED_BY_REQUIRED_TIME,
+                            NO_VALUE);
     }
     else if(subCommandName.equals(SC_GET_SECONDS_UNTIL_REQUIRED_CHANGE_TIME))
     {
-      opElements.add(encode(OP_GET_SECONDS_UNTIL_REQUIRED_CHANGE_TIME,
-                            NO_VALUE));
+      encode(writer, OP_GET_SECONDS_UNTIL_REQUIRED_CHANGE_TIME,
+                            NO_VALUE);
     }
     else if (subCommandName.equals(SC_GET_PASSWORD_HISTORY))
     {
-      opElements.add(encode(OP_GET_PASSWORD_HISTORY, NO_VALUE));
+      encode(writer, OP_GET_PASSWORD_HISTORY, NO_VALUE);
     }
     else if (subCommandName.equals(SC_CLEAR_PASSWORD_HISTORY))
     {
-      opElements.add(encode(OP_CLEAR_PASSWORD_HISTORY, NO_VALUE));
+      encode(writer, OP_CLEAR_PASSWORD_HISTORY, NO_VALUE);
     }
     else
     {
diff --git a/opends/src/server/org/opends/server/tools/RestoreDB.java b/opends/src/server/org/opends/server/tools/RestoreDB.java
index 94f07ad..8ea79db 100644
--- a/opends/src/server/org/opends/server/tools/RestoreDB.java
+++ b/opends/src/server/org/opends/server/tools/RestoreDB.java
@@ -52,14 +52,7 @@
 import org.opends.server.loggers.TextErrorLogPublisher;
 import org.opends.server.loggers.debug.TextDebugLogPublisher;
 import org.opends.server.loggers.debug.DebugLogger;
-import org.opends.server.types.BackupDirectory;
-import org.opends.server.types.BackupInfo;
-import org.opends.server.types.DirectoryException;
-import org.opends.server.types.DN;
-import org.opends.server.types.InitializationException;
-import org.opends.server.types.NullOutputStream;
-import org.opends.server.types.RestoreConfig;
-import org.opends.server.types.RawAttribute;
+import org.opends.server.types.*;
 import org.opends.server.util.args.ArgumentException;
 import org.opends.server.util.args.BooleanArgument;
 import org.opends.server.util.args.StringArgument;
@@ -72,7 +65,6 @@
 import static org.opends.server.tools.ToolConstants.*;
 import org.opends.server.tools.tasks.TaskTool;
 import org.opends.server.admin.std.server.BackendCfg;
-import org.opends.server.protocols.asn1.ASN1OctetString;
 import org.opends.server.protocols.ldap.LDAPAttribute;
 import org.opends.server.tasks.RestoreTask;
 
@@ -278,13 +270,13 @@
    */
   public void addTaskAttributes(List<RawAttribute> attributes)
   {
-    ArrayList<ASN1OctetString> values;
+    ArrayList<ByteString> values;
 
     if (backupDirectory.getValue() != null &&
             !backupDirectory.getValue().equals(
                     backupDirectory.getDefaultValue())) {
-      values = new ArrayList<ASN1OctetString>(1);
-      values.add(new ASN1OctetString(backupDirectory.getValue()));
+      values = new ArrayList<ByteString>(1);
+      values.add(ByteString.valueOf(backupDirectory.getValue()));
       attributes.add(
               new LDAPAttribute(ATTR_BACKUP_DIRECTORY_PATH, values));
     }
@@ -292,8 +284,8 @@
     if (backupIDString.getValue() != null &&
             !backupIDString.getValue().equals(
                     backupIDString.getDefaultValue())) {
-      values = new ArrayList<ASN1OctetString>(1);
-      values.add(new ASN1OctetString(backupIDString.getValue()));
+      values = new ArrayList<ByteString>(1);
+      values.add(ByteString.valueOf(backupIDString.getValue()));
       attributes.add(
               new LDAPAttribute(ATTR_BACKUP_ID, values));
     }
@@ -301,8 +293,8 @@
     if (verifyOnly.getValue() != null &&
             !verifyOnly.getValue().equals(
                     verifyOnly.getDefaultValue())) {
-      values = new ArrayList<ASN1OctetString>(1);
-      values.add(new ASN1OctetString(verifyOnly.getValue()));
+      values = new ArrayList<ByteString>(1);
+      values.add(ByteString.valueOf(verifyOnly.getValue()));
       attributes.add(
               new LDAPAttribute(ATTR_TASK_RESTORE_VERIFY_ONLY, values));
     }
diff --git a/opends/src/server/org/opends/server/tools/StopDS.java b/opends/src/server/org/opends/server/tools/StopDS.java
index 90b7f23..a4d61e2 100644
--- a/opends/src/server/org/opends/server/tools/StopDS.java
+++ b/opends/src/server/org/opends/server/tools/StopDS.java
@@ -45,21 +45,16 @@
 import org.opends.server.core.DirectoryServer;
 import org.opends.server.core.LockFileManager;
 import org.opends.server.protocols.asn1.ASN1Exception;
-import org.opends.server.protocols.asn1.ASN1OctetString;
 import org.opends.server.protocols.ldap.AddRequestProtocolOp;
 import org.opends.server.protocols.ldap.AddResponseProtocolOp;
 import org.opends.server.protocols.ldap.ExtendedResponseProtocolOp;
 import org.opends.server.protocols.ldap.LDAPAttribute;
 import org.opends.server.protocols.ldap.LDAPConstants;
-import org.opends.server.protocols.ldap.LDAPControl;
 import org.opends.server.protocols.ldap.LDAPMessage;
 import org.opends.server.protocols.ldap.LDAPResultCode;
 import org.opends.server.tasks.ShutdownTask;
 import org.opends.server.tools.tasks.TaskTool;
-import org.opends.server.types.Control;
-import org.opends.server.types.LDAPException;
-import org.opends.server.types.NullOutputStream;
-import org.opends.server.types.RawAttribute;
+import org.opends.server.types.*;
 import org.opends.server.util.args.Argument;
 import org.opends.server.util.args.ArgumentException;
 import org.opends.server.util.args.ArgumentParser;
@@ -641,61 +636,61 @@
 
     // Construct the add request to send to the server.
     String taskID = UUID.randomUUID().toString();
-    ASN1OctetString entryDN =
-         new ASN1OctetString(ATTR_TASK_ID + "=" + taskID + "," +
-                             SCHEDULED_TASK_BASE_RDN + "," + DN_TASK_ROOT);
+    ByteString entryDN =
+        ByteString.valueOf(ATTR_TASK_ID + "=" + taskID + "," +
+                            SCHEDULED_TASK_BASE_RDN + "," + DN_TASK_ROOT);
 
     ArrayList<RawAttribute> attributes = new ArrayList<RawAttribute>();
 
-    ArrayList<ASN1OctetString> ocValues = new ArrayList<ASN1OctetString>(3);
-    ocValues.add(new ASN1OctetString("top"));
-    ocValues.add(new ASN1OctetString("ds-task"));
-    ocValues.add(new ASN1OctetString("ds-task-shutdown"));
+    ArrayList<ByteString> ocValues = new ArrayList<ByteString>(3);
+    ocValues.add(ByteString.valueOf("top"));
+    ocValues.add(ByteString.valueOf("ds-task"));
+    ocValues.add(ByteString.valueOf("ds-task-shutdown"));
     attributes.add(new LDAPAttribute(ATTR_OBJECTCLASS, ocValues));
 
-    ArrayList<ASN1OctetString> taskIDValues = new ArrayList<ASN1OctetString>(1);
-    taskIDValues.add(new ASN1OctetString(taskID));
+    ArrayList<ByteString> taskIDValues = new ArrayList<ByteString>(1);
+    taskIDValues.add(ByteString.valueOf(taskID));
     attributes.add(new LDAPAttribute(ATTR_TASK_ID, taskIDValues));
 
-    ArrayList<ASN1OctetString> classValues = new ArrayList<ASN1OctetString>(1);
-    classValues.add(new ASN1OctetString(ShutdownTask.class.getName()));
+    ArrayList<ByteString> classValues = new ArrayList<ByteString>(1);
+    classValues.add(ByteString.valueOf(ShutdownTask.class.getName()));
     attributes.add(new LDAPAttribute(ATTR_TASK_CLASS, classValues));
 
     if (restart.isPresent())
     {
-      ArrayList<ASN1OctetString> restartValues =
-           new ArrayList<ASN1OctetString>(1);
-      restartValues.add(new ASN1OctetString("true"));
+      ArrayList<ByteString> restartValues =
+           new ArrayList<ByteString>(1);
+      restartValues.add(ByteString.valueOf("true"));
       attributes.add(new LDAPAttribute(ATTR_RESTART_SERVER, restartValues));
     }
 
     if (stopReason.isPresent())
     {
-      ArrayList<ASN1OctetString> stopReasonValues =
-           new ArrayList<ASN1OctetString>(1);
-      stopReasonValues.add(new ASN1OctetString(stopReason.getValue()));
+      ArrayList<ByteString> stopReasonValues =
+           new ArrayList<ByteString>(1);
+      stopReasonValues.add(ByteString.valueOf(stopReason.getValue()));
       attributes.add(new LDAPAttribute(ATTR_SHUTDOWN_MESSAGE,
                                        stopReasonValues));
     }
 
     if (stopTime != null)
     {
-      ArrayList<ASN1OctetString> stopTimeValues =
-           new ArrayList<ASN1OctetString>(1);
+      ArrayList<ByteString> stopTimeValues =
+           new ArrayList<ByteString>(1);
 
       SimpleDateFormat dateFormat = new SimpleDateFormat(DATE_FORMAT_GMT_TIME);
       dateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
-      stopTimeValues.add(new ASN1OctetString(dateFormat.format(stopTime)));
+      stopTimeValues.add(ByteString.valueOf(dateFormat.format(stopTime)));
       attributes.add(new LDAPAttribute(ATTR_TASK_SCHEDULED_START_TIME,
                                        stopTimeValues));
     }
 
-    ArrayList<LDAPControl> controls = new ArrayList<LDAPControl>();
+    ArrayList<Control> controls = new ArrayList<Control>();
     if (proxyAuthzID.isPresent())
     {
       Control c = new ProxiedAuthV2Control(
-                           new ASN1OctetString(proxyAuthzID.getValue()));
-      controls.add(new LDAPControl(c));
+          ByteString.valueOf(proxyAuthzID.getValue()));
+      controls.add(c);
     }
 
     AddRequestProtocolOp addRequest = new AddRequestProtocolOp(entryDN,
diff --git a/opends/src/server/org/opends/server/tools/VerboseTracer.java b/opends/src/server/org/opends/server/tools/VerboseTracer.java
deleted file mode 100644
index 9b5ad1c..0000000
--- a/opends/src/server/org/opends/server/tools/VerboseTracer.java
+++ /dev/null
@@ -1,172 +0,0 @@
-/*
- * CDDL HEADER START
- *
- * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
- *
- * You can obtain a copy of the license at
- * trunk/opends/resource/legal-notices/OpenDS.LICENSE
- * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
- * See the License for the specific language governing permissions
- * and limitations under the License.
- *
- * When distributing Covered Code, include this CDDL HEADER in each
- * file and include the License file at
- * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
- * add the following below this CDDL 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.server.tools;
-
-import org.opends.server.protocols.ldap.LDAPMessage;
-import org.opends.server.protocols.asn1.ASN1Element;
-import org.opends.server.util.ServerConstants;
-
-import java.io.PrintStream;
-import java.text.DateFormat;
-import java.text.SimpleDateFormat;
-import java.util.Date;
-
-/**
- * A utility class for the LDAP client tools that performs verbose tracing of
- * LDAP and ASN.1 messages.
- */
-public class VerboseTracer
-{
-  /**
-   * Indicates whether verbose mode is on or off.
-   */
-  private boolean verbose;
-
-  /**
-   * The print stream where tracing will be sent.
-   */
-  private PrintStream err;
-
-  /**
-   * The time in milliseconds of the first message traced.
-   */
-  private long firstMessageTimestamp = 0;
-
-  /**
-   * The time in millseconds of the previous message traced.
-   */
-  private long lastMessageTimestamp = 0;
-
-  /**
-   * The format used for trace timestamps.
-   */
-  private DateFormat dateFormat = new SimpleDateFormat("HH:mm:ss.SSS");
-
-  /**
-   * Constructs a tracer with a specified verbosity and print stream.
-   * @param verbose Indicates whether verbose mode is on or off.
-   * @param err The print stream where tracing will be sent.
-   */
-  public VerboseTracer(boolean verbose, PrintStream err)
-  {
-    this.verbose = verbose;
-    this.err = err;
-  }
-
-  /**
-   * Trace an incoming or outgoing message.
-   * @param messageDirection  Use "C>S" to indicate outgoing client to server.
-   *                          Use "S>C" to indicate incoming server to client.
-   * @param message The LDAP message to be traced.
-   * @param element The ASN.1 element of the message.
-   */
-  private synchronized void traceMessage(String messageDirection,
-                                         LDAPMessage message,
-                                         ASN1Element element)
-  {
-    StringBuilder header = new StringBuilder();
-    StringBuilder builder = new StringBuilder();
-
-    long timestamp = System.currentTimeMillis();
-    long timeSinceLast;
-
-    if (firstMessageTimestamp == 0)
-    {
-      firstMessageTimestamp = timestamp;
-    }
-
-    if (lastMessageTimestamp == 0)
-    {
-      lastMessageTimestamp = timestamp;
-    }
-
-    timeSinceLast = timestamp - lastMessageTimestamp;
-    if (timeSinceLast < 0)
-    {
-      timeSinceLast = 0;
-    }
-
-    String timestampString = dateFormat.format(new Date(timestamp));
-
-    header.append(messageDirection);
-    header.append(' ');
-    header.append(timestampString);
-
-    // Include the number of milliseconds since the previous traced message.
-    header.append(" (");
-    header.append(timeSinceLast);
-    header.append("ms) ");
-
-
-    builder.append("LDAP: ");
-    builder.append(header);
-    builder.append(message);
-    builder.append(ServerConstants.EOL);
-
-    builder.append("ASN1: ");
-    builder.append(header);
-    element.toString(builder, 0);
-
-    err.print(builder);
-
-    if (timestamp > lastMessageTimestamp)
-    {
-      lastMessageTimestamp = timestamp;
-    }
-  }
-
-  /**
-   * Trace an incoming message.
-   * @param message The LDAP message to be traced.
-   * @param element The ASN.1 element of the message.
-   */
-  public void traceIncomingMessage(LDAPMessage message,
-                                                ASN1Element element)
-  {
-    if (verbose)
-    {
-      traceMessage("S>C", message, element);
-    }
-  }
-
-
-  /**
-   * Trace an outgoing message.
-   * @param message The LDAP message to be traced.
-   * @param element The ASN.1 element of the message.
-   */
-  public void traceOutgoingMessage(LDAPMessage message,
-                                                ASN1Element element)
-  {
-    if (verbose)
-    {
-      traceMessage("C>S", message, element);
-    }
-  }
-
-}
diff --git a/opends/src/server/org/opends/server/tools/makeldif/Branch.java b/opends/src/server/org/opends/server/tools/makeldif/Branch.java
index 7248e8f..68ddefd 100644
--- a/opends/src/server/org/opends/server/tools/makeldif/Branch.java
+++ b/opends/src/server/org/opends/server/tools/makeldif/Branch.java
@@ -150,7 +150,7 @@
         {
           try
           {
-            String[] valueStrings = new String[] { v.getStringValue() };
+            String[] valueStrings = new String[] { v.getValue().toString()};
             Tag[] tags = new Tag[1];
             tags[0] = new StaticTextTag();
             tags[0].initializeForBranch(templateFile, this, valueStrings, 0,
@@ -174,7 +174,7 @@
         {
           try
           {
-            String[] valueStrings = new String[] { v.getStringValue() };
+            String[] valueStrings = new String[] { v.getValue().toString()};
             Tag[] tags = new Tag[1];
             tags[0] = new StaticTextTag();
             tags[0].initializeForBranch(templateFile, this, valueStrings, 0,
diff --git a/opends/src/server/org/opends/server/tools/makeldif/TemplateEntry.java b/opends/src/server/org/opends/server/tools/makeldif/TemplateEntry.java
index d54d1c0..496f3b4 100644
--- a/opends/src/server/org/opends/server/tools/makeldif/TemplateEntry.java
+++ b/opends/src/server/org/opends/server/tools/makeldif/TemplateEntry.java
@@ -33,14 +33,7 @@
 import java.util.List;
 
 import org.opends.server.core.DirectoryServer;
-import org.opends.server.types.Attribute;
-import org.opends.server.types.AttributeBuilder;
-import org.opends.server.types.AttributeType;
-import org.opends.server.types.AttributeValue;
-import org.opends.server.types.DN;
-import org.opends.server.types.Entry;
-import org.opends.server.types.ObjectClass;
-import org.opends.server.types.RDN;
+import org.opends.server.types.*;
 
 import static org.opends.server.util.StaticUtils.*;
 
@@ -168,7 +161,8 @@
           return null;
         }
 
-        AttributeValue value = new AttributeValue(t, v.getValue().toString());
+        AttributeValue value =
+            AttributeValues.create(t, v.getValue().toString());
         rdn = new RDN(t, value);
       }
       else
@@ -185,7 +179,7 @@
           }
 
           names[i]  = t.getPrimaryName();
-          values[i] = new AttributeValue(t, v.getValue().toString());
+          values[i] = AttributeValues.create(t, v.getValue().toString());
         }
 
         rdn = new RDN(rdnAttrs, names, values);
@@ -312,7 +306,7 @@
         AttributeBuilder builder = new AttributeBuilder(t, t.getNameOrOID());
         for (TemplateValue v : valueList)
         {
-          builder.add(new AttributeValue(t, v.getValue().toString()));
+          builder.add(AttributeValues.create(t, v.getValue().toString()));
         }
 
         ArrayList<Attribute> attrList = new ArrayList<Attribute>(1);
@@ -324,7 +318,7 @@
         AttributeBuilder builder = new AttributeBuilder(t, t.getNameOrOID());
         for (TemplateValue v : valueList)
         {
-          builder.add(new AttributeValue(t, v.getValue().toString()));
+          builder.add(AttributeValues.create(t, v.getValue().toString()));
         }
 
         ArrayList<Attribute> attrList = new ArrayList<Attribute>(1);
diff --git a/opends/src/server/org/opends/server/tools/tasks/TaskClient.java b/opends/src/server/org/opends/server/tools/tasks/TaskClient.java
index 9a9eeb1..a00bbdf 100644
--- a/opends/src/server/org/opends/server/tools/tasks/TaskClient.java
+++ b/opends/src/server/org/opends/server/tools/tasks/TaskClient.java
@@ -27,17 +27,31 @@
 
 package org.opends.server.tools.tasks;
 
-import org.opends.messages.Message;
 import static org.opends.messages.ToolMessages.*;
-import org.opends.server.config.ConfigConstants;
 import static org.opends.server.config.ConfigConstants.*;
+import static org.opends.server.types.ResultCode.*;
+
+import java.io.IOException;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Date;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.UUID;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.opends.messages.Message;
+import org.opends.server.backends.task.FailedDependencyAction;
+import org.opends.server.backends.task.TaskState;
+import org.opends.server.config.ConfigConstants;
 import org.opends.server.protocols.asn1.ASN1Exception;
-import org.opends.server.protocols.asn1.ASN1OctetString;
 import org.opends.server.protocols.ldap.AddRequestProtocolOp;
 import org.opends.server.protocols.ldap.AddResponseProtocolOp;
+import org.opends.server.protocols.ldap.DeleteRequestProtocolOp;
+import org.opends.server.protocols.ldap.DeleteResponseProtocolOp;
 import org.opends.server.protocols.ldap.LDAPAttribute;
 import org.opends.server.protocols.ldap.LDAPConstants;
-import org.opends.server.protocols.ldap.LDAPControl;
 import org.opends.server.protocols.ldap.LDAPFilter;
 import org.opends.server.protocols.ldap.LDAPMessage;
 import org.opends.server.protocols.ldap.LDAPModification;
@@ -49,6 +63,8 @@
 import org.opends.server.tools.LDAPConnection;
 import org.opends.server.tools.LDAPReader;
 import org.opends.server.tools.LDAPWriter;
+import org.opends.server.types.ByteString;
+import org.opends.server.types.Control;
 import org.opends.server.types.DereferencePolicy;
 import org.opends.server.types.Entry;
 import org.opends.server.types.LDAPException;
@@ -57,23 +73,8 @@
 import org.opends.server.types.RawModification;
 import org.opends.server.types.SearchResultEntry;
 import org.opends.server.types.SearchScope;
-import static org.opends.server.types.ResultCode.*;
-import org.opends.server.backends.task.TaskState;
-import org.opends.server.backends.task.FailedDependencyAction;
 import org.opends.server.util.StaticUtils;
 
-import java.io.IOException;
-import java.text.SimpleDateFormat;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Date;
-import java.util.LinkedHashSet;
-import java.util.List;
-import java.util.UUID;
-import java.util.concurrent.atomic.AtomicInteger;
-import org.opends.server.protocols.ldap.DeleteRequestProtocolOp;
-import org.opends.server.protocols.ldap.DeleteResponseProtocolOp;
-
 /**
  * Helper class for interacting with the task backend on behalf of utilities
  * that are capable of being scheduled.
@@ -88,7 +89,7 @@
   /**
    * Keeps track of message IDs.
    */
-  private AtomicInteger nextMessageID = new AtomicInteger(0);
+  private final AtomicInteger nextMessageID = new AtomicInteger(0);
 
   /**
    * Creates a new TaskClient for interacting with the task backend remotely.
@@ -113,7 +114,7 @@
           throws LDAPException, IOException, ASN1Exception, TaskClientException
   {
     String taskID = null;
-    ASN1OctetString entryDN = null;
+    ByteString entryDN = null;
     boolean scheduleRecurring = false;
 
     LDAPReader reader = connection.getLDAPReader();
@@ -129,59 +130,58 @@
         taskID = information.getTaskClass().getSimpleName() +
           "-" + UUID.randomUUID().toString();
       }
-      entryDN = new ASN1OctetString(ATTR_RECURRING_TASK_ID + "=" +
+      entryDN = ByteString.valueOf(ATTR_RECURRING_TASK_ID + "=" +
         taskID + "," + RECURRING_TASK_BASE_RDN + "," + DN_TASK_ROOT);
     } else {
       // Use a formatted time/date for the ID so that is remotely useful
       SimpleDateFormat df = new SimpleDateFormat("yyyyMMddHHmmssSSS");
       taskID = df.format(new Date());
 
-      entryDN = new ASN1OctetString(ATTR_TASK_ID + "=" + taskID + "," +
+      entryDN = ByteString.valueOf(ATTR_TASK_ID + "=" + taskID + "," +
         SCHEDULED_TASK_BASE_RDN + "," + DN_TASK_ROOT);
     }
 
-    ArrayList<LDAPControl> controls = new ArrayList<LDAPControl>();
-
+    ArrayList<Control> controls = new ArrayList<Control>();
     ArrayList<RawAttribute> attributes = new ArrayList<RawAttribute>();
 
-    ArrayList<ASN1OctetString> ocValues = new ArrayList<ASN1OctetString>(3);
-    ocValues.add(new ASN1OctetString("top"));
-    ocValues.add(new ASN1OctetString(ConfigConstants.OC_TASK));
+    ArrayList<ByteString> ocValues = new ArrayList<ByteString>(3);
+    ocValues.add(ByteString.valueOf("top"));
+    ocValues.add(ByteString.valueOf(ConfigConstants.OC_TASK));
 
     if (scheduleRecurring) {
-      ocValues.add(new ASN1OctetString(ConfigConstants.OC_RECURRING_TASK));
+      ocValues.add(ByteString.valueOf(ConfigConstants.OC_RECURRING_TASK));
     }
 
-    ocValues.add(new ASN1OctetString(information.getTaskObjectclass()));
+    ocValues.add(ByteString.valueOf(information.getTaskObjectclass()));
     attributes.add(new LDAPAttribute(ATTR_OBJECTCLASS, ocValues));
 
-    ArrayList<ASN1OctetString> taskIDValues = new ArrayList<ASN1OctetString>(1);
-    taskIDValues.add(new ASN1OctetString(taskID));
+    ArrayList<ByteString> taskIDValues = new ArrayList<ByteString>(1);
+    taskIDValues.add(ByteString.valueOf(taskID));
 
     if (scheduleRecurring) {
       attributes.add(new LDAPAttribute(ATTR_RECURRING_TASK_ID, taskIDValues));
     }
     attributes.add(new LDAPAttribute(ATTR_TASK_ID, taskIDValues));
 
-    ArrayList<ASN1OctetString> classValues = new ArrayList<ASN1OctetString>(1);
-    classValues.add(new ASN1OctetString(information.getTaskClass().getName()));
+    ArrayList<ByteString> classValues = new ArrayList<ByteString>(1);
+    classValues.add(ByteString.valueOf(information.getTaskClass().getName()));
     attributes.add(new LDAPAttribute(ATTR_TASK_CLASS, classValues));
 
     // add the start time if necessary
     Date startDate = information.getStartDateTime();
     if (startDate != null) {
       String startTimeString = StaticUtils.formatDateTimeString(startDate);
-      ArrayList<ASN1OctetString> startDateValues =
-              new ArrayList<ASN1OctetString>(1);
-      startDateValues.add(new ASN1OctetString(startTimeString));
+      ArrayList<ByteString> startDateValues =
+              new ArrayList<ByteString>(1);
+      startDateValues.add(ByteString.valueOf(startTimeString));
       attributes.add(new LDAPAttribute(ATTR_TASK_SCHEDULED_START_TIME,
               startDateValues));
     }
 
     if (scheduleRecurring) {
-      ArrayList<ASN1OctetString> recurringPatternValues =
-        new ArrayList<ASN1OctetString>(1);
-      recurringPatternValues.add(new ASN1OctetString(
+      ArrayList<ByteString> recurringPatternValues =
+        new ArrayList<ByteString>(1);
+      recurringPatternValues.add(ByteString.valueOf(
         information.getRecurringDateTime()));
       attributes.add(new LDAPAttribute(ATTR_RECURRING_TASK_SCHEDULE,
         recurringPatternValues));
@@ -190,10 +190,10 @@
     // add dependency IDs
     List<String> dependencyIds = information.getDependencyIds();
     if (dependencyIds != null && dependencyIds.size() > 0) {
-      ArrayList<ASN1OctetString> dependencyIdValues =
-              new ArrayList<ASN1OctetString>(dependencyIds.size());
+      ArrayList<ByteString> dependencyIdValues =
+              new ArrayList<ByteString>(dependencyIds.size());
       for (String dependencyId : dependencyIds) {
-        dependencyIdValues.add(new ASN1OctetString(dependencyId));
+        dependencyIdValues.add(ByteString.valueOf(dependencyId));
       }
       attributes.add(new LDAPAttribute(ATTR_TASK_DEPENDENCY_IDS,
               dependencyIdValues));
@@ -203,9 +203,9 @@
       if (fda == null) {
         fda = FailedDependencyAction.defaultValue();
       }
-      ArrayList<ASN1OctetString> fdaValues =
-              new ArrayList<ASN1OctetString>(1);
-      fdaValues.add(new ASN1OctetString(fda.name()));
+      ArrayList<ByteString> fdaValues =
+              new ArrayList<ByteString>(1);
+      fdaValues.add(ByteString.valueOf(fda.name()));
       attributes.add(new LDAPAttribute(ATTR_TASK_FAILED_DEPENDENCY_ACTION,
               fdaValues));
     }
@@ -214,10 +214,10 @@
     List<String> compNotifEmailAddresss =
             information.getNotifyUponCompletionEmailAddresses();
     if (compNotifEmailAddresss != null && compNotifEmailAddresss.size() > 0) {
-      ArrayList<ASN1OctetString> compNotifEmailAddrValues =
-              new ArrayList<ASN1OctetString>(compNotifEmailAddresss.size());
+      ArrayList<ByteString> compNotifEmailAddrValues =
+              new ArrayList<ByteString>(compNotifEmailAddresss.size());
       for (String emailAddr : compNotifEmailAddresss) {
-        compNotifEmailAddrValues.add(new ASN1OctetString(emailAddr));
+        compNotifEmailAddrValues.add(ByteString.valueOf(emailAddr));
       }
       attributes.add(new LDAPAttribute(ATTR_TASK_NOTIFY_ON_COMPLETION,
               compNotifEmailAddrValues));
@@ -227,10 +227,10 @@
     List<String> errNotifEmailAddresss =
             information.getNotifyUponErrorEmailAddresses();
     if (errNotifEmailAddresss != null && errNotifEmailAddresss.size() > 0) {
-      ArrayList<ASN1OctetString> errNotifEmailAddrValues =
-              new ArrayList<ASN1OctetString>(errNotifEmailAddresss.size());
+      ArrayList<ByteString> errNotifEmailAddrValues =
+              new ArrayList<ByteString>(errNotifEmailAddresss.size());
       for (String emailAddr : errNotifEmailAddresss) {
-        errNotifEmailAddrValues.add(new ASN1OctetString(emailAddr));
+        errNotifEmailAddrValues.add(ByteString.valueOf(emailAddr));
       }
       attributes.add(new LDAPAttribute(ATTR_TASK_NOTIFY_ON_ERROR,
               errNotifEmailAddrValues));
@@ -289,7 +289,7 @@
     List<Entry> entries = new ArrayList<Entry>();
 
     writeSearch(new SearchRequestProtocolOp(
-            new ASN1OctetString(ConfigConstants.DN_TASK_ROOT),
+        ByteString.valueOf(ConfigConstants.DN_TASK_ROOT),
             SearchScope.WHOLE_SUBTREE,
             DereferencePolicy.NEVER_DEREF_ALIASES,
             Integer.MAX_VALUE,
@@ -341,7 +341,7 @@
     Entry entry = null;
 
     writeSearch(new SearchRequestProtocolOp(
-            new ASN1OctetString(ConfigConstants.DN_TASK_ROOT),
+        ByteString.valueOf(ConfigConstants.DN_TASK_ROOT),
             SearchScope.WHOLE_SUBTREE,
             DereferencePolicy.NEVER_DEREF_ALIASES,
             Integer.MAX_VALUE,
@@ -395,18 +395,18 @@
     if (state != null) {
       if (!TaskState.isDone(state)) {
 
-        ASN1OctetString dn = new ASN1OctetString(entry.getDN().toString());
+        ByteString dn = ByteString.valueOf(entry.getDN().toString());
 
         ArrayList<RawModification> mods = new ArrayList<RawModification>();
 
-        ArrayList<ASN1OctetString> values = new ArrayList<ASN1OctetString>();
+        ArrayList<ByteString> values = new ArrayList<ByteString>();
         String newState;
         if (TaskState.isPending(state)) {
           newState = TaskState.CANCELED_BEFORE_STARTING.name();
         } else {
           newState = TaskState.STOPPED_BY_ADMINISTRATOR.name();
         }
-        values.add(new ASN1OctetString(newState));
+        values.add(ByteString.valueOf(newState));
         LDAPAttribute attr = new LDAPAttribute(ATTR_TASK_STATE, values);
         mods.add(new LDAPModification(ModificationType.REPLACE, attr));
 
@@ -443,7 +443,7 @@
         }
       } else if (TaskState.isRecurring(state)) {
 
-        ASN1OctetString dn = new ASN1OctetString(entry.getDN().toString());
+        ByteString dn = ByteString.valueOf(entry.getDN().toString());
         DeleteRequestProtocolOp deleteRequest =
           new DeleteRequestProtocolOp(dn);
 
@@ -498,7 +498,7 @@
     LDAPMessage requestMessage = new LDAPMessage(
             nextMessageID.getAndIncrement(),
             searchRequest,
-            new ArrayList<LDAPControl>());
+            new ArrayList<Control>());
 
     // Send the request to the server and read the response.
     writer.writeMessage(requestMessage);
diff --git a/opends/src/server/org/opends/server/tools/tasks/TaskEntry.java b/opends/src/server/org/opends/server/tools/tasks/TaskEntry.java
index 30448f7..279e541 100644
--- a/opends/src/server/org/opends/server/tools/tasks/TaskEntry.java
+++ b/opends/src/server/org/opends/server/tools/tasks/TaskEntry.java
@@ -149,7 +149,7 @@
               valueList = new ArrayList<String>();
               taskSpecificAttrValues.put(attrTypeName, valueList);
             }
-            valueList.add(av.getStringValue());
+            valueList.add(av.getValue().toString());
           }
         }
       }
@@ -386,7 +386,7 @@
     if (attrList != null && attrList.size() == 1) {
       Attribute attr = attrList.get(0);
       if (!attr.isEmpty()) {
-        return attr.iterator().next().getStringValue();
+        return attr.iterator().next().getValue().toString();
       }
     }
     return "";
@@ -398,7 +398,7 @@
     if (attrList != null) {
       for (Attribute attr : attrList) {
         for (AttributeValue value : attr) {
-          valuesList.add(value.getStringValue());
+          valuesList.add(value.getValue().toString());
         }
       }
     }
diff --git a/opends/src/server/org/opends/server/types/AbstractOperation.java b/opends/src/server/org/opends/server/types/AbstractOperation.java
index d7dae8c..db10ccb 100644
--- a/opends/src/server/org/opends/server/types/AbstractOperation.java
+++ b/opends/src/server/org/opends/server/types/AbstractOperation.java
@@ -22,7 +22,7 @@
  * CDDL HEADER END
  *
  *
- *      Copyright 2006-2008 Sun Microsystems, Inc.
+ *      Copyright 2006-2009 Sun Microsystems, Inc.
  */
 package org.opends.server.types;
 import org.opends.messages.Message;
@@ -45,6 +45,8 @@
     DebugLogger.debugEnabled;
 import static org.opends.server.loggers.debug.DebugLogger.getTracer;
 import org.opends.server.loggers.debug.DebugTracer;
+import org.opends.server.controls.ControlDecoder;
+import org.opends.server.protocols.ldap.LDAPControl;
 
 
 /**
@@ -378,6 +380,34 @@
     return requestControls;
   }
 
+  /**
+   * {@inheritDoc}
+   */
+  @SuppressWarnings("unchecked")
+  public final <T extends Control> T getRequestControl(
+      ControlDecoder<T> d) throws DirectoryException
+  {
+    String oid = d.getOID();
+    for(int i = 0; i < requestControls.size(); i++)
+    {
+      Control c = requestControls.get(i);
+      if(c.getOID().equals(oid))
+      {
+        if(c instanceof LDAPControl)
+        {
+          T decodedControl = d.decode(c.isCritical(),
+              ((LDAPControl) c).getValue());
+          requestControls.set(i, decodedControl);
+          return decodedControl;
+        }
+        else
+        {
+          return (T)c;
+        }
+      }
+    }
+    return null;
+  }
 
 
   /**
diff --git a/opends/src/server/org/opends/server/types/AccountStatusNotification.java b/opends/src/server/org/opends/server/types/AccountStatusNotification.java
index aae6f65..aac75fb 100644
--- a/opends/src/server/org/opends/server/types/AccountStatusNotification.java
+++ b/opends/src/server/org/opends/server/types/AccountStatusNotification.java
@@ -287,7 +287,7 @@
       propList = new ArrayList<String>(oldPasswords.size());
       for (AttributeValue v : oldPasswords)
       {
-        propList.add(v.getStringValue());
+        propList.add(v.getValue().toString());
       }
 
       props.put(OLD_PASSWORD, propList);
@@ -298,7 +298,7 @@
       propList = new ArrayList<String>(newPasswords.size());
       for (AttributeValue v : newPasswords)
       {
-        propList.add(v.getStringValue());
+        propList.add(v.getValue().toString());
       }
 
       props.put(NEW_PASSWORD, propList);
diff --git a/opends/src/server/org/opends/server/types/AttributeBuilder.java b/opends/src/server/org/opends/server/types/AttributeBuilder.java
index 5b76b89..d7d4f15 100644
--- a/opends/src/server/org/opends/server/types/AttributeBuilder.java
+++ b/opends/src/server/org/opends/server/types/AttributeBuilder.java
@@ -442,14 +442,14 @@
         }
       }
 
-      ArrayList<ByteString> normalizedSubAny;
+      ArrayList<ByteSequence> normalizedSubAny;
       if (subAny == null)
       {
         normalizedSubAny = null;
       }
       else
       {
-        normalizedSubAny = new ArrayList<ByteString>(subAny.size());
+        normalizedSubAny = new ArrayList<ByteSequence>(subAny.size());
         for (ByteString subAnyElement : subAny)
         {
           try
@@ -1296,7 +1296,7 @@
   public boolean add(String valueString)
   {
     AttributeValue value =
-      new AttributeValue(attributeType, valueString);
+        AttributeValues.create(attributeType, valueString);
     return add(value);
   }
 
@@ -1459,7 +1459,7 @@
   public boolean remove(String valueString)
   {
     AttributeValue value =
-      new AttributeValue(attributeType, valueString);
+        AttributeValues.create(attributeType, valueString);
     return remove(value);
   }
 
@@ -1530,7 +1530,7 @@
   public void replace(String valueString)
   {
     AttributeValue value =
-      new AttributeValue(attributeType, valueString);
+        AttributeValues.create(attributeType, valueString);
     replace(value);
   }
 
diff --git a/opends/src/server/org/opends/server/types/AttributeType.java b/opends/src/server/org/opends/server/types/AttributeType.java
index 4e9df4c..12206e1 100644
--- a/opends/src/server/org/opends/server/types/AttributeType.java
+++ b/opends/src/server/org/opends/server/types/AttributeType.java
@@ -25,8 +25,6 @@
  *      Copyright 2006-2008 Sun Microsystems, Inc.
  */
 package org.opends.server.types;
-import org.opends.messages.Message;
-
 
 
 import java.util.Collection;
@@ -43,7 +41,6 @@
 
 import static org.opends.server.loggers.debug.DebugLogger.*;
 import org.opends.server.loggers.debug.DebugTracer;
-import static org.opends.messages.CoreMessages.*;
 import static org.opends.server.util.ServerConstants.*;
 import static org.opends.server.util.Validator.*;
 
@@ -449,7 +446,7 @@
   public AttributeType recreateFromDefinition()
          throws DirectoryException
   {
-    ByteString value  = ByteStringFactory.create(definition);
+    ByteString value  = ByteString.valueOf(definition);
     Schema     schema = DirectoryServer.getSchema();
 
     AttributeType at =
@@ -689,94 +686,6 @@
 
 
   /**
-   * Attempts to normalize the provided value using the equality
-   * matching rule associated with this attribute type.
-   *
-   * @param  value  The value to be normalized.
-   *
-   * @return  The normalized form of the provided value.
-   *
-   * @throws  DirectoryException  If this attribute type does not have
-   *                              an equality matching rule, or if the
-   *                              provided value could not be
-   *                              normalized.
-   */
-  public ByteString normalize(ByteString value)
-         throws DirectoryException
-  {
-    if (equalityMatchingRule == null)
-    {
-      Message message = ERR_ATTR_TYPE_NORMALIZE_NO_MR.get(
-          String.valueOf(value), getNameOrOID());
-      throw new DirectoryException(ResultCode.INAPPROPRIATE_MATCHING,
-                                   message);
-    }
-
-    return equalityMatchingRule.normalizeValue(value);
-  }
-
-
-
-  /**
-   * Generates a hash code for the specified attribute value.  If an
-   * equality matching rule is defined for this type, then it will be
-   * used to generate the hash code.  If the value does not have an
-   * equality matching rule but does have a normalized form, then that
-   * will be used to obtain the hash code.  Otherwise, it will simply
-   * be the hash code of the provided value.
-   *
-   * @param  value  The attribute value for which to generate the hash
-   *                code.
-   *
-   * @return  The generated hash code for the provided value.
-   */
-  public int generateHashCode(AttributeValue value)
-  {
-    try
-    {
-      if (equalityMatchingRule == null)
-      {
-        ByteString normalizedValue = value.getNormalizedValue();
-        if (normalizedValue == null)
-        {
-          return value.getValue().hashCode();
-        }
-        else
-        {
-          return normalizedValue.hashCode();
-        }
-      }
-      else
-      {
-        return equalityMatchingRule.generateHashCode(value);
-      }
-    }
-    catch (Exception e)
-    {
-      if (debugEnabled())
-      {
-        TRACER.debugCaught(DebugLogLevel.ERROR, e);
-      }
-
-      try
-      {
-        return value.getValue().hashCode();
-      }
-      catch (Exception e2)
-      {
-        if (debugEnabled())
-        {
-          TRACER.debugCaught(DebugLogLevel.ERROR, e2);
-        }
-
-        return 0;
-      }
-    }
-  }
-
-
-
-  /**
    * Appends a string representation of this schema definition's
    * non-generic properties to the provided buffer.
    *
diff --git a/opends/src/server/org/opends/server/types/AttributeValue.java b/opends/src/server/org/opends/server/types/AttributeValue.java
index 2e72aa3..978de26 100644
--- a/opends/src/server/org/opends/server/types/AttributeValue.java
+++ b/opends/src/server/org/opends/server/types/AttributeValue.java
@@ -28,352 +28,67 @@
 
 
 
-import static org.opends.server.loggers.debug.DebugLogger.*;
-import static org.opends.server.util.Validator.*;
-
-import org.opends.server.api.EqualityMatchingRule;
-import org.opends.server.loggers.debug.DebugTracer;
-import org.opends.server.protocols.asn1.ASN1OctetString;
-
-
-
 /**
  * This class defines a data structure that holds information about a
- * single value of an attribute.  It will always store the value in
- * user-provided form, and will also store either a reference to the
- * associated attribute type or the normalized form of the value.  The
- * normalized form of the value should only be used in cases where
- * equality matching between two values can be performed with
- * byte-for-byte comparisons of the normalized values.
+ * single value of an attribute.
  */
-@org.opends.server.types.PublicAPI(
-     stability=org.opends.server.types.StabilityLevel.UNCOMMITTED,
-     mayInstantiate=true,
-     mayExtend=false,
-     mayInvoke=true)
-public final class AttributeValue
+public interface AttributeValue
 {
-  /**
-   * The tracer object for the debug logger.
-   */
-  private static final DebugTracer TRACER = getTracer();
-
-
-
-  // The normalized form of this value.
-  private ByteString normalizedValue;
-
-  // The user-provided form of this value.
-  private final ByteString value;
-
-  // The attribute type with which this value is associated.
-  private final AttributeType attributeType;
-
-
 
   /**
-   * Creates a new attribute value with the provided information.
+   * Indicates whether the provided object is an attribute value that
+   * is equal to this attribute value. It will be considered equal if
+   * the normalized representations of both attribute values are
+   * equal.
    *
-   * @param  attributeType  The attribute type for this attribute
-   *                        value.  It must not be {@code null}.
-   * @param  value          The value in user-provided form for this
-   *                        attribute value.  It must not be
-   *                        {@code null}.
+   * @param o
+   *          The object for which to make the determination.
+   * @return <CODE>true</CODE> if the provided object is an attribute
+   *         value that is equal to this attribute value, or
+   *         <CODE>false</CODE> if not.
    */
-  public AttributeValue(AttributeType attributeType, ByteString value)
-  {
-    ensureNotNull(attributeType, value);
-
-    this.attributeType = attributeType;
-    this.value         = value;
-
-    normalizedValue = null;
-  }
-
-
-  /**
-   * Creates a new attribute value with the provided information.
-   *
-   * @param  attributeType  The attribute type for this attribute
-   *                        value.  It must not be {@code null}.
-   * @param  value          The value in user-provided form for this
-   *                        attribute value.  It must not be
-   *                        {@code null}.
-   */
-  public AttributeValue(AttributeType attributeType, String value)
-  {
-    ensureNotNull(attributeType, value);
-
-    this.attributeType = attributeType;
-    this.value         = new ASN1OctetString(value);
-
-    normalizedValue = null;
-  }
-
-
-  /**
-   * Creates a new attribute value with the provided information.
-   * Note that this version of the constructor should only be used for
-   * attribute types in which equality matching can be performed by
-   * byte-for-byte comparison of normalized values.
-   *
-   * @param  value            The user-provided form of this value.
-   *                          It must not be {@code null}.
-   * @param  normalizedValue  The normalized form of this value.  It
-   *                          must not be {@code null}.
-   */
-  public AttributeValue(ByteString value, ByteString normalizedValue)
-  {
-    ensureNotNull(value, normalizedValue);
-
-    this.value           = value;
-    this.normalizedValue = normalizedValue;
-
-    attributeType = null;
-  }
-
-
-
-  /**
-   * Retrieves the user-defined form of this attribute value.
-   *
-   * @return  The user-defined form of this attribute value.
-   */
-  public ByteString getValue()
-  {
-    return value;
-  }
-
-
-
-  /**
-   * Retrieves the raw bytes that make up this attribute value.
-   *
-   * @return  The raw bytes that make up this attribute value.
-   */
-  public byte[] getValueBytes()
-  {
-    return value.value();
-  }
-
-
-
-  /**
-   * Retrieves a string representation of the user-defined form of
-   * this attribute value.
-   *
-   * @return  The string representation of the user-defined form of
-   *          this attribute value.
-   */
-  public String getStringValue()
-  {
-    return value.stringValue();
-  }
+  boolean equals(Object o);
 
 
 
   /**
    * Retrieves the normalized form of this attribute value.
    *
-   * @return  The normalized form of this attribute value.
-   *
-   * @throws  DirectoryException  If an error occurs while trying to
-   *                              normalize the value (e.g., if it is
-   *                              not acceptable for use with the
-   *                              associated equality matching rule).
+   * @return The normalized form of this attribute value.
+   * @throws DirectoryException
+   *           If an error occurs while trying to normalize the value
+   *           (e.g., if it is not acceptable for use with the
+   *           associated equality matching rule).
    */
-  public ByteString getNormalizedValue()
-         throws DirectoryException
-  {
-    if (normalizedValue == null)
-    {
-      normalizedValue = attributeType.normalize(value);
-    }
-
-    return normalizedValue;
-  }
+  ByteString getNormalizedValue() throws DirectoryException;
 
 
 
   /**
-   * Retrieves the bytes that make up the normalized form of this
-   * value.
+   * Retrieves the user-defined form of this attribute value.
    *
-   * @return  The bytes that make up the normalized form of this
-   *          value.
-   *
-   * @throws  DirectoryException  If an error occurs while trying to
-   *                              normalize the value (e.g., if it is
-   *                              not acceptable for use with the
-   *                              associated equality matching rule).
+   * @return The user-defined form of this attribute value.
    */
-  public byte[] getNormalizedValueBytes()
-         throws DirectoryException
-  {
-    return getNormalizedValue().value();
-  }
+  ByteString getValue();
 
 
 
   /**
-   * Retrieves a string representation of the normalized form of this
-   * attribute value.
+   * Retrieves the hash code for this attribute value. It will be
+   * calculated using the normalized representation of the value.
    *
-   * @return  The string representation of the normalized form of this
-   *          attribute value.
-   *
-   * @throws  DirectoryException  If an error occurs while trying to
-   *                              normalize the value (e.g., if it is
-   *                              not acceptable for use with the
-   *                              associated equality matching rule).
+   * @return The hash code for this attribute value.
    */
-  public String getNormalizedStringValue()
-         throws DirectoryException
-  {
-    if (normalizedValue == null)
-    {
-      normalizedValue = attributeType.normalize(value);
-    }
-
-    return normalizedValue.stringValue();
-  }
-
-
-
-
-  /**
-   * Determines whether this attribute value is equal to the provided
-   * object.
-   *
-   * @param  o  The object for which to make the determination.
-   *
-   * @return  <CODE>true</CODE> if this attribute value is equal to
-   *          the provided object, or <CODE>false</CODE> if not.
-   */
-  public boolean equals(Object o)
-  {
-    if (this == o)
-    {
-      return true;
-    }
-
-    if ((o != null) && (o instanceof AttributeValue))
-    {
-      AttributeValue attrValue = (AttributeValue) o;
-
-
-      try
-      {
-        if (attributeType != null)
-        {
-          EqualityMatchingRule matchingRule =
-               attributeType.getEqualityMatchingRule();
-          if (matchingRule == null)
-          {
-            return getNormalizedValue().equals(
-                        attrValue.getNormalizedValue());
-          }
-          else
-          {
-            return (matchingRule.valuesMatch(getNormalizedValue(),
-                         attrValue.getNormalizedValue()) ==
-                    ConditionResult.TRUE);
-          }
-        }
-        else if (attrValue.attributeType != null)
-        {
-          EqualityMatchingRule matchingRule =
-               attrValue.attributeType.getEqualityMatchingRule();
-          if (matchingRule == null)
-          {
-            return getNormalizedValue().equals(
-                        attrValue.getNormalizedValue());
-          }
-          else
-          {
-            return (matchingRule.valuesMatch(getNormalizedValue(),
-                         attrValue.getNormalizedValue()) ==
-                    ConditionResult.TRUE);
-          }
-        }
-        else
-        {
-          return normalizedValue.equals(
-                      attrValue.getNormalizedValue());
-        }
-      }
-      catch (Exception e)
-      {
-        if (debugEnabled())
-        {
-          TRACER.debugCaught(DebugLogLevel.ERROR, e);
-        }
-
-        return value.equals(attrValue.getValue());
-      }
-    }
-
-    return false;
-  }
-
-
-
-  /**
-   * Retrieves the hash code for this attribute value.  It will be
-   * calculated as the sum of the first two bytes in the value, or the
-   * value of a single-byte value, or zero for an empty value.
-   *
-   * @return  A hash code for this attribute value.
-   */
-  public int hashCode()
-  {
-    try
-    {
-      if (attributeType == null)
-      {
-        if (normalizedValue != null)
-        {
-          return normalizedValue.hashCode();
-        }
-        else
-        {
-          return value.hashCode();
-        }
-      }
-      else
-      {
-        return attributeType.generateHashCode(this);
-      }
-    }
-    catch (Exception e)
-    {
-      if (debugEnabled())
-      {
-        TRACER.debugCaught(DebugLogLevel.ERROR, e);
-      }
-
-      return value.hashCode();
-    }
-  }
+  int hashCode();
 
 
 
   /**
    * Retrieves a string representation of this attribute value.
    *
-   * @return  A string representation of this attribute value.
+   * @return A string representation of this attribute value.
    */
-  public String toString()
-  {
-    if (value == null)
-    {
-      return "null";
-    }
-    else
-    {
-      return value.stringValue();
-    }
-  }
+  String toString();
 
 
 
@@ -381,12 +96,8 @@
    * Appends a string representation of this attribute value to the
    * provided buffer.
    *
-   * @param  buffer  The buffer to which the information should be
-   *                 appended.
+   * @param buffer
+   *          The buffer to which the information should be appended.
    */
-  public void toString(StringBuilder buffer)
-  {
-    buffer.append(value.toString());
-  }
+  void toString(StringBuilder buffer);
 }
-
diff --git a/opends/src/server/org/opends/server/types/AttributeValues.java b/opends/src/server/org/opends/server/types/AttributeValues.java
new file mode 100644
index 0000000..b51b385
--- /dev/null
+++ b/opends/src/server/org/opends/server/types/AttributeValues.java
@@ -0,0 +1,424 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License").  You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE
+ * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
+ * add the following below this CDDL 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.server.types;
+
+
+
+import static org.opends.messages.CoreMessages.*;
+import static org.opends.server.loggers.debug.DebugLogger.*;
+
+import org.opends.messages.Message;
+import org.opends.server.api.EqualityMatchingRule;
+import org.opends.server.loggers.debug.DebugTracer;
+
+
+
+/**
+ * This class contains various methods for manipulating
+ * {@link AttributeValue}s as well as static factory methods for
+ * facilitating common {@link AttributeValue} construction use-cases.
+ * <p>
+ * Of particular interest are the following three factory methods:
+ *
+ * <pre>
+ * create(AttributeType, ByteString);
+ * create(ByteString, ByteString);
+ * </pre>
+ *
+ * These are provided in order to facilitate construction of delayed
+ * normalization using AttributeType and pre-normalized attributes
+ * values respectively.
+ */
+public final class AttributeValues
+{
+
+  /**
+   * Prevent instantiation.
+   */
+  private AttributeValues()
+  {
+    // Do nothing.
+  }
+
+
+
+  /**
+   * Creates an AttributeValue where the value will the normalized on
+   * demand using the matching rules of the provided AttributeType.
+   * Equality matching involving this AttributeValue will be based on
+   * the matching rules of the provided AttributeType.
+   *
+   * @param attributeType
+   *          The AttributeType to use.
+   * @param value
+   *          The attribute value as a ByteString.
+   * @return The newly created AttributeValue.
+   */
+  public static AttributeValue create(AttributeType attributeType,
+      ByteString value)
+  {
+    return new DelayedNormalizationValue(attributeType, value);
+  }
+
+
+
+  /**
+   * Creates an AttributeValue where the UTF-8 encoded value of the
+   * string will the normalized on demand sing the matching rules of
+   * the provided AttributeType. Equality matching involving this
+   * AttributeValue will be based on the matching rules of the
+   * provided AttributeType.
+   *
+   * @param attributeType
+   *          The AttributeType to use.
+   * @param value
+   *          The attribute value as a String.
+   * @return The newly created AttributeValue.
+   */
+  public static AttributeValue create(AttributeType attributeType,
+                                      String value)
+  {
+    return new DelayedNormalizationValue(attributeType, ByteString
+        .valueOf(value));
+  }
+
+
+
+  /**
+   * Creates an AttributeValue where the value is pre-normalized.
+   * Equality matching will be based on a byte-by-byte comparison.
+   *
+   * @param value
+   *          The attribute value as a ByteString.
+   * @param normalizedValue
+   *          The normalized attribute value as a ByteString.
+   * @return The newly created AttributeValue.
+   */
+  public static AttributeValue create(ByteString value,
+      ByteString normalizedValue)
+  {
+    return new PreNormalizedValue(value, normalizedValue);
+  }
+
+
+
+  /**
+   * This attribute value implementation will always store the value
+   * in user-provided form, and a reference to the associated
+   * attribute type. The normalized form of the value will be
+   * initialized upon first request. The normalized form of the value
+   * should only be used in cases where equality matching between two
+   * values can be performed with byte-for-byte comparisons of the
+   * normalized values.
+   */
+  private static final class DelayedNormalizationValue implements
+      AttributeValue
+  {
+
+    /**
+     * The tracer object for the debug logger.
+     */
+    private static final DebugTracer TRACER = getTracer();
+
+    private final AttributeType attributeType;
+
+    private final ByteString value;
+
+    private ByteString normalizedValue;
+
+
+    /**
+     * Construct a new DelayedNormalizationValue.
+     *
+     * @param attributeType The attribute type.
+     * @param value The value of the attriute.
+     */
+    private DelayedNormalizationValue(
+        AttributeType attributeType, ByteString value)
+    {
+      this.attributeType = attributeType;
+      this.value = value;
+      this.normalizedValue = null;
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public ByteString getNormalizedValue() throws DirectoryException
+    {
+      if (normalizedValue == null)
+      {
+        EqualityMatchingRule equalityMatchingRule = attributeType
+            .getEqualityMatchingRule();
+        if (equalityMatchingRule == null)
+        {
+          Message message = ERR_ATTR_TYPE_NORMALIZE_NO_MR.get(String
+              .valueOf(value), attributeType.getNameOrOID());
+          throw new DirectoryException(
+              ResultCode.INAPPROPRIATE_MATCHING, message);
+        }
+
+        normalizedValue = equalityMatchingRule.normalizeValue(value);
+      }
+
+      return normalizedValue;
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public ByteString getValue()
+    {
+      return value;
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean equals(Object o)
+    {
+      if (this == o)
+      {
+        return true;
+      }
+      else if (o instanceof AttributeValue)
+      {
+        AttributeValue attrValue = (AttributeValue) o;
+        try
+        {
+          return getNormalizedValue().equals(
+              attrValue.getNormalizedValue());
+        }
+        catch (Exception e)
+        {
+          if (debugEnabled())
+          {
+            TRACER.debugCaught(DebugLogLevel.ERROR, e);
+          }
+
+          return value.equals(attrValue.getValue());
+        }
+      }
+
+      return false;
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public int hashCode()
+    {
+      EqualityMatchingRule equalityMatchingRule = attributeType
+          .getEqualityMatchingRule();
+
+      ByteString valueToHash;
+      try
+      {
+        valueToHash = getNormalizedValue();
+      }
+      catch (Exception e)
+      {
+        if (debugEnabled())
+        {
+          TRACER.debugCaught(DebugLogLevel.ERROR, e);
+        }
+
+        valueToHash = value;
+      }
+
+      if (equalityMatchingRule != null)
+      {
+        return equalityMatchingRule.generateHashCode(valueToHash);
+      }
+      else
+      {
+        return valueToHash.hashCode();
+      }
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public String toString()
+    {
+      if (value == null)
+      {
+        return "null";
+      }
+      else
+      {
+        return value.toString();
+      }
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void toString(StringBuilder buffer)
+    {
+      buffer.append(value.toString());
+    }
+  }
+
+
+
+  /**
+   * This attribute value implementation will always store the value
+   * in user-provided form, and the normalized form. The normalized
+   * form of the value should only be used in cases where equality
+   * matching between two values can be performed with byte-for-byte
+   * comparisons of the normalized values.
+   */
+  private static final class PreNormalizedValue
+      implements AttributeValue
+  {
+
+    /**
+     * The tracer object for the debug logger.
+     */
+    private static final DebugTracer TRACER = getTracer();
+
+    private final ByteString value;
+
+    private final ByteString normalizedValue;
+
+
+    /**
+     * Construct a new PreNormalizedValue.
+     * @param value The user provided value of the attribute.
+     * @param normalizedValue The normalized value of the attribute.
+     */
+    private PreNormalizedValue(ByteString value,
+                               ByteString normalizedValue)
+    {
+      this.value = value;
+      this.normalizedValue = normalizedValue;
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public ByteString getNormalizedValue()
+    {
+      return normalizedValue;
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public ByteString getValue()
+    {
+      return value;
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean equals(Object o)
+    {
+      if (this == o)
+      {
+        return true;
+      }
+      else if (o instanceof AttributeValue)
+      {
+        AttributeValue attrValue = (AttributeValue) o;
+        try
+        {
+          return normalizedValue.equals(
+              attrValue.getNormalizedValue());
+        }
+        catch (Exception e)
+        {
+          if (debugEnabled())
+          {
+            TRACER.debugCaught(DebugLogLevel.ERROR, e);
+          }
+
+          return value.equals(attrValue.getValue());
+        }
+      }
+
+      return false;
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public int hashCode()
+    {
+      return normalizedValue.hashCode();
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public String toString()
+    {
+      if (value == null)
+      {
+        return "null";
+      }
+      else
+      {
+        return value.toString();
+      }
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void toString(StringBuilder buffer)
+    {
+      buffer.append(value.toString());
+    }
+  }
+}
diff --git a/opends/src/server/org/opends/server/types/Attributes.java b/opends/src/server/org/opends/server/types/Attributes.java
index b06d093..3430b70 100644
--- a/opends/src/server/org/opends/server/types/Attributes.java
+++ b/opends/src/server/org/opends/server/types/Attributes.java
@@ -135,7 +135,7 @@
   public static Attribute create(AttributeType attributeType,
       String name, String valueString)
   {
-    AttributeValue value = new AttributeValue(attributeType,
+    AttributeValue value = AttributeValues.create(attributeType,
         valueString);
     return create(attributeType, name, value);
   }
diff --git a/opends/src/server/org/opends/server/types/ByteArray.java b/opends/src/server/org/opends/server/types/ByteArray.java
deleted file mode 100644
index ba8d85f..0000000
--- a/opends/src/server/org/opends/server/types/ByteArray.java
+++ /dev/null
@@ -1,132 +0,0 @@
-/*
- * CDDL HEADER START
- *
- * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
- *
- * You can obtain a copy of the license at
- * trunk/opends/resource/legal-notices/OpenDS.LICENSE
- * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
- * See the License for the specific language governing permissions
- * and limitations under the License.
- *
- * When distributing Covered Code, include this CDDL HEADER in each
- * file and include the License file at
- * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
- * add the following below this CDDL 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.server.types;
-
-
-
-import java.util.Arrays;
-
-
-
-/**
- * This class provides a data structure that holds a byte array but
- * also includes the necessary {@code equals} and {@code hashCode}
- * methods to make it suitable for use in maps.
- */
-@org.opends.server.types.PublicAPI(
-     stability=org.opends.server.types.StabilityLevel.UNCOMMITTED,
-     mayInstantiate=false,
-     mayExtend=false,
-     mayInvoke=true)
-public final class ByteArray
-{
-  // The array that will be wrapped by this object.
-  private final byte[] array;
-
-
-
-  /**
-   * Creates a new {@code ByteArray} object that wraps the provided
-   * array.
-   *
-   * @param  array  The array to be wrapped with this
-   *                {@code ByteArray}.
-   */
-  public ByteArray(byte[] array)
-  {
-    this.array = array;
-  }
-
-
-
-  /**
-   * Retrieves the array wrapped by this {@code ByteArray} object.
-   *
-   * @return  The array wrapped by this {@code ByteArray} object.
-   */
-  public byte[] array()
-  {
-    return array;
-  }
-
-
-
-  /**
-   * Retrieves a hash code for this {@code ByteArray}.  It will be the
-   * sum of all of the bytes contained in the wrapped array.
-   *
-   * @return  A hash code for this {@code ByteArray}.
-   */
-  public int hashCode()
-  {
-    int hashCode = 0;
-    for (int i=0; i < array.length; i++)
-    {
-      hashCode += array[i];
-    }
-
-    return hashCode;
-  }
-
-
-
-  /**
-   * Indicates whether the provided object is equal to this
-   * {@code ByteArray}.  In order for it to be considered equal, the
-   * provided object must be a non-null {@code ByteArray} object with
-   * a wrapped array 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
-   *          {@code ByteArray} whose content is equal to that of this
-   *          {@code ByteArray}, or {@code false} if not.
-   */
-  public boolean equals(Object o)
-  {
-    if (o == this)
-    {
-      return true;
-    }
-
-    if (o == null)
-    {
-      return false;
-    }
-
-    if (o instanceof ByteArray)
-    {
-      ByteArray ba = (ByteArray) o;
-      return Arrays.equals(array, ba.array);
-    }
-    else
-    {
-      return false;
-    }
-  }
-}
-
diff --git a/opends/src/server/org/opends/server/types/ByteSequence.java b/opends/src/server/org/opends/server/types/ByteSequence.java
new file mode 100644
index 0000000..d43e5ac
--- /dev/null
+++ b/opends/src/server/org/opends/server/types/ByteSequence.java
@@ -0,0 +1,353 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License").  You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE
+ * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
+ * add the following below this CDDL HEADER, 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.server.types;
+
+
+
+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/opends/src/server/org/opends/server/types/ByteSequenceReader.java b/opends/src/server/org/opends/server/types/ByteSequenceReader.java
new file mode 100644
index 0000000..125e961
--- /dev/null
+++ b/opends/src/server/org/opends/server/types/ByteSequenceReader.java
@@ -0,0 +1,509 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License").  You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE
+ * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
+ * add the following below this CDDL HEADER, 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.server.types;
+
+
+
+/**
+ * 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(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() < 1}.
+   */
+  public byte get() throws IndexOutOfBoundsException
+  {
+    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() < b.length}.
+   */
+  public void get(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() < length}.
+   */
+  public void get(byte[] b, int offset, 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
+      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() < length}.
+   */
+  public ByteSequence getByteSequence(int length)
+      throws IndexOutOfBoundsException
+  {
+    int newPos = pos + length;
+    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() < length}.
+   */
+  public ByteString getByteString(int length)
+      throws IndexOutOfBoundsException
+  {
+    return getByteSequence(length).toByteString();
+  }
+
+
+
+  /**
+   * 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() < 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 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() < 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() < 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 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() < length}.
+   */
+  public String getString(int length) throws IndexOutOfBoundsException
+  {
+    if (remaining() < length)
+    {
+      throw new IndexOutOfBoundsException();
+    }
+
+    int newPos = pos + length;
+    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(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(int length) throws IndexOutOfBoundsException
+  {
+    position(pos + length);
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public String toString() {
+    return sequence.toString();
+  }
+}
diff --git a/opends/src/server/org/opends/server/types/ByteString.java b/opends/src/server/org/opends/server/types/ByteString.java
index 03b43f5..34534f7 100644
--- a/opends/src/server/org/opends/server/types/ByteString.java
+++ b/opends/src/server/org/opends/server/types/ByteString.java
@@ -22,101 +22,761 @@
  * CDDL HEADER END
  *
  *
- *      Copyright 2006-2008 Sun Microsystems, Inc.
+ *      Copyright 2009 Sun Microsystems, Inc.
  */
 package org.opends.server.types;
 
 
 
-import org.opends.server.protocols.asn1.ASN1OctetString;
+import static org.opends.server.loggers.debug.DebugLogger.*;
+import static org.opends.server.util.ServerConstants.*;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+import org.opends.server.loggers.debug.DebugTracer;
+import org.opends.server.util.StaticUtils;
 
 
 
 /**
- * This interface defines data type that is backed by a byte array but
- * may also have a string representation.  The preferred way to create
- * a <CODE>ByteString</CODE> object is to use one of the
- * <CODE>ByteStringFactory.create</CODE> methods.
+ * An immutable sequence of bytes backed by a byte array.
  */
-@org.opends.server.types.PublicAPI(
-     stability=org.opends.server.types.StabilityLevel.UNCOMMITTED,
-     mayInstantiate=false,
-     mayExtend=false,
-     mayInvoke=true)
-public interface ByteString
+public final class ByteString implements ByteSequence
 {
-  /**
-   * Retrieves the value of this byte string as a byte array.
-   *
-   * @return  The value of this byte string as a byte array.
-   */
-  public byte[] value();
+
+  // Singleton empty byte string.
+  private static final ByteString EMPTY = wrap(new byte[0]);
+
+  // Used for tracing exceptions.
+  private static final DebugTracer TRACER = getTracer();
 
 
 
   /**
-   * Retrieves the value of this byte string as a string.
+   * Returns an empty byte string.
    *
-   * @return  The value of this byte string as a string.
+   * @return An empty byte string.
    */
-  public String stringValue();
+  public static ByteString empty()
+  {
+    return EMPTY;
+  }
 
 
 
   /**
-   * Sets the value for this byte string.
+   * Returns a byte string containing the big-endian encoded bytes of
+   * the provided integer.
    *
-   * @param  value  The value for this byte string.
+   * @param i
+   *          The integer to encode.
+   * @return The byte string containing the big-endian encoded bytes
+   *         of the provided integer.
    */
-  public void setValue(byte[] value);
+  public static ByteString valueOf(int i)
+  {
+    byte[] bytes = new byte[4];
+    for (int j = 3; j >= 0; j--)
+    {
+      bytes[j] = (byte) (i & 0xFF);
+      i >>>= 8;
+    }
+    return wrap(bytes);
+  }
 
 
 
   /**
-   * Sets the value for this byte string.
+   * Returns a byte string containing the big-endian encoded bytes of
+   * the provided long.
    *
-   * @param  value  The value for this byte string.
+   * @param l
+   *          The long to encode.
+   * @return The byte string containing the big-endian encoded bytes
+   *         of the provided long.
    */
-  public void setValue(String value);
+  public static ByteString valueOf(long l)
+  {
+    byte[] bytes = new byte[8];
+    for (int i = 7; i >= 0; i--)
+    {
+      bytes[i] = (byte) (l & 0xFF);
+      l >>>= 8;
+    }
+    return wrap(bytes);
+  }
 
 
 
   /**
-   * Retrieves this byte string as an ASN.1 octet string.
+   * Returns a byte string containing the UTF-8 encoded bytes of the
+   * provided string.
    *
-   * @return  An ASN.1 octet string with the value of this byte
-   *          string.
+   * @param s
+   *          The string to use.
+   * @return The byte string with the encoded bytes of the provided
+   *         string.
    */
-  public ASN1OctetString toASN1OctetString();
+  public static ByteString valueOf(String s)
+  {
+    return wrap(StaticUtils.getBytes(s));
+  }
 
 
 
   /**
-   * Retrieves a string representation of this byte string.
+   * 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.
    *
-   * @return  A string representation of this byte string.
+   * @param b
+   *          The byte array to wrap.
+   * @return The byte string that wraps the given byte array.
    */
-  public String toString();
+  public static ByteString wrap(byte[] b)
+  {
+    return new ByteString(b, 0, b.length);
+  }
 
 
 
   /**
-   * Appends a string representation of this byte string to the
-   * provided buffer.
+   * 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  buffer  The buffer to which the information should be
-   *                 appended.
+   * @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 void toString(StringBuilder buffer);
+  public static ByteString wrap(byte[] b, int offset, int length)
+      throws IndexOutOfBoundsException
+  {
+    checkArrayBounds(b, offset, length);
+    return new ByteString(b, offset, length);
+  }
 
 
 
   /**
-   * Creates a duplicate of this byte string whose contents can be
-   * altered without impacting this byte string.
+   * Checks the array bounds of the provided byte array sub-sequence,
+   * throwing an {@code IndexOutOfBoundsException} if they are
+   * illegal.
    *
-   * @return  A duplicate of this byte string.
+   * @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}.
    */
-  public ByteString duplicate();
+  static void checkArrayBounds(byte[] b, int offset, 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(byte[] b1, int offset1, int length1, byte[] b2,
+      int offset2, int length2)
+  {
+    int count = Math.min(length1, length2);
+    int i = offset1;
+    int j = offset2;
+    while (count-- != 0)
+    {
+      int firstByte = 0xFF & b1[i++];
+      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(byte[] b1, int offset1, int length1,
+      byte[] b2, int offset2, 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(byte[] b, int offset, 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(byte[] b, int offset, int length)
+  {
+    String stringValue;
+    try
+    {
+      stringValue = new String(b, offset, length, "UTF-8");
+    }
+    catch (Exception e)
+    {
+      if (debugEnabled())
+      {
+        TRACER.debugCaught(DebugLogLevel.ERROR, e);
+      }
+
+      stringValue = new String(b, offset, length);
+    }
+
+    return stringValue;
+  }
+
+  // The buffer where data is stored.
+  private final byte[] buffer;
+
+  // The number of bytes to expose from the buffer.
+  private final int length;
+
+  // The start index of the range of bytes to expose through this byte
+  // string.
+  private 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(byte[] b, int offset, 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(int index) throws IndexOutOfBoundsException
+  {
+    if (index >= length || index < 0)
+    {
+      throw new IndexOutOfBoundsException();
+    }
+    return buffer[offset + index];
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public int compareTo(byte[] b, int offset, int length)
+      throws IndexOutOfBoundsException
+  {
+    checkArrayBounds(b, offset, length);
+    return compareTo(this.buffer, this.offset, this.length,
+        b, offset, length);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public int compareTo(ByteSequence o)
+  {
+    if (this == o) return 0;
+    return -(o.compareTo(buffer, offset, length));
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public byte[] copyTo(byte[] b)
+  {
+    copyTo(b, 0);
+    return b;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public byte[] copyTo(byte[] b, 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(ByteStringBuilder builder)
+  {
+    builder.append(buffer, offset, length);
+    return builder;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public OutputStream copyTo(OutputStream stream) throws IOException
+  {
+    stream.write(buffer, offset, length);
+    return stream;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public boolean equals(byte[] b, int offset, 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(Object o)
+  {
+    if (this == o)
+    {
+      return true;
+    }
+    else if (o instanceof ByteSequence)
+    {
+      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(int start, 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 a string representation of the contents of this byte
+   * sequence using hexadecimal characters and a space between each
+   * byte.
+   *
+   * @return A string representation of the contents of this byte
+   *         sequence using hexadecimal characters.
+   */
+  public String toHex()
+  {
+    StringBuilder builder = new StringBuilder((length - 1) * 3 + 2);
+    builder.append(StaticUtils.byteToHex(buffer[offset]));
+
+    for (int i = 1; i < length; i++)
+    {
+      builder.append(" ");
+      builder.append(StaticUtils.byteToHex(buffer[offset + i]));
+    }
+
+    return builder.toString();
+  }
+
+
+
+  /**
+   * Appends a string representation of the data in this byte sequence
+   * to the given buffer 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 builder
+   *          The buffer to which the information is to be appended.
+   * @param indent
+   *          The number of spaces to indent the output.
+   */
+  public void toHexPlusAscii(StringBuilder builder, int indent)
+  {
+    StringBuilder indentBuf = new StringBuilder(indent);
+    for (int i = 0; i < indent; i++)
+    {
+      indentBuf.append(' ');
+    }
+
+    int pos = 0;
+    while ((length - pos) >= 16)
+    {
+      StringBuilder asciiBuf = new StringBuilder(17);
+
+      byte currentByte = buffer[offset + pos];
+      builder.append(indentBuf);
+      builder.append(StaticUtils.byteToHex(currentByte));
+      asciiBuf.append(StaticUtils.byteToASCII(currentByte));
+      pos++;
+
+      for (int i = 1; i < 16; i++, pos++)
+      {
+        currentByte = buffer[offset + pos];
+        builder.append(' ');
+        builder.append(StaticUtils.byteToHex(currentByte));
+        asciiBuf.append(StaticUtils.byteToASCII(currentByte));
+
+        if (i == 7)
+        {
+          builder.append("  ");
+          asciiBuf.append(' ');
+        }
+      }
+
+      builder.append("  ");
+      builder.append(asciiBuf);
+      builder.append(EOL);
+    }
+
+    int remaining = (length - pos);
+    if (remaining > 0)
+    {
+      StringBuilder asciiBuf = new StringBuilder(remaining + 1);
+
+      byte currentByte = buffer[offset + pos];
+      builder.append(indentBuf);
+      builder.append(StaticUtils.byteToHex(currentByte));
+      asciiBuf.append(StaticUtils.byteToASCII(currentByte));
+      pos++;
+
+      for (int i = 1; i < 16; i++, pos++)
+      {
+        builder.append(' ');
+
+        if (i < remaining)
+        {
+          currentByte = buffer[offset + pos];
+          builder.append(StaticUtils.byteToHex(currentByte));
+          asciiBuf.append(StaticUtils.byteToASCII(currentByte));
+        }
+        else
+        {
+          builder.append("  ");
+        }
+
+        if (i == 7)
+        {
+          builder.append("  ");
+
+          if (i < remaining)
+          {
+            asciiBuf.append(' ');
+          }
+        }
+      }
+
+      builder.append("  ");
+      builder.append(asciiBuf);
+      builder.append(EOL);
+    }
+  }
+
+
+
+  /**
+   * 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/opends/src/server/org/opends/server/types/ByteStringBuilder.java b/opends/src/server/org/opends/server/types/ByteStringBuilder.java
new file mode 100644
index 0000000..6428187
--- /dev/null
+++ b/opends/src/server/org/opends/server/types/ByteStringBuilder.java
@@ -0,0 +1,1155 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License").  You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE
+ * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
+ * add the following below this CDDL HEADER, 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.server.types;
+
+
+
+import static org.opends.server.loggers.debug.DebugLogger.*;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.nio.ByteBuffer;
+import java.util.zip.DataFormatException;
+
+import org.opends.server.loggers.debug.DebugTracer;
+
+
+
+/**
+ * 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(int offset, int length)
+    {
+      this.subOffset = offset;
+      this.subLength = length;
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public ByteSequenceReader asReader()
+    {
+      return new ByteSequenceReader(this);
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public byte byteAt(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(byte[] b, int offset, 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(ByteSequence o)
+    {
+      if (this == o) return 0;
+
+      // Protect against reallocation: use builder's buffer.
+      return -(o.compareTo(buffer, subOffset, subLength));
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public byte[] copyTo(byte[] b)
+    {
+      copyTo(b, 0);
+      return b;
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public byte[] copyTo(byte[] b, 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(ByteStringBuilder builder)
+    {
+      // Protect against reallocation: use builder's buffer.
+      return builder.append(buffer, subOffset, subLength);
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public OutputStream copyTo(OutputStream stream) throws IOException
+    {
+      // Protect against reallocation: use builder's buffer.
+      stream.write(buffer, subOffset, subLength);
+      return stream;
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean equals(byte[] b, int offset, 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(Object o)
+    {
+      if (this == o)
+      {
+        return true;
+      }
+      else if (o instanceof ByteSequence)
+      {
+        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(int start, 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.
+      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);
+    }
+  }
+
+  // Used for tracing exceptions.
+  private static final DebugTracer TRACER = getTracer();
+
+  // The buffer where data is stored.
+  private byte[] buffer;
+
+  // The number of bytes to expose from the buffer.
+  private 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(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(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(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(byte[] b, int offset, 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(ByteBuffer buffer, 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(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(
+      ByteSequenceReader reader, 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(InputStream stream, int length)
+      throws IndexOutOfBoundsException, IOException
+  {
+    if (length < 0)
+    {
+      throw new IndexOutOfBoundsException();
+    }
+
+    ensureAdditionalCapacity(length);
+    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 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 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 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(String s)
+  {
+    if (s == null)
+    {
+      return this;
+    }
+
+    // Assume that each char is 1 byte
+    int len = s.length();
+    ensureAdditionalCapacity(len);
+
+    for (int i = 0; i < len; i++)
+    {
+      char c = s.charAt(i);
+      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 (Exception e)
+        {
+          if (debugEnabled())
+          {
+            TRACER.debugCaught(DebugLogLevel.ERROR, e);
+          }
+          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(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(int index) throws IndexOutOfBoundsException
+  {
+    if (index >= length || index < 0)
+    {
+      throw new IndexOutOfBoundsException();
+    }
+    return buffer[index];
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public int compareTo(byte[] b, int offset, int length)
+      throws IndexOutOfBoundsException
+  {
+    ByteString.checkArrayBounds(b, offset, length);
+    return ByteString.compareTo(this.buffer, 0, this.length,
+        b, offset, length);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public int compareTo(ByteSequence o)
+  {
+    if (this == o) return 0;
+    return -(o.compareTo(buffer, 0, length));
+  }
+
+
+
+  /**
+   * 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;
+  }
+
+
+
+  /**
+   * Attempts to compress the data in this buffer into the given
+   * buffer. Note that if copmpression was not successful, then the
+   * data in the destination buffer should be considered invalid.
+   *
+   * @param output
+   *          The destination buffer of compressed data.
+   * @param cryptoManager
+   *          The cryptoManager to use to compress the data.
+   * @return <code>true</code> if compression was successful or
+   *         <code>false</code> otherwise.
+   */
+  public boolean compress(ByteStringBuilder output,
+                          CryptoManager cryptoManager)
+  {
+    // Make sure the free space in the destination buffer is at least
+    // as big as this.
+    output.ensureAdditionalCapacity(length);
+
+    int compressedSize = cryptoManager.compress(buffer, 0, length,
+        output.buffer, output.length, output.buffer.length);
+
+    if (compressedSize != -1)
+    {
+      if (debugEnabled())
+      {
+        TRACER.debugInfo("Compression %d/%d%n", compressedSize,
+            length);
+      }
+
+      output.length += compressedSize;
+      return true;
+    }
+
+    return false;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public byte[] copyTo(byte[] b)
+  {
+    copyTo(b, 0);
+    return b;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public byte[] copyTo(byte[] b, 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(ByteStringBuilder builder)
+  {
+    builder.append(buffer, 0, length);
+    return builder;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public OutputStream copyTo(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(int size)
+  {
+    int newCount = this.length + size;
+    if (newCount > buffer.length)
+    {
+      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(byte[] b, int offset, 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(Object o)
+  {
+    if (this == o)
+    {
+      return true;
+    }
+    else if (o instanceof ByteSequence)
+    {
+      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;
+  }
+
+
+
+  /**
+   * 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(int start, 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()
+  {
+    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)
+    {
+      byte[] newBuffer = new byte[length];
+      System.arraycopy(buffer, 0, newBuffer, 0, length);
+      buffer = newBuffer;
+    }
+    return this;
+  }
+
+
+
+  /**
+   * Attempts to uncompress the data in this buffer into the given
+   * destination buffer. Note that if decompression was not
+   * successful, then the data in the destination buffer should be
+   * considered invalid.
+   *
+   * @param output
+   *          The destination buffer of compressed data.
+   * @param cryptoManager
+   *          The cryptoManager to use to compress the data.
+   * @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 boolean uncompress(ByteStringBuilder output,
+      CryptoManager cryptoManager, int uncompressedSize)
+      throws DataFormatException
+  {
+    // Resize destination buffer if a uncompressed size was provided.
+    if (uncompressedSize > 0)
+      output.ensureAdditionalCapacity(uncompressedSize);
+
+    int decompressResult = cryptoManager.uncompress(buffer, 0, length,
+        output.buffer, output.length, output.buffer.length);
+
+    if (decompressResult < 0)
+    {
+      // The destiation buffer wasn't big enough. Resize and retry.
+      output.ensureAdditionalCapacity(-(decompressResult));
+      decompressResult = cryptoManager.uncompress(buffer, 0, length,
+          output.buffer, output.length, output.buffer.length);
+    }
+
+    if (decompressResult >= 0)
+    {
+      // It was successful.
+      output.length += decompressResult;
+      return true;
+    }
+
+    // Still unsuccessful. Give up.
+    return false;
+  }
+}
diff --git a/opends/src/server/org/opends/server/types/ByteStringFactory.java b/opends/src/server/org/opends/server/types/ByteStringFactory.java
deleted file mode 100644
index 6ec0307..0000000
--- a/opends/src/server/org/opends/server/types/ByteStringFactory.java
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * CDDL HEADER START
- *
- * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
- *
- * You can obtain a copy of the license at
- * trunk/opends/resource/legal-notices/OpenDS.LICENSE
- * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
- * See the License for the specific language governing permissions
- * and limitations under the License.
- *
- * When distributing Covered Code, include this CDDL HEADER in each
- * file and include the License file at
- * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
- * add the following below this CDDL 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.server.types;
-
-
-
-import org.opends.server.protocols.asn1.ASN1OctetString;
-
-
-
-
-/**
- * This class provides static factory methods for creating ByteString
- * objects.
- */
-@org.opends.server.types.PublicAPI(
-     stability=org.opends.server.types.StabilityLevel.UNCOMMITTED,
-     mayInstantiate=false,
-     mayExtend=false,
-     mayInvoke=true)
-public final class ByteStringFactory
-{
-  /**
-   * Creates a new <CODE>ByteString</CODE> object with no value.
-   *
-   * @return  A new <CODE>ByteString</CODE> object with no value.
-   */
-  public static ByteString create()
-  {
-    return new ASN1OctetString();
-  }
-
-
-
-  /**
-   * Creates a new <CODE>ByteString</CODE> object for the provided
-   * byte array value.
-   *
-   * @param  value  The value to use to create the
-   *                <CODE>ByteString</CODE> object.
-   *
-   * @return  A new <CODE>ByteString</CODE> object with the specified
-   *          value.
-   */
-  public static ByteString create(byte[] value)
-  {
-    return new ASN1OctetString(value);
-  }
-
-
-
-  /**
-   * Creates a new <CODE>ByteString</CODE> object for the provided
-   * string value.
-   *
-   * @param  value  The value to use to create the
-   *                <CODE>ByteString</CODE> object.
-   *
-   * @return  A new <CODE>ByteString</CODE> object with the specified
-   *          value.
-   */
-  public static ByteString create(String value)
-  {
-    return new ASN1OctetString(value);
-  }
-}
-
diff --git a/opends/src/server/org/opends/server/types/CommonSchemaElements.java b/opends/src/server/org/opends/server/types/CommonSchemaElements.java
index fcec5c1..1f87664 100644
--- a/opends/src/server/org/opends/server/types/CommonSchemaElements.java
+++ b/opends/src/server/org/opends/server/types/CommonSchemaElements.java
@@ -22,7 +22,7 @@
  * CDDL HEADER END
  *
  *
- *      Copyright 2006-2008 Sun Microsystems, Inc.
+ *      Copyright 2006-2009 Sun Microsystems, Inc.
  */
 package org.opends.server.types;
 
@@ -287,6 +287,23 @@
     }
   }
 
+  /**
+   * Retrieves the normalized primary name or OID for this schema
+   * definition. If it does not have any names, then the OID will be
+   * returned.
+   *
+   * @return The name or OID for this schema definition.
+   */
+  public final String getNormalizedPrimaryNameOrOID() {
+
+    if (lowerName != null) {
+      return lowerName;
+    } else {
+      // Guaranteed not to be null.
+      return oid;
+    }
+  }
+
 
 
   /**
diff --git a/opends/src/server/org/opends/server/types/Control.java b/opends/src/server/org/opends/server/types/Control.java
index e4eb788..ef68615 100644
--- a/opends/src/server/org/opends/server/types/Control.java
+++ b/opends/src/server/org/opends/server/types/Control.java
@@ -22,15 +22,13 @@
  * CDDL HEADER END
  *
  *
- *      Copyright 2006-2008 Sun Microsystems, Inc.
+ *      Copyright 2006-2009 Sun Microsystems, Inc.
  */
 package org.opends.server.types;
 
+import org.opends.server.protocols.asn1.ASN1Writer;
 
-
-import org.opends.server.protocols.asn1.ASN1OctetString;
-
-
+import java.io.IOException;
 
 
 /**
@@ -42,11 +40,8 @@
      mayInstantiate=true,
      mayExtend=true,
      mayInvoke=true)
-public class Control
+public abstract class Control
 {
-  // The value for this control.
-  private ASN1OctetString value;
-
   // The criticality for this control.
   private boolean isCritical;
 
@@ -63,30 +58,10 @@
    *                     considered critical in processing the
    *                     request.
    */
-  public Control(String oid, boolean isCritical)
+  protected Control(String oid, boolean isCritical)
   {
     this.oid        = oid;
     this.isCritical = isCritical;
-    this.value      = null;
-  }
-
-
-
-  /**
-   * Creates a new control with the specified information.
-   *
-   * @param  oid         The OID for this control.
-   * @param  isCritical  Indicates whether this control should be
-   *                     considered critical in processing the
-   *                     request.
-   * @param  value       The value for this control.
-   */
-  public Control(String oid, boolean isCritical,
-                 ASN1OctetString value)
-  {
-    this.oid        = oid;
-    this.isCritical = isCritical;
-    this.value      = value;
   }
 
 
@@ -102,19 +77,6 @@
   }
 
 
-
-  /**
-   * Specifies the OID for this control.
-   *
-   * @param  oid  The OID for this control.
-   */
-  public final void setOID(String oid)
-  {
-    this.oid = oid;
-  }
-
-
-
   /**
    * Indicates whether this control should be considered critical in
    * processing the request.
@@ -130,70 +92,48 @@
 
 
   /**
-   * Specifies whether this control should be considered critical in
-   * processing the request.
-   *
-   * @param  isCritical  Specifies whether this control should be
-   *                     considered critical in processing the
-   *                     request.
-   */
-  public final void setCritical(boolean isCritical)
-  {
-    this.isCritical = isCritical;
-  }
-
-
-
-  /**
-   * Retrieves the value for this control.
-   *
-   * @return  The value for this control, or <CODE>null</CODE> if
-   *          there is no value.
-   */
-  public final ASN1OctetString getValue()
-  {
-    return value;
-  }
-
-
-
-  /**
-   * Indicates whether this control has a value.
-   *
-   * @return  <CODE>true</CODE> if this control has a value, or
-   *          <CODE>false</CODE> if it does not.
-   */
-  public final boolean hasValue()
-  {
-    return (value != null);
-  }
-
-
-
-  /**
-   * Specifies the value for this control.
-   *
-   * @param  value  The value for this control.
-   */
-  public final void setValue(ASN1OctetString value)
-  {
-    this.value = value;
-  }
-
-
-
-  /**
    * Retrieves a string representation of this control.
    *
    * @return  A string representation of this control.
    */
-  public String toString()
+  @Override
+  public final String toString()
   {
     StringBuilder buffer = new StringBuilder();
     toString(buffer);
     return buffer.toString();
   }
 
+  /**
+   * Writes this control to an ASN.1 writer.
+   *
+   * @param writer The ASN.1 writer to use.
+   * @throws IOException If a problem occurs while writing to the
+   *                     stream.
+   */
+  public final void write(ASN1Writer writer) throws IOException
+  {
+    writer.writeStartSequence();
+    writer.writeOctetString(getOID());
+    if(isCritical())
+    {
+      writer.writeBoolean(isCritical());
+    }
+    writeValue(writer);
+    writer.writeEndSequence();
+  }
+
+  /**
+   * Writes this control's value to an ASN.1 writer. The value
+   * (if any) must be written as an ASN1OctetString.
+   *
+   * @param writer The ASN.1 writer to use.
+   * @throws IOException If a problem occurs while writing to the
+   *                     stream.
+   */
+  protected abstract void writeValue(ASN1Writer writer)
+      throws IOException;
+
 
 
   /**
@@ -209,13 +149,6 @@
     buffer.append(oid);
     buffer.append(",isCritical=");
     buffer.append(isCritical);
-
-    if (value != null)
-    {
-      buffer.append(",value=");
-      value.toString(buffer);
-    }
-
     buffer.append(")");
   }
 }
diff --git a/opends/src/server/org/opends/server/types/CryptoManager.java b/opends/src/server/org/opends/server/types/CryptoManager.java
index 42f7ff6..bdeb37b 100644
--- a/opends/src/server/org/opends/server/types/CryptoManager.java
+++ b/opends/src/server/org/opends/server/types/CryptoManager.java
@@ -22,7 +22,7 @@
  * CDDL HEADER END
  *
  *
- *      Copyright 2006-2008 Sun Microsystems, Inc.
+ *      Copyright 2006-2009 Sun Microsystems, Inc.
  */
 package org.opends.server.types;
 
@@ -348,13 +348,19 @@
    * 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.
    */
-  int compress(byte[] src, byte[] dst);
+  int compress(byte[] src, int srcOff, int srcLen,
+               byte[] dst, int dstOff, int dstLen);
 
   /**
    * Attempts to uncompress the data in the provided source array into
@@ -368,9 +374,14 @@
    * if a negative value is returned, then the data in the destination
    * array should be considered invalid.
    *
-   * @param  src  The array containing the compressed data.
-   * @param  dst  The array into which the uncompressed data should be
+   * @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,
@@ -381,7 +392,8 @@
    * @throws java.util.zip.DataFormatException  If a problem occurs
    * while attempting to uncompress the data.
    */
-  int uncompress(byte[] src, byte[] dst)
+  int uncompress(byte[] src, int srcOff, int srcLen,
+                 byte[] dst, int dstOff, int dstLen)
          throws DataFormatException;
 
   /**
diff --git a/opends/src/server/org/opends/server/types/DITContentRule.java b/opends/src/server/org/opends/server/types/DITContentRule.java
index 9717a21..ae855cf 100644
--- a/opends/src/server/org/opends/server/types/DITContentRule.java
+++ b/opends/src/server/org/opends/server/types/DITContentRule.java
@@ -268,7 +268,7 @@
   public DITContentRule recreateFromDefinition()
          throws DirectoryException
   {
-    ByteString value  = ByteStringFactory.create(definition);
+    ByteString value  = ByteString.valueOf(definition);
     Schema     schema = DirectoryConfig.getSchema();
 
     DITContentRule dcr =
diff --git a/opends/src/server/org/opends/server/types/DITStructureRule.java b/opends/src/server/org/opends/server/types/DITStructureRule.java
index bb9c3d7..525b603 100644
--- a/opends/src/server/org/opends/server/types/DITStructureRule.java
+++ b/opends/src/server/org/opends/server/types/DITStructureRule.java
@@ -218,7 +218,7 @@
   public DITStructureRule recreateFromDefinition()
          throws DirectoryException
   {
-    ByteString value  = ByteStringFactory.create(definition);
+    ByteString value  = ByteString.valueOf(definition);
     Schema     schema = DirectoryConfig.getSchema();
 
     DITStructureRule dsr =
diff --git a/opends/src/server/org/opends/server/types/DN.java b/opends/src/server/org/opends/server/types/DN.java
index 720f299..953f864 100644
--- a/opends/src/server/org/opends/server/types/DN.java
+++ b/opends/src/server/org/opends/server/types/DN.java
@@ -22,7 +22,7 @@
  * CDDL HEADER END
  *
  *
- *      Copyright 2006-2008 Sun Microsystems, Inc.
+ *      Copyright 2006-2009 Sun Microsystems, Inc.
  */
 package org.opends.server.types;
 
@@ -35,7 +35,6 @@
 import org.opends.messages.Message;
 import org.opends.server.core.DirectoryServer;
 import org.opends.server.loggers.debug.DebugTracer;
-import org.opends.server.protocols.asn1.ASN1OctetString;
 
 import static org.opends.messages.SchemaMessages.*;
 import static org.opends.server.config.ConfigConstants.*;
@@ -44,7 +43,6 @@
 import static org.opends.server.util.Validator.*;
 
 
-
 /**
  * This class defines a data structure for storing and interacting
  * with the distinguished names associated with entries in the
@@ -102,7 +100,7 @@
   private String dnString;
 
   // The normalized string representation of this DN.
-  private final String normalizedDN;
+  private String normalizedDN;
 
 
 
@@ -137,7 +135,7 @@
 
     numComponents = this.rdnComponents.length;
     dnString      = null;
-    normalizedDN  = normalize(this.rdnComponents);
+    normalizedDN  = null;
   }
 
 
@@ -163,7 +161,7 @@
 
     numComponents = this.rdnComponents.length;
     dnString      = null;
-    normalizedDN  = normalize(this.rdnComponents);
+    normalizedDN  = null;
   }
 
 
@@ -193,7 +191,7 @@
 
     numComponents = this.rdnComponents.length;
     dnString      = null;
-    normalizedDN  = normalize(this.rdnComponents);
+    normalizedDN  = null;
   }
 
 
@@ -528,8 +526,7 @@
       return NULL_DN;
     }
 
-    byte[] dnBytes = dnString.value();
-    int    length  = dnBytes.length;
+    int    length  = dnString.length();
     if (length == 0)
     {
       return NULL_DN;
@@ -540,36 +537,33 @@
     // escaped characters.  If so, then the easiest and safest
     // approach is to convert the DN to a string and decode it that
     // way.
-    for (byte b : dnBytes)
+    byte b = 0;
+    for (int i = 0; i < length; i++)
     {
+      b = dnString.byteAt(i);
       if (((b & 0x7F) != b) || (b == '\\'))
       {
-        return decode(dnString.stringValue());
+        return decode(dnString.toString());
       }
     }
 
 
     // Iterate through the DN string.  The first thing to do is to get
     // rid of any leading spaces.
-    int pos = 0;
-    byte b = dnBytes[pos];
-    while (b == ' ')
+    ByteSequenceReader dnReader = dnString.asReader();
+    b = ' ';
+    while (dnReader.remaining() > 0 && (b = dnReader.get()) == ' ')
+    {}
+
+    if(b == ' ')
     {
-      pos++;
-      if (pos == length)
-      {
-        // This means that the DN was completely comprised of spaces
-        // and therefore should be considered the same as a null or
-        // empty DN.
-        return NULL_DN;
-      }
-      else
-      {
-        b = dnBytes[pos];
-      }
+      // This means that the DN was completely comprised of spaces
+      // and therefore should be considered the same as a null or
+      // empty DN.
+      return NULL_DN;
     }
 
-
+    dnReader.skip(-1);
     // We know that it's not an empty DN, so we can do the real
     // processing.  Create a loop and iterate through all the RDN
     // components.
@@ -578,17 +572,16 @@
     LinkedList<RDN> rdnComponents = new LinkedList<RDN>();
     while (true)
     {
-      StringBuilder attributeName = new StringBuilder();
-      pos = parseAttributeName(dnBytes, pos, attributeName,
-                               allowExceptions);
+      ByteString attributeName =
+          parseAttributeName(dnReader, allowExceptions);
 
 
       // Make sure that we're not at the end of the DN string because
       // that would be invalid.
-      if (pos >= length)
+      if (dnReader.remaining() <= 0)
       {
         Message message = ERR_ATTR_SYNTAX_DN_END_WITH_ATTR_NAME.get(
-            dnString.stringValue(), attributeName.toString());
+            dnString.toString(), attributeName.toString());
         throw new DirectoryException(ResultCode.INVALID_DN_SYNTAX,
                                      message);
       }
@@ -596,37 +589,27 @@
 
       // Skip over any spaces between the attribute name and its
       // value.
-      b = dnBytes[pos];
-      while (b == ' ')
-      {
-        pos++;
-        if (pos >= length)
-        {
-          // This means that we hit the end of the value before
-          // finding a '='.  This is illegal because there is no
-          // attribute-value separator.
-          Message message = ERR_ATTR_SYNTAX_DN_END_WITH_ATTR_NAME.get(
-              dnString.stringValue(), attributeName.toString());
-          throw new DirectoryException(ResultCode.INVALID_DN_SYNTAX,
-                                       message);
-        }
-        else
-        {
-          b = dnBytes[pos];
-        }
-      }
+      b = ' ';
+      while (dnReader.remaining() > 0 && (b = dnReader.get()) == ' ')
+      {}
 
+      if(b == ' ')
+      {
+        // This means that we hit the end of the value before
+        // finding a '='.  This is illegal because there is no
+        // attribute-value separator.
+        Message message = ERR_ATTR_SYNTAX_DN_END_WITH_ATTR_NAME.get(
+            dnString.toString(), attributeName.toString());
+        throw new DirectoryException(ResultCode.INVALID_DN_SYNTAX,
+            message);
+      }
 
       // The next character must be an equal sign.  If it is not,
       // then that's an error.
-      if (b == '=')
-      {
-        pos++;
-      }
-      else
+      if (b != '=')
       {
         Message message = ERR_ATTR_SYNTAX_DN_NO_EQUAL.
-            get(dnString.stringValue(), attributeName.toString(),
+            get(dnString.toString(), attributeName.toString(),
                 (char) b);
         throw new DirectoryException(ResultCode.INVALID_DN_SYNTAX,
                                      message);
@@ -634,10 +617,9 @@
 
 
       // Skip over any spaces after the equal sign.
-      while ((pos < length) && ((b = dnBytes[pos]) == ' '))
-      {
-        pos++;
-      }
+      b = ' ';
+      while (dnReader.remaining() > 0 && (b = dnReader.get()) == ' ')
+      {}
 
 
       // If we are at the end of the DN string, then that must mean
@@ -645,12 +627,13 @@
       // happen in a real-world environment, but technically isn't
       // illegal.  If it does happen, then go ahead and create the RDN
       // component and return the DN.
-      if (pos >= length)
+      if (b == ' ')
       {
-        String        name      = attributeName.toString();
-        String        lowerName = toLowerCase(name);
+        StringBuilder lowerName = new StringBuilder();
+        toLowerCase(attributeName, lowerName, true);
         AttributeType attrType  =
-             DirectoryServer.getAttributeType(lowerName);
+             DirectoryServer.getAttributeType(lowerName.toString());
+        String attributeNameString = attributeName.toString();
 
         if (attrType == null)
         {
@@ -659,27 +642,30 @@
           // default syntax.  If this is a problem, it will be caught
           // later either by not finding the target entry or by not
           // allowing the entry to be added.
-          attrType = DirectoryServer.getDefaultAttributeType(name);
+          attrType = DirectoryServer.getDefaultAttributeType(
+              attributeNameString);
         }
 
         AttributeValue value =
-             new AttributeValue(new ASN1OctetString(),
-                                new ASN1OctetString());
-        rdnComponents.add(new RDN(attrType, name, value));
+            AttributeValues.create(ByteString.empty(),
+                               ByteString.empty());
+        rdnComponents.add(
+            new RDN(attrType, attributeNameString, value));
         return new DN(rdnComponents);
       }
 
+      dnReader.skip(-1);
 
       // Parse the value for this RDN component.
-      ByteString parsedValue = new ASN1OctetString();
-      pos = parseAttributeValue(dnBytes, pos, parsedValue);
+      ByteString parsedValue = parseAttributeValue(dnReader);
 
 
       // Create the new RDN with the provided information.
-      String name            = attributeName.toString();
-      String lowerName       = toLowerCase(name);
-      AttributeType attrType =
-           DirectoryServer.getAttributeType(lowerName);
+      StringBuilder lowerName = new StringBuilder();
+      toLowerCase(attributeName, lowerName, true);
+      AttributeType attrType  =
+          DirectoryServer.getAttributeType(lowerName.toString());
+      String attributeNameString = attributeName.toString();
       if (attrType == null)
       {
         // This must be an attribute type that we don't know about.
@@ -687,25 +673,25 @@
         // default syntax.  If this is a problem, it will be caught
         // later either by not finding the target entry or by not
         // allowing the entry to be added.
-        attrType = DirectoryServer.getDefaultAttributeType(name);
+        attrType = DirectoryServer.getDefaultAttributeType(
+            attributeNameString);
       }
 
       AttributeValue value =
-           new AttributeValue(attrType, parsedValue);
-      RDN rdn = new RDN(attrType, name, value);
+           AttributeValues.create(attrType, parsedValue);
+      RDN rdn = new RDN(attrType, attributeNameString, value);
 
 
       // Skip over any spaces that might be after the attribute value.
-      while ((pos < length) && ((b = dnBytes[pos]) == ' '))
-      {
-        pos++;
-      }
+      b = ' ';
+      while (dnReader.remaining() > 0 && (b = dnReader.get()) == ' ')
+      {}
 
 
       // Most likely, we will be at either the end of the RDN
       // component or the end of the DN.  If so, then handle that
       // appropriately.
-      if (pos >= length)
+      if (b == ' ')
       {
         // We're at the end of the DN string and should have a valid
         // DN so return it.
@@ -718,7 +704,6 @@
         // list, skip over the comma/semicolon, and start on the next
         // component.
         rdnComponents.add(rdn);
-        pos++;
         continue;
       }
       else if (b != '+')
@@ -726,7 +711,7 @@
         // This should not happen.  At any rate, it's an illegal
         // character, so throw an exception.
         Message message = ERR_ATTR_SYNTAX_DN_INVALID_CHAR.get(
-            new String(dnBytes), (char) b, pos);
+            dnReader.toString(), (char) b, dnReader.position()-1);
         throw new DirectoryException(ResultCode.INVALID_DN_SYNTAX,
                                      message);
       }
@@ -739,25 +724,22 @@
       {
         // Skip over the plus sign and any spaces that may follow it
         // before the next attribute name.
-        pos++;
-        while ((pos < length) && (dnBytes[pos] == ' '))
-        {
-          pos++;
-        }
+        b = ' ';
+        while (dnReader.remaining() > 0 &&
+            (b = dnReader.get()) == ' ')
+        {}
 
-
+        dnReader.skip(-1);
         // Parse the attribute name from the DN string.
-        attributeName = new StringBuilder();
-        pos = parseAttributeName(dnBytes, pos, attributeName,
-                                 allowExceptions);
+        attributeName = parseAttributeName(dnReader, allowExceptions);
 
 
         // Make sure that we're not at the end of the DN string
         // because that would be invalid.
-        if (pos >= length)
+        if (b == ' ')
         {
           Message message = ERR_ATTR_SYNTAX_DN_END_WITH_ATTR_NAME.get(
-              dnString.stringValue(), attributeName.toString());
+              dnString.toString(), attributeName.toString());
           throw new DirectoryException(ResultCode.INVALID_DN_SYNTAX,
                                        message);
         }
@@ -765,37 +747,29 @@
 
         // Skip over any spaces between the attribute name and its
         // value.
-        b = dnBytes[pos];
-        while (b == ' ')
+        b = ' ';
+        while (dnReader.remaining() > 0 &&
+            (b = dnReader.get()) == ' ')
+        {}
+
+        if(b == ' ')
         {
-          pos++;
-          if (pos >= length)
-          {
-            // This means that we hit the end of the value before
-            // finding a '='.  This is illegal because there is no
-            // attribute-value separator.
-            Message message = ERR_ATTR_SYNTAX_DN_END_WITH_ATTR_NAME.
-                get(dnString.stringValue(), attributeName.toString());
-            throw new DirectoryException(ResultCode.INVALID_DN_SYNTAX,
-                                         message);
-          }
-          else
-          {
-            b = dnBytes[pos];
-          }
+          // This means that we hit the end of the value before
+          // finding a '='.  This is illegal because there is no
+          // attribute-value separator.
+          Message message = ERR_ATTR_SYNTAX_DN_END_WITH_ATTR_NAME.
+              get(dnString.toString(), attributeName.toString());
+          throw new DirectoryException(ResultCode.INVALID_DN_SYNTAX,
+              message);
         }
 
 
         // The next character must be an equal sign.  If it is not,
         // then that's an error.
-        if (b == '=')
-        {
-          pos++;
-        }
-        else
+        if (b != '=')
         {
           Message message = ERR_ATTR_SYNTAX_DN_NO_EQUAL.
-              get(dnString.stringValue(), attributeName.toString(),
+              get(dnString.toString(), attributeName.toString(),
                   (char) b);
           throw new DirectoryException(ResultCode.INVALID_DN_SYNTAX,
                                        message);
@@ -803,10 +777,10 @@
 
 
         // Skip over any spaces after the equal sign.
-        while ((pos < length) && ((b = dnBytes[pos]) == ' '))
-        {
-          pos++;
-        }
+        b = ' ';
+        while (dnReader.remaining() > 0 &&
+            (b = dnReader.get()) == ' ')
+        {}
 
 
         // If we are at the end of the DN string, then that must mean
@@ -814,11 +788,13 @@
         // never happen in a real-world environment, but technically
         // isn't illegal.  If it does happen, then go ahead and create
         // the RDN component and return the DN.
-        if (pos >= length)
+        if (b == ' ')
         {
-          name      = attributeName.toString();
-          lowerName = toLowerCase(name);
-          attrType  = DirectoryServer.getAttributeType(lowerName);
+          lowerName = new StringBuilder();
+          toLowerCase(attributeName, lowerName, true);
+          attrType =
+              DirectoryServer.getAttributeType(lowerName.toString());
+          attributeNameString = attributeName.toString();
 
           if (attrType == null)
           {
@@ -827,26 +803,28 @@
             // using the default syntax.  If this is a problem, it
             // will be caught later either by not finding the target
             // entry or by not allowing the entry to be added.
-            attrType = DirectoryServer.getDefaultAttributeType(name);
+            attrType = DirectoryServer.getDefaultAttributeType(
+                attributeNameString);
           }
 
-          value = new AttributeValue(new ASN1OctetString(),
-                                     new ASN1OctetString());
-          rdn.addValue(attrType, name, value);
+          value = AttributeValues.create(ByteString.empty(),
+                                     ByteString.empty());
+          rdn.addValue(attrType, attributeNameString, value);
           rdnComponents.add(rdn);
           return new DN(rdnComponents);
         }
 
+        dnReader.skip(-1);
 
         // Parse the value for this RDN component.
-        parsedValue = new ASN1OctetString();
-        pos = parseAttributeValue(dnBytes, pos, parsedValue);
+        parsedValue = parseAttributeValue(dnReader);
 
 
-        // Create the new RDN with the provided information.
-        name      = attributeName.toString();
-        lowerName = toLowerCase(name);
-        attrType  = DirectoryServer.getAttributeType(lowerName);
+        lowerName = new StringBuilder();
+        toLowerCase(attributeName, lowerName, true);
+        attrType =
+            DirectoryServer.getAttributeType(lowerName.toString());
+        attributeNameString = attributeName.toString();
         if (attrType == null)
         {
           // This must be an attribute type that we don't know about.
@@ -854,25 +832,28 @@
           // default syntax.  If this is a problem, it will be caught
           // later either by not finding the target entry or by not
           // allowing the entry to be added.
-          attrType = DirectoryServer.getDefaultAttributeType(name);
+          attrType = DirectoryServer.getDefaultAttributeType(
+              attributeNameString);
         }
 
-        value = new AttributeValue(attrType, parsedValue);
-        rdn.addValue(attrType, name, value);
+        value = AttributeValues.create(attrType, parsedValue);
+        rdn.addValue(attrType, attributeNameString, value);
 
 
         // Skip over any spaces that might be after the attribute
         // value.
-        while ((pos < length) && ((b = dnBytes[pos]) == ' '))
-        {
-          pos++;
-        }
+        // Skip over any spaces that might be after the attribute
+        // value.
+        b = ' ';
+        while (dnReader.remaining() > 0 &&
+            (b = dnReader.get()) == ' ')
+        {}
 
 
         // Most likely, we will be at either the end of the RDN
         // component or the end of the DN.  If so, then handle that
         // appropriately.
-        if (pos >= length)
+        if (b == ' ')
         {
           // We're at the end of the DN string and should have a valid
           // DN so return it.
@@ -885,7 +866,6 @@
           // list, skip over the comma/semicolon, and start on the
           // next component.
           rdnComponents.add(rdn);
-          pos++;
           break;
         }
         else if (b != '+')
@@ -893,9 +873,9 @@
           // This should not happen.  At any rate, it's an illegal
           // character, so throw an exception.
           Message message = ERR_ATTR_SYNTAX_DN_INVALID_CHAR.get(
-              dnString.stringValue(), (char) b, pos);
+              dnString.toString(), (char) b, dnReader.position()-1);
           throw new DirectoryException(ResultCode.INVALID_DN_SYNTAX,
-                                       message);
+              message);
         }
       }
     }
@@ -1042,15 +1022,15 @@
         }
 
         AttributeValue value =
-             new AttributeValue(new ASN1OctetString(),
-                                new ASN1OctetString());
+            AttributeValues.create(ByteString.empty(),
+                                ByteString.empty());
         rdnComponents.add(new RDN(attrType, name, value));
         return new DN(rdnComponents);
       }
 
 
       // Parse the value for this RDN component.
-      ByteString parsedValue = new ASN1OctetString();
+      ByteStringBuilder parsedValue = new ByteStringBuilder(0);
       pos = parseAttributeValue(dnString, pos, parsedValue);
 
 
@@ -1070,7 +1050,8 @@
       }
 
       AttributeValue value =
-           new AttributeValue(attrType, parsedValue);
+          AttributeValues.create(attrType,
+              parsedValue.toByteString());
       RDN rdn = new RDN(attrType, name, value);
 
 
@@ -1208,8 +1189,8 @@
             attrType = DirectoryServer.getDefaultAttributeType(name);
           }
 
-          value = new AttributeValue(new ASN1OctetString(),
-                                     new ASN1OctetString());
+          value = AttributeValues.create(ByteString.empty(),
+                                     ByteString.empty());
           rdn.addValue(attrType, name, value);
           rdnComponents.add(rdn);
           return new DN(rdnComponents);
@@ -1217,7 +1198,7 @@
 
 
         // Parse the value for this RDN component.
-        parsedValue = new ASN1OctetString();
+        parsedValue.clear();
         pos = parseAttributeValue(dnString, pos, parsedValue);
 
 
@@ -1235,7 +1216,8 @@
           attrType = DirectoryServer.getDefaultAttributeType(name);
         }
 
-        value = new AttributeValue(attrType, parsedValue);
+        value = AttributeValues.create(attrType,
+            parsedValue.toByteString());
         rdn.addValue(attrType, name, value);
 
 
@@ -1287,50 +1269,40 @@
    *
    * @param  dnBytes          The byte array containing the DN to
    *                          parse.
-   * @param  pos              The position at which to start parsing
-   *                          the attribute name.
-   * @param  attributeName    The buffer to which to append the parsed
-   *                          attribute name.
    * @param  allowExceptions  Indicates whether to allow certain
    *                          exceptions to the strict requirements
    *                          for attribute names.
    *
-   * @return  The position of the first character that is not part of
-   *          the attribute name.
+   * @return  The parsed attribute name.
    *
    * @throws  DirectoryException  If it was not possible to parse a
    *                              valid attribute name from the
    *                              provided DN string.
    */
-  static int parseAttributeName(byte[] dnBytes, int pos,
-                                StringBuilder attributeName,
+  static ByteString parseAttributeName(ByteSequenceReader dnBytes,
                                 boolean allowExceptions)
           throws DirectoryException
   {
-    int length = dnBytes.length;
-
-
     // Skip over any leading spaces.
-    if (pos < length)
+    while(dnBytes.remaining() > 0 && dnBytes.get() == ' ')
+    {}
+
+    if(dnBytes.remaining() <= 0)
     {
-      while (dnBytes[pos] == ' ')
-      {
-        pos++;
-        if (pos == length)
-        {
-          // This means that the remainder of the DN was completely
-          // comprised of spaces.  If we have gotten here, then we
-          // know that there is at least one RDN component, and
-          // therefore the last non-space character of the DN must
-          // have been a comma. This is not acceptable.
-          Message message = ERR_ATTR_SYNTAX_DN_END_WITH_COMMA.get(
-              new String(dnBytes));
-          throw new DirectoryException(ResultCode.INVALID_DN_SYNTAX,
-                                       message);
-        }
-      }
+      // This means that the remainder of the DN was completely
+      // comprised of spaces.  If we have gotten here, then we
+      // know that there is at least one RDN component, and
+      // therefore the last non-space character of the DN must
+      // have been a comma. This is not acceptable.
+      Message message = ERR_ATTR_SYNTAX_DN_END_WITH_COMMA.get(
+          dnBytes.toString());
+      throw new DirectoryException(ResultCode.INVALID_DN_SYNTAX,
+          message);
     }
 
+    dnBytes.skip(-1);
+    int nameStartPos = dnBytes.position();
+    ByteString nameBytes = null;
 
     // Next, we should find the attribute name for this RDN component.
     // It may either be a name (with only letters, digits, and dashes
@@ -1341,12 +1313,12 @@
     // minimal validation and then do more thorough validation later.
     boolean       checkForOID   = false;
     boolean       endOfName     = false;
-    while (pos < length)
+    while (dnBytes.remaining() > 0)
     {
       // To make the switch more efficient, we'll include all ASCII
       // characters in the range of allowed values and then reject the
       // ones that aren't allowed.
-      byte b = dnBytes[pos];
+      byte b = dnBytes.get();
       switch (b)
       {
         case ' ':
@@ -1370,7 +1342,7 @@
           // None of these are allowed in an attribute name or any
           // character immediately following it.
           Message msg = ERR_ATTR_SYNTAX_DN_ATTR_ILLEGAL_CHAR.get(
-              new String(dnBytes), (char) b, pos);
+              dnBytes.toString(), (char) b, dnBytes.position()-1);
           throw new DirectoryException(ResultCode.INVALID_DN_SYNTAX,
                                        msg);
 
@@ -1378,14 +1350,10 @@
         case '-':
           // This will be allowed as long as it isn't the first
           // character in the attribute name.
-          if (attributeName.length() > 0)
-          {
-            attributeName.append((char) b);
-          }
-          else
+          if (dnBytes.position() == nameStartPos + 1)
           {
             msg = ERR_ATTR_SYNTAX_DN_ATTR_ILLEGAL_INITIAL_DASH.
-                  get(new String(dnBytes));
+                  get(dnBytes.toString());
             throw new DirectoryException(ResultCode.INVALID_DN_SYNTAX,
                                          msg);
           }
@@ -1396,7 +1364,6 @@
           // The period could be allowed if the attribute name is
           // actually expressed as an OID.  We'll accept it for now,
           // but make sure to check it later.
-          attributeName.append((char) b);
           checkForOID = true;
           break;
 
@@ -1405,7 +1372,7 @@
           // This is not allowed in an attribute name or any character
           // immediately following it.
           msg = ERR_ATTR_SYNTAX_DN_ATTR_ILLEGAL_CHAR.get(
-              new String(dnBytes), (char) b, pos);
+              dnBytes.toString(), (char) b, dnBytes.position()-1);
           throw new DirectoryException(ResultCode.INVALID_DN_SYNTAX,
                                        msg);
 
@@ -1425,7 +1392,6 @@
           // first character if the valid is an OID or if the
           // attribute name exceptions option is enabled.  Therefore,
           // we'll accept it now and check it later.
-          attributeName.append((char) b);
           break;
 
 
@@ -1435,7 +1401,7 @@
           // None of these are allowed in an attribute name or any
           // character immediately following it.
           msg = ERR_ATTR_SYNTAX_DN_ATTR_ILLEGAL_CHAR.get(
-              new String(dnBytes), (char) b, pos);
+              dnBytes.toString(), (char) b, dnBytes.position()-1);
           throw new DirectoryException(ResultCode.INVALID_DN_SYNTAX,
                                        msg);
 
@@ -1452,7 +1418,7 @@
           // None of these are allowed in an attribute name or any
           // character immediately following it.
           msg = ERR_ATTR_SYNTAX_DN_ATTR_ILLEGAL_CHAR.get(
-              new String(dnBytes), (char) b, pos);
+              dnBytes.toString(), (char) b, dnBytes.position()-1);
           throw new DirectoryException(ResultCode.INVALID_DN_SYNTAX,
                                        msg);
 
@@ -1484,7 +1450,6 @@
         case 'Y':
         case 'Z':
           // These will always be allowed.
-          attributeName.append((char) b);
           break;
 
 
@@ -1495,7 +1460,7 @@
           // None of these are allowed in an attribute name or any
           // character immediately following it.
           msg = ERR_ATTR_SYNTAX_DN_ATTR_ILLEGAL_CHAR.get(
-              new String(dnBytes), (char) b, pos);
+              dnBytes.toString(), (char) b, dnBytes.position()-1);
           throw new DirectoryException(ResultCode.INVALID_DN_SYNTAX,
                                        msg);
 
@@ -1504,22 +1469,18 @@
           // This will never be allowed as the first character.  It
           // may be allowed for subsequent characters if the attribute
           // name exceptions option is enabled.
-          if (attributeName.length() == 0)
+          if (dnBytes.position() == nameStartPos + 1)
           {
             msg = ERR_ATTR_SYNTAX_DN_ATTR_ILLEGAL_INITIAL_UNDERSCORE.
-                  get(new String(dnBytes),
+                  get(dnBytes.toString(),
                       ATTR_ALLOW_ATTRIBUTE_NAME_EXCEPTIONS);
             throw new DirectoryException(ResultCode.INVALID_DN_SYNTAX,
                                          msg);
           }
-          else if (allowExceptions)
-          {
-            attributeName.append((char) b);
-          }
-          else
+          else if (!allowExceptions)
           {
             msg = ERR_ATTR_SYNTAX_DN_ATTR_ILLEGAL_UNDERSCORE_CHAR.
-                  get(new String(dnBytes),
+                  get(dnBytes.toString(),
                       ATTR_ALLOW_ATTRIBUTE_NAME_EXCEPTIONS);
             throw new DirectoryException(ResultCode.INVALID_DN_SYNTAX,
                                          msg);
@@ -1531,7 +1492,7 @@
           // This is not allowed in an attribute name or any character
           // immediately following it.
           msg = ERR_ATTR_SYNTAX_DN_ATTR_ILLEGAL_CHAR.get(
-              new String(dnBytes), (char) b, pos);
+              dnBytes.toString(), (char) b, dnBytes.position()-1);
           throw new DirectoryException(ResultCode.INVALID_DN_SYNTAX,
                                        msg);
 
@@ -1563,7 +1524,6 @@
         case 'y':
         case 'z':
           // These will always be allowed.
-          attributeName.append((char) b);
           break;
 
 
@@ -1571,7 +1531,7 @@
           // This is not allowed in an attribute name or any character
           // immediately following it.
           msg = ERR_ATTR_SYNTAX_DN_ATTR_ILLEGAL_CHAR.get(
-              new String(dnBytes), (char) b, pos);
+              dnBytes.toString(), (char) b, dnBytes.position()-1);
           throw new DirectoryException(ResultCode.INVALID_DN_SYNTAX,
                                        msg);
       }
@@ -1579,10 +1539,12 @@
 
       if (endOfName)
       {
+        int nameEndPos = dnBytes.position() - 1;
+        dnBytes.position(nameStartPos);
+        nameBytes =
+            dnBytes.getByteString(nameEndPos - nameStartPos);
         break;
       }
-
-      pos++;
     }
 
 
@@ -1590,10 +1552,10 @@
     // still need to perform some validation, particularly if the name
     // contains a period or starts with a digit.  It must also have at
     // least one character.
-    if (attributeName.length() == 0)
+    if (nameBytes == null || nameBytes.length() == 0)
     {
       Message message =
-          ERR_ATTR_SYNTAX_DN_ATTR_NO_NAME.get(new String(dnBytes));
+          ERR_ATTR_SYNTAX_DN_ATTR_NO_NAME.get(dnBytes.toString());
       throw new DirectoryException(ResultCode.INVALID_DN_SYNTAX,
                                    message);
     }
@@ -1602,8 +1564,8 @@
       boolean validOID = true;
 
       int namePos = 0;
-      int nameLength = attributeName.length();
-      char ch = attributeName.charAt(0);
+      int nameLength = nameBytes.length();
+      byte ch = nameBytes.byteAt(0);
       if ((ch == 'o') || (ch == 'O'))
       {
         if (nameLength <= 4)
@@ -1612,13 +1574,13 @@
         }
         else
         {
-          if ((((ch = attributeName.charAt(1)) == 'i') ||
+          if ((((ch = nameBytes.byteAt(1)) == 'i') ||
                (ch == 'I')) &&
-              (((ch = attributeName.charAt(2)) == 'd') ||
+              (((ch = nameBytes.byteAt(2)) == 'd') ||
                (ch == 'D')) &&
-              (attributeName.charAt(3) == '.'))
+              (nameBytes.byteAt(3) == '.'))
           {
-            attributeName.delete(0, 4);
+            nameBytes = nameBytes.subSequence(4, nameBytes.length());
             nameLength -= 4;
           }
           else
@@ -1630,17 +1592,17 @@
 
       while (validOID && (namePos < nameLength))
       {
-        ch = attributeName.charAt(namePos++);
-        if (isDigit(ch))
+        ch = nameBytes.byteAt(namePos++);
+        if (isDigit((char)ch))
         {
           while (validOID && (namePos < nameLength) &&
-                 isDigit(attributeName.charAt(namePos)))
+                 isDigit((char)nameBytes.byteAt(namePos)))
           {
             namePos++;
           }
 
           if ((namePos < nameLength) &&
-              (attributeName.charAt(namePos) != '.'))
+              (nameBytes.byteAt(namePos) != '.'))
           {
             validOID = false;
           }
@@ -1648,7 +1610,7 @@
         else if (ch == '.')
         {
           if ((namePos == 1) ||
-              (attributeName.charAt(namePos-2) == '.'))
+              (nameBytes.byteAt(namePos-2) == '.'))
           {
             validOID = false;
           }
@@ -1660,7 +1622,7 @@
       }
 
 
-      if (validOID && (attributeName.charAt(nameLength-1) == '.'))
+      if (validOID && (nameBytes.byteAt(nameLength-1) == '.'))
       {
         validOID = false;
       }
@@ -1669,22 +1631,22 @@
       if (! validOID)
       {
         Message message = ERR_ATTR_SYNTAX_DN_ATTR_ILLEGAL_PERIOD.get(
-            new String(dnBytes), attributeName.toString());
+            dnBytes.toString(), nameBytes.toString());
         throw new DirectoryException(ResultCode.INVALID_DN_SYNTAX,
                                      message);
       }
     }
-    else if (isDigit(attributeName.charAt(0)) && (! allowExceptions))
+    else if (isDigit((char)nameBytes.byteAt(0)) && (!allowExceptions))
     {
       Message message = ERR_ATTR_SYNTAX_DN_ATTR_ILLEGAL_INITIAL_DIGIT.
-          get(new String(dnBytes), attributeName.charAt(0),
+          get(dnBytes.toString(), ((char)nameBytes.byteAt(0)),
               ATTR_ALLOW_ATTRIBUTE_NAME_EXCEPTIONS);
       throw new DirectoryException(ResultCode.INVALID_DN_SYNTAX,
                                    message);
     }
 
 
-    return pos;
+    return nameBytes;
   }
 
 
@@ -2101,51 +2063,42 @@
    *
    * @param  dnBytes         The byte array containing the DN to be
    *                         parsed.
-   * @param  pos             The position of the first character in
-   *                         the attribute value to parse.
-   * @param  attributeValue  The ASN.1 octet string whose value should
-   *                         be set to the parsed attribute value when
-   *                         this method completes successfully.
    *
-   * @return  The position of the first character that is not part of
-   *          the attribute value.
+   * @return  The parsed attribute value.
    *
    * @throws  DirectoryException  If it was not possible to parse a
    *                              valid attribute value from the
    *                              provided DN string.
    */
-  static int parseAttributeValue(byte[] dnBytes, int pos,
-                                 ByteString attributeValue)
+  static ByteString parseAttributeValue(ByteSequenceReader dnBytes)
           throws DirectoryException
   {
     // All leading spaces have already been stripped so we can start
     // reading the value.  However, it may be empty so check for that.
-    int length = dnBytes.length;
-    if (pos >= length)
+    if (dnBytes.remaining() <= 0)
     {
-      attributeValue.setValue("");
-      return pos;
+      return ByteString.empty();
     }
 
 
     // Look at the first character.  If it is an octothorpe (#), then
     // that means that the value should be a hex string.
-    byte b = dnBytes[pos++];
+    byte b = dnBytes.get();
     if (b == '#')
     {
       // The first two characters must be hex characters.
       StringBuilder hexString = new StringBuilder();
-      if ((pos+2) > length)
+      if (dnBytes.remaining() < 2)
       {
         Message message = ERR_ATTR_SYNTAX_DN_HEX_VALUE_TOO_SHORT.get(
-            new String(dnBytes));
+            dnBytes.toString());
         throw new DirectoryException(ResultCode.INVALID_DN_SYNTAX,
                                      message);
       }
 
       for (int i=0; i < 2; i++)
       {
-        b = dnBytes[pos++];
+        b = dnBytes.get();
         if (isHexDigit(b))
         {
           hexString.append((char) b);
@@ -2153,7 +2106,7 @@
         else
         {
           Message message = ERR_ATTR_SYNTAX_DN_INVALID_HEX_DIGIT.get(
-              new String(dnBytes), (char) b);
+              dnBytes.toString(), (char) b);
           throw new DirectoryException(ResultCode.INVALID_DN_SYNTAX,
                                        message);
         }
@@ -2163,16 +2116,16 @@
       // 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, a plus sign, or a space.
-      while (pos < length)
+      while (dnBytes.remaining() > 0)
       {
-        b = dnBytes[pos++];
+        b = dnBytes.get();
         if (isHexDigit(b))
         {
           hexString.append((char) b);
 
-          if (pos < length)
+          if (dnBytes.remaining() > 0)
           {
-            b = dnBytes[pos++];
+            b = dnBytes.get();
             if (isHexDigit(b))
             {
               hexString.append((char) b);
@@ -2180,7 +2133,7 @@
             else
             {
               Message message = ERR_ATTR_SYNTAX_DN_INVALID_HEX_DIGIT.
-                  get(new String(dnBytes), (char) b);
+                  get(dnBytes.toString(), (char) b);
               throw new DirectoryException(
                              ResultCode.INVALID_DN_SYNTAX, message);
             }
@@ -2188,7 +2141,7 @@
           else
           {
             Message message = ERR_ATTR_SYNTAX_DN_HEX_VALUE_TOO_SHORT.
-                get(new String(dnBytes));
+                get(dnBytes.toString());
             throw new DirectoryException(ResultCode.INVALID_DN_SYNTAX,
                                          message);
           }
@@ -2196,13 +2149,13 @@
         else if ((b == ' ') || (b == ',') || (b == ';') || (b == '+'))
         {
           // This denotes the end of the value.
-          pos--;
+          dnBytes.skip(-1);
           break;
         }
         else
         {
           Message message = ERR_ATTR_SYNTAX_DN_INVALID_HEX_DIGIT.get(
-              new String(dnBytes), (char) b);
+              dnBytes.toString(), (char) b);
           throw new DirectoryException(ResultCode.INVALID_DN_SYNTAX,
                                        message);
         }
@@ -2214,9 +2167,8 @@
       // octet string.
       try
       {
-        attributeValue.setValue(hexStringToByteArray(
+        return ByteString.wrap(hexStringToByteArray(
                                      hexString.toString()));
-        return pos;
       }
       catch (Exception e)
       {
@@ -2227,7 +2179,7 @@
 
         Message message =
             ERR_ATTR_SYNTAX_DN_ATTR_VALUE_DECODE_FAILURE.
-              get(new String(dnBytes), String.valueOf(e));
+              get(dnBytes.toString(), String.valueOf(e));
         throw new DirectoryException(ResultCode.INVALID_DN_SYNTAX,
                                      message);
       }
@@ -2238,49 +2190,34 @@
     // should continue until the corresponding closing quotation mark.
     else if (b == '"')
     {
-      int valueStartPos = pos;
+      int valueStartPos = dnBytes.position();
 
       // Keep reading until we find a closing quotation mark.
       while (true)
       {
-        if (pos >= length)
+        if (dnBytes.remaining() <= 0)
         {
           // We hit the end of the DN before the closing quote.
           // That's an error.
           Message message = ERR_ATTR_SYNTAX_DN_UNMATCHED_QUOTE.get(
-              new String(dnBytes));
+              dnBytes.toString());
           throw new DirectoryException(ResultCode.INVALID_DN_SYNTAX,
                                        message);
         }
 
-        if (dnBytes[pos++] == '"')
+        if (dnBytes.get() == '"')
         {
           // This is the end of the value.
           break;
         }
       }
 
-      byte[] valueBytes = new byte[pos - valueStartPos - 1];
-      System.arraycopy(dnBytes, valueStartPos, valueBytes, 0,
-                       valueBytes.length);
-
-      try
-      {
-        attributeValue.setValue(valueBytes);
-      }
-      catch (Exception e)
-      {
-        if (debugEnabled())
-        {
-          TRACER.debugCaught(DebugLogLevel.ERROR, e);
-        }
-
-        // This should never happen.  Just in case, work around it by
-        // converting to a string and back.
-        String valueStr = new String(valueBytes);
-        attributeValue.setValue(valueStr);
-      }
-      return pos;
+      int valueEndPos = dnBytes.position();
+      dnBytes.position(valueStartPos);
+      ByteString bs =
+          dnBytes.getByteString(valueEndPos - valueStartPos - 1);
+      dnBytes.skip(1);
+      return bs;
     }
 
 
@@ -2289,74 +2226,34 @@
     {
       // Keep reading until we find a comma/semicolon, a plus sign, or
       // the end of the DN.
-      int valueStartPos = pos - 1;
-
+      int valueEndPos = dnBytes.position();
+      int valueStartPos = valueEndPos - 1;
       while (true)
       {
-        if (pos >= length)
+        if (dnBytes.remaining() <= 0)
         {
           // This is the end of the DN and therefore the end of the
           // value.
           break;
         }
 
-        b = dnBytes[pos++];
+        b = dnBytes.get();
         if ((b == ',') || (b == ';') || (b == '+'))
         {
-          pos--;
+          dnBytes.skip(-1);
           break;
         }
+
+        if(b != ' ')
+        {
+          valueEndPos = dnBytes.position();
+        }
       }
 
 
       // Convert the byte buffer to an array.
-      byte[] valueBytes = new byte[pos - valueStartPos];
-      System.arraycopy(dnBytes, valueStartPos, valueBytes, 0,
-                       valueBytes.length);
-
-
-      // Strip off any unescaped spaces that may be at the end of the
-      // value.
-      boolean extraSpaces = false;
-      int     lastPos     = valueBytes.length - 1;
-      while (lastPos > 0)
-      {
-        if (valueBytes[lastPos] == ' ')
-        {
-          extraSpaces = true;
-          lastPos--;
-        }
-        else
-        {
-          break;
-        }
-      }
-
-      if (extraSpaces)
-      {
-        byte[] newValueBytes = new byte[lastPos+1];
-        System.arraycopy(valueBytes, 0, newValueBytes, 0, lastPos+1);
-        valueBytes = newValueBytes;
-      }
-
-
-      try
-      {
-        attributeValue.setValue(valueBytes);
-      }
-      catch (Exception e)
-      {
-        if (debugEnabled())
-        {
-          TRACER.debugCaught(DebugLogLevel.ERROR, e);
-        }
-
-        // This should never happen.  Just in case, work around it by
-        // converting to a string and back.
-        String valueStr = new String(valueBytes);
-        attributeValue.setValue(valueStr);
-      }
-      return pos;
+      dnBytes.position(valueStartPos);
+      return dnBytes.getByteString(valueEndPos - valueStartPos);
     }
   }
 
@@ -2382,7 +2279,7 @@
    *                              provided DN string.
    */
   static int parseAttributeValue(String dnString, int pos,
-                                 ByteString attributeValue)
+                                 ByteStringBuilder attributeValue)
           throws DirectoryException
   {
     // All leading spaces have already been stripped so we can start
@@ -2390,7 +2287,7 @@
     int length = dnString.length();
     if (pos >= length)
     {
-      attributeValue.setValue("");
+      attributeValue.append("");
       return pos;
     }
 
@@ -2481,8 +2378,8 @@
       // octet string.
       try
       {
-        attributeValue.setValue(hexStringToByteArray(
-                                     hexString.toString()));
+        attributeValue.append(
+            hexStringToByteArray(hexString.toString()));
         return pos;
       }
       catch (Exception e)
@@ -2548,7 +2445,7 @@
         }
       }
 
-      attributeValue.setValue(valueString.toString());
+      attributeValue.append(valueString.toString());
       return pos;
     }
 
@@ -2681,7 +2578,7 @@
       }
 
 
-      attributeValue.setValue(valueString.toString());
+      attributeValue.append(valueString.toString());
       return pos;
     }
   }
@@ -2747,6 +2644,7 @@
    * @return  <CODE>true</CODE> if the provided object is a DN that is
    *          equal to this DN, or <CODE>false</CODE> if it is not.
    */
+  @Override
   public boolean equals(Object o)
   {
     if (this == o)
@@ -2761,7 +2659,8 @@
 
     try
     {
-      return (normalizedDN.equals(((DN) o).normalizedDN));
+      return (toNormalizedString().equals(
+          ((DN) o).toNormalizedString()));
     }
     catch (Exception e)
     {
@@ -2787,9 +2686,10 @@
    *
    * @return  The hash code for this DN.
    */
+  @Override
   public int hashCode()
   {
-    return normalizedDN.hashCode();
+    return toNormalizedString().hashCode();
   }
 
 
@@ -2799,6 +2699,7 @@
    *
    * @return  A string representation of this DN.
    */
+  @Override
   public String toString()
   {
     if (dnString == null)
@@ -2879,6 +2780,10 @@
    */
   public String toNormalizedString()
   {
+    if(normalizedDN == null)
+    {
+      normalizedDN = normalize(this.rdnComponents);
+    }
     return normalizedDN;
   }
 
diff --git a/opends/src/server/org/opends/server/types/Entry.java b/opends/src/server/org/opends/server/types/Entry.java
index c5ecce2..68991e3 100644
--- a/opends/src/server/org/opends/server/types/Entry.java
+++ b/opends/src/server/org/opends/server/types/Entry.java
@@ -50,8 +50,6 @@
 import org.opends.server.api.plugin.PluginResult;
 import org.opends.server.core.DirectoryServer;
 import org.opends.server.core.PluginConfigManager;
-import org.opends.server.protocols.asn1.ASN1Element;
-import org.opends.server.protocols.asn1.ASN1OctetString;
 import org.opends.server.util.LDIFException;
 
 import static org.opends.server.config.ConfigConstants.*;
@@ -109,6 +107,8 @@
   // The set of objectclasses for this entry.
   private Map<ObjectClass,String> objectClasses;
 
+  private Attribute objectClassAttribute;
+
   // The DN for this entry.
   private DN dn;
 
@@ -310,12 +310,12 @@
          new LinkedHashMap<ObjectClass,String>();
     for (AttributeValue v : objectClassNames)
     {
-      String name = v.getStringValue();
+      String name = v.getValue().toString();
 
       String lowerName;
       try
       {
-        lowerName = v.getNormalizedStringValue();
+        lowerName = v.getNormalizedValue().toString();
       }
       catch (Exception e)
       {
@@ -324,7 +324,7 @@
           TRACER.debugCaught(DebugLogLevel.ERROR, e);
         }
 
-        lowerName = toLowerCase(v.getStringValue());
+        lowerName = toLowerCase(v.getValue().toString());
       }
 
       ObjectClass oc = DirectoryServer.getObjectClass(lowerName);
@@ -340,9 +340,10 @@
     }
 
 
-    // If we've gotten here, then everything is fine so put the new
+    // If we've gotten here, then everything is fine so append the new
     // set of objectclasses.
     objectClasses = ocMap;
+    objectClassAttribute = null;
   }
 
 
@@ -455,17 +456,26 @@
       return null;
     }
 
-    AttributeType ocType =
-      DirectoryServer.getObjectClassAttributeType();
-    AttributeBuilder builder =
-      new AttributeBuilder(ocType, ATTR_OBJECTCLASS);
-
-    for (String s : objectClasses.values())
+    if(objectClassAttribute == null)
     {
-      builder.add(new AttributeValue(ocType, new ASN1OctetString(s)));
+      AttributeType ocType =
+          DirectoryServer.getObjectClassAttributeType();
+      AttributeBuilder builder =
+          new AttributeBuilder(ocType, ATTR_OBJECTCLASS);
+
+      for (Map.Entry<ObjectClass, String> e :
+          objectClasses.entrySet())
+      {
+        builder.add(AttributeValues.create(
+            ByteString.valueOf(e.getValue()),
+            ByteString.valueOf(e.getKey()
+                .getNormalizedPrimaryName())));
+      }
+
+      objectClassAttribute = builder.toAttribute();
     }
 
-    return builder.toAttribute();
+    return objectClassAttribute;
   }
 
 
@@ -1487,7 +1497,7 @@
           ResultCode.CONSTRAINT_VIOLATION, message);
     }
 
-    String incrementValue = i.next().getStringValue();
+    String incrementValue = i.next().getValue().toString();
     long increment;
     try
     {
@@ -1514,7 +1524,7 @@
 
     for (AttributeValue v : a)
     {
-      String s = v.getStringValue();
+      String s = v.getValue().toString();
       long currentValue;
       try
       {
@@ -1529,7 +1539,7 @@
       }
 
       long newValue = currentValue + increment;
-      builder.add(new AttributeValue(attributeType, String
+      builder.add(AttributeValues.create(attributeType, String
           .valueOf(newValue)));
     }
 
@@ -1615,7 +1625,7 @@
         String ocName;
         try
         {
-          ocName = v.getNormalizedStringValue();
+          ocName = v.getNormalizedValue().toString();
         }
         catch (Exception e)
         {
@@ -1624,7 +1634,7 @@
             TRACER.debugCaught(DebugLogLevel.ERROR, e);
           }
 
-          ocName = toLowerCase(v.getStringValue());
+          ocName = toLowerCase(v.getValue().toString());
         }
 
         boolean matchFound = false;
@@ -1788,7 +1798,7 @@
              LinkedHashMap<ObjectClass,String>();
       for (AttributeValue v : a)
       {
-        String ocName    = v.getStringValue();
+        String ocName    = v.getValue().toString();
         String lowerName = toLowerCase(ocName);
         ObjectClass oc   =
              DirectoryServer.getObjectClass(lowerName, true);
@@ -1813,6 +1823,7 @@
               objectClasses.put(oc, ocs.get(oc));
             }
           }
+          objectClassAttribute = null;
           break;
 
         case DELETE:
@@ -1826,10 +1837,12 @@
                              ResultCode.NO_SUCH_ATTRIBUTE, message);
             }
           }
+          objectClassAttribute = null;
           break;
 
         case REPLACE:
           objectClasses = ocs;
+          objectClassAttribute = null;
           break;
 
         case INCREMENT:
@@ -3052,7 +3065,7 @@
     {
       for (AttributeValue v : a)
       {
-        referralURLs.add(v.getStringValue());
+        referralURLs.add(v.getValue().toString());
       }
     }
 
@@ -3179,7 +3192,7 @@
       else
       {
         return DN.decode(
-            aliasAttr.iterator().next().getStringValue());
+            aliasAttr.iterator().next().getValue().toString());
       }
     }
   }
@@ -3386,306 +3399,119 @@
    * that if the way we store entries changes in the future we will
    * still be able to read entries encoded in an older format.
    *
+   * @param  buffer  The buffer to encode into.
    * @param  config  The configuration that may be used to control how
    *                 the entry is encoded.
    *
-   * @return  The entry encoded in a form that is suitable for
-   *          long-term persistent storage.
-   *
    * @throws  DirectoryException  If a problem occurs while attempting
    *                              to encode the entry.
    */
-  public byte[] encode(EntryEncodeConfig config)
+  public void encode(ByteStringBuilder buffer,
+                     EntryEncodeConfig config)
          throws DirectoryException
   {
-    return encodeV2(config);
+    encodeV3(buffer, config);
   }
 
-
-
   /**
-   * Encodes this entry using the V1 encoding.
+   * Encodes this entry using the V3 encoding.
    *
-   * @return  The entry encoded in the V1 encoding.
-   */
-  public byte[] encodeV1()
-  {
-    // The version number will be one byte.  We'll add that later.
-
-
-    // The DN will be encoded as a one-to-five byte length followed
-    // byte the UTF-8 byte representation.
-    byte[] dnBytes  = getBytes(dn.toString());
-    byte[] dnLength = ASN1Element.encodeLength(dnBytes.length);
-    int totalBytes = 1 + dnBytes.length + dnLength.length;
-
-
-    // The object classes will be encoded as one-to-five byte length
-    // followed by a zero-delimited UTF-8 byte representation of the
-    // names (e.g., top\0person\0organizationalPerson\0inetOrgPerson).
-    int i=0;
-    int totalOCBytes = objectClasses.size() - 1;
-    byte[][] ocBytes = new byte[objectClasses.size()][];
-    for (String ocName : objectClasses.values())
-    {
-      ocBytes[i] = getBytes(ocName);
-      totalOCBytes += ocBytes[i++].length;
-    }
-    byte[] ocLength = ASN1Element.encodeLength(totalOCBytes);
-    totalBytes += totalOCBytes + ocLength.length;
-
-
-    // The user attributes will be encoded as a one-to-five byte
-    // number of attributes followed by a sequence of:
-    // - A UTF-8 byte representation of the attribute name.
-    // - A zero delimiter
-    // - A one-to-five byte number of values for the attribute
-    // - A sequence of:
-    //   - A one-to-five byte length for the value
-    //   - A UTF-8 byte representation for the value
-    i=0;
-    int numUserAttributes = 0;
-    int totalUserAttrBytes = 0;
-    LinkedList<byte[]> userAttrBytes = new LinkedList<byte[]>();
-    for (List<Attribute> attrList : userAttributes.values())
-    {
-      for (Attribute a : attrList)
-      {
-        if (a.isVirtual() || a.isEmpty())
-        {
-          continue;
-        }
-
-        numUserAttributes++;
-
-        byte[] nameBytes = getBytes(a.getNameWithOptions());
-
-        int numValues = 0;
-        int totalValueBytes = 0;
-        LinkedList<byte[]> valueBytes = new LinkedList<byte[]>();
-        for (AttributeValue v : a)
-        {
-          numValues++;
-          byte[] vBytes = v.getValueBytes();
-          byte[] vLength = ASN1Element.encodeLength(vBytes.length);
-          valueBytes.add(vLength);
-          valueBytes.add(vBytes);
-          totalValueBytes += vLength.length + vBytes.length;
-        }
-        byte[] numValuesBytes = ASN1Element.encodeLength(numValues);
-
-        byte[] attrBytes = new byte[nameBytes.length +
-                                    numValuesBytes.length +
-                                    totalValueBytes + 1];
-        System.arraycopy(nameBytes, 0, attrBytes, 0,
-                         nameBytes.length);
-
-        int pos = nameBytes.length+1;
-        System.arraycopy(numValuesBytes, 0, attrBytes, pos,
-                         numValuesBytes.length);
-        pos += numValuesBytes.length;
-        for (byte[] b : valueBytes)
-        {
-          System.arraycopy(b, 0, attrBytes, pos, b.length);
-          pos += b.length;
-        }
-
-        userAttrBytes.add(attrBytes);
-        totalUserAttrBytes += attrBytes.length;
-      }
-    }
-    byte[] userAttrCount =
-         ASN1OctetString.encodeLength(numUserAttributes);
-    totalBytes += totalUserAttrBytes + userAttrCount.length;
-
-
-    // The operational attributes will be encoded in the same way as
-    // the user attributes.
-    i=0;
-    int numOperationalAttributes = 0;
-    int totalOperationalAttrBytes = 0;
-    LinkedList<byte[]> operationalAttrBytes =
-                            new LinkedList<byte[]>();
-    for (List<Attribute> attrList : operationalAttributes.values())
-    {
-      for (Attribute a : attrList)
-      {
-        if (a.isVirtual() || a.isEmpty())
-        {
-          continue;
-        }
-
-        numOperationalAttributes++;
-
-        byte[] nameBytes = getBytes(a.getNameWithOptions());
-
-        int numValues = 0;
-        int totalValueBytes = 0;
-        LinkedList<byte[]> valueBytes = new LinkedList<byte[]>();
-        for (AttributeValue v : a)
-        {
-          numValues++;
-          byte[] vBytes = v.getValueBytes();
-          byte[] vLength = ASN1Element.encodeLength(vBytes.length);
-          valueBytes.add(vLength);
-          valueBytes.add(vBytes);
-          totalValueBytes += vLength.length + vBytes.length;
-        }
-        byte[] numValuesBytes = ASN1Element.encodeLength(numValues);
-
-        byte[] attrBytes = new byte[nameBytes.length +
-                                    numValuesBytes.length +
-                                    totalValueBytes + 1];
-        System.arraycopy(nameBytes, 0, attrBytes, 0,
-                         nameBytes.length);
-
-        int pos = nameBytes.length+1;
-        System.arraycopy(numValuesBytes, 0, attrBytes, pos,
-                         numValuesBytes.length);
-        pos += numValuesBytes.length;
-        for (byte[] b : valueBytes)
-        {
-          System.arraycopy(b, 0, attrBytes, pos, b.length);
-          pos += b.length;
-        }
-
-        operationalAttrBytes.add(attrBytes);
-        totalOperationalAttrBytes += attrBytes.length;
-      }
-    }
-    byte[] operationalAttrCount =
-         ASN1OctetString.encodeLength(numOperationalAttributes);
-    totalBytes += totalOperationalAttrBytes +
-                  operationalAttrCount.length;
-
-
-    // Now we've got all the data that we need.  Create a big byte
-    // array to hold it all and pack it in.
-    byte[] entryBytes = new byte[totalBytes];
-
-
-    // Add the entry version number as the first byte.
-    entryBytes[0] = 0x01;
-
-
-    // Next, add the DN length and value.
-    System.arraycopy(dnLength, 0, entryBytes, 1, dnLength.length);
-    int pos = 1 + dnLength.length;
-    System.arraycopy(dnBytes, 0, entryBytes, pos,  dnBytes.length);
-    pos += dnBytes.length;
-
-
-    // Next, add the object classes length and values.
-    System.arraycopy(ocLength, 0, entryBytes, pos, ocLength.length);
-    pos += ocLength.length;
-    for (byte[] b : ocBytes)
-    {
-      System.arraycopy(b, 0, entryBytes, pos, b.length);
-      pos += b.length + 1;
-    }
-
-    // We need to back up one because there's no zero-teriminator
-    // after the last object class name.
-    pos--;
-
-
-    // Next, add the user attribute count and the user attribute
-    // data.
-    System.arraycopy(userAttrCount, 0, entryBytes, pos,
-                     userAttrCount.length);
-    pos += userAttrCount.length;
-    for (byte[] b : userAttrBytes)
-    {
-      System.arraycopy(b, 0, entryBytes, pos, b.length);
-      pos += b.length;
-    }
-
-
-    // Finally, add the operational attribute count and the
-    // operational attribute data.
-    System.arraycopy(operationalAttrCount, 0, entryBytes, pos,
-                     operationalAttrCount.length);
-    pos += operationalAttrCount.length;
-    for (byte[] b : operationalAttrBytes)
-    {
-      System.arraycopy(b, 0, entryBytes, pos, b.length);
-      pos += b.length;
-    }
-
-    return entryBytes;
-  }
-
-
-
-  /**
-   * Encodes this entry using the V2 encoding.
-   *
+   * @param  buffer  The buffer to encode into.
    * @param  config  The configuration that should be used to encode
    *                 the entry.
    *
-   * @return  The entry encoded in the V2 encoding.
-   *
    * @throws  DirectoryException  If a problem occurs while attempting
    *                              to encode the entry.
    */
-  public byte[] encodeV2(EntryEncodeConfig config)
+  private void encodeV3(ByteStringBuilder buffer,
+                        EntryEncodeConfig config)
          throws DirectoryException
   {
-    // The version number will be one byte.  We'll add that later.
-
+    // The version number will be one byte.
+    buffer.append((byte)0x03);
 
     // Get the encoded respresentation of the config.
-    byte[] configBytes = config.encode();
-    byte[] configLength =
-                ASN1Element.encodeLength(configBytes.length);
-    int totalBytes = 1 + configBytes.length + configLength.length;
-
+    config.encode(buffer);
 
     // If we should include the DN, then it will be encoded as a
     // one-to-five byte length followed by the UTF-8 byte
     // representation.
-    byte[] dnBytes  = null;
-    byte[] dnLength = null;
     if (! config.excludeDN())
     {
-      dnBytes  = getBytes(dn.toString());
-      dnLength = ASN1Element.encodeLength(dnBytes.length);
-      totalBytes += dnBytes.length + dnLength.length;
+      // TODO: Can we encode the DN directly into buffer?
+      byte[] dnBytes  = getBytes(dn.toString());
+      buffer.appendBERLength(dnBytes.length);
+      buffer.append(dnBytes);
     }
 
 
     // Encode the object classes in the appropriate manner.
-    byte[] ocLength;
-    LinkedList<byte[]> ocBytes = new LinkedList<byte[]>();
     if (config.compressObjectClassSets())
     {
-      byte[] b = config.getCompressedSchema().
-                      encodeObjectClasses(objectClasses);
-      ocBytes.add(b);
-      ocLength = ASN1Element.encodeLength(b.length);
-      totalBytes += ocLength.length + b.length;
+      config.getCompressedSchema().encodeObjectClasses(buffer,
+          objectClasses);
     }
     else
     {
-      int totalOCBytes = objectClasses.size() - 1;
+      // Encode number of OCs and 0 terminated names.
+      buffer.appendBERLength(objectClasses.size());
       for (String ocName : objectClasses.values())
       {
-        byte[] b = getBytes(ocName);
-        ocBytes.add(b);
-        totalOCBytes += b.length;
+        buffer.append(ocName);
+        buffer.append((byte)0x00);
       }
-      ocLength = ASN1Element.encodeLength(totalOCBytes);
-      totalBytes += totalOCBytes + ocLength.length;
     }
 
 
     // Encode the user attributes in the appropriate manner.
-    int numUserAttributes = 0;
-    int totalUserAttrBytes = 0;
-    LinkedList<byte[]> userAttrBytes = new LinkedList<byte[]>();
+    encodeAttributes(buffer, userAttributes, config);
+
+
+    // The operational attributes will be encoded in the same way as
+    // the user attributes.
+    encodeAttributes(buffer, operationalAttributes, config);
+  }
+
+  /**
+   * Encode the given attributes of an entry.
+   *
+   * @param  buffer  The buffer to encode into.
+   * @param  attributes The attributes to encode.
+   * @param  config  The configuration that may be used to control how
+   *                 the entry is encoded.
+   *
+   * @throws  DirectoryException  If a problem occurs while attempting
+   *                              to encode the entry.
+   */
+  private void encodeAttributes(ByteStringBuilder buffer,
+                    Map<AttributeType,List<Attribute>> attributes,
+                                EntryEncodeConfig config)
+      throws DirectoryException
+  {
+    int numAttributes = 0;
+
+    // First count how many attributes are there to encode.
+    for (List<Attribute> attrList : attributes.values())
+    {
+      Attribute a;
+      for (int i = 0; i < attrList.size(); i++)
+      {
+        a = attrList.get(i);
+        if (a.isVirtual() || a.isEmpty())
+        {
+          continue;
+        }
+
+        numAttributes++;
+      }
+    }
+
+    // Encoded one-to-five byte number of attributes
+    buffer.appendBERLength(numAttributes);
+
     if (config.compressAttributeDescriptions())
     {
-      for (List<Attribute> attrList : userAttributes.values())
+      for (List<Attribute> attrList : attributes.values())
       {
         for (Attribute a : attrList)
         {
@@ -3694,273 +3520,64 @@
             continue;
           }
 
-          numUserAttributes++;
-
-          byte[] attrBytes =
-               config.getCompressedSchema().encodeAttribute(a);
-          byte[] lengthBytes =
-               ASN1Element.encodeLength(attrBytes.length);
-          userAttrBytes.add(lengthBytes);
-          userAttrBytes.add(attrBytes);
-          totalUserAttrBytes += lengthBytes.length + attrBytes.length;
+          config.getCompressedSchema().encodeAttribute(buffer, a);
         }
       }
     }
     else
     {
-      // The user attributes will be encoded as a one-to-five byte
-      // number of attributes followed by a sequence of:
+      // The attributes will be encoded as a sequence of:
       // - A UTF-8 byte representation of the attribute name.
       // - A zero delimiter
       // - A one-to-five byte number of values for the attribute
       // - A sequence of:
       //   - A one-to-five byte length for the value
       //   - A UTF-8 byte representation for the value
-      for (List<Attribute> attrList : userAttributes.values())
+      for (List<Attribute> attrList : attributes.values())
       {
         for (Attribute a : attrList)
         {
-          if (a.isVirtual() || a.isEmpty())
-          {
-            continue;
-          }
-
-          numUserAttributes++;
-
           byte[] nameBytes = getBytes(a.getNameWithOptions());
+          buffer.append(nameBytes);
+          buffer.append((byte)0x00);
 
-          int numValues = 0;
-          int totalValueBytes = 0;
-          LinkedList<byte[]> valueBytes = new LinkedList<byte[]>();
-          for (AttributeValue v : a)
+          buffer.appendBERLength(a.size());
+          for(AttributeValue v : a)
           {
-            numValues++;
-            byte[] vBytes = v.getValueBytes();
-            byte[] vLength = ASN1Element.encodeLength(vBytes.length);
-            valueBytes.add(vLength);
-            valueBytes.add(vBytes);
-            totalValueBytes += vLength.length + vBytes.length;
+            buffer.appendBERLength(v.getValue().length());
+            buffer.append(v.getValue());
           }
-          byte[] numValuesBytes = ASN1Element.encodeLength(numValues);
-
-          byte[] attrBytes = new byte[nameBytes.length +
-                                      numValuesBytes.length +
-                                      totalValueBytes + 1];
-          System.arraycopy(nameBytes, 0, attrBytes, 0,
-                           nameBytes.length);
-
-          int pos = nameBytes.length+1;
-          System.arraycopy(numValuesBytes, 0, attrBytes, pos,
-                           numValuesBytes.length);
-          pos += numValuesBytes.length;
-          for (byte[] b : valueBytes)
-          {
-            System.arraycopy(b, 0, attrBytes, pos, b.length);
-            pos += b.length;
-          }
-
-          userAttrBytes.add(attrBytes);
-          totalUserAttrBytes += attrBytes.length;
         }
       }
     }
-    byte[] userAttrCount =
-         ASN1OctetString.encodeLength(numUserAttributes);
-    totalBytes += totalUserAttrBytes + userAttrCount.length;
-
-
-    // Encode the operational attributes in the appropriate manner.
-    int numOperationalAttributes = 0;
-    int totalOperationalAttrBytes = 0;
-    LinkedList<byte[]> operationalAttrBytes =
-                            new LinkedList<byte[]>();
-    if (config.compressAttributeDescriptions())
-    {
-      for (List<Attribute> attrList : operationalAttributes.values())
-      {
-        for (Attribute a : attrList)
-        {
-          if (a.isVirtual() || a.isEmpty())
-          {
-            continue;
-          }
-
-          numOperationalAttributes++;
-
-          byte[] attrBytes =
-               config.getCompressedSchema().encodeAttribute(a);
-          byte[] lengthBytes =
-               ASN1Element.encodeLength(attrBytes.length);
-          operationalAttrBytes.add(lengthBytes);
-          operationalAttrBytes.add(attrBytes);
-          totalOperationalAttrBytes +=
-               lengthBytes.length + attrBytes.length;
-        }
-      }
-    }
-    else
-    {
-      // Encode the operational attributes in the same way as the user
-      // attributes.
-      for (List<Attribute> attrList : operationalAttributes.values())
-      {
-        for (Attribute a : attrList)
-        {
-          if (a.isVirtual() || a.isEmpty())
-          {
-            continue;
-          }
-
-          numOperationalAttributes++;
-
-          byte[] nameBytes = getBytes(a.getNameWithOptions());
-
-          int numValues = 0;
-          int totalValueBytes = 0;
-          LinkedList<byte[]> valueBytes = new LinkedList<byte[]>();
-          for (AttributeValue v : a)
-          {
-            numValues++;
-            byte[] vBytes = v.getValueBytes();
-            byte[] vLength = ASN1Element.encodeLength(vBytes.length);
-            valueBytes.add(vLength);
-            valueBytes.add(vBytes);
-            totalValueBytes += vLength.length + vBytes.length;
-          }
-          byte[] numValuesBytes = ASN1Element.encodeLength(numValues);
-
-          byte[] attrBytes = new byte[nameBytes.length +
-                                      numValuesBytes.length +
-                                      totalValueBytes + 1];
-          System.arraycopy(nameBytes, 0, attrBytes, 0,
-                           nameBytes.length);
-
-          int pos = nameBytes.length+1;
-          System.arraycopy(numValuesBytes, 0, attrBytes, pos,
-                           numValuesBytes.length);
-          pos += numValuesBytes.length;
-          for (byte[] b : valueBytes)
-          {
-            System.arraycopy(b, 0, attrBytes, pos, b.length);
-            pos += b.length;
-          }
-
-          operationalAttrBytes.add(attrBytes);
-          totalOperationalAttrBytes += attrBytes.length;
-        }
-      }
-    }
-    byte[] operationalAttrCount =
-         ASN1OctetString.encodeLength(numOperationalAttributes);
-    totalBytes += totalOperationalAttrBytes +
-                  operationalAttrCount.length;
-
-
-    // Now we've got all the data that we need.  Create a big byte
-    // array to hold it all and pack it in.
-    byte[] entryBytes = new byte[totalBytes];
-
-
-    // Add the entry version number as the first byte.
-    entryBytes[0] = 0x02;
-
-
-    // Next, add the encoded config.
-    System.arraycopy(configLength, 0, entryBytes, 1,
-                     configLength.length);
-    int pos = 1 + configLength.length;
-    System.arraycopy(configBytes, 0, entryBytes, pos,
-                     configBytes.length);
-    pos += configBytes.length;
-
-
-    // Next, add the DN length and value.
-    if (! config.excludeDN())
-    {
-      System.arraycopy(dnLength, 0, entryBytes, pos, dnLength.length);
-      pos += dnLength.length;
-      System.arraycopy(dnBytes, 0, entryBytes, pos,  dnBytes.length);
-      pos += dnBytes.length;
-    }
-
-
-    // Next, add the object classes length and values.
-    System.arraycopy(ocLength, 0, entryBytes, pos, ocLength.length);
-    pos += ocLength.length;
-    if (config.compressObjectClassSets())
-    {
-      for (byte[] b : ocBytes)
-      {
-        System.arraycopy(b, 0, entryBytes, pos, b.length);
-        pos += b.length;
-      }
-    }
-    else
-    {
-      for (byte[] b : ocBytes)
-      {
-        System.arraycopy(b, 0, entryBytes, pos, b.length);
-        pos += b.length + 1;
-      }
-
-      // We need to back up one because there's no zero-teriminator
-      // after the last object class name.
-      pos--;
-    }
-
-
-    // Next, add the user attribute count and the user attribute
-    // data.
-    System.arraycopy(userAttrCount, 0, entryBytes, pos,
-                     userAttrCount.length);
-    pos += userAttrCount.length;
-    for (byte[] b : userAttrBytes)
-    {
-      System.arraycopy(b, 0, entryBytes, pos, b.length);
-      pos += b.length;
-    }
-
-
-    // Finally, add the operational attribute count and the
-    // operational attribute data.
-    System.arraycopy(operationalAttrCount, 0, entryBytes, pos,
-                     operationalAttrCount.length);
-    pos += operationalAttrCount.length;
-    for (byte[] b : operationalAttrBytes)
-    {
-      System.arraycopy(b, 0, entryBytes, pos, b.length);
-      pos += b.length;
-    }
-
-    return entryBytes;
   }
 
 
-
   /**
    * Decodes the provided byte array as an entry.
    *
-   * @param  entryBytes  The byte array containing the data to be
-   *                     decoded.
+   * @param  entryBuffer  The byte array containing the data to be
+   *                      decoded.
    *
    * @return  The decoded entry.
    *
    * @throws  DirectoryException  If the provided byte array cannot be
    *                              decoded as an entry.
    */
-  public static Entry decode(byte[] entryBytes)
+  public static Entry decode(ByteSequenceReader entryBuffer)
          throws DirectoryException
   {
-    return decode(entryBytes,
+    return decode(entryBuffer,
                   DirectoryServer.getDefaultCompressedSchema());
   }
 
 
 
-  /**
-   * Decodes the provided byte array as an entry.
+    /**
+   * Decodes the provided byte array as an entry using the V3
+   * encoding.
    *
-   * @param  entryBytes        The byte array containing the data to
+   * @param  entryBuffer       The byte buffer containing the data to
    *                           be decoded.
    * @param  compressedSchema  The compressed schema manager to use
    *                           when decoding tokenized schema
@@ -3971,437 +3588,40 @@
    * @throws  DirectoryException  If the provided byte array cannot be
    *                              decoded as an entry.
    */
-  public static Entry decode(byte[] entryBytes,
+  public static Entry decode(ByteSequenceReader entryBuffer,
                              CompressedSchema compressedSchema)
          throws DirectoryException
   {
-    switch(entryBytes[0])
-    {
-      case 0x01:
-        return decodeV1(entryBytes);
-      case 0x02:
-        return decodeV2(entryBytes, compressedSchema);
-      default:
-        Message message = ERR_ENTRY_DECODE_UNRECOGNIZED_VERSION.get(
-            byteToHex(entryBytes[0]));
-        throw new DirectoryException(
-                       DirectoryServer.getServerErrorResultCode(),
-                       message);
-    }
-  }
-
-
-
-  /**
-   * Decodes the provided byte array as an entry using the V1
-   * encoding.
-   *
-   * @param  entryBytes  The byte array containing the data to be
-   *                     decoded.
-   *
-   * @return  The decoded entry.
-   *
-   * @throws  DirectoryException  If the provided byte array cannot be
-   *                              decoded as an entry.
-   */
-  public static Entry decodeV1(byte[] entryBytes)
-         throws DirectoryException
-  {
     try
     {
       // The first byte must be the entry version.  If it's not one
       // we recognize, then that's an error.
-      if (entryBytes[0] != 0x01)
+      Byte version = entryBuffer.get();
+      if (version != 0x03 && version != 0x02 && version != 0x01)
       {
         Message message = ERR_ENTRY_DECODE_UNRECOGNIZED_VERSION.get(
-            byteToHex(entryBytes[0]));
+            byteToHex(version));
         throw new DirectoryException(
                        DirectoryServer.getServerErrorResultCode(),
                        message);
       }
 
-
-      // Next is the length of the DN.  It may be a single byte or
-      // multiple bytes.
-      int pos = 1;
-      int dnLength = entryBytes[pos] & 0x7F;
-      if (entryBytes[pos++] != dnLength)
+      EntryEncodeConfig config;
+      if(version != 0x01)
       {
-        int numLengthBytes = dnLength;
-        dnLength = 0;
-        for (int i=0; i < numLengthBytes; i++, pos++)
-        {
-          dnLength = (dnLength << 8) | (entryBytes[pos] & 0xFF);
-        }
+        // Next is the length of the encoded configuration.
+        int configLength = entryBuffer.getBERLength();
+
+        // Next is the encoded configuration itself.
+        config =
+            EntryEncodeConfig.decode(entryBuffer, configLength,
+                compressedSchema);
       }
-
-
-      // Next is the DN itself.
-      byte[] dnBytes = new byte[dnLength];
-      System.arraycopy(entryBytes, pos, dnBytes, 0, dnLength);
-      pos += dnLength;
-      DN dn = DN.decode(new ASN1OctetString(dnBytes));
-
-
-      // Next is the length of the object classes.  It may be a single
-      // byte or multiple bytes.
-      int ocLength = entryBytes[pos] & 0x7F;
-      if (entryBytes[pos++] != ocLength)
+      else
       {
-        int numLengthBytes = ocLength;
-        ocLength = 0;
-        for (int i=0; i < numLengthBytes; i++, pos++)
-        {
-          ocLength = (ocLength << 8) | (entryBytes[pos] & 0xFF);
-        }
+        config = EntryEncodeConfig.DEFAULT_CONFIG;
       }
 
-
-      // Next is the encoded set of object classes.  It will be a
-      // single string with the object class names separated by zeros.
-      LinkedHashMap<ObjectClass,String> objectClasses =
-           new LinkedHashMap<ObjectClass,String>();
-      int startPos = pos;
-      for (int i=0; i < ocLength; i++,pos++)
-      {
-        if (entryBytes[pos] == 0x00)
-        {
-          String name = new String(entryBytes, startPos, pos-startPos,
-                                   "UTF-8");
-          String lowerName = toLowerCase(name);
-          ObjectClass oc =
-               DirectoryServer.getObjectClass(lowerName, true);
-          objectClasses.put(oc, name);
-          startPos = pos+1;
-        }
-      }
-      String name = new String(entryBytes, startPos, pos-startPos,
-                               "UTF-8");
-      String lowerName = toLowerCase(name);
-      ObjectClass oc =
-           DirectoryServer.getObjectClass(lowerName, true);
-      objectClasses.put(oc, name);
-
-
-      // Next is the total number of user attributes.  It may be a
-      // single byte or multiple bytes.
-      int numUserAttrs = entryBytes[pos] & 0x7F;
-      if (entryBytes[pos++] != numUserAttrs)
-      {
-        int numLengthBytes = numUserAttrs;
-        numUserAttrs = 0;
-        for (int i=0; i < numLengthBytes; i++, pos++)
-        {
-          numUserAttrs = (numUserAttrs << 8) |
-                         (entryBytes[pos] & 0xFF);
-        }
-      }
-
-
-      // Now, we should iterate through the user attributes and decode
-      // each one.
-      LinkedHashMap<AttributeType,List<Attribute>> userAttributes =
-           new LinkedHashMap<AttributeType,List<Attribute>>();
-      AttributeBuilder builder = new AttributeBuilder();
-      for (int i=0; i < numUserAttrs; i++)
-      {
-        AttributeType attributeType;
-
-        // First, we have the zero-terminated attribute name.
-        startPos = pos;
-        while (entryBytes[pos] != 0x00)
-        {
-          pos++;
-        }
-        name = new String(entryBytes, startPos, pos-startPos,
-                          "UTF-8");
-        int semicolonPos = name.indexOf(';');
-        if (semicolonPos > 0)
-        {
-          builder.setAttributeType(name.substring(0, semicolonPos));
-          attributeType = builder.getAttributeType();
-
-          int nextPos = name.indexOf(';', semicolonPos+1);
-          while (nextPos > 0)
-          {
-            String option = name.substring(semicolonPos+1, nextPos);
-            if (option.length() > 0)
-            {
-              builder.setOption(option);
-            }
-
-            semicolonPos = nextPos;
-            nextPos = name.indexOf(';', semicolonPos+1);
-          }
-
-          String option = name.substring(semicolonPos+1);
-          if (option.length() > 0)
-          {
-            builder.setOption(option);
-          }
-        }
-        else
-        {
-          builder.setAttributeType(name);
-          attributeType = builder.getAttributeType();
-        }
-
-
-        // Next, we have the number of values.
-        int numValues = entryBytes[++pos] & 0x7F;
-        if (entryBytes[pos++] != numValues)
-        {
-          int numLengthBytes = numValues;
-          numValues = 0;
-          for (int j=0; j < numLengthBytes; j++, pos++)
-          {
-            numValues = (numValues << 8) | (entryBytes[pos] & 0xFF);
-          }
-        }
-
-        // Next, we have the sequence of length-value pairs.
-        builder.setInitialCapacity(numValues);
-        for (int j=0; j < numValues; j++)
-        {
-          int valueLength = entryBytes[pos] & 0x7F;
-          if (entryBytes[pos++] != valueLength)
-          {
-            int numLengthBytes = valueLength;
-            valueLength = 0;
-            for (int k=0; k < numLengthBytes; k++, pos++)
-            {
-              valueLength = (valueLength << 8) |
-                            (entryBytes[pos] & 0xFF);
-            }
-          }
-
-          byte[] valueBytes = new byte[valueLength];
-          System.arraycopy(entryBytes, pos, valueBytes, 0,
-                           valueLength);
-          builder.add(new AttributeValue(attributeType,
-              new ASN1OctetString(valueBytes)));
-          pos += valueLength;
-        }
-
-
-        // Create the attribute and add it to the set of user
-        // attributes.
-        Attribute a = builder.toAttribute();
-        List<Attribute> attrList = userAttributes.get(attributeType);
-        if (attrList == null)
-        {
-          attrList = new ArrayList<Attribute>(1);
-          attrList.add(a);
-          userAttributes.put(attributeType, attrList);
-        }
-        else
-        {
-          attrList.add(a);
-        }
-      }
-
-
-      // Next is the total number of operational attributes.  It may
-      // be a single byte or multiple bytes.
-      int numOperationalAttrs = entryBytes[pos] & 0x7F;
-      if (entryBytes[pos++] != numOperationalAttrs)
-      {
-        int numLengthBytes = numOperationalAttrs;
-        numOperationalAttrs = 0;
-        for (int i=0; i < numLengthBytes; i++, pos++)
-        {
-          numOperationalAttrs =
-               (numOperationalAttrs << 8) | (entryBytes[pos] & 0xFF);
-        }
-      }
-
-
-      // Now, we should iterate through the operational attributes and
-      // decode each one.
-      LinkedHashMap<AttributeType,List<Attribute>>
-           operationalAttributes =
-              new LinkedHashMap<AttributeType,List<Attribute>>();
-      for (int i=0; i < numOperationalAttrs; i++)
-      {
-        AttributeType attributeType;
-
-        // First, we have the zero-terminated attribute name.
-        startPos = pos;
-        while (entryBytes[pos] != 0x00)
-        {
-          pos++;
-        }
-        name = new String(entryBytes, startPos, pos-startPos,
-                          "UTF-8");
-        int semicolonPos = name.indexOf(';');
-        if (semicolonPos > 0)
-        {
-          builder.setAttributeType(name.substring(0, semicolonPos));
-          attributeType = builder.getAttributeType();
-
-          int nextPos = name.indexOf(';', semicolonPos+1);
-          while (nextPos > 0)
-          {
-            String option = name.substring(semicolonPos+1, nextPos);
-            if (option.length() > 0)
-            {
-              builder.setOption(option);
-            }
-
-            semicolonPos = nextPos;
-            nextPos = name.indexOf(';', semicolonPos+1);
-          }
-
-          String option = name.substring(semicolonPos+1);
-          if (option.length() > 0)
-          {
-            builder.setOption(option);
-          }
-        }
-        else
-        {
-          builder.setAttributeType(name);
-          attributeType = builder.getAttributeType();
-        }
-
-
-        // Next, we have the number of values.
-        int numValues = entryBytes[++pos] & 0x7F;
-        if (entryBytes[pos++] != numValues)
-        {
-          int numLengthBytes = numValues;
-          numValues = 0;
-          for (int j=0; j < numLengthBytes; j++, pos++)
-          {
-            numValues = (numValues << 8) | (entryBytes[pos] & 0xFF);
-          }
-        }
-
-        // Next, we have the sequence of length-value pairs.
-        builder.setInitialCapacity(numValues);
-        for (int j=0; j < numValues; j++)
-        {
-          int valueLength = entryBytes[pos] & 0x7F;
-          if (entryBytes[pos++] != valueLength)
-          {
-            int numLengthBytes = valueLength;
-            valueLength = 0;
-            for (int k=0; k < numLengthBytes; k++, pos++)
-            {
-              valueLength = (valueLength << 8) |
-                            (entryBytes[pos] & 0xFF);
-            }
-          }
-
-          byte[] valueBytes = new byte[valueLength];
-          System.arraycopy(
-              entryBytes, pos, valueBytes, 0, valueLength);
-          builder.add(new AttributeValue(attributeType,
-              new ASN1OctetString(valueBytes)));
-          pos += valueLength;
-        }
-
-
-        // Create the attribute and add it to the set of operational
-        // attributes.
-        Attribute a = builder.toAttribute();
-        List<Attribute> attrList =
-          operationalAttributes.get(attributeType);
-        if (attrList == null)
-        {
-          attrList = new ArrayList<Attribute>(1);
-          attrList.add(a);
-          operationalAttributes.put(attributeType, attrList);
-        }
-        else
-        {
-          attrList.add(a);
-        }
-      }
-
-
-      // We've got everything that we need, so create and return the
-      // entry.
-      return new Entry(dn, objectClasses, userAttributes,
-                       operationalAttributes);
-    }
-    catch (DirectoryException de)
-    {
-      throw de;
-    }
-    catch (Exception e)
-    {
-      if (debugEnabled())
-      {
-        TRACER.debugCaught(DebugLogLevel.ERROR, e);
-      }
-
-      Message message =
-          ERR_ENTRY_DECODE_EXCEPTION.get(getExceptionMessage(e));
-      throw new DirectoryException(
-                     DirectoryServer.getServerErrorResultCode(),
-                     message, e);
-    }
-  }
-
-
-
-  /**
-   * Decodes the provided byte array as an entry using the V2
-   * encoding.
-   *
-   * @param  entryBytes        The byte array containing the data to
-   *                           be decoded.
-   * @param  compressedSchema  The compressed schema manager to use
-   *                           when decoding tokenized schema
-   *                           elements.
-   *
-   * @return  The decoded entry.
-   *
-   * @throws  DirectoryException  If the provided byte array cannot be
-   *                              decoded as an entry.
-   */
-  public static Entry decodeV2(byte[] entryBytes,
-                               CompressedSchema compressedSchema)
-         throws DirectoryException
-  {
-    try
-    {
-      // The first byte must be the entry version.  If it's not one
-      // we recognize, then that's an error.
-      if (entryBytes[0] != 0x02)
-      {
-        Message message = ERR_ENTRY_DECODE_UNRECOGNIZED_VERSION.get(
-            byteToHex(entryBytes[0]));
-        throw new DirectoryException(
-                       DirectoryServer.getServerErrorResultCode(),
-                       message);
-      }
-
-
-      // Next is the length of the encoded configuration.  It may be a
-      // single byte or multiple bytes.
-      int pos = 1;
-      int configLength = entryBytes[pos] & 0x7F;
-      if (entryBytes[pos++] != configLength)
-      {
-        int numLengthBytes = configLength;
-        configLength = 0;
-        for (int i=0; i < numLengthBytes; i++, pos++)
-        {
-          configLength =
-               (configLength << 8) | (entryBytes[pos] & 0xFF);
-        }
-      }
-
-
-      // Next is the encoded configuration itself.
-      EntryEncodeConfig config =
-           EntryEncodeConfig.decode(entryBytes, pos, configLength,
-                                    compressedSchema);
-      pos += configLength;
-
-
       // If we should have included the DN in the entry, then it's
       // next.
       DN dn;
@@ -4413,387 +3633,32 @@
       {
         // Next is the length of the DN.  It may be a single byte or
         // multiple bytes.
-        int dnLength = entryBytes[pos] & 0x7F;
-        if (entryBytes[pos++] != dnLength)
-        {
-          int numLengthBytes = dnLength;
-          dnLength = 0;
-          for (int i=0; i < numLengthBytes; i++, pos++)
-          {
-            dnLength = (dnLength << 8) | (entryBytes[pos] & 0xFF);
-          }
-        }
+        int dnLength = entryBuffer.getBERLength();
 
 
         // Next is the DN itself.
-        byte[] dnBytes = new byte[dnLength];
-        System.arraycopy(entryBytes, pos, dnBytes, 0, dnLength);
-        pos += dnLength;
-        dn = DN.decode(new ASN1OctetString(dnBytes));
-      }
-
-
-      // Next is the length of the object classes.  It may be a single
-      // byte or multiple bytes.
-      int ocLength = entryBytes[pos] & 0x7F;
-      if (entryBytes[pos++] != ocLength)
-      {
-        int numLengthBytes = ocLength;
-        ocLength = 0;
-        for (int i=0; i < numLengthBytes; i++, pos++)
-        {
-          ocLength = (ocLength << 8) | (entryBytes[pos] & 0xFF);
-        }
+        ByteSequence dnBytes = entryBuffer.getByteSequence(dnLength);
+        dn = DN.decode(dnBytes.toByteString());
       }
 
 
       // Next is the set of encoded object classes.  The encoding will
       // depend on the configuration.
-      Map<ObjectClass,String> objectClasses;
-      if (config.compressObjectClassSets())
-      {
-        byte[] ocBytes = new byte[ocLength];
-        System.arraycopy(entryBytes, pos, ocBytes, 0, ocLength);
-        objectClasses = config.getCompressedSchema().
-                             decodeObjectClasses(ocBytes);
-        pos += ocLength;
-      }
-      else
-      {
-        // The set of object classes will be encoded as a single
-        // string with the oibject class names separated by zeros.
-        objectClasses = new LinkedHashMap<ObjectClass,String>();
-        int startPos = pos;
-        for (int i=0; i < ocLength; i++,pos++)
-        {
-          if (entryBytes[pos] == 0x00)
-          {
-            String name = new String(entryBytes, startPos,
-                                     pos-startPos, "UTF-8");
-            String lowerName = toLowerCase(name);
-            ObjectClass oc =
-                 DirectoryServer.getObjectClass(lowerName, true);
-            objectClasses.put(oc, name);
-            startPos = pos+1;
-          }
-        }
-        String name = new String(entryBytes, startPos, pos-startPos,
-                                 "UTF-8");
-        String lowerName = toLowerCase(name);
-        ObjectClass oc =
-             DirectoryServer.getObjectClass(lowerName, true);
-        objectClasses.put(oc, name);
-      }
-
-
-      // Next is the total number of user attributes.  It may be a
-      // single byte or multiple bytes.
-      int numUserAttrs = entryBytes[pos] & 0x7F;
-      if (entryBytes[pos++] != numUserAttrs)
-      {
-        int numLengthBytes = numUserAttrs;
-        numUserAttrs = 0;
-        for (int i=0; i < numLengthBytes; i++, pos++)
-        {
-          numUserAttrs = (numUserAttrs << 8) |
-                         (entryBytes[pos] & 0xFF);
-        }
-      }
+      Map<ObjectClass,String> objectClasses =
+          decodeObjectClasses(version, entryBuffer, config);
 
 
       // Now, we should iterate through the user attributes and decode
       // each one.
       LinkedHashMap<AttributeType,List<Attribute>> userAttributes =
-           new LinkedHashMap<AttributeType,List<Attribute>>();
-      if (config.compressAttributeDescriptions())
-      {
-        for (int i=0; i < numUserAttrs; i++)
-        {
-          // Get the length of the attribute.
-          int attrLength = entryBytes[pos] & 0x7F;
-          if (entryBytes[pos++] != attrLength)
-          {
-            int attrLengthBytes = attrLength;
-            attrLength = 0;
-            for (int j=0; j < attrLengthBytes; j++, pos++)
-            {
-              attrLength = (attrLength << 8) |
-                           (entryBytes[pos] & 0xFF);
-            }
-          }
-
-          // Decode the attribute.
-          Attribute a = config.getCompressedSchema().decodeAttribute(
-                             entryBytes, pos, attrLength);
-          List<Attribute> attrList =
-               userAttributes.get(a.getAttributeType());
-          if (attrList == null)
-          {
-            attrList = new ArrayList<Attribute>(1);
-            userAttributes.put(a.getAttributeType(), attrList);
-          }
-
-          attrList.add(a);
-          pos += attrLength;
-        }
-      }
-      else
-      {
-        AttributeBuilder builder = new AttributeBuilder();
-        for (int i=0; i < numUserAttrs; i++)
-        {
-          AttributeType attributeType;
-
-          // First, we have the zero-terminated attribute name.
-          int startPos = pos;
-          while (entryBytes[pos] != 0x00)
-          {
-            pos++;
-          }
-
-          String name = new String(entryBytes, startPos, pos-startPos,
-                                   "UTF-8");
-          int semicolonPos = name.indexOf(';');
-          if (semicolonPos > 0)
-          {
-            builder.setAttributeType(name.substring(0, semicolonPos));
-            attributeType = builder.getAttributeType();
-
-            int nextPos = name.indexOf(';', semicolonPos+1);
-            while (nextPos > 0)
-            {
-              String option = name.substring(semicolonPos+1, nextPos);
-              if (option.length() > 0)
-              {
-                builder.setOption(option);
-              }
-
-              semicolonPos = nextPos;
-              nextPos = name.indexOf(';', semicolonPos+1);
-            }
-
-            String option = name.substring(semicolonPos+1);
-            if (option.length() > 0)
-            {
-              builder.setOption(option);
-            }
-          }
-          else
-          {
-            builder.setAttributeType(name);
-            attributeType = builder.getAttributeType();
-          }
-
-
-          // Next, we have the number of values.
-          int numValues = entryBytes[++pos] & 0x7F;
-          if (entryBytes[pos++] != numValues)
-          {
-            int numLengthBytes = numValues;
-            numValues = 0;
-            for (int j=0; j < numLengthBytes; j++, pos++)
-            {
-              numValues = (numValues << 8) | (entryBytes[pos] & 0xFF);
-            }
-          }
-
-          // Next, we have the sequence of length-value pairs.
-          builder.setInitialCapacity(numValues);
-          for (int j=0; j < numValues; j++)
-          {
-            int valueLength = entryBytes[pos] & 0x7F;
-            if (entryBytes[pos++] != valueLength)
-            {
-              int numLengthBytes = valueLength;
-              valueLength = 0;
-              for (int k=0; k < numLengthBytes; k++, pos++)
-              {
-                valueLength = (valueLength << 8) |
-                              (entryBytes[pos] & 0xFF);
-              }
-            }
-
-            byte[] valueBytes = new byte[valueLength];
-            System.arraycopy(entryBytes, pos, valueBytes, 0,
-                             valueLength);
-            builder.add(new AttributeValue(attributeType,
-                new ASN1OctetString(valueBytes)));
-            pos += valueLength;
-          }
-
-
-          // Create the attribute and add it to the set of user
-          // attributes.
-          Attribute a = builder.toAttribute();
-          List<Attribute> attrList =
-            userAttributes.get(attributeType);
-          if (attrList == null)
-          {
-            attrList = new ArrayList<Attribute>(1);
-            attrList.add(a);
-            userAttributes.put(attributeType, attrList);
-          }
-          else
-          {
-            attrList.add(a);
-          }
-        }
-      }
-
-
-      // Next is the total number of operational attributes.  It may
-      // be a single byte or multiple bytes.
-      int numOperationalAttrs = entryBytes[pos] & 0x7F;
-      if (entryBytes[pos++] != numOperationalAttrs)
-      {
-        int numLengthBytes = numOperationalAttrs;
-        numOperationalAttrs = 0;
-        for (int i=0; i < numLengthBytes; i++, pos++)
-        {
-          numOperationalAttrs =
-               (numOperationalAttrs << 8) | (entryBytes[pos] & 0xFF);
-        }
-      }
+          decodeAttributes(version, entryBuffer, config);
 
 
       // Now, we should iterate through the operational attributes and
       // decode each one.
       LinkedHashMap<AttributeType,List<Attribute>>
-           operationalAttributes =
-              new LinkedHashMap<AttributeType,List<Attribute>>();
-      if (config.compressAttributeDescriptions())
-      {
-        for (int i=0; i < numOperationalAttrs; i++)
-        {
-          // Get the length of the attribute.
-          int attrLength = entryBytes[pos] & 0x7F;
-          if (entryBytes[pos++] != attrLength)
-          {
-            int attrLengthBytes = attrLength;
-            attrLength = 0;
-            for (int j=0; j < attrLengthBytes; j++, pos++)
-            {
-              attrLength = (attrLength << 8) |
-                           (entryBytes[pos] & 0xFF);
-            }
-          }
-
-          // Decode the attribute.
-          Attribute a = config.getCompressedSchema().decodeAttribute(
-                             entryBytes, pos, attrLength);
-          List<Attribute> attrList =
-               operationalAttributes.get(a.getAttributeType());
-          if (attrList == null)
-          {
-            attrList = new ArrayList<Attribute>(1);
-            operationalAttributes.put(a.getAttributeType(), attrList);
-          }
-
-          attrList.add(a);
-          pos += attrLength;
-        }
-      }
-      else
-      {
-        AttributeBuilder builder = new AttributeBuilder();
-        for (int i=0; i < numOperationalAttrs; i++)
-        {
-          AttributeType attributeType;
-
-          // First, we have the zero-terminated attribute name.
-          int startPos = pos;
-          while (entryBytes[pos] != 0x00)
-          {
-            pos++;
-          }
-          String name = new String(entryBytes, startPos, pos-startPos,
-                                   "UTF-8");
-          int semicolonPos = name.indexOf(';');
-          if (semicolonPos > 0)
-          {
-            builder.setAttributeType(name.substring(0, semicolonPos));
-            attributeType = builder.getAttributeType();
-
-            int nextPos = name.indexOf(';', semicolonPos+1);
-            while (nextPos > 0)
-            {
-              String option = name.substring(semicolonPos+1, nextPos);
-              if (option.length() > 0)
-              {
-                builder.setOption(option);
-              }
-
-              semicolonPos = nextPos;
-              nextPos = name.indexOf(';', semicolonPos+1);
-            }
-
-            String option = name.substring(semicolonPos+1);
-            if (option.length() > 0)
-            {
-              builder.setOption(option);
-            }
-          }
-          else
-          {
-            builder.setAttributeType(name);
-            attributeType = builder.getAttributeType();
-          }
-
-
-          // Next, we have the number of values.
-          int numValues = entryBytes[++pos] & 0x7F;
-          if (entryBytes[pos++] != numValues)
-          {
-            int numLengthBytes = numValues;
-            numValues = 0;
-            for (int j=0; j < numLengthBytes; j++, pos++)
-            {
-              numValues = (numValues << 8) | (entryBytes[pos] & 0xFF);
-            }
-          }
-
-          // Next, we have the sequence of length-value pairs.
-          builder.setInitialCapacity(numValues);
-          for (int j=0; j < numValues; j++)
-          {
-            int valueLength = entryBytes[pos] & 0x7F;
-            if (entryBytes[pos++] != valueLength)
-            {
-              int numLengthBytes = valueLength;
-              valueLength = 0;
-              for (int k=0; k < numLengthBytes; k++, pos++)
-              {
-                valueLength = (valueLength << 8) |
-                              (entryBytes[pos] & 0xFF);
-              }
-            }
-
-            byte[] valueBytes = new byte[valueLength];
-            System.arraycopy(
-                entryBytes, pos, valueBytes, 0, valueLength);
-            builder.add(new AttributeValue(attributeType,
-                new ASN1OctetString(valueBytes)));
-            pos += valueLength;
-          }
-
-
-          // Create the attribute and add it to the set of operational
-          // attributes.
-          Attribute a = builder.toAttribute();
-          List<Attribute> attrList =
-            operationalAttributes.get(attributeType);
-          if (attrList == null)
-          {
-            attrList = new ArrayList<Attribute>(1);
-            attrList.add(a);
-            operationalAttributes.put(attributeType, attrList);
-          }
-          else
-          {
-            attrList.add(a);
-          }
-        }
-      }
+          operationalAttributes =
+          decodeAttributes(version, entryBuffer, config);
 
 
       // We've got everything that we need, so create and return the
@@ -4821,6 +3686,239 @@
   }
 
 
+  /**
+   * Decode the object classes of an encoded entry.
+   *
+   * @param  ver The version of the entry encoding.
+   * @param  entryBuffer The byte sequence containing the encoded
+   *                     entry.
+   * @param  config  The configuration that may be used to control how
+   *                 the entry is encoded.
+   *
+   * @return  A map of the decoded object classes.
+   * @throws  DirectoryException  If a problem occurs while attempting
+   *                              to encode the entry.
+   */
+  private static Map<ObjectClass,String> decodeObjectClasses(
+      byte ver, ByteSequenceReader entryBuffer,
+      EntryEncodeConfig config) throws DirectoryException
+  {
+    // Next is the set of encoded object classes.  The encoding will
+    // depend on the configuration.
+    Map<ObjectClass,String> objectClasses;
+    if (config.compressObjectClassSets())
+    {
+      if(ver < 0x03)
+      {
+        // Next is the length of the object classes. It may be a
+        // single byte or multiple bytes.
+        entryBuffer.getBERLength();
+      }
+
+      objectClasses = config.getCompressedSchema().
+          decodeObjectClasses(entryBuffer);
+    }
+    else
+    {
+      if(ver < 0x03)
+      {
+        // Next is the length of the object classes. It may be a
+        // single byte or multiple bytes.
+        int ocLength = entryBuffer.getBERLength();
+
+        // The set of object classes will be encoded as a single
+        // string with the object class names separated by zeros.
+        objectClasses = new LinkedHashMap<ObjectClass,String>();
+        int startPos = entryBuffer.position();
+        int endPos;
+        for (int i=0; i < ocLength; i++)
+        {
+          if (entryBuffer.get() == 0x00)
+          {
+            endPos = entryBuffer.position()-1;
+            entryBuffer.position(startPos);
+            String name = entryBuffer.getString(endPos - startPos);
+            String lowerName = toLowerCase(name);
+            ObjectClass oc =
+                DirectoryServer.getObjectClass(lowerName, true);
+            objectClasses.put(oc, name);
+
+            entryBuffer.skip(1);
+            startPos = entryBuffer.position();
+          }
+        }
+        endPos = entryBuffer.position();
+        entryBuffer.position(startPos);
+        String name = entryBuffer.getString(endPos - startPos);
+        String lowerName = toLowerCase(name);
+        ObjectClass oc =
+            DirectoryServer.getObjectClass(lowerName, true);
+        objectClasses.put(oc, name);
+      }
+      else
+      {
+        // Next is the number of zero terminated object classes.
+        int numOC = entryBuffer.getBERLength();
+        int startPos;
+        int endPos;
+        objectClasses = new LinkedHashMap<ObjectClass,String>(numOC);
+        for(int i = 0; i < numOC; i++)
+        {
+          startPos = entryBuffer.position();
+          while(entryBuffer.get() != 0x00)
+          {}
+          endPos = entryBuffer.position()-1;
+          entryBuffer.position(startPos);
+          String name = entryBuffer.getString(endPos - startPos);
+          String lowerName = toLowerCase(name);
+          ObjectClass oc =
+              DirectoryServer.getObjectClass(lowerName, true);
+          objectClasses.put(oc, name);
+          entryBuffer.skip(1);
+        }
+      }
+    }
+
+    return objectClasses;
+  }
+
+  /**
+   * Decode the attributes of an encoded entry.
+   *
+   * @param  ver The version of the entry encoding.
+   * @param  entryBuffer The byte sequence containing the encoded
+   *                     entry.
+   * @param  config  The configuration that may be used to control how
+   *                 the entry is encoded.
+   *
+   * @return  A map of the decoded object classes.
+   * @throws  DirectoryException  If a problem occurs while attempting
+   *                              to encode the entry.
+   */
+  private static LinkedHashMap<AttributeType,List<Attribute>>
+  decodeAttributes(Byte ver, ByteSequenceReader entryBuffer,
+                   EntryEncodeConfig config) throws DirectoryException
+  {
+    // Next is the total number of attributes.  It may be a
+    // single byte or multiple bytes.
+    int attrs = entryBuffer.getBERLength();
+
+
+    // Now, we should iterate through the attributes and decode
+    // each one.
+    LinkedHashMap<AttributeType,List<Attribute>> attributes =
+        new LinkedHashMap<AttributeType,List<Attribute>>(attrs);
+    if (config.compressAttributeDescriptions())
+    {
+      for (int i=0; i < attrs; i++)
+      {
+        if(ver < 0x03)
+        {
+          // Version 2 includes a total attribute length
+          entryBuffer.getBERLength();
+        }
+        // Decode the attribute.
+        Attribute a = config.getCompressedSchema().decodeAttribute(
+            entryBuffer);
+        List<Attribute> attrList =
+            attributes.get(a.getAttributeType());
+        if (attrList == null)
+        {
+          attrList = new ArrayList<Attribute>(1);
+          attributes.put(a.getAttributeType(), attrList);
+        }
+
+        attrList.add(a);
+      }
+    }
+    else
+    {
+      AttributeBuilder builder = new AttributeBuilder();
+      int startPos;
+      int endPos;
+      for (int i=0; i < attrs; i++)
+      {
+        AttributeType attributeType;
+
+        // First, we have the zero-terminated attribute name.
+        startPos = entryBuffer.position();
+        while (entryBuffer.get() != 0x00)
+        {}
+        endPos = entryBuffer.position()-1;
+        entryBuffer.position(startPos);
+        String name = entryBuffer.getString(endPos - startPos);
+        entryBuffer.skip(1);
+
+        int semicolonPos = name.indexOf(';');
+        if (semicolonPos > 0)
+        {
+          builder.setAttributeType(name.substring(0, semicolonPos));
+          attributeType = builder.getAttributeType();
+
+          int nextPos = name.indexOf(';', semicolonPos+1);
+          while (nextPos > 0)
+          {
+            String option = name.substring(semicolonPos+1, nextPos);
+            if (option.length() > 0)
+            {
+              builder.setOption(option);
+            }
+
+            semicolonPos = nextPos;
+            nextPos = name.indexOf(';', semicolonPos+1);
+          }
+
+          String option = name.substring(semicolonPos+1);
+          if (option.length() > 0)
+          {
+            builder.setOption(option);
+          }
+        }
+        else
+        {
+          builder.setAttributeType(name);
+          attributeType = builder.getAttributeType();
+        }
+
+
+        // Next, we have the number of values.
+        int numValues = entryBuffer.getBERLength();
+
+        // Next, we have the sequence of length-value pairs.
+        builder.setInitialCapacity(numValues);
+        for (int j=0; j < numValues; j++)
+        {
+          int valueLength = entryBuffer.getBERLength();
+
+          ByteString valueBytes =
+              entryBuffer.getByteSequence(valueLength).toByteString();
+          builder.add(AttributeValues.create(attributeType,
+              valueBytes));
+        }
+
+
+        // Create the attribute and add it to the set of
+        // attributes.
+        Attribute a = builder.toAttribute();
+        List<Attribute> attrList =
+            attributes.get(attributeType);
+        if (attrList == null)
+        {
+          attrList = new ArrayList<Attribute>(1);
+          attrList.add(a);
+          attributes.put(attributeType, attrList);
+        }
+        else
+        {
+          attrList.add(a);
+        }
+      }
+    }
+
+    return attributes;
+  }
+
+
 
   /**
    * Retrieves a list of the lines for this entry in LDIF form.  Long
@@ -4837,7 +3935,8 @@
     // First, append the DN.
     StringBuilder dnLine = new StringBuilder();
     dnLine.append("dn");
-    appendLDIFSeparatorAndValue(dnLine, getBytes(dn.toString()));
+    appendLDIFSeparatorAndValue(dnLine,
+        ByteString.valueOf(dn.toString()));
     ldifLines.add(dnLine);
 
 
@@ -4867,7 +3966,7 @@
         {
           StringBuilder attrLine = new StringBuilder();
           attrLine.append(attrName);
-          appendLDIFSeparatorAndValue(attrLine, v.getValueBytes());
+          appendLDIFSeparatorAndValue(attrLine, v.getValue());
           ldifLines.add(attrLine);
         }
       }
@@ -4890,7 +3989,7 @@
         {
           StringBuilder attrLine = new StringBuilder();
           attrLine.append(attrName);
-          appendLDIFSeparatorAndValue(attrLine, v.getValueBytes());
+          appendLDIFSeparatorAndValue(attrLine, v.getValue());
           ldifLines.add(attrLine);
         }
       }
@@ -4973,7 +4072,8 @@
     // First, write the DN.  It will always be included.
     StringBuilder dnLine = new StringBuilder();
     dnLine.append("dn");
-    appendLDIFSeparatorAndValue(dnLine, getBytes(dn.toString()));
+    appendLDIFSeparatorAndValue(dnLine,
+        ByteString.valueOf(dn.toString()));
     writeLDIFLine(dnLine, writer, wrapLines, wrapColumn);
 
 
@@ -5048,7 +4148,7 @@
               StringBuilder attrLine = new StringBuilder();
               attrLine.append(attrName);
               appendLDIFSeparatorAndValue(attrLine,
-                                          v.getValueBytes());
+                                          v.getValue());
               writeLDIFLine(attrLine, writer, wrapLines, wrapColumn);
             }
           }
@@ -5110,7 +4210,7 @@
                 StringBuilder attrLine = new StringBuilder();
                 attrLine.append(attrName);
                 appendLDIFSeparatorAndValue(attrLine,
-                                            v.getValueBytes());
+                                            v.getValue());
                 writeLDIFLine(attrLine, writer, wrapLines,
                               wrapColumn);
               }
@@ -5178,7 +4278,7 @@
                 StringBuilder attrLine = new StringBuilder();
                 attrLine.append(attrName);
                 appendLDIFSeparatorAndValue(attrLine,
-                                            v.getValueBytes());
+                                            v.getValue());
                 writeLDIFLine(attrLine, writer, wrapLines,
                               wrapColumn);
               }
@@ -5517,12 +4617,12 @@
         Iterator<AttributeValue> valueIterator = a.iterator();
         if (valueIterator.hasNext())
         {
-          buffer.append(valueIterator.next().getStringValue());
+          buffer.append(valueIterator.next().getValue().toString());
 
           while (valueIterator.hasNext())
           {
             buffer.append(",");
-            buffer.append(valueIterator.next().getStringValue());
+            buffer.append(valueIterator.next().getValue().toString());
           }
         }
 
@@ -5559,12 +4659,12 @@
         Iterator<AttributeValue> valueIterator = a.iterator();
         if (valueIterator.hasNext())
         {
-          buffer.append(valueIterator.next().getStringValue());
+          buffer.append(valueIterator.next().getValue().toString());
 
           while (valueIterator.hasNext())
           {
             buffer.append(",");
-            buffer.append(valueIterator.next().getStringValue());
+            buffer.append(valueIterator.next().getValue().toString());
           }
         }
 
@@ -5654,12 +4754,12 @@
 
       for (AttributeValue v : attribute)
       {
-        String name = v.getStringValue();
+        String name = v.getValue().toString();
 
         String lowerName;
         try
         {
-          lowerName = v.getNormalizedStringValue();
+          lowerName = v.getNormalizedValue().toString();
         }
         catch (Exception e)
         {
@@ -5668,7 +4768,7 @@
             TRACER.debugCaught(DebugLogLevel.ERROR, e);
           }
 
-          lowerName = toLowerCase(v.getStringValue());
+          lowerName = toLowerCase(v.getValue().toString());
         }
 
         // Create a default object class if necessary.
diff --git a/opends/src/server/org/opends/server/types/EntryEncodeConfig.java b/opends/src/server/org/opends/server/types/EntryEncodeConfig.java
index 08540c0..0c86c06 100644
--- a/opends/src/server/org/opends/server/types/EntryEncodeConfig.java
+++ b/opends/src/server/org/opends/server/types/EntryEncodeConfig.java
@@ -22,7 +22,7 @@
  * CDDL HEADER END
  *
  *
- *      Copyright 2008 Sun Microsystems, Inc.
+ *      Copyright 2009 Sun Microsystems, Inc.
  */
 package org.opends.server.types;
 
@@ -91,7 +91,7 @@
   private final boolean excludeDN;
 
   // The encoded representation of this encode configuration.
-  private final byte[] encodedRepresentation;
+  private final byte encodedRepresentation;
 
   // The compressed schema handler for this encode configuration.
   private final CompressedSchema compressedSchema;
@@ -110,7 +110,7 @@
 
     compressedSchema = DirectoryServer.getDefaultCompressedSchema();
 
-    encodedRepresentation = new byte[] { 0x00 };
+    encodedRepresentation = 0x00;
   }
 
 
@@ -152,7 +152,7 @@
       flagByte |= ENCODE_FLAG_COMPRESS_OCS;
     }
 
-    encodedRepresentation = new byte[] { flagByte };
+    encodedRepresentation = flagByte;
   }
 
 
@@ -196,7 +196,7 @@
       flagByte |= ENCODE_FLAG_COMPRESS_OCS;
     }
 
-    encodedRepresentation = new byte[] { flagByte };
+    encodedRepresentation = flagByte;
   }
 
 
@@ -262,23 +262,21 @@
    * Encodes this entry encode configuration into a byte array
    * suitable for inclusion in the encoded entry.
    *
-   * @return  A byte array containing the encoded configuration.
+   * @param buffer The buffer to encode this configuration to.
    */
-  public byte[] encode()
+  public void encode(ByteStringBuilder buffer)
   {
-    return encodedRepresentation;
+    buffer.appendBERLength(1);
+    buffer.append(encodedRepresentation);
   }
 
 
-
   /**
-   * Decodes the entry encode configuration from the specified portion
-   * of the given byte array.
+   * Decodes the entry encode configuration from current position and
+   * length of the given byte array.
    *
-   * @param  encodedEntry      The byte array containing the encoded
+   * @param  buffer            The byte array containing the encoded
    *                           entry.
-   * @param  startPos          The position at which to start decoding
-   *                           the encode configuration.
    * @param  length            The number of bytes contained in the
    *                           encode configuration.
    * @param  compressedSchema  The compressed schema manager to use
@@ -290,8 +288,8 @@
    *                              properly decoded.
    */
   public static EntryEncodeConfig
-                     decode(byte[] encodedEntry, int startPos,
-                     int length, CompressedSchema compressedSchema)
+                     decode(ByteSequenceReader buffer, int length,
+                            CompressedSchema compressedSchema)
          throws DirectoryException
   {
     if (length != 1)
@@ -303,21 +301,22 @@
     }
 
     boolean excludeDN = false;
-    if ((encodedEntry[startPos] & ENCODE_FLAG_EXCLUDE_DN) ==
+    byte b = buffer.get();
+    if ((b & ENCODE_FLAG_EXCLUDE_DN) ==
         ENCODE_FLAG_EXCLUDE_DN)
     {
       excludeDN = true;
     }
 
     boolean compressAttrDescriptions = false;
-    if ((encodedEntry[startPos] & ENCODE_FLAG_COMPRESS_ADS) ==
+    if ((b & ENCODE_FLAG_COMPRESS_ADS) ==
         ENCODE_FLAG_COMPRESS_ADS)
     {
       compressAttrDescriptions = true;
     }
 
     boolean compressObjectClassSets = false;
-    if ((encodedEntry[startPos] & ENCODE_FLAG_COMPRESS_OCS) ==
+    if ((b & ENCODE_FLAG_COMPRESS_OCS) ==
         ENCODE_FLAG_COMPRESS_OCS)
     {
       compressObjectClassSets = true;
diff --git a/opends/src/server/org/opends/server/types/IntermediateResponse.java b/opends/src/server/org/opends/server/types/IntermediateResponse.java
index fe678a8..19a6a42 100644
--- a/opends/src/server/org/opends/server/types/IntermediateResponse.java
+++ b/opends/src/server/org/opends/server/types/IntermediateResponse.java
@@ -32,8 +32,6 @@
 import java.util.Iterator;
 import java.util.List;
 
-import org.opends.server.protocols.asn1.ASN1OctetString;
-
 
 
 
@@ -50,7 +48,7 @@
 public final class IntermediateResponse
 {
   // The value for this intermediate response.
-  private ASN1OctetString value;
+  private ByteString value;
 
   // The set of controls for this intermediate response.
   private List<Control> controls;
@@ -76,7 +74,7 @@
    *                    response.
    */
   public IntermediateResponse(Operation operation, String oid,
-                              ASN1OctetString value,
+                              ByteString value,
                               List<Control> controls)
   {
     this.operation = operation;
@@ -140,7 +138,7 @@
    * @return  The value for this intermediate response, or
    *          <CODE>null</CODE> if there is none.
    */
-  public ASN1OctetString getValue()
+  public ByteString getValue()
   {
     return value;
   }
@@ -152,7 +150,7 @@
    *
    * @param  value  The value for this intermediate response.
    */
-  public void setValue(ASN1OctetString value)
+  public void setValue(ByteString value)
   {
     this.value = value;
   }
diff --git a/opends/src/server/org/opends/server/types/MatchingRuleUse.java b/opends/src/server/org/opends/server/types/MatchingRuleUse.java
index d7612b8..7b00944 100644
--- a/opends/src/server/org/opends/server/types/MatchingRuleUse.java
+++ b/opends/src/server/org/opends/server/types/MatchingRuleUse.java
@@ -42,7 +42,6 @@
 import static org.opends.server.loggers.debug.DebugLogger.*;
 import org.opends.server.loggers.debug.DebugTracer;
 import static org.opends.server.util.ServerConstants.*;
-import static org.opends.server.util.StaticUtils.*;
 import static org.opends.server.util.Validator.*;
 
 
@@ -219,7 +218,7 @@
   public MatchingRuleUse recreateFromDefinition()
          throws DirectoryException
   {
-    ByteString value  = ByteStringFactory.create(definition);
+    ByteString value  = ByteString.valueOf(definition);
     Schema     schema = DirectoryConfig.getSchema();
 
     MatchingRuleUse mru =
diff --git a/opends/src/server/org/opends/server/types/NameForm.java b/opends/src/server/org/opends/server/types/NameForm.java
index c7dd2e5..623db7f 100644
--- a/opends/src/server/org/opends/server/types/NameForm.java
+++ b/opends/src/server/org/opends/server/types/NameForm.java
@@ -41,7 +41,6 @@
 import static org.opends.server.loggers.debug.DebugLogger.*;
 import org.opends.server.loggers.debug.DebugTracer;
 import static org.opends.server.util.ServerConstants.*;
-import static org.opends.server.util.StaticUtils.*;
 import static org.opends.server.util.Validator.*;
 
 
@@ -234,7 +233,7 @@
   public NameForm recreateFromDefinition()
          throws DirectoryException
   {
-    ByteString value  = ByteStringFactory.create(definition);
+    ByteString value  = ByteString.valueOf(definition);
     Schema     schema = DirectoryConfig.getSchema();
 
     NameForm nf = NameFormSyntax.decodeNameForm(value, schema, false);
diff --git a/opends/src/server/org/opends/server/types/ObjectClass.java b/opends/src/server/org/opends/server/types/ObjectClass.java
index a7adbf4..d49b733 100644
--- a/opends/src/server/org/opends/server/types/ObjectClass.java
+++ b/opends/src/server/org/opends/server/types/ObjectClass.java
@@ -314,7 +314,7 @@
   public ObjectClass recreateFromDefinition()
          throws DirectoryException
   {
-    ByteString value  = ByteStringFactory.create(definition);
+    ByteString value  = ByteString.valueOf(definition);
     Schema     schema = DirectoryConfig.getSchema();
 
     ObjectClass oc = ObjectClassSyntax.decodeObjectClass(value,
diff --git a/opends/src/server/org/opends/server/types/Operation.java b/opends/src/server/org/opends/server/types/Operation.java
index 1d9bf0f..301379b 100644
--- a/opends/src/server/org/opends/server/types/Operation.java
+++ b/opends/src/server/org/opends/server/types/Operation.java
@@ -22,7 +22,7 @@
  * CDDL HEADER END
  *
  *
- *      Copyright 2006-2008 Sun Microsystems, Inc.
+ *      Copyright 2006-2009 Sun Microsystems, Inc.
  */
 package org.opends.server.types;
 import org.opends.messages.Message;
@@ -33,6 +33,7 @@
 import java.util.Map;
 
 import org.opends.server.api.ClientConnection;
+import org.opends.server.controls.ControlDecoder;
 import org.opends.messages.MessageBuilder;
 
 
@@ -169,6 +170,22 @@
   public abstract List<Control> getRequestControls();
 
   /**
+   * Retrieves a control included in the request from the client.
+   *
+   * @param <T>
+   *          The type of control requested.
+   * @param d
+   *          The requested control's decoder.
+   * @return The decoded form of the requested control included in the
+   *         request from the client or <code>null</code> if the
+   *         control was not found.
+   * @throws DirectoryException
+   *           if an error occurs while decoding the control.
+   */
+  public abstract <T extends Control> T getRequestControl(
+      ControlDecoder<T> d) throws DirectoryException;
+
+  /**
    * Adds the provided control to the set of request controls for this
    * operation.  This method may only be called by pre-parse plugins.
    *
diff --git a/opends/src/server/org/opends/server/types/RDN.java b/opends/src/server/org/opends/server/types/RDN.java
index cfe151a..97426aa 100644
--- a/opends/src/server/org/opends/server/types/RDN.java
+++ b/opends/src/server/org/opends/server/types/RDN.java
@@ -22,7 +22,7 @@
  * CDDL HEADER END
  *
  *
- *      Copyright 2006-2008 Sun Microsystems, Inc.
+ *      Copyright 2006-2009 Sun Microsystems, Inc.
  */
 package org.opends.server.types;
 import org.opends.messages.Message;
@@ -36,7 +36,6 @@
 
 import org.opends.server.api.OrderingMatchingRule;
 import org.opends.server.core.DirectoryServer;
-import org.opends.server.protocols.asn1.ASN1OctetString;
 
 import static org.opends.server.loggers.debug.DebugLogger.*;
 import org.opends.server.loggers.debug.DebugTracer;
@@ -44,7 +43,6 @@
 import static org.opends.server.util.StaticUtils.*;
 
 
-
 /**
  * This class defines a data structure for storing and interacting
  * with the relative distinguished names associated with entries in
@@ -694,15 +692,15 @@
         attrType = DirectoryServer.getDefaultAttributeType(name);
       }
 
-      AttributeValue value = new AttributeValue(new ASN1OctetString(),
-                                     new ASN1OctetString());
+      AttributeValue value = AttributeValues.create(
+          ByteString.empty(), ByteString.empty());
       return new RDN(attrType, name, value);
     }
 
 
     // Parse the value for this RDN component.  This can be done using
     // the DN code.
-    ByteString parsedValue = new ASN1OctetString();
+    ByteStringBuilder parsedValue = new ByteStringBuilder(0);
     pos = DN.parseAttributeValue(rdnString, pos, parsedValue);
 
 
@@ -722,7 +720,8 @@
       attrType = DirectoryServer.getDefaultAttributeType(name);
     }
 
-    AttributeValue value = new AttributeValue(attrType, parsedValue);
+    AttributeValue value = AttributeValues.create(attrType,
+        parsedValue.toByteString());
     RDN rdn = new RDN(attrType, name, value);
 
 
@@ -857,15 +856,15 @@
           attrType = DirectoryServer.getDefaultAttributeType(name);
         }
 
-        value = new AttributeValue(new ASN1OctetString(),
-                                   new ASN1OctetString());
+        value = AttributeValues.create(ByteString.empty(),
+                                   ByteString.empty());
         rdn.addValue(attrType, name, value);
         return rdn;
       }
 
 
       // Parse the value for this RDN component.
-      parsedValue = new ASN1OctetString();
+      parsedValue.clear();
       pos = DN.parseAttributeValue(rdnString, pos, parsedValue);
 
 
@@ -883,7 +882,8 @@
         attrType = DirectoryServer.getDefaultAttributeType(name);
       }
 
-      value = new AttributeValue(attrType, parsedValue);
+      value = AttributeValues.create(attrType,
+          parsedValue.toByteString());
       rdn.addValue(attrType, name, value);
 
 
@@ -1006,7 +1006,7 @@
       buffer.append(attributeNames[0]);
       buffer.append("=");
 
-      String s = attributeValues[0].getStringValue();
+      String s = attributeValues[0].getValue().toString();
       buffer.append(getDNValue(s));
 
       for (int i=1; i < numValues; i++)
@@ -1015,7 +1015,7 @@
         buffer.append(attributeNames[i]);
         buffer.append("=");
 
-        s = attributeValues[i].getStringValue();
+        s = attributeValues[i].getValue().toString();
         buffer.append(getDNValue(s));
       }
 
@@ -1077,12 +1077,13 @@
 
     if (attributeNames.length == 1)
     {
-      toLowerCase(attributeTypes[0].getNameOrOID(), buffer);
+      buffer.append(
+          attributeTypes[0].getNormalizedPrimaryNameOrOID());
       buffer.append('=');
 
       try
       {
-        String s = attributeValues[0].getNormalizedStringValue();
+        String s = attributeValues[0].getNormalizedValue().toString();
         buffer.append(getDNValue(s));
       }
       catch (Exception e)
@@ -1092,7 +1093,7 @@
           TRACER.debugCaught(DebugLogLevel.ERROR, e);
         }
 
-        String s = attributeValues[0].getStringValue();
+        String s = attributeValues[0].getValue().toString();
         buffer.append(getDNValue(s));
       }
     }
@@ -1103,12 +1104,13 @@
       for (int i=0; i < attributeNames.length; i++)
       {
         StringBuilder b2 = new StringBuilder();
-        toLowerCase(attributeTypes[i].getNameOrOID(), b2);
+        b2.append(attributeTypes[i].getNormalizedPrimaryNameOrOID());
         b2.append('=');
 
         try
         {
-          String s = attributeValues[i].getNormalizedStringValue();
+          String s =
+              attributeValues[i].getNormalizedValue().toString();
           b2.append(getDNValue(s));
         }
         catch (Exception e)
@@ -1118,7 +1120,7 @@
             TRACER.debugCaught(DebugLogLevel.ERROR, e);
           }
 
-          String s = attributeValues[i].getStringValue();
+          String s = attributeValues[i].getValue().toString();
           b2.append(getDNValue(s));
         }
 
@@ -1167,9 +1169,9 @@
         {
           try
           {
-            return attributeValues[0].getNormalizedStringValue().
+            return attributeValues[0].getNormalizedValue().toString().
                         compareTo(rdn.attributeValues[0].
-                             getNormalizedStringValue());
+                             getNormalizedValue().toString());
           }
           catch (Exception e)
           {
@@ -1178,9 +1180,9 @@
               TRACER.debugCaught(DebugLogLevel.ERROR, e);
             }
 
-            return attributeValues[0].getStringValue().
+            return attributeValues[0].getValue().toString().
                 compareTo(rdn.attributeValues[0].
-                    getStringValue());
+                    getValue().toString());
           }
         }
         else
@@ -1206,9 +1208,10 @@
       }
       else
       {
-        String name1 = toLowerCase(attributeTypes[0].getNameOrOID());
+        String name1 =
+            attributeTypes[0].getNormalizedPrimaryNameOrOID();
         String name2 =
-             toLowerCase(rdn.attributeTypes[0].getNameOrOID());
+             rdn.attributeTypes[0].getNormalizedPrimaryNameOrOID();
         return name1.compareTo(name2);
       }
     }
@@ -1225,7 +1228,7 @@
     for (int i=0; i < attributeTypes.length; i++)
     {
       String lowerName =
-           toLowerCase(attributeTypes[i].getNameOrOID());
+           attributeTypes[i].getNormalizedPrimaryNameOrOID();
       typeMap1.put(lowerName, attributeTypes[i]);
       valueMap1.put(lowerName, attributeValues[i]);
     }
@@ -1237,7 +1240,7 @@
     for (int i=0; i < rdn.attributeTypes.length; i++)
     {
       String lowerName =
-           toLowerCase(rdn.attributeTypes[i].getNameOrOID());
+          rdn.attributeTypes[i].getNormalizedPrimaryNameOrOID();
       typeMap2.put(lowerName, rdn.attributeTypes[i]);
       valueMap2.put(lowerName, rdn.attributeValues[i]);
     }
@@ -1262,8 +1265,8 @@
           try
           {
             valueComparison =
-                 value1.getNormalizedStringValue().compareTo(
-                      value2.getNormalizedStringValue());
+                 value1.getNormalizedValue().toString().compareTo(
+                      value2.getNormalizedValue().toString());
           }
           catch (Exception e)
           {
@@ -1273,8 +1276,8 @@
             }
 
             valueComparison =
-                value1.getStringValue().compareTo(
-                    value2.getStringValue());
+                value1.getValue().toString().compareTo(
+                    value2.getValue().toString());
           }
         }
         else
diff --git a/opends/src/server/org/opends/server/types/RawAttribute.java b/opends/src/server/org/opends/server/types/RawAttribute.java
index fb4d8be..35435ef 100644
--- a/opends/src/server/org/opends/server/types/RawAttribute.java
+++ b/opends/src/server/org/opends/server/types/RawAttribute.java
@@ -22,7 +22,7 @@
  * CDDL HEADER END
  *
  *
- *      Copyright 2006-2008 Sun Microsystems, Inc.
+ *      Copyright 2006-2009 Sun Microsystems, Inc.
  */
 package org.opends.server.types;
 import org.opends.messages.Message;
@@ -30,12 +30,9 @@
 
 
 import java.util.ArrayList;
-import java.util.List;
+import java.io.IOException;
 
-import org.opends.server.protocols.asn1.ASN1Element;
-import org.opends.server.protocols.asn1.ASN1OctetString;
-import org.opends.server.protocols.asn1.ASN1Sequence;
-import org.opends.server.protocols.asn1.ASN1Set;
+import org.opends.server.protocols.asn1.*;
 import org.opends.server.protocols.ldap.LDAPAttribute;
 
 import static org.opends.server.loggers.debug.DebugLogger.*;
@@ -118,8 +115,7 @@
   {
     ensureNotNull(attributeType);
 
-    return new LDAPAttribute(attributeType,
-                             value.toASN1OctetString());
+    return new LDAPAttribute(attributeType, value);
   }
 
 
@@ -134,11 +130,11 @@
    * @return  The created raw attribute.
    */
   public static RawAttribute create(String attributeType,
-                                    List<ByteString> values)
+                                    ArrayList<ByteString> values)
   {
     ensureNotNull(attributeType);
 
-    return new LDAPAttribute(attributeType, convertValues(values));
+    return new LDAPAttribute(attributeType, values);
   }
 
 
@@ -161,34 +157,6 @@
 
 
   /**
-   * Converts the provided <CODE>List&lt;ByteString&gt;</CODE> to an
-   * <CODE>ArrayList&lt;ASN1OctetString&gt;</CODE>.
-   *
-   * @param  values  The list to be converted.
-   *
-   * @return  The converted {@code ArrayList} object.
-   */
-  private static ArrayList<ASN1OctetString>
-                      convertValues(List<ByteString> values)
-  {
-    if (values == null)
-    {
-      return null;
-    }
-
-    ArrayList<ASN1OctetString> convertedList =
-         new ArrayList<ASN1OctetString>(values.size());
-    for (ByteString s : values)
-    {
-      convertedList.add(s.toASN1OctetString());
-    }
-
-    return convertedList;
-  }
-
-
-
-  /**
    * Retrieves the attribute type for this attribute.
    *
    * @return  The attribute type for this attribute.
@@ -212,7 +180,7 @@
    *
    * @return  The set of values for this attribute.
    */
-  public abstract ArrayList<ASN1OctetString> getValues();
+  public abstract ArrayList<ByteString> getValues();
 
 
 
@@ -229,37 +197,37 @@
   public abstract Attribute toAttribute()
          throws LDAPException;
 
-
-
   /**
-   * Encodes this attribute to an ASN.1 element.
+   * Writes this attribute to an ASN.1 output stream.
    *
-   * @return  The ASN.1 element containing the encoded attribute.
+   * @param stream The ASN.1 output stream to write to.
+   * @throws IOException If a problem occurs while writing to the
+   *                     stream.
    */
-  public final ASN1Element encode()
+  public void write(ASN1Writer stream) throws IOException
   {
-    ArrayList<ASN1Element> elements = new ArrayList<ASN1Element>(2);
-    elements.add(new ASN1OctetString(getAttributeType()));
+    stream.writeStartSequence();
+    stream.writeOctetString(getAttributeType());
 
-    ArrayList<ASN1OctetString> values = getValues();
-    if ((values == null) || values.isEmpty())
+    stream.writeStartSet();
+    ArrayList<ByteString> values = getValues();
+    if ((values != null))
     {
-      elements.add(new ASN1Set());
+      for(ByteString value : values)
+      {
+        stream.writeOctetString(value);
+      }
     }
-    else
-    {
-      elements.add(new ASN1Set(new ArrayList<ASN1Element>(values)));
-    }
+    stream.writeEndSequence();
 
-    return new ASN1Sequence(elements);
+    stream.writeEndSequence();
   }
 
-
-
   /**
-   * Decodes the provided ASN.1 element as an LDAP attribute.
+   * Decodes the elements from the provided ASN.1 reader as an
+   * LDAP attribute.
    *
-   * @param  element  The ASN.1 element to decode.
+   * @param  reader The ASN.1 reader.
    *
    * @return  The decoded LDAP attribute.
    *
@@ -267,13 +235,12 @@
    *                         decode the provided ASN.1 element as a
    *                         raw attribute.
    */
-  public static LDAPAttribute decode(ASN1Element element)
+  public static LDAPAttribute decode(ASN1Reader reader)
          throws LDAPException
   {
-    ArrayList<ASN1Element> elements;
     try
     {
-      elements = element.decodeAsSequence().elements();
+      reader.readStartSequence();
     }
     catch (Exception e)
     {
@@ -288,21 +255,10 @@
     }
 
 
-    int numElements = elements.size();
-    if (numElements != 2)
-    {
-      Message message =
-          ERR_LDAP_ATTRIBUTE_DECODE_INVALID_ELEMENT_COUNT.
-            get(numElements);
-      throw new LDAPException(PROTOCOL_ERROR, message);
-    }
-
-
     String attributeType;
     try
     {
-      attributeType =
-           elements.get(0).decodeAsOctetString().stringValue();
+      attributeType = reader.readOctetStringAsString();
     }
     catch (Exception e)
     {
@@ -317,16 +273,16 @@
     }
 
 
-    ArrayList<ASN1OctetString> values;
+    ArrayList<ByteString> values;
     try
     {
-      ArrayList<ASN1Element> valueElements =
-           elements.get(1).decodeAsSet().elements();
-      values = new ArrayList<ASN1OctetString>(valueElements.size());
-      for (ASN1Element e : valueElements)
+      reader.readStartSequence();
+      values = new ArrayList<ByteString>();
+      while(reader.hasNextElement())
       {
-        values.add(e.decodeAsOctetString());
+        values.add(reader.readOctetString());
       }
+      reader.readEndSequence();
     }
     catch (Exception e)
     {
@@ -340,6 +296,22 @@
       throw new LDAPException(PROTOCOL_ERROR, message, e);
     }
 
+    try
+    {
+      reader.readEndSequence();
+    }
+    catch (Exception e)
+    {
+      if (debugEnabled())
+      {
+        TRACER.debugCaught(DebugLogLevel.ERROR, e);
+      }
+
+      Message message =
+          ERR_LDAP_ATTRIBUTE_DECODE_SEQUENCE.get(String.valueOf(e));
+      throw new LDAPException(PROTOCOL_ERROR, message, e);
+    }
+
     return new LDAPAttribute(attributeType, values);
   }
 
diff --git a/opends/src/server/org/opends/server/types/RawFilter.java b/opends/src/server/org/opends/server/types/RawFilter.java
index 6a4c65b..4ee48b0 100644
--- a/opends/src/server/org/opends/server/types/RawFilter.java
+++ b/opends/src/server/org/opends/server/types/RawFilter.java
@@ -22,7 +22,7 @@
  * CDDL HEADER END
  *
  *
- *      Copyright 2006-2008 Sun Microsystems, Inc.
+ *      Copyright 2006-2009 Sun Microsystems, Inc.
  */
 package org.opends.server.types;
 import org.opends.messages.Message;
@@ -30,12 +30,9 @@
 
 
 import java.util.ArrayList;
+import java.io.IOException;
 
-import org.opends.server.protocols.asn1.ASN1Boolean;
-import org.opends.server.protocols.asn1.ASN1Element;
-import org.opends.server.protocols.asn1.ASN1OctetString;
-import org.opends.server.protocols.asn1.ASN1Sequence;
-import org.opends.server.protocols.asn1.ASN1Set;
+import org.opends.server.protocols.asn1.*;
 import org.opends.server.protocols.ldap.LDAPFilter;
 
 import static org.opends.server.loggers.debug.DebugLogger.*;
@@ -337,18 +334,6 @@
 
 
   /**
-   * Specifies the set of subordinate filter components for AND or OR
-   * searches.  This will be ignored for all other filter types.
-   *
-   * @param  filterComponents  The set of subordinate filter
-   *                           components for AND or OR searches.
-   */
-  public abstract void setFilterComponents(
-                            ArrayList<RawFilter> filterComponents);
-
-
-
-  /**
    * Retrieves the subordinate filter component for NOT searches.
    *
    * @return  The subordinate filter component for NOT searches, or
@@ -359,17 +344,6 @@
 
 
   /**
-   * Specifies the subordinate filter component for NOT searches.
-   * This will be ignored for any other type of search.
-   *
-   * @param  notComponent  The subordinate filter component for NOT
-   *                       searches.
-   */
-  public abstract void setNOTComponent(RawFilter notComponent);
-
-
-
-  /**
    * Retrieves the attribute type for this search filter.  This will
    * not be applicable for AND, OR, or NOT filters.
    *
@@ -381,16 +355,6 @@
 
 
   /**
-   * Specifies the attribute type for this search filter.  This will
-   * be ignored for AND, OR, and NOT searches.
-   *
-   * @param  attributeType  The attribute type for this search filter.
-   */
-  public abstract void setAttributeType(String attributeType);
-
-
-
-  /**
    * Retrieves the assertion value for this search filter.  This will
    * only be applicable for equality, greater or equal, less or equal,
    * approximate, or extensible matching filters.
@@ -403,18 +367,6 @@
 
 
   /**
-   * Specifies the assertion value for this search filter.  This will
-   * be ignored for types of filters that do not have an assertion
-   * value.
-   *
-   * @param  assertionValue  The assertion value for this search
-   *                         filter.
-   */
-  public abstract void setAssertionValue(ByteString assertionValue);
-
-
-
-  /**
    * Retrieves the subInitial component for this substring filter.
    * This is only applicable for substring search filters, but even
    * substring filters might not have a value for this component.
@@ -427,18 +379,6 @@
 
 
   /**
-   * Specifies the subInitial element for this substring filter.
-   * This will be ignored for all other types of filters.
-   *
-   * @param  subInitialElement  The subInitial element for this
-   *                            substring filter.
-   */
-  public abstract void setSubInitialElement(
-                            ByteString subInitialElement);
-
-
-
-  /**
    * Retrieves the set of subAny elements for this substring filter.
    * This is only applicable for substring search filters, and even
    * then may be {@code null} or empty for some substring filters.
@@ -451,18 +391,6 @@
 
 
   /**
-   * Specifies the set of subAny values for this substring filter.
-   * This will be ignored for other filter types.
-   *
-   * @param  subAnyElements  The set of subAny elements for this
-   *                         substring filter.
-   */
-  public abstract void setSubAnyElements(ArrayList<ByteString>
-                                              subAnyElements);
-
-
-
-  /**
    * Retrieves the subFinal element for this substring filter.  This
    * is not applicable for any other filter type, and may not be
    * provided even for some substring filters.
@@ -475,17 +403,6 @@
 
 
   /**
-   * Specifies the subFinal element for this substring filter.  This
-   * will be ignored for all other filter types.
-   *
-   * @param  subFinalElement  The subFinal element for this substring
-   *                          filter.
-   */
-  public abstract void setSubFinalElement(ByteString subFinalElement);
-
-
-
-  /**
    * Retrieves the matching rule ID for this extensible match filter.
    * This is not applicable for any other type of filter and may not
    * be included in some extensible matching filters.
@@ -498,17 +415,6 @@
 
 
   /**
-   * Specifies the matching rule ID for this extensible match filter.
-   * It will be ignored for all other filter types.
-   *
-   * @param  matchingRuleID  The matching rule ID for this extensible
-   *                         match filter.
-   */
-  public abstract void setMatchingRuleID(String matchingRuleID);
-
-
-
-  /**
    * Retrieves the value of the DN attributes flag for this extensible
    * match filter, which indicates whether to perform matching on the
    * components of the DN.  This does not apply for any other type of
@@ -519,66 +425,50 @@
    */
   public abstract boolean getDNAttributes();
 
-
-
   /**
-   * Specifies the value of the DN attributes flag for this extensible
-   * match filter.  It will be ignored for all other filter types.
+   * Writes this protocol op to an ASN.1 output stream.
    *
-   * @param  dnAttributes  The value of the DN attributes flag for
-   *                       this extensible match filter.
+   * @param stream The ASN.1 output stream to write to.
+   * @throws IOException If a problem occurs while writing to the
+   *                     stream.
    */
-  public abstract void setDNAttributes(boolean dnAttributes);
-
-
-
-  /**
-   * Encodes this search filter to an ASN.1 element.
-   *
-   * @return  The ASN.1 element containing the encoded search filter.
-   */
-  public final ASN1Element encode()
+  public void write(ASN1Writer stream) throws IOException
   {
-    FilterType filterType = getFilterType();
+      FilterType filterType = getFilterType();
     switch (filterType)
     {
       case AND:
       case OR:
-        ArrayList<RawFilter> filterComponents = getFilterComponents();
-        ArrayList<ASN1Element> elements =
-             new ArrayList<ASN1Element>(filterComponents.size());
-        for (RawFilter f : filterComponents)
+        stream.writeStartSequence(filterType.getBERType());
+        for(RawFilter f : getFilterComponents())
         {
-          elements.add(f.encode());
+          f.write(stream);
         }
-        return new ASN1Set(filterType.getBERType(), elements);
+        stream.writeEndSequence();
+        return;
       case NOT:
-        return new ASN1Element(filterType.getBERType(),
-                               getNOTComponent().encode().encode());
+        stream.writeStartSequence(filterType.getBERType());
+        getNOTComponent().write(stream);
+        stream.writeEndSequence();
+        return;
       case EQUALITY:
       case GREATER_OR_EQUAL:
       case LESS_OR_EQUAL:
       case APPROXIMATE_MATCH:
-        String attributeType = getAttributeType();
-        ByteString assertionValue = getAssertionValue();
-        elements = new ArrayList<ASN1Element>(2);
-        elements.add(new ASN1OctetString(attributeType));
-        elements.add(assertionValue.toASN1OctetString());
-        return new ASN1Sequence(filterType.getBERType(), elements);
+        stream.writeStartSequence(filterType.getBERType());
+        stream.writeOctetString(getAttributeType());
+        stream.writeOctetString(getAssertionValue());
+        stream.writeEndSequence();
+        return;
       case SUBSTRING:
-        attributeType = getAttributeType();
-        elements = new ArrayList<ASN1Element>(2);
-        elements.add(new ASN1OctetString(attributeType));
+        stream.writeStartSequence(filterType.getBERType());
+        stream.writeOctetString(getAttributeType());
 
+        stream.writeStartSequence();
         ByteString subInitialElement = getSubInitialElement();
-        ArrayList<ASN1Element> subElements =
-             new ArrayList<ASN1Element>();
         if (subInitialElement != null)
         {
-          ASN1OctetString subInitialOS =
-               subInitialElement.toASN1OctetString();
-          subInitialOS.setType(TYPE_SUBINITIAL);
-          subElements.add(subInitialOS);
+          stream.writeOctetString(TYPE_SUBINITIAL, subInitialElement);
         }
 
         ArrayList<ByteString> subAnyElements = getSubAnyElements();
@@ -586,125 +476,121 @@
         {
           for (ByteString s : subAnyElements)
           {
-            ASN1OctetString os = s.toASN1OctetString();
-            os.setType(TYPE_SUBANY);
-            subElements.add(os);
+            stream.writeOctetString(TYPE_SUBANY, s);
           }
         }
 
         ByteString subFinalElement = getSubFinalElement();
         if (subFinalElement != null)
         {
-          ASN1OctetString subFinalOS =
-               subFinalElement.toASN1OctetString();
-          subFinalOS.setType(TYPE_SUBFINAL);
-          subElements.add(subFinalOS);
+          stream.writeOctetString(TYPE_SUBFINAL, subFinalElement);
         }
+        stream.writeEndSequence();
 
-        elements.add(new ASN1Sequence(subElements));
-        return new ASN1Sequence(filterType.getBERType(), elements);
+        stream.writeEndSequence();
+        return;
       case PRESENT:
-        return new ASN1OctetString(filterType.getBERType(),
-                                   getAttributeType());
+        stream.writeOctetString(filterType.getBERType(),
+            getAttributeType());
+        return;
       case EXTENSIBLE_MATCH:
-        elements = new ArrayList<ASN1Element>(4);
+        stream.writeStartSequence(filterType.getBERType());
 
         String matchingRuleID = getMatchingRuleID();
         if (matchingRuleID != null)
         {
-          elements.add(new ASN1OctetString(TYPE_MATCHING_RULE_ID,
-                                           matchingRuleID));
+          stream.writeOctetString(TYPE_MATCHING_RULE_ID,
+              matchingRuleID);
         }
 
-        attributeType = getAttributeType();
+        String attributeType = getAttributeType();
         if (attributeType != null)
         {
-          elements.add(new ASN1OctetString(TYPE_MATCHING_RULE_TYPE,
-                                           attributeType));
+          stream.writeOctetString(TYPE_MATCHING_RULE_TYPE,
+              attributeType);
         }
 
-        ASN1OctetString assertionValueOS =
-             getAssertionValue().toASN1OctetString();
-        assertionValueOS.setType(TYPE_MATCHING_RULE_VALUE);
-        elements.add(assertionValueOS);
+        stream.writeOctetString(TYPE_MATCHING_RULE_VALUE,
+            getAssertionValue());
 
         if (getDNAttributes())
         {
-          elements.add(new ASN1Boolean(
-               TYPE_MATCHING_RULE_DN_ATTRIBUTES, true));
+          stream.writeBoolean(TYPE_MATCHING_RULE_DN_ATTRIBUTES, true);
         }
 
-        return new ASN1Sequence(filterType.getBERType(), elements);
+        stream.writeEndSequence();
+        return;
       default:
         if (debugEnabled())
         {
           TRACER.debugError("Invalid search filter type: %s",
                             filterType);
         }
-        return null;
     }
   }
 
-
-
   /**
-   * Decodes the provided ASN.1 element as a raw search filter.
+   * Decodes the elements from the provided ASN.1 reader as a
+   * raw search filter.
    *
-   * @param  element  The ASN.1 element to decode.
+   * @param  reader The ASN.1 reader.
    *
    * @return  The decoded search filter.
    *
    * @throws  LDAPException  If the provided ASN.1 element cannot be
    *                         decoded as a raw search filter.
    */
-  public static LDAPFilter decode(ASN1Element element)
+  public static LDAPFilter decode(ASN1Reader reader)
          throws LDAPException
   {
-    if (element == null)
+    byte type;
+    try
+    {
+      type = reader.peekType();
+    }
+    catch(Exception e)
     {
       Message message = ERR_LDAP_FILTER_DECODE_NULL.get();
       throw new LDAPException(PROTOCOL_ERROR, message);
     }
 
-    switch (element.getType())
+    switch (type)
     {
       case TYPE_FILTER_AND:
       case TYPE_FILTER_OR:
-        return decodeCompoundFilter(element);
+        return decodeCompoundFilter(reader);
 
       case TYPE_FILTER_NOT:
-        return decodeNotFilter(element);
+        return decodeNotFilter(reader);
 
       case TYPE_FILTER_EQUALITY:
       case TYPE_FILTER_GREATER_OR_EQUAL:
       case TYPE_FILTER_LESS_OR_EQUAL:
       case TYPE_FILTER_APPROXIMATE:
-        return decodeTypeAndValueFilter(element);
+        return decodeAVAFilter(reader);
 
       case TYPE_FILTER_SUBSTRING:
-        return decodeSubstringFilter(element);
+        return decodeSubstringFilter(reader);
 
       case TYPE_FILTER_PRESENCE:
-        return decodePresenceFilter(element);
+        return decodePresenceFilter(reader);
 
       case TYPE_FILTER_EXTENSIBLE_MATCH:
-        return decodeExtensibleMatchFilter(element);
+        return decodeExtensibleMatchFilter(reader);
 
       default:
-        Message message = ERR_LDAP_FILTER_DECODE_INVALID_TYPE.get(
-            element.getType());
+        Message message =
+            ERR_LDAP_FILTER_DECODE_INVALID_TYPE.get(type);
         throw new LDAPException(PROTOCOL_ERROR, message);
     }
   }
 
-
-
   /**
-   * Decodes the provided ASN.1 element as a compound filter (i.e.,
-   * one that holds a set of subordinate filter components, like AND
-   * or OR filters).
+   * Decodes the elements from the provided ASN.1 reader as a compound
+   * filter (i.e. one that holds a set of subordinate filter
+   * components, like AND  or OR filters).
    *
-   * @param  element  the ASN.1 element to decode.
+   * @param  reader The ASN.1 reader.
    *
    * @return  The decoded LDAP search filter.
    *
@@ -712,11 +598,22 @@
    *                         decode the provided ASN.1 element as a
    *                         raw search filter.
    */
-  private static LDAPFilter decodeCompoundFilter(ASN1Element element)
-          throws LDAPException
+  private static LDAPFilter decodeCompoundFilter(ASN1Reader reader)
+      throws LDAPException
   {
+    byte type;
+    try
+    {
+      type = reader.peekType();
+    }
+    catch(Exception e)
+    {
+      Message message = ERR_LDAP_FILTER_DECODE_NULL.get();
+      throw new LDAPException(PROTOCOL_ERROR, message);
+    }
+
     FilterType filterType;
-    switch (element.getType())
+    switch (type)
     {
       case TYPE_FILTER_AND:
         filterType = FilterType.AND;
@@ -729,38 +626,21 @@
         if (debugEnabled())
         {
           TRACER.debugError("Invalid filter type %x for a " +
-              "compound filter", element.getType());
+              "compound filter", type);
         }
         filterType = null;
     }
 
-
-    ArrayList<ASN1Element> elements;
-    try
-    {
-      elements = element.decodeAsSet().elements();
-    }
-    catch (Exception e)
-    {
-      if (debugEnabled())
-      {
-        TRACER.debugCaught(DebugLogLevel.ERROR, e);
-      }
-
-      Message message =
-          ERR_LDAP_FILTER_DECODE_COMPOUND_SET.get(String.valueOf(e));
-      throw new LDAPException(PROTOCOL_ERROR, message, e);
-    }
-
-
     ArrayList<RawFilter> filterComponents =
-         new ArrayList<RawFilter>(elements.size());
+        new ArrayList<RawFilter>();
     try
     {
-      for (ASN1Element e : elements)
+      reader.readStartSequence();
+      while(reader.hasNextElement())
       {
-        filterComponents.add(LDAPFilter.decode(e));
+        filterComponents.add(LDAPFilter.decode(reader));
       }
+      reader.readEndSequence();
     }
     catch (LDAPException le)
     {
@@ -778,17 +658,15 @@
       throw new LDAPException(PROTOCOL_ERROR, message, e);
     }
 
-
     return new LDAPFilter(filterType, filterComponents, null, null,
-                          null, null, null, null, null, false);
+        null, null, null, null, null, false);
   }
 
-
-
   /**
-   * Decodes the provided ASN.1 element as a NOT filter.
+   * Decodes the elements from the provided ASN.1 reader as a NOT
+   * filter.
    *
-   * @param  element  the ASN.1 element to decode.
+   * @param  reader The ASN.1 reader.
    *
    * @return  The decoded LDAP search filter.
    *
@@ -796,31 +674,15 @@
    *                         decode the provided ASN.1 element as a
    *                         raw search filter.
    */
-  private static LDAPFilter decodeNotFilter(ASN1Element element)
+  private static LDAPFilter decodeNotFilter(ASN1Reader reader)
           throws LDAPException
   {
-    ASN1Element notFilterElement;
-    try
-    {
-      notFilterElement = ASN1Element.decode(element.value());
-    }
-    catch (Exception e)
-    {
-      if (debugEnabled())
-      {
-        TRACER.debugCaught(DebugLogLevel.ERROR, e);
-      }
-
-      Message message =
-          ERR_LDAP_FILTER_DECODE_NOT_ELEMENT.get(String.valueOf(e));
-      throw new LDAPException(PROTOCOL_ERROR, message, e);
-    }
-
-
     RawFilter notComponent;
     try
     {
-      notComponent = decode(notFilterElement);
+      reader.readStartSequence();
+      notComponent = decode(reader);
+      reader.readEndSequence();
     }
     catch (LDAPException le)
     {
@@ -843,14 +705,13 @@
                           null, null, null, null, null, false);
   }
 
-
-
   /**
-   * Decodes the provided ASN.1 element as a filter containing an
-   * attribute type and an assertion value.  This includes equality,
-   * greater or equal, less or equal, and approximate search filters.
+   * Decodes the elements from the provided ASN.1 read as as a filter
+   * containing an attribute type and an assertion value.  This
+   * includes equality, greater or equal, less or equal, and
+   * approximate search filters.
    *
-   * @param  element  the ASN.1 element to decode.
+   * @param  reader The ASN.1 reader.
    *
    * @return  The decoded LDAP search filter.
    *
@@ -858,12 +719,22 @@
    *                         decode the provided ASN.1 element as a
    *                         raw search filter.
    */
-  private static LDAPFilter decodeTypeAndValueFilter(
-                                 ASN1Element element)
+  private static LDAPFilter decodeAVAFilter(ASN1Reader reader)
           throws LDAPException
   {
+    byte type;
+    try
+    {
+      type = reader.peekType();
+    }
+    catch(Exception e)
+    {
+      Message message = ERR_LDAP_FILTER_DECODE_NULL.get();
+      throw new LDAPException(PROTOCOL_ERROR, message);
+    }
+
     FilterType filterType;
-    switch (element.getType())
+    switch (type)
     {
       case TYPE_FILTER_EQUALITY:
         filterType = FilterType.EQUALITY;
@@ -882,16 +753,14 @@
         if (debugEnabled())
         {
           TRACER.debugError("Invalid filter type %x for a " +
-              "type-and-value filter", element.getType());
+              "type-and-value filter", type);
         }
         filterType = null;
     }
 
-
-    ArrayList<ASN1Element> elements;
     try
     {
-      elements = element.decodeAsSequence().elements();
+      reader.readStartSequence();
     }
     catch (Exception e)
     {
@@ -905,21 +774,10 @@
       throw new LDAPException(PROTOCOL_ERROR, message, e);
     }
 
-
-    if (elements.size() != 2)
-    {
-      Message message =
-          ERR_LDAP_FILTER_DECODE_TV_INVALID_ELEMENT_COUNT.
-            get(elements.size());
-      throw new LDAPException(PROTOCOL_ERROR, message);
-    }
-
-
     String attributeType;
     try
     {
-      attributeType =
-           elements.get(0).decodeAsOctetString().stringValue();
+      attributeType = reader.readOctetStringAsString();
     }
     catch (Exception e)
     {
@@ -937,7 +795,7 @@
     ByteString assertionValue;
     try
     {
-      assertionValue = elements.get(1).decodeAsOctetString();
+      assertionValue = reader.readOctetString();
     }
     catch (Exception e)
     {
@@ -951,18 +809,33 @@
       throw new LDAPException(PROTOCOL_ERROR, message, e);
     }
 
+    try
+    {
+      reader.readEndSequence();
+    }
+    catch (Exception e)
+    {
+      if (debugEnabled())
+      {
+        TRACER.debugCaught(DebugLogLevel.ERROR, e);
+      }
+
+      Message message =
+          ERR_LDAP_FILTER_DECODE_TV_SEQUENCE.get(String.valueOf(e));
+      throw new LDAPException(PROTOCOL_ERROR, message, e);
+    }
+
 
     return new LDAPFilter(filterType, null, null, attributeType,
                           assertionValue, null, null, null, null,
                           false);
   }
 
-
-
   /**
-   * Decodes the provided ASN.1 element as a substring filter.
+   * Decodes the elements from the provided ASN.1 reader as a
+   * substring filter.
    *
-   * @param  element  the ASN.1 element to decode.
+   * @param  reader The ASN.1 reader.
    *
    * @return  The decoded LDAP search filter.
    *
@@ -970,13 +843,12 @@
    *                         decode the provided ASN.1 element as a
    *                         raw search filter.
    */
-  private static LDAPFilter decodeSubstringFilter(ASN1Element element)
+  private static LDAPFilter decodeSubstringFilter(ASN1Reader reader)
           throws LDAPException
   {
-    ArrayList<ASN1Element> elements;
     try
     {
-      elements = element.decodeAsSequence().elements();
+      reader.readStartSequence();
     }
     catch (Exception e)
     {
@@ -991,20 +863,10 @@
     }
 
 
-    if (elements.size() != 2)
-    {
-      Message message =
-          ERR_LDAP_FILTER_DECODE_SUBSTRING_INVALID_ELEMENT_COUNT.
-            get(elements.size());
-      throw new LDAPException(PROTOCOL_ERROR, message);
-    }
-
-
     String attributeType;
     try
     {
-      attributeType =
-           elements.get(0).decodeAsOctetString().stringValue();
+      attributeType = reader.readOctetStringAsString();
     }
     catch (Exception e)
     {
@@ -1018,11 +880,9 @@
       throw new LDAPException(PROTOCOL_ERROR, message, e);
     }
 
-
-    ArrayList<ASN1Element> subElements;
     try
     {
-      subElements = elements.get(1).decodeAsSequence().elements();
+      reader.readStartSequence();
     }
     catch (Exception e)
     {
@@ -1037,7 +897,12 @@
     }
 
 
-    if (subElements.isEmpty())
+    try
+    {
+      // Make sure we have at least 1 substring
+      reader.peekType();
+    }
+    catch (Exception e)
     {
       Message message =
           ERR_LDAP_FILTER_DECODE_SUBSTRING_NO_SUBELEMENTS.get();
@@ -1050,15 +915,15 @@
     ArrayList<ByteString> subAnyElements = null;
     try
     {
-      for (ASN1Element e : subElements)
+      while(reader.hasNextElement())
       {
-        switch (e.getType())
+        switch (reader.peekType())
         {
           case TYPE_SUBINITIAL:
-            subInitialElement = e.decodeAsOctetString();
+            subInitialElement = reader.readOctetString();
             break;
           case TYPE_SUBFINAL:
-            subFinalElement = e.decodeAsOctetString();
+            subFinalElement = reader.readOctetString();
             break;
           case TYPE_SUBANY:
             if (subAnyElements == null)
@@ -1066,12 +931,12 @@
               subAnyElements = new ArrayList<ByteString>();
             }
 
-            subAnyElements.add(e.decodeAsOctetString());
+            subAnyElements.add(reader.readOctetString());
             break;
           default:
             Message message =
                 ERR_LDAP_FILTER_DECODE_SUBSTRING_INVALID_SUBTYPE.
-                  get(e.getType());
+                  get(reader.peekType());
             throw new LDAPException(PROTOCOL_ERROR, message);
         }
       }
@@ -1092,6 +957,38 @@
       throw new LDAPException(PROTOCOL_ERROR, message, e);
     }
 
+    try
+    {
+      reader.readEndSequence();
+    }
+    catch (Exception e)
+    {
+      if (debugEnabled())
+      {
+        TRACER.debugCaught(DebugLogLevel.ERROR, e);
+      }
+
+      Message message = ERR_LDAP_FILTER_DECODE_SUBSTRING_ELEMENTS.get(
+          String.valueOf(e));
+      throw new LDAPException(PROTOCOL_ERROR, message, e);
+    }
+
+    try
+    {
+      reader.readEndSequence();
+    }
+    catch (Exception e)
+    {
+      if (debugEnabled())
+      {
+        TRACER.debugCaught(DebugLogLevel.ERROR, e);
+      }
+
+      Message message = ERR_LDAP_FILTER_DECODE_SUBSTRING_SEQUENCE.get(
+          String.valueOf(e));
+      throw new LDAPException(PROTOCOL_ERROR, message, e);
+    }
+
 
     return new LDAPFilter(FilterType.SUBSTRING, null, null,
                           attributeType, null, subInitialElement,
@@ -1099,12 +996,11 @@
                           false);
   }
 
-
-
   /**
-   * Decodes the provided ASN.1 element as a presence filter.
+   * Decodes the elements from the provided ASN.1 reader as a
+   * presence filter.
    *
-   * @param  element  the ASN.1 element to decode.
+   * @param  reader The ASN.1 reader.
    *
    * @return  The decoded LDAP search filter.
    *
@@ -1112,13 +1008,13 @@
    *                         decode the provided ASN.1 element as a
    *                         raw search filter.
    */
-  private static LDAPFilter decodePresenceFilter(ASN1Element element)
+  private static LDAPFilter decodePresenceFilter(ASN1Reader reader)
           throws LDAPException
   {
     String attributeType;
     try
     {
-      attributeType = element.decodeAsOctetString().stringValue();
+      attributeType = reader.readOctetStringAsString();
     }
     catch (Exception e)
     {
@@ -1138,12 +1034,11 @@
                           false);
   }
 
-
-
   /**
-   * Decodes the provided ASN.1 element as an extensible match filter.
+   * Decodes the elements from the provided ASN.1 reader as an
+   * extensible match filter.
    *
-   * @param  element  the ASN.1 element to decode.
+   * @param  reader The ASN.1 reader.
    *
    * @return  The decoded LDAP search filter.
    *
@@ -1151,14 +1046,12 @@
    *                         decode the provided ASN.1 element as a
    *                         raw search filter.
    */
-  private static LDAPFilter decodeExtensibleMatchFilter(ASN1Element
-                                                             element)
-          throws LDAPException
+  private static LDAPFilter decodeExtensibleMatchFilter(
+      ASN1Reader reader) throws LDAPException
   {
-    ArrayList<ASN1Element> elements;
     try
     {
-      elements = element.decodeAsSequence().elements();
+      reader.readStartSequence();
     }
     catch (Exception e)
     {
@@ -1179,26 +1072,26 @@
     String     matchingRuleID = null;
     try
     {
-      for (ASN1Element e : elements)
+      while(reader.hasNextElement())
       {
-        switch (e.getType())
+        switch (reader.peekType())
         {
           case TYPE_MATCHING_RULE_ID:
-            matchingRuleID = e.decodeAsOctetString().stringValue();
+            matchingRuleID = reader.readOctetStringAsString();
             break;
           case TYPE_MATCHING_RULE_TYPE:
-            attributeType = e.decodeAsOctetString().stringValue();
+            attributeType = reader.readOctetStringAsString();
             break;
           case TYPE_MATCHING_RULE_VALUE:
-            assertionValue = e.decodeAsOctetString();
+            assertionValue = reader.readOctetString();
             break;
           case TYPE_MATCHING_RULE_DN_ATTRIBUTES:
-            dnAttributes = e.decodeAsBoolean().booleanValue();
+            dnAttributes = reader.readBoolean();
             break;
           default:
             Message message =
                 ERR_LDAP_FILTER_DECODE_EXTENSIBLE_INVALID_TYPE.
-                  get(e.getType());
+                  get(reader.peekType());
             throw new LDAPException(PROTOCOL_ERROR, message);
         }
       }
@@ -1219,6 +1112,22 @@
       throw new LDAPException(PROTOCOL_ERROR, message, e);
     }
 
+    try
+    {
+      reader.readEndSequence();
+    }
+    catch (Exception e)
+    {
+      if (debugEnabled())
+      {
+        TRACER.debugCaught(DebugLogLevel.ERROR, e);
+      }
+
+      Message message = ERR_LDAP_FILTER_DECODE_EXTENSIBLE_SEQUENCE.
+          get(String.valueOf(e));
+      throw new LDAPException(PROTOCOL_ERROR, message, e);
+    }
+
 
     return new LDAPFilter(FilterType.EXTENSIBLE_MATCH, null, null,
                           attributeType, assertionValue, null, null,
@@ -1290,10 +1199,10 @@
     // it to see if there are any unsafe characters.  If there are,
     // then escape them and replace them with a two-digit hex
     // equivalent.
-    byte[] valueBytes = value.value();
-    buffer.ensureCapacity(buffer.length() + valueBytes.length);
-    for (byte b : valueBytes)
+    buffer.ensureCapacity(buffer.length() + value.length());
+    for (int i = 0; i < value.length(); i++)
     {
+      byte b = value.byteAt(i);
       if (((b & 0x7F) != b) ||  // Not 7-bit clean
           (b <= 0x1F) ||        // Below the printable character range
           (b == 0x28) ||        // Open parenthesis
diff --git a/opends/src/server/org/opends/server/types/RawModification.java b/opends/src/server/org/opends/server/types/RawModification.java
index eb7723e..1065336 100644
--- a/opends/src/server/org/opends/server/types/RawModification.java
+++ b/opends/src/server/org/opends/server/types/RawModification.java
@@ -22,27 +22,23 @@
  * CDDL HEADER END
  *
  *
- *      Copyright 2006-2008 Sun Microsystems, Inc.
+ *      Copyright 2006-2009 Sun Microsystems, Inc.
  */
 package org.opends.server.types;
-import org.opends.messages.Message;
 
-
-
-import java.util.ArrayList;
-import java.util.List;
-
-import org.opends.server.protocols.asn1.ASN1Element;
-import org.opends.server.protocols.asn1.ASN1Enumerated;
-import org.opends.server.protocols.asn1.ASN1Sequence;
-import org.opends.server.protocols.ldap.LDAPModification;
-
-import static org.opends.server.loggers.debug.DebugLogger.*;
-import org.opends.server.loggers.debug.DebugTracer;
 import static org.opends.messages.ProtocolMessages.*;
+import static org.opends.server.loggers.debug.DebugLogger.*;
 import static org.opends.server.protocols.ldap.LDAPConstants.*;
 import static org.opends.server.protocols.ldap.LDAPResultCode.*;
-import static org.opends.server.util.ServerConstants.*;
+
+import java.io.IOException;
+import java.util.ArrayList;
+
+import org.opends.messages.Message;
+import org.opends.server.loggers.debug.DebugTracer;
+import org.opends.server.protocols.asn1.ASN1Reader;
+import org.opends.server.protocols.asn1.ASN1Writer;
+import org.opends.server.protocols.ldap.LDAPModification;
 
 
 
@@ -172,7 +168,7 @@
   public static RawModification
                      create(ModificationType modificationType,
                             String attributeType,
-                            List<ByteString> attributeValues)
+                            ArrayList<ByteString> attributeValues)
   {
     RawAttribute rawAttribute =
          RawAttribute.create(attributeType, attributeValues);
@@ -221,26 +217,26 @@
 
 
   /**
-   * Encodes this modification to an ASN.1 element.
+   * Writes this modification to an ASN.1 stream.
    *
-   * @return  The ASN.1 element containing the encoded modification.
+   * @param stream The ASN.1 output stream to write to.
+   * @throws IOException If a problem occurs while writing to the
+   *                     stream.
    */
-  public final ASN1Element encode()
+  public void write(ASN1Writer stream) throws IOException
   {
-    ArrayList<ASN1Element> elements = new ArrayList<ASN1Element>(2);
-    elements.add(new ASN1Enumerated(
-                          getModificationType().intValue()));
-    elements.add(getAttribute().encode());
-
-    return new ASN1Sequence(elements);
+    stream.writeStartSequence();
+    stream.writeEnumerated(getModificationType().intValue());
+    getAttribute().write(stream);
+    stream.writeEndSequence();
   }
 
 
-
   /**
-   * Decodes the provided ASN.1 element as an LDAP modification.
+   * Decodes the elements from the provided ASN.1 reader as an
+   * LDAP modification.
    *
-   * @param  element  The ASN.1 element to decode.
+   * @param  reader The ASN.1 reader.
    *
    * @return  The decoded LDAP modification.
    *
@@ -248,13 +244,12 @@
    *                         decode the provided ASN.1 element as a
    *                         raw modification.
    */
-  public static LDAPModification decode(ASN1Element element)
+  public static LDAPModification decode(ASN1Reader reader)
          throws LDAPException
   {
-    ArrayList<ASN1Element> elements;
     try
     {
-      elements = element.decodeAsSequence().elements();
+      reader.readStartSequence();
     }
     catch (Exception e)
     {
@@ -269,20 +264,11 @@
     }
 
 
-    int numElements = elements.size();
-    if (numElements != 2)
-    {
-      Message message =
-          ERR_LDAP_MODIFICATION_DECODE_INVALID_ELEMENT_COUNT.
-            get(numElements);
-      throw new LDAPException(PROTOCOL_ERROR, message);
-    }
-
-
     ModificationType modificationType;
     try
     {
-      switch (elements.get(0).decodeAsEnumerated().intValue())
+      int type = (int)reader.readInteger();
+      switch (type)
       {
         case MOD_TYPE_ADD:
           modificationType = ModificationType.ADD;
@@ -297,11 +283,9 @@
           modificationType = ModificationType.INCREMENT;
           break;
         default:
-          int intValue =
-                   elements.get(0).decodeAsEnumerated().intValue();
           Message message =
               ERR_LDAP_MODIFICATION_DECODE_INVALID_MOD_TYPE.
-                get(intValue);
+                get(type);
           throw new LDAPException(PROTOCOL_ERROR, message);
       }
     }
@@ -325,7 +309,7 @@
     RawAttribute attribute;
     try
     {
-      attribute = RawAttribute.decode(elements.get(1));
+      attribute = RawAttribute.decode(reader);
     }
     catch (Exception e)
     {
@@ -339,6 +323,22 @@
       throw new LDAPException(PROTOCOL_ERROR, message, e);
     }
 
+    try
+    {
+      reader.readEndSequence();
+    }
+    catch (Exception e)
+    {
+      if (debugEnabled())
+      {
+        TRACER.debugCaught(DebugLogLevel.ERROR, e);
+      }
+
+      Message message = ERR_LDAP_MODIFICATION_DECODE_SEQUENCE.get(
+          String.valueOf(e));
+      throw new LDAPException(PROTOCOL_ERROR, message, e);
+    }
+
 
     return new LDAPModification(modificationType, attribute);
   }
diff --git a/opends/src/server/org/opends/server/types/RecordingInputStream.java b/opends/src/server/org/opends/server/types/RecordingInputStream.java
new file mode 100644
index 0000000..cecad84
--- /dev/null
+++ b/opends/src/server/org/opends/server/types/RecordingInputStream.java
@@ -0,0 +1,180 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License").  You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE
+ * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
+ * add the following below this CDDL 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.server.types;
+
+import java.io.InputStream;
+import java.io.IOException;
+
+/**
+ * A wrapper InputStream that will record all reads from an underlying
+ * InputStream. The recorded bytes will append to any previous
+ * recorded bytes until the clear method is called.
+ */
+public class RecordingInputStream extends InputStream
+{
+  private boolean enableRecording;
+  private InputStream parentStream;
+  private ByteStringBuilder buffer;
+
+  /**
+   * Constructs a new RecordingInputStream that will record all reads
+   * from the given input stream.
+   *
+   * @param parentStream The input stream to record.
+   */
+  public RecordingInputStream(InputStream parentStream)
+  {
+    this.enableRecording = false;
+    this.parentStream = parentStream;
+    this.buffer = new ByteStringBuilder(32);
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  public int read() throws IOException {
+    int readByte = parentStream.read();
+    if(enableRecording)
+    {
+      buffer.append((byte)readByte);
+    }
+    return readByte;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public int read(byte[] bytes) throws IOException {
+    int bytesRead = parentStream.read(bytes);
+    if(enableRecording)
+    {
+      buffer.append(bytes, 0, bytesRead);
+    }
+    return bytesRead;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public int read(byte[] bytes, int i, int i1) throws IOException {
+    int bytesRead = parentStream.read(bytes, i, i1);
+    if(enableRecording)
+    {
+      buffer.append(bytes, i, bytesRead);
+    }
+    return bytesRead;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public long skip(long l) throws IOException {
+    return parentStream.skip(l);
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public int available() throws IOException {
+    return parentStream.available();
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public void close() throws IOException {
+    parentStream.close();
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public void mark(int i) {
+    parentStream.mark(i);
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public void reset() throws IOException {
+    parentStream.reset();
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public boolean markSupported() {
+    return parentStream.markSupported();
+  }
+
+  /**
+   * Retrieve the bytes read from this input stream since the last
+   * clear.
+   *
+   * @return the bytes read from this input stream since the last
+   *         clear.
+   */
+  public ByteString getRecordedBytes() {
+    return buffer.toByteString();
+  }
+
+  /**
+   * Clear the bytes currently recorded by this input stream.
+   */
+  public void clearRecordedBytes() {
+    buffer.clear();
+  }
+
+  /**
+   * Retrieves whether recording is enabled.
+   *
+   * @return whether recording is enabled.
+   */
+  public boolean isRecordingEnabled()
+  {
+    return enableRecording;
+  }
+
+  /**
+   * Set whether if this input stream is recording all reads or not.
+   *
+   * @param enabled <code>true</code> to recording all reads or
+   *                <code>false</code> otherwise.
+   */
+  public void setRecordingEnabled(boolean enabled)
+  {
+    this.enableRecording = enabled;
+  }
+}
diff --git a/opends/src/server/org/opends/server/types/RecordingOutputStream.java b/opends/src/server/org/opends/server/types/RecordingOutputStream.java
new file mode 100644
index 0000000..1fa17d7
--- /dev/null
+++ b/opends/src/server/org/opends/server/types/RecordingOutputStream.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-2009 Sun Microsystems, Inc.
+ */
+package org.opends.server.types;
+
+import java.io.OutputStream;
+import java.io.IOException;
+
+/**
+ * A wrapper OutputStream that will record all writes to an underlying
+ * OutputStream. The recorded bytes will append to any previous
+ * recorded bytes until the clear method is called.
+ */
+public class RecordingOutputStream extends OutputStream
+{
+  private boolean enableRecording;
+  private OutputStream parentStream;
+  private ByteStringBuilder buffer;
+
+  /**
+   * Constructs a new RecordingOutputStream that will all writes to
+   * the given OutputStream.
+   *
+   * @param parentStream The output stream to record.
+   */
+  public RecordingOutputStream(OutputStream parentStream) {
+    this.enableRecording = false;
+    this.parentStream = parentStream;
+    this.buffer = new ByteStringBuilder(32);
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  public void write(int i) throws IOException {
+    if(enableRecording)
+    {
+      buffer.append((byte) i);
+    }
+    parentStream.write(i);
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public void write(byte[] bytes) throws IOException {
+    if(enableRecording)
+    {
+      buffer.append(bytes);
+    }
+    parentStream.write(bytes);
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public void write(byte[] bytes, int i, int i1) throws IOException {
+    if(enableRecording)
+    {
+      buffer.append(bytes, i, i1);
+    }
+    parentStream.write(bytes, i, i1);
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public void flush() throws IOException {
+    parentStream.flush();
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public void close() throws IOException {
+    parentStream.close();
+  }
+
+  /**
+   * Retrieve the bytes read from this output stream since the last
+   * clear.
+   *
+   * @return the bytes read from this output stream since the last
+   *         clear.
+   */
+  public ByteString getRecordedBytes() {
+    return buffer.toByteString();
+  }
+
+  /**
+   * Clear the bytes currently recorded by this output stream.
+   */
+  public void clearRecordedBytes() {
+    buffer.clear();
+  }
+
+  /**
+   * Retrieves whether recording is enabled.
+   *
+   * @return whether recording is enabled.
+   */
+  public boolean isRecordingEnabled()
+  {
+    return enableRecording;
+  }
+
+  /**
+   * Set whether if this output stream is recording all reads or not.
+   *
+   * @param enabled <code>true</code> to recording all reads or
+   *                <code>false</code> otherwise.
+   */
+  public void setRecordingEnabled(boolean enabled)
+  {
+    this.enableRecording = enabled;
+  }
+}
diff --git a/opends/src/server/org/opends/server/types/Schema.java b/opends/src/server/org/opends/server/types/Schema.java
index 52216f3..a287491 100644
--- a/opends/src/server/org/opends/server/types/Schema.java
+++ b/opends/src/server/org/opends/server/types/Schema.java
@@ -54,7 +54,6 @@
 import org.opends.server.core.DirectoryServer;
 import org.opends.server.core.SchemaConfigManager;
 import org.opends.server.loggers.debug.DebugTracer;
-import org.opends.server.protocols.asn1.ASN1OctetString;
 import org.opends.server.schema.CaseIgnoreEqualityMatchingRule;
 
 import static org.opends.messages.BackendMessages.*;
@@ -415,10 +414,11 @@
       // a very expensive matching rule (OID first component match)
       // that would kill performance.
       String valueString = attributeType.getDefinition();
-      ASN1OctetString rawValue = new ASN1OctetString(valueString);
-      ByteString normValue = normalizationMatchingRule.normalizeValue(
-                                  new ASN1OctetString(valueString));
-      attributeTypeSet.add(new AttributeValue(rawValue, normValue));
+      ByteString rawValue = ByteString.valueOf(valueString);
+      ByteString normValue =
+          normalizationMatchingRule.normalizeValue(rawValue);
+      attributeTypeSet.add(AttributeValues.create(rawValue,
+          normValue));
     }
   }
 
@@ -456,20 +456,19 @@
       try
       {
         String valueString = attributeType.getDefinition();
-        ASN1OctetString rawValue = new ASN1OctetString(valueString);
+        ByteString rawValue = ByteString.valueOf(valueString);
         ByteString normValue =
-             normalizationMatchingRule.normalizeValue(
-                  new ASN1OctetString(valueString));
-        attributeTypeSet.remove(new AttributeValue(rawValue,
+             normalizationMatchingRule.normalizeValue(rawValue);
+        attributeTypeSet.remove(AttributeValues.create(rawValue,
                                                    normValue));
       }
       catch (Exception e)
       {
         String valueString = attributeType.getDefinition();
-        ASN1OctetString rawValue = new ASN1OctetString(valueString);
-        ASN1OctetString normValue =
-             new ASN1OctetString(toLowerCase(valueString));
-        attributeTypeSet.remove(new AttributeValue(rawValue,
+        ByteString rawValue = ByteString.valueOf(valueString);
+        ByteString normValue =
+            ByteString.valueOf(toLowerCase(valueString));
+        attributeTypeSet.remove(AttributeValues.create(rawValue,
                                                    normValue));
       }
     }
@@ -696,10 +695,10 @@
       // a very expensive matching rule (OID first component match)
       // that would kill performance.
       String valueString = objectClass.getDefinition();
-      ASN1OctetString rawValue = new ASN1OctetString(valueString);
-      ByteString normValue = normalizationMatchingRule.normalizeValue(
-                                  new ASN1OctetString(valueString));
-      objectClassSet.add(new AttributeValue(rawValue, normValue));
+      ByteString rawValue = ByteString.valueOf(valueString);
+      ByteString normValue =
+          normalizationMatchingRule.normalizeValue(rawValue);
+      objectClassSet.add(AttributeValues.create(rawValue, normValue));
     }
   }
 
@@ -731,20 +730,19 @@
       try
       {
         String valueString = objectClass.getDefinition();
-        ASN1OctetString rawValue = new ASN1OctetString(valueString);
+        ByteString rawValue = ByteString.valueOf(valueString);
         ByteString normValue =
-             normalizationMatchingRule.normalizeValue(
-                  new ASN1OctetString(valueString));
-        objectClassSet.remove(new AttributeValue(rawValue,
+             normalizationMatchingRule.normalizeValue(rawValue);
+        objectClassSet.remove(AttributeValues.create(rawValue,
                                                  normValue));
       }
       catch (Exception e)
       {
         String valueString = objectClass.getDefinition();
-        ASN1OctetString rawValue = new ASN1OctetString(valueString);
-        ASN1OctetString normValue =
-             new ASN1OctetString(toLowerCase(valueString));
-        objectClassSet.remove(new AttributeValue(rawValue,
+        ByteString rawValue = ByteString.valueOf(valueString);
+        ByteString normValue =
+            ByteString.valueOf(toLowerCase(valueString));
+        objectClassSet.remove(AttributeValues.create(rawValue,
                                                  normValue));
       }
     }
@@ -857,10 +855,10 @@
       // a very expensive matching rule (OID first component match)
       // that would kill performance.
       String valueString = syntax.toString();
-      ASN1OctetString rawValue = new ASN1OctetString(valueString);
-      ByteString normValue = normalizationMatchingRule.normalizeValue(
-                                  new ASN1OctetString(valueString));
-      syntaxSet.add(new AttributeValue(rawValue, normValue));
+      ByteString rawValue = ByteString.valueOf(valueString);
+      ByteString normValue =
+          normalizationMatchingRule.normalizeValue(rawValue);
+      syntaxSet.add(AttributeValues.create(rawValue, normValue));
     }
   }
 
@@ -886,19 +884,18 @@
       try
       {
         String valueString = syntax.toString();
-        ASN1OctetString rawValue = new ASN1OctetString(valueString);
+        ByteString rawValue = ByteString.valueOf(valueString);
         ByteString normValue =
-             normalizationMatchingRule.normalizeValue(
-                  new ASN1OctetString(valueString));
-        syntaxSet.remove(new AttributeValue(rawValue, normValue));
+             normalizationMatchingRule.normalizeValue(rawValue);
+        syntaxSet.remove(AttributeValues.create(rawValue, normValue));
       }
       catch (Exception e)
       {
         String valueString = syntax.toString();
-        ASN1OctetString rawValue = new ASN1OctetString(valueString);
-        ASN1OctetString normValue =
-             new ASN1OctetString(toLowerCase(valueString));
-        syntaxSet.remove(new AttributeValue(rawValue, normValue));
+        ByteString rawValue = ByteString.valueOf(valueString);
+        ByteString normValue =
+            ByteString.valueOf(toLowerCase(valueString));
+        syntaxSet.remove(AttributeValues.create(rawValue, normValue));
       }
     }
   }
@@ -1068,11 +1065,11 @@
         // use a very expensive matching rule (OID first component
         // match) that would kill performance.
         String valueString = matchingRule.toString();
-        ASN1OctetString rawValue  = new ASN1OctetString(valueString);
+        ByteString rawValue = ByteString.valueOf(valueString);
         ByteString normValue =
-             normalizationMatchingRule.normalizeValue(
-                  new ASN1OctetString(valueString));
-        matchingRuleSet.add(new AttributeValue(rawValue, normValue));
+             normalizationMatchingRule.normalizeValue(rawValue);
+        matchingRuleSet.add(
+            AttributeValues.create(rawValue, normValue));
       }
     }
   }
@@ -1130,20 +1127,19 @@
         try
         {
           String valueString = matchingRule.toString();
-          ASN1OctetString rawValue = new ASN1OctetString(valueString);
+          ByteString rawValue = ByteString.valueOf(valueString);
           ByteString normValue =
-               normalizationMatchingRule.normalizeValue(
-                    new ASN1OctetString(valueString));
-          matchingRuleSet.remove(new AttributeValue(rawValue,
-                                                    normValue));
+              normalizationMatchingRule.normalizeValue(rawValue);
+          matchingRuleSet.remove(AttributeValues.create(rawValue,
+              normValue));
         }
         catch (Exception e)
         {
           String valueString = matchingRule.toString();
-          ASN1OctetString rawValue = new ASN1OctetString(valueString);
-          ASN1OctetString normValue =
-               new ASN1OctetString(toLowerCase(valueString));
-          matchingRuleSet.remove(new AttributeValue(rawValue,
+          ByteString rawValue = ByteString.valueOf(valueString);
+          ByteString normValue =
+              ByteString.valueOf(toLowerCase(valueString));
+          matchingRuleSet.remove(AttributeValues.create(rawValue,
                                                     normValue));
         }
       }
@@ -1264,10 +1260,11 @@
       // a very expensive matching rule (OID first component match)
       // that would kill performance.
       String valueString = matchingRule.toString();
-      ASN1OctetString rawValue  = new ASN1OctetString(valueString);
-      ByteString normValue = normalizationMatchingRule.normalizeValue(
-                                  new ASN1OctetString(valueString));
-      matchingRuleSet.add(new AttributeValue(rawValue, normValue));
+      ByteString rawValue = ByteString.valueOf(valueString);
+      ByteString normValue =
+          normalizationMatchingRule.normalizeValue(rawValue);
+      matchingRuleSet.add(AttributeValues.create(rawValue,
+          normValue));
     }
   }
 
@@ -1305,20 +1302,19 @@
       try
       {
         String valueString = matchingRule.toString();
-        ASN1OctetString rawValue = new ASN1OctetString(valueString);
+        ByteString rawValue = ByteString.valueOf(valueString);
         ByteString normValue =
-             normalizationMatchingRule.normalizeValue(
-                  new ASN1OctetString(valueString));
-        matchingRuleSet.remove(new AttributeValue(rawValue,
+             normalizationMatchingRule.normalizeValue(rawValue);
+        matchingRuleSet.remove(AttributeValues.create(rawValue,
                                                   normValue));
       }
       catch (Exception e)
       {
         String valueString = matchingRule.toString();
-        ASN1OctetString rawValue = new ASN1OctetString(valueString);
-        ASN1OctetString normValue =
-             new ASN1OctetString(toLowerCase(valueString));
-        matchingRuleSet.remove(new AttributeValue(rawValue,
+        ByteString rawValue = ByteString.valueOf(valueString);
+        ByteString normValue =
+            ByteString.valueOf(toLowerCase(valueString));
+        matchingRuleSet.remove(AttributeValues.create(rawValue,
                                                   normValue));
       }
     }
@@ -1438,10 +1434,11 @@
       // a very expensive matching rule (OID first component match)
       // that would kill performance.
       String valueString = matchingRule.toString();
-      ASN1OctetString rawValue  = new ASN1OctetString(valueString);
-      ByteString normValue = normalizationMatchingRule.normalizeValue(
-                                  new ASN1OctetString(valueString));
-      matchingRuleSet.add(new AttributeValue(rawValue, normValue));
+      ByteString rawValue = ByteString.valueOf(valueString);
+      ByteString normValue =
+          normalizationMatchingRule.normalizeValue(rawValue);
+      matchingRuleSet.add(AttributeValues.create(rawValue,
+          normValue));
     }
   }
 
@@ -1480,20 +1477,19 @@
       try
       {
         String valueString = matchingRule.toString();
-        ASN1OctetString rawValue = new ASN1OctetString(valueString);
+        ByteString rawValue = ByteString.valueOf(valueString);
         ByteString normValue =
-             normalizationMatchingRule.normalizeValue(
-                  new ASN1OctetString(valueString));
-        matchingRuleSet.remove(new AttributeValue(rawValue,
+             normalizationMatchingRule.normalizeValue(rawValue);
+        matchingRuleSet.remove(AttributeValues.create(rawValue,
                                                   normValue));
       }
       catch (Exception e)
       {
         String valueString = matchingRule.toString();
-        ASN1OctetString rawValue = new ASN1OctetString(valueString);
-        ASN1OctetString normValue =
-             new ASN1OctetString(toLowerCase(valueString));
-        matchingRuleSet.remove(new AttributeValue(rawValue,
+        ByteString rawValue = ByteString.valueOf(valueString);
+        ByteString normValue =
+            ByteString.valueOf(toLowerCase(valueString));
+        matchingRuleSet.remove(AttributeValues.create(rawValue,
                                                   normValue));
       }
     }
@@ -1612,10 +1608,11 @@
       // a very expensive matching rule (OID first component match)
       // that would kill performance.
       String valueString = matchingRule.toString();
-      ASN1OctetString rawValue  = new ASN1OctetString(valueString);
-      ByteString normValue = normalizationMatchingRule.normalizeValue(
-                                  new ASN1OctetString(valueString));
-      matchingRuleSet.add(new AttributeValue(rawValue, normValue));
+        ByteString rawValue = ByteString.valueOf(valueString);
+        ByteString normValue =
+             normalizationMatchingRule.normalizeValue(rawValue);
+      matchingRuleSet.add(AttributeValues.create(rawValue,
+          normValue));
     }
   }
 
@@ -1653,20 +1650,19 @@
       try
       {
         String valueString = matchingRule.toString();
-        ASN1OctetString rawValue = new ASN1OctetString(valueString);
+        ByteString rawValue = ByteString.valueOf(valueString);
         ByteString normValue =
-             normalizationMatchingRule.normalizeValue(
-                  new ASN1OctetString(valueString));
-        matchingRuleSet.remove(new AttributeValue(rawValue,
+             normalizationMatchingRule.normalizeValue(rawValue);
+        matchingRuleSet.remove(AttributeValues.create(rawValue,
                                                   normValue));
       }
       catch (Exception e)
       {
         String valueString = matchingRule.toString();
-        ASN1OctetString rawValue = new ASN1OctetString(valueString);
-        ASN1OctetString normValue =
-             new ASN1OctetString(toLowerCase(valueString));
-        matchingRuleSet.remove(new AttributeValue(rawValue,
+        ByteString rawValue = ByteString.valueOf(valueString);
+        ByteString normValue =
+            ByteString.valueOf(toLowerCase(valueString));
+        matchingRuleSet.remove(AttributeValues.create(rawValue,
                                                   normValue));
       }
     }
@@ -1785,10 +1781,11 @@
       // a very expensive matching rule (OID first component match)
       // that would kill performance.
       String valueString = matchingRule.toString();
-      ASN1OctetString rawValue  = new ASN1OctetString(valueString);
-      ByteString normValue = normalizationMatchingRule.normalizeValue(
-                                  new ASN1OctetString(valueString));
-      matchingRuleSet.add(new AttributeValue(rawValue, normValue));
+        ByteString rawValue = ByteString.valueOf(valueString);
+        ByteString normValue =
+             normalizationMatchingRule.normalizeValue(rawValue);
+      matchingRuleSet.add(AttributeValues.create(rawValue,
+          normValue));
     }
   }
 
@@ -1826,20 +1823,19 @@
       try
       {
         String valueString = matchingRule.toString();
-        ASN1OctetString rawValue = new ASN1OctetString(valueString);
+        ByteString rawValue = ByteString.valueOf(valueString);
         ByteString normValue =
-             normalizationMatchingRule.normalizeValue(
-                  new ASN1OctetString(valueString));
-        matchingRuleSet.remove(new AttributeValue(rawValue,
+             normalizationMatchingRule.normalizeValue(rawValue);
+        matchingRuleSet.remove(AttributeValues.create(rawValue,
                                                   normValue));
       }
       catch (Exception e)
       {
         String valueString = matchingRule.toString();
-        ASN1OctetString rawValue = new ASN1OctetString(valueString);
-        ASN1OctetString normValue =
-             new ASN1OctetString(toLowerCase(valueString));
-        matchingRuleSet.remove(new AttributeValue(rawValue,
+        ByteString rawValue = ByteString.valueOf(valueString);
+        ByteString normValue =
+            ByteString.valueOf(toLowerCase(valueString));
+        matchingRuleSet.remove(AttributeValues.create(rawValue,
                                                   normValue));
       }
     }
@@ -1958,10 +1954,11 @@
       // a very expensive matching rule (OID first component match)
       // that would kill performance.
       String valueString = matchingRule.toString();
-      ASN1OctetString rawValue  = new ASN1OctetString(valueString);
+      ByteString rawValue  = ByteString.valueOf(valueString);
       ByteString normValue = normalizationMatchingRule.normalizeValue(
-                                  new ASN1OctetString(valueString));
-      matchingRuleSet.add(new AttributeValue(rawValue, normValue));
+                                  rawValue);
+      matchingRuleSet.add(
+          AttributeValues.create(rawValue, normValue));
     }
   }
 
@@ -1999,21 +1996,20 @@
       try
       {
         String valueString = matchingRule.toString();
-        ASN1OctetString rawValue = new ASN1OctetString(valueString);
+        ByteString rawValue = ByteString.valueOf(valueString);
         ByteString normValue =
-             normalizationMatchingRule.normalizeValue(
-                  new ASN1OctetString(valueString));
-        matchingRuleSet.remove(new AttributeValue(rawValue,
-                                                  normValue));
+            normalizationMatchingRule.normalizeValue(rawValue);
+        matchingRuleSet.remove(AttributeValues.create(rawValue,
+            normValue));
       }
       catch (Exception e)
       {
         String valueString = matchingRule.toString();
-        ASN1OctetString rawValue = new ASN1OctetString(valueString);
-        ASN1OctetString normValue =
-             new ASN1OctetString(toLowerCase(valueString));
-        matchingRuleSet.remove(new AttributeValue(rawValue,
-                                                  normValue));
+        ByteString rawValue = ByteString.valueOf(valueString);
+        ByteString normValue =
+            ByteString.valueOf(toLowerCase(valueString));
+        matchingRuleSet.remove(AttributeValues.create(rawValue,
+            normValue));
       }
     }
   }
@@ -2130,10 +2126,11 @@
       // a very expensive matching rule (OID first component match)
       // that would kill performance.
       String valueString = matchingRuleUse.getDefinition();
-      ASN1OctetString rawValue  = new ASN1OctetString(valueString);
-      ByteString normValue = normalizationMatchingRule.normalizeValue(
-                                  new ASN1OctetString(valueString));
-      matchingRuleUseSet.add(new AttributeValue(rawValue, normValue));
+      ByteString rawValue = ByteString.valueOf(valueString);
+      ByteString normValue =
+          normalizationMatchingRule.normalizeValue(rawValue);
+      matchingRuleUseSet.add(AttributeValues.create(rawValue,
+          normValue));
     }
   }
 
@@ -2161,20 +2158,19 @@
       try
       {
         String valueString = matchingRuleUse.getDefinition();
-        ASN1OctetString rawValue = new ASN1OctetString(valueString);
+        ByteString rawValue = ByteString.valueOf(valueString);
         ByteString normValue =
-             normalizationMatchingRule.normalizeValue(
-                  new ASN1OctetString(valueString));
-        matchingRuleUseSet.remove(new AttributeValue(rawValue,
+             normalizationMatchingRule.normalizeValue(rawValue);
+        matchingRuleUseSet.remove(AttributeValues.create(rawValue,
                                                      normValue));
       }
       catch (Exception e)
       {
         String valueString = matchingRuleUse.getDefinition();
-        ASN1OctetString rawValue = new ASN1OctetString(valueString);
-        ASN1OctetString normValue =
-             new ASN1OctetString(toLowerCase(valueString));
-        matchingRuleUseSet.remove(new AttributeValue(rawValue,
+        ByteString rawValue = ByteString.valueOf(valueString);
+        ByteString normValue =
+            ByteString.valueOf(toLowerCase(valueString));
+        matchingRuleUseSet.remove(AttributeValues.create(rawValue,
                                                      normValue));
       }
     }
@@ -2291,10 +2287,11 @@
       // a very expensive matching rule (OID first component match)
       // that would kill performance.
       String valueString = ditContentRule.getDefinition();
-      ASN1OctetString rawValue  = new ASN1OctetString(valueString);
-      ByteString normValue = normalizationMatchingRule.normalizeValue(
-                                  new ASN1OctetString(valueString));
-      ditContentRuleSet.add(new AttributeValue(rawValue, normValue));
+      ByteString rawValue = ByteString.valueOf(valueString);
+      ByteString normValue =
+          normalizationMatchingRule.normalizeValue(rawValue);
+      ditContentRuleSet.add(AttributeValues.create(rawValue,
+          normValue));
     }
   }
 
@@ -2321,20 +2318,19 @@
       try
       {
         String valueString = ditContentRule.getDefinition();
-        ASN1OctetString rawValue = new ASN1OctetString(valueString);
+        ByteString rawValue = ByteString.valueOf(valueString);
         ByteString normValue =
-             normalizationMatchingRule.normalizeValue(
-                  new ASN1OctetString(valueString));
-        ditContentRuleSet.remove(new AttributeValue(rawValue,
+             normalizationMatchingRule.normalizeValue(rawValue);
+        ditContentRuleSet.remove(AttributeValues.create(rawValue,
                                                     normValue));
       }
       catch (Exception e)
       {
         String valueString = ditContentRule.getDefinition();
-        ASN1OctetString rawValue = new ASN1OctetString(valueString);
-        ASN1OctetString normValue =
-             new ASN1OctetString(toLowerCase(valueString));
-        ditContentRuleSet.remove(new AttributeValue(rawValue,
+        ByteString rawValue = ByteString.valueOf(valueString);
+        ByteString normValue =
+            ByteString.valueOf(toLowerCase(valueString));
+        ditContentRuleSet.remove(AttributeValues.create(rawValue,
                                                     normValue));
       }
     }
@@ -2520,10 +2516,10 @@
       // a very expensive matching rule (OID first component match)
       // that would kill performance.
       String valueString = ditStructureRule.getDefinition();
-      ASN1OctetString rawValue = new ASN1OctetString(valueString);
-      ByteString normValue = normalizationMatchingRule.normalizeValue(
-                                  new ASN1OctetString(valueString));
-      ditStructureRuleSet.add(new AttributeValue(rawValue,
+      ByteString rawValue = ByteString.valueOf(valueString);
+      ByteString normValue =
+          normalizationMatchingRule.normalizeValue(rawValue);
+      ditStructureRuleSet.add(AttributeValues.create(rawValue,
                                                  normValue));
     }
   }
@@ -2554,20 +2550,19 @@
       try
       {
         String valueString = ditStructureRule.getDefinition();
-        ASN1OctetString rawValue = new ASN1OctetString(valueString);
+        ByteString rawValue = ByteString.valueOf(valueString);
         ByteString normValue =
-             normalizationMatchingRule.normalizeValue(
-                  new ASN1OctetString(valueString));
-        ditStructureRuleSet.remove(new AttributeValue(rawValue,
+             normalizationMatchingRule.normalizeValue(rawValue);
+        ditStructureRuleSet.remove(AttributeValues.create(rawValue,
                                                       normValue));
       }
       catch (Exception e)
       {
         String valueString = ditStructureRule.getDefinition();
-        ASN1OctetString rawValue = new ASN1OctetString(valueString);
-        ASN1OctetString normValue =
-             new ASN1OctetString(toLowerCase(valueString));
-        ditStructureRuleSet.remove(new AttributeValue(rawValue,
+        ByteString rawValue = ByteString.valueOf(valueString);
+        ByteString normValue =
+            ByteString.valueOf(toLowerCase(valueString));
+        ditStructureRuleSet.remove(AttributeValues.create(rawValue,
                                                       normValue));
       }
     }
@@ -2762,10 +2757,10 @@
       // a very expensive matching rule (OID first component match)
       // that would kill performance.
       String valueString = nameForm.getDefinition();
-      ASN1OctetString rawValue  = new ASN1OctetString(valueString);
-      ByteString normValue = normalizationMatchingRule.normalizeValue(
-                                  new ASN1OctetString(valueString));
-      nameFormSet.add(new AttributeValue(rawValue, normValue));
+      ByteString rawValue = ByteString.valueOf(valueString);
+      ByteString normValue =
+          normalizationMatchingRule.normalizeValue(rawValue);
+      nameFormSet.add(AttributeValues.create(rawValue, normValue));
     }
   }
 
@@ -2796,19 +2791,20 @@
       try
       {
         String valueString = nameForm.getDefinition();
-        ASN1OctetString rawValue = new ASN1OctetString(valueString);
+        ByteString rawValue = ByteString.valueOf(valueString);
         ByteString normValue =
-             normalizationMatchingRule.normalizeValue(
-                  new ASN1OctetString(valueString));
-        nameFormSet.remove(new AttributeValue(rawValue, normValue));
+             normalizationMatchingRule.normalizeValue(rawValue);
+        nameFormSet.remove(AttributeValues.create(rawValue,
+            normValue));
       }
       catch (Exception e)
       {
         String valueString = nameForm.getDefinition();
-        ASN1OctetString rawValue = new ASN1OctetString(valueString);
-        ASN1OctetString normValue =
-             new ASN1OctetString(toLowerCase(valueString));
-        nameFormSet.remove(new AttributeValue(rawValue, normValue));
+        ByteString rawValue = ByteString.valueOf(valueString);
+        ByteString normValue =
+            ByteString.valueOf(toLowerCase(valueString));
+        nameFormSet.remove(AttributeValues.create(rawValue,
+            normValue));
       }
     }
   }
@@ -3583,7 +3579,7 @@
     {
       if (!newElements.contains(s))
       {
-        builder.add(new AttributeValue(attributeTypesType, s));
+        builder.add(AttributeValues.create(attributeTypesType, s));
       }
     }
 
@@ -3598,7 +3594,7 @@
     {
       if (!oldElements.contains(s))
       {
-        builder.add(new AttributeValue(attributeTypesType, s));
+        builder.add(AttributeValues.create(attributeTypesType, s));
       }
     }
 
diff --git a/opends/src/server/org/opends/server/types/SearchFilter.java b/opends/src/server/org/opends/server/types/SearchFilter.java
index 5bb6795..8226eb2 100644
--- a/opends/src/server/org/opends/server/types/SearchFilter.java
+++ b/opends/src/server/org/opends/server/types/SearchFilter.java
@@ -22,16 +22,13 @@
  * CDDL HEADER END
  *
  *
- *      Copyright 2006-2008 Sun Microsystems, Inc.
+ *      Copyright 2006-2009 Sun Microsystems, Inc.
  */
 package org.opends.server.types;
 import org.opends.messages.Message;
 
 
-
-import java.nio.ByteBuffer;
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.HashSet;
 import java.util.LinkedList;
 import java.util.List;
@@ -43,7 +40,6 @@
 import org.opends.server.api.MatchingRule;
 import org.opends.server.api.SubstringMatchingRule;
 import org.opends.server.core.DirectoryServer;
-import org.opends.server.protocols.asn1.ASN1OctetString;
 
 import static org.opends.server.loggers.debug.DebugLogger.*;
 import org.opends.server.loggers.debug.DebugTracer;
@@ -53,7 +49,6 @@
 import static org.opends.server.util.ServerConstants.*;
 
 
-
 /**
  * This class defines a data structure for storing and interacting
  * with a search filter that may serve as criteria for locating
@@ -829,8 +824,8 @@
     {
       return new SearchFilter(filterType, null, null, attributeType,
                     attributeOptions,
-                    new AttributeValue(new ASN1OctetString(),
-                                       new ASN1OctetString()),
+          AttributeValues.create(ByteString.empty(),
+                                       ByteString.empty()),
                     null, null, null, null, false);
     }
     else if (valueStr.equals("*"))
@@ -861,8 +856,8 @@
       ByteString userValue;
       if (hasEscape)
       {
-        ByteBuffer valueBuffer =
-             ByteBuffer.allocate(valueStr.length());
+        ByteStringBuilder valueBuffer =
+            new ByteStringBuilder(valueStr.length());
         for (int i=0; i < valueBytes.length; i++)
         {
           if (valueBytes[i] == 0x5C) // The backslash character
@@ -1005,26 +1000,23 @@
                                ResultCode.PROTOCOL_ERROR, message);
             }
 
-            valueBuffer.put(byteValue);
+            valueBuffer.append(byteValue);
           }
           else
           {
-            valueBuffer.put(valueBytes[i]);
+            valueBuffer.append(valueBytes[i]);
           }
         }
 
-        valueBytes = new byte[valueBuffer.position()];
-        valueBuffer.flip();
-        valueBuffer.get(valueBytes);
-        userValue = new ASN1OctetString(valueBytes);
+        userValue = valueBuffer.toByteString();
       }
       else
       {
-        userValue = new ASN1OctetString(valueBytes);
+        userValue = ByteString.wrap(valueBytes);
       }
 
       AttributeValue value =
-           new AttributeValue(attributeType, userValue);
+          AttributeValues.create(attributeType, userValue);
       return new SearchFilter(filterType, null, null, attributeType,
                               attributeOptions, value, null, null,
                               null, null, false);
@@ -1258,7 +1250,7 @@
     {
       if (hasEscape)
       {
-        ByteBuffer buffer = ByteBuffer.allocate(firstPos);
+        ByteStringBuilder buffer = new ByteStringBuilder(firstPos);
         for (int i=0; i < firstPos; i++)
         {
           if (valueBytes[i] == 0x5C)
@@ -1401,24 +1393,19 @@
                                ResultCode.PROTOCOL_ERROR, message);
             }
 
-            buffer.put(byteValue);
+            buffer.append(byteValue);
           }
           else
           {
-            buffer.put(valueBytes[i]);
+            buffer.append(valueBytes[i]);
           }
         }
 
-        byte[] subInitialBytes = new byte[buffer.position()];
-        buffer.flip();
-        buffer.get(subInitialBytes);
-        subInitial = new ASN1OctetString(subInitialBytes);
+        subInitial = buffer.toByteString();
       }
       else
       {
-        byte[] subInitialBytes = new byte[firstPos];
-        System.arraycopy(valueBytes, 0, subInitialBytes, 0, firstPos);
-        subInitial = new ASN1OctetString(subInitialBytes);
+        subInitial = ByteString.wrap(valueBytes, 0, firstPos);
       }
     }
 
@@ -1432,7 +1419,7 @@
 
       if (hasEscape)
       {
-        ByteBuffer buffer = ByteBuffer.allocate(length);
+        ByteStringBuilder buffer = new ByteStringBuilder(length);
         for (int i=firstPos+1; i < asteriskPos; i++)
         {
           if (valueBytes[i] == 0x5C)
@@ -1575,25 +1562,20 @@
                                ResultCode.PROTOCOL_ERROR, message);
             }
 
-            buffer.put(byteValue);
+            buffer.append(byteValue);
           }
           else
           {
-            buffer.put(valueBytes[i]);
+            buffer.append(valueBytes[i]);
           }
         }
 
-        byte[] subAnyBytes = new byte[buffer.position()];
-        buffer.flip();
-        buffer.get(subAnyBytes);
-        subAny.add(new ASN1OctetString(subAnyBytes));
+        subAny.add(buffer.toByteString());
+        buffer.clear();
       }
       else
       {
-        byte[] subAnyBytes = new byte[length];
-        System.arraycopy(valueBytes, firstPos+1, subAnyBytes, 0,
-                         length);
-        subAny.add(new ASN1OctetString(subAnyBytes));
+        subAny.add(ByteString.wrap(valueBytes, firstPos+1, length));
       }
 
 
@@ -1614,7 +1596,7 @@
 
       if (hasEscape)
       {
-        ByteBuffer buffer = ByteBuffer.allocate(length);
+        ByteStringBuilder buffer = new ByteStringBuilder(length);
         for (int i=firstPos+1; i < endPos; i++)
         {
           if (valueBytes[i] == 0x5C)
@@ -1757,25 +1739,19 @@
                                ResultCode.PROTOCOL_ERROR, message);
             }
 
-            buffer.put(byteValue);
+            buffer.append(byteValue);
           }
           else
           {
-            buffer.put(valueBytes[i]);
+            buffer.append(valueBytes[i]);
           }
         }
 
-        byte[] subFinalBytes = new byte[buffer.position()];
-        buffer.flip();
-        buffer.get(subFinalBytes);
-        subFinal = new ASN1OctetString(subFinalBytes);
+        subFinal = buffer.toByteString();
       }
       else
       {
-        byte[] subFinalBytes = new byte[length];
-        System.arraycopy(valueBytes, firstPos+1, subFinalBytes, 0,
-                         length);
-        subFinal = new ASN1OctetString(subFinalBytes);
+        subFinal = ByteString.wrap(valueBytes, firstPos+1, length);
       }
     }
 
@@ -1934,7 +1910,8 @@
     ByteString userValue;
     if (hasEscape)
     {
-      ByteBuffer valueBuffer = ByteBuffer.allocate(valueBytes.length);
+      ByteStringBuilder valueBuffer =
+          new ByteStringBuilder(valueBytes.length);
       for (int i=0; i < valueBytes.length; i++)
       {
         if (valueBytes[i] == 0x5C) // The backslash character
@@ -2076,22 +2053,19 @@
                                            message);
           }
 
-          valueBuffer.put(byteValue);
+          valueBuffer.append(byteValue);
         }
         else
         {
-          valueBuffer.put(valueBytes[i]);
+          valueBuffer.append(valueBytes[i]);
         }
       }
 
-      valueBytes = new byte[valueBuffer.position()];
-      valueBuffer.flip();
-      valueBuffer.get(valueBytes);
-      userValue = new ASN1OctetString(valueBytes);
+      userValue = valueBuffer.toByteString();
     }
     else
     {
-      userValue = new ASN1OctetString(valueBytes);
+      userValue = ByteString.wrap(valueBytes);
     }
 
     // Make sure that the filter contains at least one of an attribute
@@ -2122,14 +2096,15 @@
         }
         else
         {
-          value = new AttributeValue(userValue,
+          value = AttributeValues.create(userValue,
                                      mr.normalizeValue(userValue));
         }
       }
     }
     else
     {
-      value = new AttributeValue(attributeType, userValue);
+      value = AttributeValues.create(attributeType,
+          userValue);
     }
 
     return new SearchFilter(FilterType.EXTENSIBLE_MATCH, null, null,
@@ -2787,7 +2762,7 @@
           "%s with value %s",
                    this, completeFilter, entry.getDN(),
                    attributeType.getNameOrOID(),
-                   assertionValue.getStringValue());
+                   assertionValue.getValue().toString());
     }
     return ConditionResult.FALSE;
   }
@@ -3758,7 +3733,7 @@
             ByteString nSI2 =
                  smr.normalizeSubstring(f.subInitialElement);
 
-            if (! Arrays.equals(nSI1.value(), nSI2.value()))
+            if (! nSI1.equals(nSI2))
             {
               return false;
             }
@@ -3785,7 +3760,7 @@
             ByteString nSF2 =
                  smr.normalizeSubstring(f.subFinalElement);
 
-            if (! Arrays.equals(nSF1.value(), nSF2.value()))
+            if (! nSF1.equals(nSF2))
             {
               return false;
             }
@@ -3810,7 +3785,7 @@
             ByteString nSA2 =
                  smr.normalizeSubstring(f.subAnyElements.get(i));
 
-            if (! Arrays.equals(nSA1.value(), nSA2.value()))
+            if (! nSA1.equals(nSA2))
             {
               return false;
             }
@@ -4338,10 +4313,11 @@
     // it to see if there are any unsafe characters.  If there are,
     // then escape them and replace them with a two-digit hex
     // equivalent.
-    byte[] valueBytes = value.value();
-    buffer.ensureCapacity(buffer.length() + valueBytes.length);
-    for (byte b : valueBytes)
+    buffer.ensureCapacity(buffer.length() + value.length());
+    byte b;
+    for (int i = 0; i < value.length(); i++)
     {
+      b = value.byteAt(i);
       if (((b & 0x7F) != b) ||  // Not 7-bit clean
           (b <= 0x1F) ||        // Below the printable character range
           (b == 0x28) ||        // Open parenthesis
diff --git a/opends/src/server/org/opends/server/types/operation/PluginOperation.java b/opends/src/server/org/opends/server/types/operation/PluginOperation.java
index 3098a78..87a56fe 100644
--- a/opends/src/server/org/opends/server/types/operation/PluginOperation.java
+++ b/opends/src/server/org/opends/server/types/operation/PluginOperation.java
@@ -34,6 +34,7 @@
 
 import org.opends.server.api.ClientConnection;
 import org.opends.server.types.*;
+import org.opends.server.controls.ControlDecoder;
 
 
 /**
@@ -132,6 +133,24 @@
 
 
   /**
+   * Retrieves a control included in the request from the client.
+   *
+   * @param <T>
+   *          The type of control requested.
+   * @param d
+   *          The requested control's decoder.
+   * @return The decoded form of the requested control included in the
+   *         request from the client or <code>null</code> if the
+   *         control was not found.
+   * @throws DirectoryException
+   *           if an error occurs while decoding the control.
+   */
+  public <T extends Control> T getRequestControl(ControlDecoder<T> d)
+      throws DirectoryException;
+
+
+
+  /**
    * Retrieves the set of controls to include in the response to the
    * client.  The contents of this list must not be altered.
    *
diff --git a/opends/src/server/org/opends/server/types/operation/PostOperationBindOperation.java b/opends/src/server/org/opends/server/types/operation/PostOperationBindOperation.java
index 761b71a..14c9d8e 100644
--- a/opends/src/server/org/opends/server/types/operation/PostOperationBindOperation.java
+++ b/opends/src/server/org/opends/server/types/operation/PostOperationBindOperation.java
@@ -29,7 +29,6 @@
 
 
 
-import org.opends.server.protocols.asn1.ASN1OctetString;
 import org.opends.server.types.AuthenticationType;
 import org.opends.server.types.ByteString;
 import org.opends.server.types.DN;
@@ -121,7 +120,7 @@
    *          <CODE>null</CODE> if there are none or if the bind does
    *          not use SASL authentication.
    */
-  public ASN1OctetString getSASLCredentials();
+  public ByteString getSASLCredentials();
 
 
 
@@ -132,7 +131,7 @@
    * @return  The set of server SASL credentials to include in the
    *          bind response, or <CODE>null</CODE> if there are none.
    */
-  public ASN1OctetString getServerSASLCredentials();
+  public ByteString getServerSASLCredentials();
 
 
 
@@ -143,7 +142,7 @@
    * @param  serverSASLCredentials  The set of server SASL credentials
    *                                to include in the bind response.
    */
-  public void setServerSASLCredentials(ASN1OctetString
+  public void setServerSASLCredentials(ByteString
                                             serverSASLCredentials);
 
 
diff --git a/opends/src/server/org/opends/server/types/operation/PostOperationExtendedOperation.java b/opends/src/server/org/opends/server/types/operation/PostOperationExtendedOperation.java
index e2d5731..277b629 100644
--- a/opends/src/server/org/opends/server/types/operation/PostOperationExtendedOperation.java
+++ b/opends/src/server/org/opends/server/types/operation/PostOperationExtendedOperation.java
@@ -28,8 +28,7 @@
 
 
 
-import org.opends.server.protocols.asn1.ASN1OctetString;
-
+import org.opends.server.types.ByteString;
 
 
 /**
@@ -64,7 +63,7 @@
    * @return  The value for the request associated with this extended
    *          operation.
    */
-  public ASN1OctetString getRequestValue();
+  public ByteString getRequestValue();
 
 
 
@@ -92,7 +91,7 @@
    *
    * @return  The value to include in the response to the client.
    */
-  public ASN1OctetString getResponseValue();
+  public ByteString getResponseValue();
 
 
 
@@ -102,6 +101,6 @@
    * @param  responseValue  The value to include in the response to
    *                        the client.
    */
-  public void setResponseValue(ASN1OctetString responseValue);
+  public void setResponseValue(ByteString responseValue);
 }
 
diff --git a/opends/src/server/org/opends/server/types/operation/PostResponseAddOperation.java b/opends/src/server/org/opends/server/types/operation/PostResponseAddOperation.java
index 6c68063..46d5e34 100644
--- a/opends/src/server/org/opends/server/types/operation/PostResponseAddOperation.java
+++ b/opends/src/server/org/opends/server/types/operation/PostResponseAddOperation.java
@@ -31,14 +31,7 @@
 import java.util.List;
 import java.util.Map;
 
-import org.opends.server.types.Attribute;
-import org.opends.server.types.AttributeType;
-import org.opends.server.types.ByteString;
-import org.opends.server.types.DN;
-import org.opends.server.types.Entry;
-import org.opends.server.types.ObjectClass;
-import org.opends.server.types.RawAttribute;
-
+import org.opends.server.types.*;
 
 
 /**
diff --git a/opends/src/server/org/opends/server/types/operation/PostResponseBindOperation.java b/opends/src/server/org/opends/server/types/operation/PostResponseBindOperation.java
index 3fe0902..021f9d9 100644
--- a/opends/src/server/org/opends/server/types/operation/PostResponseBindOperation.java
+++ b/opends/src/server/org/opends/server/types/operation/PostResponseBindOperation.java
@@ -29,7 +29,6 @@
 
 
 
-import org.opends.server.protocols.asn1.ASN1OctetString;
 import org.opends.server.types.AuthenticationType;
 import org.opends.server.types.ByteString;
 import org.opends.server.types.DN;
@@ -121,7 +120,7 @@
    *          <CODE>null</CODE> if there are none or if the bind does
    *          not use SASL authentication.
    */
-  public ASN1OctetString getSASLCredentials();
+  public ByteString getSASLCredentials();
 
 
 
@@ -132,7 +131,7 @@
    * @return  The set of server SASL credentials to include in the
    *          bind response, or <CODE>null</CODE> if there are none.
    */
-  public ASN1OctetString getServerSASLCredentials();
+  public ByteString getServerSASLCredentials();
 
 
 
diff --git a/opends/src/server/org/opends/server/types/operation/PostResponseCompareOperation.java b/opends/src/server/org/opends/server/types/operation/PostResponseCompareOperation.java
index 2e828fa..98bcdaf 100644
--- a/opends/src/server/org/opends/server/types/operation/PostResponseCompareOperation.java
+++ b/opends/src/server/org/opends/server/types/operation/PostResponseCompareOperation.java
@@ -28,11 +28,7 @@
 
 
 
-import org.opends.server.types.AttributeType;
-import org.opends.server.types.ByteString;
-import org.opends.server.types.DN;
-import org.opends.server.types.Entry;
-
+import org.opends.server.types.*;
 
 
 /**
diff --git a/opends/src/server/org/opends/server/types/operation/PostResponseDeleteOperation.java b/opends/src/server/org/opends/server/types/operation/PostResponseDeleteOperation.java
index 59c6a14..e92f825 100644
--- a/opends/src/server/org/opends/server/types/operation/PostResponseDeleteOperation.java
+++ b/opends/src/server/org/opends/server/types/operation/PostResponseDeleteOperation.java
@@ -33,7 +33,6 @@
 import org.opends.server.types.Entry;
 
 
-
 /**
  * This class defines a set of methods that are available for use by
  * post-response plugins for delete operations.  Note that this
diff --git a/opends/src/server/org/opends/server/types/operation/PostResponseExtendedOperation.java b/opends/src/server/org/opends/server/types/operation/PostResponseExtendedOperation.java
index 0afc761..52490d1 100644
--- a/opends/src/server/org/opends/server/types/operation/PostResponseExtendedOperation.java
+++ b/opends/src/server/org/opends/server/types/operation/PostResponseExtendedOperation.java
@@ -28,8 +28,7 @@
 
 
 
-import org.opends.server.protocols.asn1.ASN1OctetString;
-
+import org.opends.server.types.ByteString;
 
 
 /**
@@ -64,7 +63,7 @@
    * @return  The value for the request associated with this extended
    *          operation.
    */
-  public ASN1OctetString getRequestValue();
+  public ByteString getRequestValue();
 
 
 
@@ -82,6 +81,6 @@
    *
    * @return  The value to include in the response to the client.
    */
-  public ASN1OctetString getResponseValue();
+  public ByteString getResponseValue();
 }
 
diff --git a/opends/src/server/org/opends/server/types/operation/PostResponseModifyDNOperation.java b/opends/src/server/org/opends/server/types/operation/PostResponseModifyDNOperation.java
index d1f665e..598c200 100644
--- a/opends/src/server/org/opends/server/types/operation/PostResponseModifyDNOperation.java
+++ b/opends/src/server/org/opends/server/types/operation/PostResponseModifyDNOperation.java
@@ -30,12 +30,7 @@
 
 import java.util.List;
 
-import org.opends.server.types.ByteString;
-import org.opends.server.types.DN;
-import org.opends.server.types.Entry;
-import org.opends.server.types.Modification;
-import org.opends.server.types.RDN;
-
+import org.opends.server.types.*;
 
 
 /**
diff --git a/opends/src/server/org/opends/server/types/operation/PostResponseModifyOperation.java b/opends/src/server/org/opends/server/types/operation/PostResponseModifyOperation.java
index 1264710..b794f0d 100644
--- a/opends/src/server/org/opends/server/types/operation/PostResponseModifyOperation.java
+++ b/opends/src/server/org/opends/server/types/operation/PostResponseModifyOperation.java
@@ -30,13 +30,7 @@
 
 import java.util.List;
 
-import org.opends.server.types.AttributeValue;
-import org.opends.server.types.ByteString;
-import org.opends.server.types.DN;
-import org.opends.server.types.Entry;
-import org.opends.server.types.Modification;
-import org.opends.server.types.RawModification;
-
+import org.opends.server.types.*;
 
 
 /**
diff --git a/opends/src/server/org/opends/server/types/operation/PostResponseSearchOperation.java b/opends/src/server/org/opends/server/types/operation/PostResponseSearchOperation.java
index 5883e35..2af4351 100644
--- a/opends/src/server/org/opends/server/types/operation/PostResponseSearchOperation.java
+++ b/opends/src/server/org/opends/server/types/operation/PostResponseSearchOperation.java
@@ -30,13 +30,7 @@
 
 import java.util.LinkedHashSet;
 
-import org.opends.server.types.ByteString;
-import org.opends.server.types.DereferencePolicy;
-import org.opends.server.types.DN;
-import org.opends.server.types.RawFilter;
-import org.opends.server.types.SearchScope;
-import org.opends.server.types.SearchFilter;
-
+import org.opends.server.types.*;
 
 
 /**
diff --git a/opends/src/server/org/opends/server/types/operation/PreOperationBindOperation.java b/opends/src/server/org/opends/server/types/operation/PreOperationBindOperation.java
index 9ab97c9..e927431 100644
--- a/opends/src/server/org/opends/server/types/operation/PreOperationBindOperation.java
+++ b/opends/src/server/org/opends/server/types/operation/PreOperationBindOperation.java
@@ -29,7 +29,6 @@
 
 
 
-import org.opends.server.protocols.asn1.ASN1OctetString;
 import org.opends.server.types.AuthenticationType;
 import org.opends.server.types.ByteString;
 import org.opends.server.types.DN;
@@ -120,7 +119,7 @@
    *          <CODE>null</CODE> if there are none or if the bind does
    *          not use SASL authentication.
    */
-  public ASN1OctetString getSASLCredentials();
+  public ByteString getSASLCredentials();
 
 
 
@@ -131,7 +130,7 @@
    * @param  serverSASLCredentials  The set of server SASL credentials
    *                                to include in the bind response.
    */
-  public void setServerSASLCredentials(ASN1OctetString
+  public void setServerSASLCredentials(ByteString
                                             serverSASLCredentials);
 
 
diff --git a/opends/src/server/org/opends/server/types/operation/PreOperationExtendedOperation.java b/opends/src/server/org/opends/server/types/operation/PreOperationExtendedOperation.java
index e5dcf7c..bc54a3a 100644
--- a/opends/src/server/org/opends/server/types/operation/PreOperationExtendedOperation.java
+++ b/opends/src/server/org/opends/server/types/operation/PreOperationExtendedOperation.java
@@ -28,8 +28,7 @@
 
 
 
-import org.opends.server.protocols.asn1.ASN1OctetString;
-
+import org.opends.server.types.ByteString;
 
 
 /**
@@ -64,7 +63,7 @@
    * @return  The value for the request associated with this extended
    *          operation.
    */
-  public ASN1OctetString getRequestValue();
+  public ByteString getRequestValue();
 
 
 
@@ -84,6 +83,6 @@
    * @param  responseValue  The value to include in the response to
    *                        the client.
    */
-  public void setResponseValue(ASN1OctetString responseValue);
+  public void setResponseValue(ByteString responseValue);
 }
 
diff --git a/opends/src/server/org/opends/server/types/operation/PreParseAddOperation.java b/opends/src/server/org/opends/server/types/operation/PreParseAddOperation.java
index a4be778..724d7d4 100644
--- a/opends/src/server/org/opends/server/types/operation/PreParseAddOperation.java
+++ b/opends/src/server/org/opends/server/types/operation/PreParseAddOperation.java
@@ -34,7 +34,6 @@
 import org.opends.server.types.RawAttribute;
 
 
-
 /**
  * This class defines a set of methods that are available for use by
  * pre-parse plugins for add operations.  Note that this interface is
diff --git a/opends/src/server/org/opends/server/types/operation/PreParseBindOperation.java b/opends/src/server/org/opends/server/types/operation/PreParseBindOperation.java
index 9fd0cd8..9427f79 100644
--- a/opends/src/server/org/opends/server/types/operation/PreParseBindOperation.java
+++ b/opends/src/server/org/opends/server/types/operation/PreParseBindOperation.java
@@ -29,12 +29,10 @@
 
 
 
-import org.opends.server.protocols.asn1.ASN1OctetString;
 import org.opends.server.types.AuthenticationType;
 import org.opends.server.types.ByteString;
 
 
-
 /**
  * This class defines a set of methods that are available for use by
  * pre-parse plugins for bind operations.  Note that this
@@ -97,7 +95,6 @@
    * Specifies the raw, unprocessed bind DN for this bind operation.
    *
    * @param  rawBindDN  The raw, unprocessed bind DN for this bind
-   *                    operation.
    */
   public void setRawBindDN(ByteString rawBindDN);
 
@@ -143,7 +140,7 @@
    *          <CODE>null</CODE> if there are none or if the bind does
    *          not use SASL authentication.
    */
-  public ASN1OctetString getSASLCredentials();
+  public ByteString getSASLCredentials();
 
 
 
@@ -157,7 +154,7 @@
    *                          are none.
    */
   public void setSASLCredentials(String saslMechanism,
-                                 ASN1OctetString saslCredentials);
+                                 ByteString saslCredentials);
 
 
 
@@ -168,7 +165,7 @@
    * @param  serverSASLCredentials  The set of server SASL credentials
    *                                to include in the bind response.
    */
-  public void setServerSASLCredentials(ASN1OctetString
+  public void setServerSASLCredentials(ByteString
                                             serverSASLCredentials);
 
 
diff --git a/opends/src/server/org/opends/server/types/operation/PreParseCompareOperation.java b/opends/src/server/org/opends/server/types/operation/PreParseCompareOperation.java
index 3752d46..b9c64a8 100644
--- a/opends/src/server/org/opends/server/types/operation/PreParseCompareOperation.java
+++ b/opends/src/server/org/opends/server/types/operation/PreParseCompareOperation.java
@@ -31,7 +31,6 @@
 import org.opends.server.types.ByteString;
 
 
-
 /**
  * This class defines a set of methods that are available for use by
  * pre-parse plugins for compare operations.  Note that this interface
diff --git a/opends/src/server/org/opends/server/types/operation/PreParseDeleteOperation.java b/opends/src/server/org/opends/server/types/operation/PreParseDeleteOperation.java
index 515c813..82636ee 100644
--- a/opends/src/server/org/opends/server/types/operation/PreParseDeleteOperation.java
+++ b/opends/src/server/org/opends/server/types/operation/PreParseDeleteOperation.java
@@ -31,7 +31,6 @@
 import org.opends.server.types.ByteString;
 
 
-
 /**
  * This class defines a set of methods that are available for use by
  * pre-parse plugins for delete operations.  Note that this interface
diff --git a/opends/src/server/org/opends/server/types/operation/PreParseExtendedOperation.java b/opends/src/server/org/opends/server/types/operation/PreParseExtendedOperation.java
index 84e4893..5cbf3b5 100644
--- a/opends/src/server/org/opends/server/types/operation/PreParseExtendedOperation.java
+++ b/opends/src/server/org/opends/server/types/operation/PreParseExtendedOperation.java
@@ -28,8 +28,7 @@
 
 
 
-import org.opends.server.protocols.asn1.ASN1OctetString;
-
+import org.opends.server.types.ByteString;
 
 
 /**
@@ -75,7 +74,7 @@
    * @return  The value for the request associated with this extended
    *          operation.
    */
-  public ASN1OctetString getRequestValue();
+  public ByteString getRequestValue();
 
 
 
@@ -86,7 +85,7 @@
    * @param  requestValue  The value for the request associated with
    *                       this extended operation.
    */
-  public void setRequestValue(ASN1OctetString requestValue);
+  public void setRequestValue(ByteString requestValue);
 
 
 
@@ -106,6 +105,6 @@
    * @param  responseValue  The value to include in the response to
    *                        the client.
    */
-  public void setResponseValue(ASN1OctetString responseValue);
+  public void setResponseValue(ByteString responseValue);
 }
 
diff --git a/opends/src/server/org/opends/server/types/operation/PreParseModifyDNOperation.java b/opends/src/server/org/opends/server/types/operation/PreParseModifyDNOperation.java
index fb7ab8e..7c789d1 100644
--- a/opends/src/server/org/opends/server/types/operation/PreParseModifyDNOperation.java
+++ b/opends/src/server/org/opends/server/types/operation/PreParseModifyDNOperation.java
@@ -31,7 +31,6 @@
 import org.opends.server.types.ByteString;
 
 
-
 /**
  * This class defines a set of methods that are available for use by
  * pre-parse plugins for modify DN operations.  Note that this
diff --git a/opends/src/server/org/opends/server/types/operation/PreParseModifyOperation.java b/opends/src/server/org/opends/server/types/operation/PreParseModifyOperation.java
index 0af9956..4e7e972 100644
--- a/opends/src/server/org/opends/server/types/operation/PreParseModifyOperation.java
+++ b/opends/src/server/org/opends/server/types/operation/PreParseModifyOperation.java
@@ -34,7 +34,6 @@
 import org.opends.server.types.RawModification;
 
 
-
 /**
  * This class defines a set of methods that are available for use by
  * pre-parse plugins for modify operations.  Note that this interface
diff --git a/opends/src/server/org/opends/server/types/operation/SearchEntrySearchOperation.java b/opends/src/server/org/opends/server/types/operation/SearchEntrySearchOperation.java
index 42e40f0..5a38422 100644
--- a/opends/src/server/org/opends/server/types/operation/SearchEntrySearchOperation.java
+++ b/opends/src/server/org/opends/server/types/operation/SearchEntrySearchOperation.java
@@ -30,13 +30,7 @@
 
 import java.util.LinkedHashSet;
 
-import org.opends.server.types.ByteString;
-import org.opends.server.types.DereferencePolicy;
-import org.opends.server.types.DN;
-import org.opends.server.types.RawFilter;
-import org.opends.server.types.SearchScope;
-import org.opends.server.types.SearchFilter;
-
+import org.opends.server.types.*;
 
 
 /**
diff --git a/opends/src/server/org/opends/server/types/operation/SearchReferenceSearchOperation.java b/opends/src/server/org/opends/server/types/operation/SearchReferenceSearchOperation.java
index 7b3df52..c46e785 100644
--- a/opends/src/server/org/opends/server/types/operation/SearchReferenceSearchOperation.java
+++ b/opends/src/server/org/opends/server/types/operation/SearchReferenceSearchOperation.java
@@ -30,13 +30,7 @@
 
 import java.util.LinkedHashSet;
 
-import org.opends.server.types.ByteString;
-import org.opends.server.types.DereferencePolicy;
-import org.opends.server.types.DN;
-import org.opends.server.types.RawFilter;
-import org.opends.server.types.SearchScope;
-import org.opends.server.types.SearchFilter;
-
+import org.opends.server.types.*;
 
 
 /**
diff --git a/opends/src/server/org/opends/server/types/operation/SubordinateModifyDNOperation.java b/opends/src/server/org/opends/server/types/operation/SubordinateModifyDNOperation.java
index 8c271e4..419fe7a 100644
--- a/opends/src/server/org/opends/server/types/operation/SubordinateModifyDNOperation.java
+++ b/opends/src/server/org/opends/server/types/operation/SubordinateModifyDNOperation.java
@@ -28,11 +28,7 @@
 
 
 
-import org.opends.server.types.ByteString;
-import org.opends.server.types.DN;
-import org.opends.server.types.Entry;
-import org.opends.server.types.RDN;
-
+import org.opends.server.types.*;
 
 
 /**
diff --git a/opends/src/server/org/opends/server/util/Base64.java b/opends/src/server/org/opends/server/util/Base64.java
index 8d71e09..bb8a518 100644
--- a/opends/src/server/org/opends/server/util/Base64.java
+++ b/opends/src/server/org/opends/server/util/Base64.java
@@ -46,6 +46,7 @@
 import org.opends.messages.MessageBuilder;
 import org.opends.server.core.DirectoryServer;
 import org.opends.server.types.NullOutputStream;
+import org.opends.server.types.ByteSequence;
 import org.opends.server.util.args.ArgumentException;
 import org.opends.server.util.args.BooleanArgument;
 import org.opends.server.util.args.StringArgument;
@@ -133,6 +134,55 @@
     return buffer.toString();
   }
 
+  /**
+   * Encodes the provided raw data using base64.
+   *
+   * @param  rawData  The raw data to encode.  It must not be <CODE>null</CODE>.
+   *
+   * @return  The base64-encoded representation of the provided raw data.
+   */
+  public static String encode(ByteSequence rawData)
+  {
+    ensureNotNull(rawData);
+
+
+    StringBuilder buffer = new StringBuilder(4 * rawData.length() / 3);
+
+    int pos = 0;
+    int iterations = rawData.length() / 3;
+    for (int i=0; i < iterations; i++)
+    {
+      int value = ((rawData.byteAt(pos++) & 0xFF) << 16) |
+                  ((rawData.byteAt(pos++) & 0xFF) <<  8) |
+          (rawData.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 (rawData.length() % 3)
+    {
+      case 1:
+        buffer.append(BASE64_ALPHABET[(rawData.byteAt(pos) >>> 2) & 0x3F]);
+        buffer.append(BASE64_ALPHABET[(rawData.byteAt(pos) <<  4) & 0x3F]);
+        buffer.append("==");
+        break;
+      case 2:
+        int value = ((rawData.byteAt(pos++) & 0xFF) << 8) |
+            (rawData.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();
+  }
+
 
 
   /**
diff --git a/opends/src/server/org/opends/server/util/LDIFReader.java b/opends/src/server/org/opends/server/util/LDIFReader.java
index b350ceb..daba4f9 100644
--- a/opends/src/server/org/opends/server/util/LDIFReader.java
+++ b/opends/src/server/org/opends/server/util/LDIFReader.java
@@ -22,7 +22,7 @@
  * CDDL HEADER END
  *
  *
- *      Copyright 2006-2008 Sun Microsystems, Inc.
+ *      Copyright 2006-2009 Sun Microsystems, Inc.
  */
 package org.opends.server.util;
 import org.opends.messages.Message;
@@ -38,7 +38,6 @@
 
 import java.io.BufferedReader;
 import java.io.BufferedWriter;
-import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.net.URL;
@@ -49,25 +48,11 @@
 
 import org.opends.server.core.DirectoryServer;
 import org.opends.server.core.PluginConfigManager;
-import org.opends.server.protocols.asn1.ASN1OctetString;
 import org.opends.server.protocols.ldap.LDAPAttribute;
 import org.opends.server.protocols.ldap.LDAPModification;
-import org.opends.server.types.AcceptRejectWarn;
-import org.opends.server.types.Attribute;
-import org.opends.server.types.AttributeBuilder;
-import org.opends.server.types.AttributeType;
-import org.opends.server.types.AttributeValue;
-import org.opends.server.types.DirectoryException;
-import org.opends.server.types.DN;
-import org.opends.server.types.DebugLogLevel;
-import org.opends.server.types.Entry;
 
 
-import org.opends.server.types.LDIFImportConfig;
-import org.opends.server.types.ModificationType;
-import org.opends.server.types.ObjectClass;
-import org.opends.server.types.RawModification;
-import org.opends.server.types.RDN;
+import org.opends.server.types.*;
 import org.opends.server.api.plugin.PluginResult;
 
 
@@ -264,7 +249,7 @@
       // import.
       Entry entry =  new Entry(entryDN, objectClasses, userAttributes,
                                operationalAttributes);
-      TRACER.debugProtocolElement(DebugLogLevel.VERBOSE, entry);
+      TRACER.debugProtocolElement(DebugLogLevel.VERBOSE, entry.toString());
 
       try
       {
@@ -857,7 +842,7 @@
     final String lowerName = toLowerCase(attrName);
 
     // Now parse the attribute value.
-    ASN1OctetString value = parseSingleValue(lines, line, entryDN,
+    ByteString value = parseSingleValue(lines, line, entryDN,
         colonPos, attrName);
 
     // See if this is an objectclass or an attribute.  Then get the
@@ -874,7 +859,7 @@
         return;
       }
 
-      String ocName      = value.stringValue();
+      String ocName      = value.toString();
       String lowerOCName = toLowerCase(ocName);
 
       ObjectClass objectClass = DirectoryServer.getObjectClass(lowerOCName);
@@ -932,7 +917,7 @@
         {
           Message message = WARN_LDIF_VALUE_VIOLATES_SYNTAX.get(
                   String.valueOf(entryDN),
-                  lastEntryLineNumber, value.stringValue(),
+                  lastEntryLineNumber, value.toString(),
                   attrName, invalidReason.toString());
           if (DirectoryServer.getSyntaxEnforcementPolicy() ==
                    AcceptRejectWarn.WARN)
@@ -948,7 +933,8 @@
         }
       }
 
-      AttributeValue attributeValue = new AttributeValue(attrType, value);
+      AttributeValue attributeValue =
+          AttributeValues.create(attrType, value);
       List<Attribute> attrList;
       if (attrType.isOperational())
       {
@@ -1001,7 +987,7 @@
                   Message message = WARN_LDIF_DUPLICATE_ATTR.get(
                           String.valueOf(entryDN),
                           lastEntryLineNumber, attrName,
-                          value.stringValue());
+                          value.toString());
                   logToRejectWriter(lines, message);
                   throw new LDIFException(message, lastEntryLineNumber,
                                           true);
@@ -1013,7 +999,7 @@
               Message message = WARN_LDIF_DUPLICATE_ATTR.get(
                       String.valueOf(entryDN),
                       lastEntryLineNumber, attrName,
-                      value.stringValue());
+                      value.toString());
               logToRejectWriter(lines, message);
               throw new LDIFException(message, lastEntryLineNumber,
                                       true);
@@ -1088,12 +1074,12 @@
     }
 
     //  Now parse the attribute value.
-    ASN1OctetString value = parseSingleValue(lines, line, entryDN,
+    ByteString value = parseSingleValue(lines, line, entryDN,
         colonPos, attrName);
 
     AttributeBuilder builder = new AttributeBuilder(attribute, true);
     AttributeType attrType = attribute.getAttributeType();
-    builder.add(new AttributeValue(attrType, value));
+    builder.add(AttributeValues.create(attrType, value));
 
     return builder.toAttribute();
   }
@@ -1406,7 +1392,7 @@
   {
     Attribute attr =
       readSingleValueAttribute(lines, line, entryDN, attributeName);
-    return attr.iterator().next().getStringValue();
+    return attr.iterator().next().getValue().toString();
   }
 
 
@@ -1436,7 +1422,7 @@
       String name = attr.getName();
 
       // Get the attribute description
-      String attrDescr = attr.iterator().next().getStringValue();
+      String attrDescr = attr.iterator().next().getValue().toString();
 
       String lowerName = toLowerCase(name);
       if (lowerName.equals("add"))
@@ -1541,7 +1527,7 @@
     AttributeType ocType = DirectoryServer.getObjectClassAttributeType();
     AttributeBuilder builder = new AttributeBuilder(ocType, "objectClass");
     for (String value : objectClasses.values()) {
-      AttributeValue av = new AttributeValue(ocType, value);
+      AttributeValue av = AttributeValues.create(ocType, value);
       builder.add(av);
     }
     List<Attribute> ocAttrList = new ArrayList<Attribute>(1);
@@ -1597,7 +1583,7 @@
    * @throws LDIFException
    *           If an error occurred when parsing the attribute value.
    */
-  private ASN1OctetString parseSingleValue(
+  private ByteString parseSingleValue(
       LinkedList<StringBuilder> lines,
       StringBuilder line,
       DN entryDN,
@@ -1609,10 +1595,10 @@
     // 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.
     int length = line.length();
-    ASN1OctetString value;
+    ByteString value;
     if (colonPos == (length-1))
     {
-      value = new ASN1OctetString();
+      value = ByteString.empty();
     }
     else
     {
@@ -1629,7 +1615,7 @@
 
         try
         {
-          value = new ASN1OctetString(Base64.decode(line.substring(pos)));
+          value = ByteString.wrap(Base64.decode(line.substring(pos)));
         }
         catch (Exception e)
         {
@@ -1680,19 +1666,19 @@
 
 
         InputStream inputStream = null;
-        ByteArrayOutputStream outputStream = null;
+        ByteStringBuilder builder = null;
         try
         {
-          outputStream = new ByteArrayOutputStream();
+          builder = new ByteStringBuilder();
           inputStream  = contentURL.openConnection().getInputStream();
 
           int bytesRead;
           while ((bytesRead = inputStream.read(buffer)) > 0)
           {
-            outputStream.write(buffer, 0, bytesRead);
+            builder.append(buffer, 0, bytesRead);
           }
 
-          value = new ASN1OctetString(outputStream.toByteArray());
+          value = builder.toByteString();
         }
         catch (Exception e)
         {
@@ -1713,14 +1699,6 @@
         }
         finally
         {
-          if (outputStream != null)
-          {
-            try
-            {
-              outputStream.close();
-            } catch (Exception e) {}
-          }
-
           if (inputStream != null)
           {
             try
@@ -1740,7 +1718,7 @@
           pos++;
         }
 
-        value = new ASN1OctetString(line.substring(pos));
+        value = ByteString.valueOf(line.substring(pos));
       }
     }
     return value;
diff --git a/opends/src/server/org/opends/server/util/LDIFWriter.java b/opends/src/server/org/opends/server/util/LDIFWriter.java
index 1bdcde3..0e2125b 100644
--- a/opends/src/server/org/opends/server/util/LDIFWriter.java
+++ b/opends/src/server/org/opends/server/util/LDIFWriter.java
@@ -36,19 +36,8 @@
 import java.util.Collection;
 
 import org.opends.messages.Message;
-import org.opends.server.protocols.asn1.ASN1OctetString;
 import org.opends.server.loggers.debug.DebugTracer;
-import org.opends.server.types.Attribute;
-import org.opends.server.types.AttributeType;
-import org.opends.server.types.AttributeValue;
-import org.opends.server.types.DebugLogLevel;
-import org.opends.server.types.DN;
-import org.opends.server.types.Entry;
-import org.opends.server.types.LDIFExportConfig;
-import org.opends.server.types.Modification;
-import org.opends.server.types.RawAttribute;
-import org.opends.server.types.RawModification;
-import org.opends.server.types.RDN;
+import org.opends.server.types.*;
 
 import static org.opends.server.loggers.debug.DebugLogger.*;
 import static org.opends.server.util.StaticUtils.*;
@@ -283,7 +272,7 @@
     StringBuilder dnLine = new StringBuilder();
     dnLine.append("dn");
     appendLDIFSeparatorAndValue(dnLine,
-                                getBytes(changeRecord.getDN().toString()));
+        ByteString.valueOf(changeRecord.getDN().toString()));
     writeLDIFLine(dnLine, writer, wrapLines, wrapColumn);
 
 
@@ -300,17 +289,7 @@
         {
           StringBuilder line = new StringBuilder();
           line.append(a.getNameWithOptions());
-          String stringValue = v.getStringValue();
-          if (needsBase64Encoding(stringValue))
-          {
-            line.append(":: ");
-            line.append(Base64.encode(v.getValueBytes()));
-          }
-          else
-          {
-            line.append(": ");
-            line.append(stringValue);
-          }
+          appendLDIFSeparatorAndValue(line, v.getValue());
           writeLDIFLine(line, writer, wrapLines, wrapColumn);
         }
       }
@@ -340,16 +319,16 @@
         modTypeLine.append(attrName);
         writeLDIFLine(modTypeLine, writer, wrapLines, wrapColumn);
 
-        for (ASN1OctetString s : a.getValues())
+        for (ByteString s : a.getValues())
         {
           StringBuilder valueLine = new StringBuilder();
-          String stringValue = s.stringValue();
+          String stringValue = s.toString();
 
           valueLine.append(attrName);
           if (needsBase64Encoding(stringValue))
           {
             valueLine.append(":: ");
-            valueLine.append(Base64.encode(s.value()));
+            valueLine.append(Base64.encode(s));
           }
           else
           {
@@ -434,7 +413,8 @@
     // First, write the DN.
     StringBuilder dnLine = new StringBuilder();
     dnLine.append("dn");
-    appendLDIFSeparatorAndValue(dnLine, getBytes(entry.getDN().toString()));
+    appendLDIFSeparatorAndValue(dnLine,
+        ByteString.valueOf(entry.getDN().toString()));
     writeLDIFLine(dnLine, writer, wrapLines, wrapColumn);
 
 
@@ -470,7 +450,7 @@
         {
           StringBuilder attrLine = new StringBuilder();
           attrLine.append(attrName);
-          appendLDIFSeparatorAndValue(attrLine, v.getValueBytes());
+          appendLDIFSeparatorAndValue(attrLine, v.getValue());
           writeLDIFLine(attrLine, writer, wrapLines, wrapColumn);
         }
       }
@@ -510,7 +490,8 @@
     // Add the DN and changetype lines.
     StringBuilder dnLine = new StringBuilder();
     dnLine.append("dn");
-    appendLDIFSeparatorAndValue(dnLine, getBytes(entry.getDN().toString()));
+    appendLDIFSeparatorAndValue(dnLine,
+        ByteString.valueOf(entry.getDN().toString()));
     writeLDIFLine(dnLine, writer, wrapLines, wrapColumn);
 
     StringBuilder changeTypeLine = new StringBuilder("changetype: delete");
@@ -549,7 +530,7 @@
           {
             StringBuilder attrLine = new StringBuilder();
             attrLine.append(attrName);
-            appendLDIFSeparatorAndValue(attrLine, v.getValueBytes());
+            appendLDIFSeparatorAndValue(attrLine, v.getValue());
             writeLDIFLine(attrLine, writer, wrapLines, wrapColumn);
           }
         }
@@ -595,7 +576,7 @@
     // Write the DN and changetype.
     StringBuilder dnLine = new StringBuilder();
     dnLine.append("dn");
-    appendLDIFSeparatorAndValue(dnLine, getBytes(dn.toString()));
+    appendLDIFSeparatorAndValue(dnLine, ByteString.valueOf(dn.toString()));
     writeLDIFLine(dnLine, writer, wrapLines, wrapColumn);
 
     StringBuilder changeTypeLine = new StringBuilder("changetype: modify");
@@ -646,7 +627,7 @@
       {
         StringBuilder valueLine = new StringBuilder();
         valueLine.append(name);
-        appendLDIFSeparatorAndValue(valueLine, v.getValueBytes());
+        appendLDIFSeparatorAndValue(valueLine, v.getValue());
         writeLDIFLine(valueLine, writer, wrapLines, wrapColumn);
       }
 
@@ -699,7 +680,7 @@
     // Write the current DN.
     StringBuilder dnLine = new StringBuilder();
     dnLine.append("dn");
-    appendLDIFSeparatorAndValue(dnLine, getBytes(dn.toString()));
+    appendLDIFSeparatorAndValue(dnLine, ByteString.valueOf(dn.toString()));
     writeLDIFLine(dnLine, writer, wrapLines, wrapColumn);
 
 
@@ -721,7 +702,7 @@
     // Write the newRDN element.
     StringBuilder rdnLine = new StringBuilder();
     rdnLine.append("newrdn");
-    appendLDIFSeparatorAndValue(rdnLine, getBytes(newRDN.toString()));
+    appendLDIFSeparatorAndValue(rdnLine, ByteString.valueOf(newRDN.toString()));
     writeLDIFLine(rdnLine, writer, wrapLines, wrapColumn);
 
 
@@ -736,7 +717,7 @@
       StringBuilder newSuperiorLine = new StringBuilder();
       newSuperiorLine.append("newsuperior");
       appendLDIFSeparatorAndValue(newSuperiorLine,
-                                  getBytes(newSuperior.toString()));
+          ByteString.valueOf(newSuperior.toString()));
       writeLDIFLine(newSuperiorLine, writer, wrapLines, wrapColumn);
     }
 
@@ -787,14 +768,14 @@
    *                     <CODE>null</CODE>.
    */
   public static void appendLDIFSeparatorAndValue(StringBuilder buffer,
-                                                 byte[] valueBytes)
+                                                 ByteSequence valueBytes)
   {
     ensureNotNull(buffer, valueBytes);
 
 
     // If the value is empty, then just append a single colon and a single
     // space.
-    if ((valueBytes == null) || (valueBytes.length == 0))
+    if ((valueBytes == null) || (valueBytes.length() == 0))
     {
       buffer.append(": ");
       return;
@@ -809,20 +790,7 @@
     else
     {
       buffer.append(": ");
-
-      try
-      {
-        buffer.append(new String(valueBytes, "UTF-8"));
-      }
-      catch (Exception e)
-      {
-        // This should never happen.
-        if (debugEnabled())
-        {
-          TRACER.debugCaught(DebugLogLevel.ERROR, e);
-        }
-        buffer.append(new String(valueBytes));
-      }
+      buffer.append(valueBytes.toString());
     }
   }
 
diff --git a/opends/src/server/org/opends/server/util/ServerConstants.java b/opends/src/server/org/opends/server/util/ServerConstants.java
index 084cb82..15934a0 100644
--- a/opends/src/server/org/opends/server/util/ServerConstants.java
+++ b/opends/src/server/org/opends/server/util/ServerConstants.java
@@ -26,7 +26,7 @@
  */
 package org.opends.server.util;
 
-
+import org.opends.server.types.ByteString;
 
 /**
  * This class defines a set of constants that may be referenced throughout the
@@ -2969,5 +2969,20 @@
     "",
     "CDDL HEADER END"
   };
+
+  /**
+   * 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");
 }
 
diff --git a/opends/src/server/org/opends/server/util/SizeLimitInputStream.java b/opends/src/server/org/opends/server/util/SizeLimitInputStream.java
new file mode 100644
index 0000000..ca51ea5
--- /dev/null
+++ b/opends/src/server/org/opends/server/util/SizeLimitInputStream.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 2006-2009 Sun Microsystems, Inc.
+ */
+package org.opends.server.util;
+
+import java.io.InputStream;
+import java.io.IOException;
+
+/**
+ * An implementation of input stream that enforces an read size limit.
+ */
+public class SizeLimitInputStream extends InputStream
+{
+  private int bytesRead;
+  private int markBytesRead;
+  private int readLimit;
+  private InputStream parentStream;
+
+  /**
+   * Creates a new a new size limit input stream.
+   *
+   * @param parentStream
+   *          The parent stream.
+   * @param readLimit
+   *          The size limit.
+   */
+  public SizeLimitInputStream(InputStream parentStream, int readLimit)
+  {
+    this.parentStream = parentStream;
+    this.readLimit = readLimit;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  public int available() throws IOException
+  {
+    int streamAvail = parentStream.available();
+    int limitedAvail = readLimit - bytesRead;
+    return limitedAvail < streamAvail ? limitedAvail : streamAvail;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  public synchronized void mark(int readlimit)
+  {
+    parentStream.mark(readlimit);
+    markBytesRead = bytesRead;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  public int read() throws IOException
+  {
+    if(bytesRead >= readLimit)
+    {
+      return -1;
+    }
+
+    int b = parentStream.read();
+    if (b != -1)
+    {
+      ++bytesRead;
+    }
+    return b;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  public int read(byte b[], 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;
+    }
+
+    int readLen = parentStream.read(b, off, len);
+    if(readLen > 0)
+    {
+      bytesRead += readLen;
+    }
+    return readLen;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  public synchronized void reset() throws IOException
+  {
+    parentStream.reset();
+    bytesRead = markBytesRead;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  public long skip(long n) throws IOException
+  {
+    if(bytesRead + n > readLimit)
+    {
+      n = readLimit - bytesRead;
+    }
+
+    bytesRead += n;
+    return parentStream.skip(n);
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  public boolean markSupported() {
+    return parentStream.markSupported();
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  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;
+  }
+}
diff --git a/opends/src/server/org/opends/server/util/StaticUtils.java b/opends/src/server/org/opends/server/util/StaticUtils.java
index ce001b2..c14119b 100644
--- a/opends/src/server/org/opends/server/util/StaticUtils.java
+++ b/opends/src/server/org/opends/server/util/StaticUtils.java
@@ -22,52 +22,56 @@
  * CDDL HEADER END
  *
  *
- *      Copyright 2006-2008 Sun Microsystems, Inc.
+ *      Copyright 2006-2009 Sun Microsystems, Inc.
  */
 package org.opends.server.util;
 
+import static org.opends.messages.CoreMessages.*;
 import static org.opends.messages.UtilityMessages.*;
 import static org.opends.server.loggers.debug.DebugLogger.*;
 import static org.opends.server.util.ServerConstants.*;
-import org.opends.server.util.args.ArgumentException;
-import org.opends.server.util.args.Argument;
 
 import java.io.BufferedReader;
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.FileOutputStream;
 import java.io.IOException;
-import java.io.InputStreamReader;
 import java.io.InputStream;
+import java.io.InputStreamReader;
 import java.lang.reflect.InvocationTargetException;
 import java.net.InetAddress;
 import java.net.InetSocketAddress;
 import java.net.ServerSocket;
 import java.net.Socket;
 import java.nio.ByteBuffer;
+import java.nio.channels.SelectionKey;
+import java.nio.channels.Selector;
+import java.nio.channels.SocketChannel;
 import java.text.ParseException;
 import java.text.SimpleDateFormat;
 import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Date;
+import java.util.Iterator;
 import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.RandomAccess;
 import java.util.StringTokenizer;
-import java.util.Date;
 import java.util.TimeZone;
-import java.util.Collection;
-import java.util.Iterator;
 
 import org.opends.messages.Message;
 import org.opends.messages.MessageBuilder;
 import org.opends.messages.MessageDescriptor;
 import org.opends.messages.ToolMessages;
+import org.opends.server.api.ClientConnection;
 import org.opends.server.core.DirectoryServer;
 import org.opends.server.loggers.debug.DebugTracer;
 import org.opends.server.types.Attribute;
 import org.opends.server.types.AttributeBuilder;
 import org.opends.server.types.AttributeType;
 import org.opends.server.types.AttributeValue;
+import org.opends.server.types.ByteSequence;
 import org.opends.server.types.DN;
 import org.opends.server.types.DebugLogLevel;
 import org.opends.server.types.DirectoryException;
@@ -76,7 +80,8 @@
 import org.opends.server.types.ObjectClass;
 import org.opends.server.types.RDN;
 import org.opends.server.types.ResultCode;
-import static org.opends.messages.CoreMessages.*;
+import org.opends.server.util.args.Argument;
+import org.opends.server.util.args.ArgumentException;
 
 
 /**
@@ -1398,6 +1403,48 @@
 
 
   /**
+   * Compare two byte arrays for order. Returns a negative integer,
+   * zero, or a positive integer as the first argument is less than,
+   * equal to, or greater than the second.
+   *
+   * @param a
+   *          The first byte array to be compared.
+   * @param a2
+   *          The second byte array to be compared.
+   * @return Returns a negative integer, zero, or a positive integer
+   *         if the first byte array is less than, equal to, or greater
+   *         than the second.
+   */
+  public static int compare(ByteSequence a, ByteSequence a2) {
+    if (a == a2) {
+      return 0;
+    }
+
+    if (a == null) {
+      return -1;
+    }
+
+    if (a2 == null) {
+      return 1;
+    }
+
+    int minLength = Math.min(a.length(), a2.length());
+    for (int i = 0; i < minLength; i++) {
+      if (a.byteAt(i) != a2.byteAt(i)) {
+        if (a.byteAt(i) < a2.byteAt(i)) {
+          return -1;
+        } else if (a.byteAt(i) > a2.byteAt(i)) {
+          return 1;
+        }
+      }
+    }
+
+    return (a.length() - a2.length());
+  }
+
+
+
+  /**
    * Indicates whether the two array lists are equal. They will be
    * considered equal if they have the same number of elements, and
    * the corresponding elements between them are equal (in the same
@@ -2203,10 +2250,10 @@
    * @return  <CODE>true</CODE> if the value needs to be base64-encoded if it is
    *          represented in LDIF form, or <CODE>false</CODE> if not.
    */
-  public static boolean needsBase64Encoding(byte[] valueBytes)
+  public static boolean needsBase64Encoding(ByteSequence valueBytes)
   {
     int length;
-    if ((valueBytes == null) || ((length = valueBytes.length) == 0))
+    if ((valueBytes == null) || ((length = valueBytes.length()) == 0))
     {
       return false;
     }
@@ -2214,7 +2261,7 @@
 
     // If the value starts with a space, colon, or less than, then it needs to
     // be base64-encoded.
-    switch (valueBytes[0])
+    switch (valueBytes.byteAt(0))
     {
       case 0x20: // Space
       case 0x3A: // Colon
@@ -2224,7 +2271,7 @@
 
 
     // If the value ends with a space, then it needs to be base64-encoded.
-    if ((length > 1) && (valueBytes[length-1] == 0x20))
+    if ((length > 1) && (valueBytes.byteAt(length-1) == 0x20))
     {
       return true;
     }
@@ -2232,8 +2279,10 @@
 
     // If the value contains a null, newline, or return character, then it needs
     // to be base64-encoded.
-    for (byte b : valueBytes)
+    byte b;
+    for (int i = 0; i < valueBytes.length(); i++)
     {
+      b = valueBytes.byteAt(i);
       if ((b > 127) || (b < 0))
       {
         return true;
@@ -2825,35 +2874,27 @@
    * @param  trim    Indicates whether leading and trailing spaces should be
    *                 omitted from the string representation.
    */
-  public static void toLowerCase(byte[] b, StringBuilder buffer, boolean trim)
+  public static void toLowerCase(ByteSequence b, StringBuilder buffer,
+                                 boolean trim)
   {
     if (b == null)
     {
       return;
     }
 
-    int length = b.length;
+    int origBufferLen = buffer.length();
+    int length = b.length();
     for (int i=0; i < length; i++)
     {
-      if ((b[i] & 0x7F) != b[i])
+      if ((b.byteAt(i) & 0x7F) != b.byteAt(i))
       {
-        try
-        {
-          buffer.append(new String(b, i, (length-i), "UTF-8").toLowerCase());
-        }
-        catch (Exception e)
-        {
-          if (debugEnabled())
-          {
-            TRACER.debugCaught(DebugLogLevel.ERROR, e);
-          }
-          buffer.append(new String(b, i, (length - i)).toLowerCase());
-        }
+        buffer.replace(origBufferLen, buffer.length(),
+            b.toString().toLowerCase());
         break;
       }
 
       int bufferLength = buffer.length();
-      switch (b[i])
+      switch (b.byteAt(i))
       {
         case ' ':
           // If we don't care about trimming, then we can always append the
@@ -2945,7 +2986,7 @@
           buffer.append('z');
           break;
         default:
-          buffer.append((char) b[i]);
+          buffer.append((char) b.byteAt(i));
       }
     }
 
@@ -4121,161 +4162,292 @@
 
 
 
-   /**
-    * Evaluates  and converts 2 consequetive characters  of the provided
-    * string starting at startPos and converts them into a single escaped char.
-    *
-    * @param  hexString  The hexadecimal string containing
-    *                 the escape sequence.
-    * @param startPos The starting position of the hexadecimal escape
-    *                  sequence.
-    *
-    * @return The escaped character
-    *
-    * @throws  DirectoryException  If the provided string contains invalid
-    *                          hexadecimal digits .
+  /**
+   * Writes the contents of the provided buffer to the client,
+   * terminating the connection if the write is unsuccessful for too
+   * long (e.g., if the client is unresponsive or there is a network
+   * problem). If possible, it will attempt to use the selector returned
+   * by the {@code ClientConnection.getWriteSelector} method, but it is
+   * capable of working even if that method returns {@code null}. <BR>
+   * <BR>
+   * Note that this method has been written in a generic manner so that
+   * other connection security providers can use it to send data to the
+   * client, provided that the given buffer contains the appropriate
+   * pre-encoded information. <BR>
+   * <BR>
+   * Also note that the original position and limit values will not be
+   * preserved, so if that is important to the caller, then it should
+   * record them before calling this method and restore them after it
+   * returns.
+   *
+   * @param clientConnection
+   *          The client connection to which the data is to be written.
+   * @param socketChannel
+   *          The socket channel over which to write the data.
+   * @param buffer
+   *          The data to be written to the client.
+   * @return <CODE>true</CODE> if all the data in the provided buffer was
+   *         written to the client and the connection may remain
+   *         established, or <CODE>false</CODE> if a problem occurred
+   *         and the client connection is no longer valid. Note that if
+   *         this method does return <CODE>false</CODE>, then it must
+   *         have already disconnected the client.
+   * @throws IOException
+   *           If a problem occurs while attempting to write data to the
+   *           client. The caller will be responsible for catching this
+   *           and terminating the client connection.
    */
-  public static char hexToEscapedChar(String hexString,int startPos)
-          throws DirectoryException
+  public static boolean writeWithTimeout(
+      ClientConnection clientConnection, SocketChannel socketChannel,
+      ByteBuffer buffer) throws IOException
   {
+    long startTime = System.currentTimeMillis();
+    long waitTime = clientConnection.getMaxBlockedWriteTimeLimit();
+    if (waitTime <= 0)
+    {
+      // We won't support an infinite time limit, so fall back to using
+      // five minutes, which is a very long timeout given that we're
+      // blocking a worker thread.
+      waitTime = 300000L;
+    }
 
-    // The two positions  must be the hex characters that
+    long stopTime = startTime + waitTime;
+
+    Selector selector = clientConnection.getWriteSelector();
+    if (selector == null)
+    {
+      // The client connection does not provide a selector, so we'll
+      // fall back
+      // to a more inefficient way that will work without a selector.
+      while (buffer.hasRemaining()
+          && (System.currentTimeMillis() < stopTime))
+      {
+        if (socketChannel.write(buffer) < 0)
+        {
+          // The client connection has been closed.
+          return false;
+        }
+      }
+
+      if (buffer.hasRemaining())
+      {
+        // If we've gotten here, then the write timed out.
+        return false;
+      }
+
+      return true;
+    }
+
+    // Register with the selector for handling write operations.
+    SelectionKey key =
+        socketChannel.register(selector, SelectionKey.OP_WRITE);
+
+    try
+    {
+      selector.select(waitTime);
+      while (buffer.hasRemaining())
+      {
+        long currentTime = System.currentTimeMillis();
+        if (currentTime >= stopTime)
+        {
+          // We've been blocked for too long.
+          return false;
+        }
+        else
+        {
+          waitTime = stopTime - currentTime;
+        }
+
+        Iterator<SelectionKey> iterator =
+            selector.selectedKeys().iterator();
+        while (iterator.hasNext())
+        {
+          SelectionKey k = iterator.next();
+          if (k.isWritable())
+          {
+            int bytesWritten = socketChannel.write(buffer);
+            if (bytesWritten < 0)
+            {
+              // The client connection has been closed.
+              return false;
+            }
+
+            iterator.remove();
+          }
+        }
+
+        if (buffer.hasRemaining())
+        {
+          selector.select(waitTime);
+        }
+      }
+
+      return true;
+    }
+    finally
+    {
+      if (key.isValid())
+      {
+        key.cancel();
+        selector.selectNow();
+      }
+    }
+  }
+
+
+
+  /**
+   * Evaluates and converts 2 consequetive characters of the provided
+   * string starting at startPos and converts them into a single escaped
+   * char.
+   *
+   * @param hexString
+   *          The hexadecimal string containing the escape sequence.
+   * @param startPos
+   *          The starting position of the hexadecimal escape sequence.
+   * @return The escaped character
+   * @throws DirectoryException
+   *           If the provided string contains invalid hexadecimal
+   *           digits .
+   */
+  public static char hexToEscapedChar(String hexString, int startPos)
+      throws DirectoryException
+  {
+    // The two positions must be the hex characters that
     // comprise the escaped value.
-    if ((startPos+ 1) >= hexString.length())
+    if ((startPos + 1) >= hexString.length())
     {
       Message message =
-          ERR_SEARCH_FILTER_INVALID_ESCAPED_BYTE.
-            get(hexString, startPos+1);
+          ERR_SEARCH_FILTER_INVALID_ESCAPED_BYTE.get(hexString,
+              startPos + 1);
 
-      throw new DirectoryException(ResultCode.PROTOCOL_ERROR,
-                                   message);
+      throw new DirectoryException(ResultCode.PROTOCOL_ERROR, message);
     }
     byte byteValue = 0;
-    switch(hexString.charAt(startPos))
+    switch (hexString.charAt(startPos))
     {
-      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:
-        Message message =
-                      ERR_SEARCH_FILTER_INVALID_ESCAPED_BYTE.
-                        get(hexString, startPos);
-        throw new DirectoryException(
-                                 ResultCode.PROTOCOL_ERROR, message);
+    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:
+      Message message =
+          ERR_SEARCH_FILTER_INVALID_ESCAPED_BYTE.get(hexString,
+              startPos);
+      throw new DirectoryException(ResultCode.PROTOCOL_ERROR, message);
     }
 
     switch (hexString.charAt(++startPos))
     {
-      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:
-        Message message =ERR_SEARCH_FILTER_INVALID_ESCAPED_BYTE.
-                        get(hexString, startPos);
-        throw new DirectoryException(
-                                 ResultCode.PROTOCOL_ERROR, message);
+    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:
+      Message message =
+          ERR_SEARCH_FILTER_INVALID_ESCAPED_BYTE.get(hexString,
+              startPos);
+      throw new DirectoryException(ResultCode.PROTOCOL_ERROR, message);
     }
-    return (char)byteValue;
+    return (char) byteValue;
   }
 }
 
diff --git a/opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendAddOperation.java b/opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendAddOperation.java
index f1fdefe..2f6cd3f 100644
--- a/opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendAddOperation.java
+++ b/opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendAddOperation.java
@@ -70,27 +70,7 @@
 import org.opends.server.loggers.debug.DebugTracer;
 import org.opends.server.schema.AuthPasswordSyntax;
 import org.opends.server.schema.UserPasswordSyntax;
-import org.opends.server.types.Attribute;
-import org.opends.server.types.AttributeBuilder;
-import org.opends.server.types.AttributeType;
-import org.opends.server.types.AttributeValue;
-import org.opends.server.types.Attributes;
-import org.opends.server.types.ByteString;
-import org.opends.server.types.CanceledOperationException;
-import org.opends.server.types.Control;
-import org.opends.server.types.DN;
-import org.opends.server.types.DebugLogLevel;
-import org.opends.server.types.DirectoryException;
-import org.opends.server.types.Entry;
-import org.opends.server.types.LDAPException;
-import org.opends.server.types.LockManager;
-import org.opends.server.types.ObjectClass;
-import org.opends.server.types.Privilege;
-import org.opends.server.types.RDN;
-import org.opends.server.types.ResultCode;
-import org.opends.server.types.SearchFilter;
-import org.opends.server.types.SearchResultEntry;
-import org.opends.server.types.SynchronizationProviderResult;
+import org.opends.server.types.*;
 import org.opends.server.types.operation.PostOperationAddOperation;
 import org.opends.server.types.operation.PostResponseAddOperation;
 import org.opends.server.types.operation.PostSynchronizationAddOperation;
@@ -1221,7 +1201,8 @@
         for (PasswordStorageScheme s : defaultStorageSchemes)
         {
           ByteString encodedValue = s.encodeAuthPassword(value);
-          builder.add(new AttributeValue(passwordAttribute, encodedValue));
+          builder.add(AttributeValues.create(
+              passwordAttribute, encodedValue));
         }
       }
       else
@@ -1229,7 +1210,8 @@
         for (PasswordStorageScheme s : defaultStorageSchemes)
         {
           ByteString encodedValue = s.encodePasswordWithScheme(value);
-          builder.add(new AttributeValue(passwordAttribute, encodedValue));
+          builder.add(AttributeValues.create(
+              passwordAttribute, encodedValue));
         }
       }
     }
@@ -1317,10 +1299,10 @@
                   if (! syntax.valueIsAcceptable(v.getValue(), invalidReason))
                   {
                     Message message = WARN_ADD_OP_INVALID_SYNTAX.get(
-                                           String.valueOf(entryDN),
-                                           String.valueOf(v.getStringValue()),
-                                           String.valueOf(a.getName()),
-                                           String.valueOf(invalidReason));
+                                        String.valueOf(entryDN),
+                                        String.valueOf(v.getValue().toString()),
+                                        String.valueOf(a.getName()),
+                                        String.valueOf(invalidReason));
 
                     throw new DirectoryException(
                                    ResultCode.INVALID_ATTRIBUTE_SYNTAX,
@@ -1346,7 +1328,7 @@
                   {
                     Message message = WARN_ADD_OP_INVALID_SYNTAX.
                         get(String.valueOf(entryDN),
-                            String.valueOf(v.getStringValue()),
+                            String.valueOf(v.getValue().toString()),
                             String.valueOf(a.getName()),
                             String.valueOf(invalidReason));
 
@@ -1378,7 +1360,7 @@
                   {
                     logError(WARN_ADD_OP_INVALID_SYNTAX.get(
                                   String.valueOf(entryDN),
-                                  String.valueOf(v.getStringValue()),
+                                  String.valueOf(v.getValue().toString()),
                                   String.valueOf(a.getName()),
                                   String.valueOf(invalidReason)));
                   }
@@ -1401,7 +1383,7 @@
                   {
                     logError(WARN_ADD_OP_INVALID_SYNTAX.get(
                                   String.valueOf(entryDN),
-                                  String.valueOf(v.getStringValue()),
+                                  String.valueOf(v.getValue().toString()),
                                   String.valueOf(a.getName()),
                                   String.valueOf(invalidReason)));
                   }
@@ -1481,30 +1463,8 @@
 
         if (oid.equals(OID_LDAP_ASSERTION))
         {
-          LDAPAssertionRequestControl assertControl;
-          if (c instanceof LDAPAssertionRequestControl)
-          {
-            assertControl = (LDAPAssertionRequestControl) c;
-          }
-          else
-          {
-            try
-            {
-              assertControl = LDAPAssertionRequestControl.decodeControl(c);
-              requestControls.set(i, assertControl);
-            }
-            catch (LDAPException le)
-            {
-              if (debugEnabled())
-              {
-                TRACER.debugCaught(DebugLogLevel.ERROR, le);
-              }
-
-              throw new DirectoryException(
-                             ResultCode.valueOf(le.getResultCode()),
-                             le.getMessageObject());
-            }
-          }
+          LDAPAssertionRequestControl assertControl =
+            getRequestControl(LDAPAssertionRequestControl.DECODER);
 
           try
           {
@@ -1542,29 +1502,8 @@
         }
         else if (oid.equals(OID_LDAP_READENTRY_POSTREAD))
         {
-          if (c instanceof LDAPPostReadRequestControl)
-          {
-            postReadRequest = (LDAPPostReadRequestControl) c;
-          }
-          else
-          {
-            try
-            {
-              postReadRequest = LDAPPostReadRequestControl.decodeControl(c);
-              requestControls.set(i, postReadRequest);
-            }
-            catch (LDAPException le)
-            {
-              if (debugEnabled())
-              {
-                TRACER.debugCaught(DebugLogLevel.ERROR, le);
-              }
-
-              throw new DirectoryException(
-                             ResultCode.valueOf(le.getResultCode()),
-                             le.getMessageObject());
-            }
-          }
+          postReadRequest =
+                getRequestControl(LDAPPostReadRequestControl.DECODER);
         }
         else if (oid.equals(OID_PROXIED_AUTH_V1))
         {
@@ -1577,31 +1516,8 @@
                            ERR_PROXYAUTH_INSUFFICIENT_PRIVILEGES.get());
           }
 
-
-          ProxiedAuthV1Control proxyControl;
-          if (c instanceof ProxiedAuthV1Control)
-          {
-            proxyControl = (ProxiedAuthV1Control) c;
-          }
-          else
-          {
-            try
-            {
-              proxyControl = ProxiedAuthV1Control.decodeControl(c);
-            }
-            catch (LDAPException le)
-            {
-              if (debugEnabled())
-              {
-                TRACER.debugCaught(DebugLogLevel.ERROR, le);
-              }
-
-              throw new DirectoryException(
-                             ResultCode.valueOf(le.getResultCode()),
-                             le.getMessageObject());
-            }
-          }
-
+          ProxiedAuthV1Control proxyControl =
+              getRequestControl(ProxiedAuthV1Control.DECODER);
 
           Entry authorizationEntry = proxyControl.getAuthorizationEntry();
           setAuthorizationEntry(authorizationEntry);
@@ -1622,34 +1538,11 @@
                                                    this))
           {
             throw new DirectoryException(ResultCode.AUTHORIZATION_DENIED,
-                           ERR_PROXYAUTH_INSUFFICIENT_PRIVILEGES.get());
+                ERR_PROXYAUTH_INSUFFICIENT_PRIVILEGES.get());
           }
 
-
-          ProxiedAuthV2Control proxyControl;
-          if (c instanceof ProxiedAuthV2Control)
-          {
-            proxyControl = (ProxiedAuthV2Control) c;
-          }
-          else
-          {
-            try
-            {
-              proxyControl = ProxiedAuthV2Control.decodeControl(c);
-            }
-            catch (LDAPException le)
-            {
-              if (debugEnabled())
-              {
-                TRACER.debugCaught(DebugLogLevel.ERROR, le);
-              }
-
-              throw new DirectoryException(
-                             ResultCode.valueOf(le.getResultCode()),
-                             le.getMessageObject());
-            }
-          }
-
+          ProxiedAuthV2Control proxyControl =
+              getRequestControl(ProxiedAuthV2Control.DECODER);
 
           Entry authorizationEntry = proxyControl.getAuthorizationEntry();
           setAuthorizationEntry(authorizationEntry);
@@ -1731,9 +1624,7 @@
     //          out..
     SearchResultEntry searchEntry = new SearchResultEntry(addedEntry);
     LDAPPostReadResponseControl responseControl =
-         new LDAPPostReadResponseControl(postReadRequest.getOID(),
-                                         postReadRequest.isCritical(),
-                                         searchEntry);
+         new LDAPPostReadResponseControl(searchEntry);
     addResponseControl(responseControl);
   }
 }
diff --git a/opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendBindOperation.java b/opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendBindOperation.java
index aa6e895..bce9971 100644
--- a/opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendBindOperation.java
+++ b/opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendBindOperation.java
@@ -481,7 +481,7 @@
     // See if this is an anonymous bind.  If so, then determine whether
     // to allow it.
     ByteString simplePassword = getSimplePassword();
-    if ((simplePassword == null) || (simplePassword.value().length == 0))
+    if ((simplePassword == null) || (simplePassword.length() == 0))
     {
       return processAnonymousSimpleBind();
     }
@@ -1141,7 +1141,7 @@
         {
           try
           {
-            sizeLimit = Integer.parseInt(v.getStringValue());
+            sizeLimit = Integer.parseInt(v.getValue().toString());
           }
           catch (Exception e)
           {
@@ -1151,7 +1151,7 @@
             }
 
             logError(WARN_BIND_CANNOT_PROCESS_USER_SIZE_LIMIT.get(
-                          v.getStringValue(),
+                          v.getValue().toString(),
                           String.valueOf(userEntry.getDN())));
           }
         }
@@ -1178,7 +1178,7 @@
         {
           try
           {
-            timeLimit = Integer.parseInt(v.getStringValue());
+            timeLimit = Integer.parseInt(v.getValue().toString());
           }
           catch (Exception e)
           {
@@ -1188,7 +1188,7 @@
             }
 
             logError(WARN_BIND_CANNOT_PROCESS_USER_TIME_LIMIT.get(
-                          v.getStringValue(),
+                          v.getValue().toString(),
                           String.valueOf(userEntry.getDN())));
           }
         }
@@ -1216,7 +1216,7 @@
         {
           try
           {
-            idleTimeLimit = 1000L * Long.parseLong(v.getStringValue());
+            idleTimeLimit = 1000L * Long.parseLong(v.getValue().toString());
           }
           catch (Exception e)
           {
@@ -1226,7 +1226,7 @@
             }
 
             logError(WARN_BIND_CANNOT_PROCESS_USER_IDLE_TIME_LIMIT.get(
-                          v.getStringValue(),
+                          v.getValue().toString(),
                           String.valueOf(userEntry.getDN())));
           }
         }
@@ -1254,7 +1254,7 @@
         {
           try
           {
-            lookthroughLimit = Integer.parseInt(v.getStringValue());
+            lookthroughLimit = Integer.parseInt(v.getValue().toString());
           }
           catch (Exception e)
           {
@@ -1264,7 +1264,7 @@
             }
 
             logError(WARN_BIND_CANNOT_PROCESS_USER_LOOKTHROUGH_LIMIT.get(
-                          v.getStringValue(),
+                          v.getValue().toString(),
                           String.valueOf(userEntry.getDN())));
           }
         }
diff --git a/opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendCompareOperation.java b/opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendCompareOperation.java
index 83d2279..0c0aa6b 100644
--- a/opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendCompareOperation.java
+++ b/opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendCompareOperation.java
@@ -349,7 +349,7 @@
         }
         else
         {
-          AttributeValue value = new AttributeValue(attrType,
+          AttributeValue value = AttributeValues.create(attrType,
                                                     getAssertionValue());
 
           boolean matchFound = false;
@@ -426,30 +426,8 @@
 
         if (oid.equals(OID_LDAP_ASSERTION))
         {
-          LDAPAssertionRequestControl assertControl;
-          if (c instanceof LDAPAssertionRequestControl)
-          {
-            assertControl = (LDAPAssertionRequestControl) c;
-          }
-          else
-          {
-            try
-            {
-              assertControl = LDAPAssertionRequestControl.decodeControl(c);
-              requestControls.set(i, assertControl);
-            }
-            catch (LDAPException le)
-            {
-              if (debugEnabled())
-              {
-                TRACER.debugCaught(DebugLogLevel.ERROR, le);
-              }
-
-              throw new DirectoryException(
-                             ResultCode.valueOf(le.getResultCode()),
-                             le.getMessageObject());
-            }
-          }
+          LDAPAssertionRequestControl assertControl =
+                getRequestControl(LDAPAssertionRequestControl.DECODER);
 
           try
           {
@@ -491,31 +469,8 @@
                            ERR_PROXYAUTH_INSUFFICIENT_PRIVILEGES.get());
           }
 
-
-          ProxiedAuthV1Control proxyControl;
-          if (c instanceof ProxiedAuthV1Control)
-          {
-            proxyControl = (ProxiedAuthV1Control) c;
-          }
-          else
-          {
-            try
-            {
-              proxyControl = ProxiedAuthV1Control.decodeControl(c);
-            }
-            catch (LDAPException le)
-            {
-              if (debugEnabled())
-              {
-                TRACER.debugCaught(DebugLogLevel.ERROR, le);
-              }
-
-              throw new DirectoryException(
-                             ResultCode.valueOf(le.getResultCode()),
-                             le.getMessageObject());
-            }
-          }
-
+          ProxiedAuthV1Control proxyControl =
+                getRequestControl(ProxiedAuthV1Control.DECODER);
 
           Entry authorizationEntry = proxyControl.getAuthorizationEntry();
           setAuthorizationEntry(authorizationEntry);
@@ -538,31 +493,8 @@
                            ERR_PROXYAUTH_INSUFFICIENT_PRIVILEGES.get());
           }
 
-
-          ProxiedAuthV2Control proxyControl;
-          if (c instanceof ProxiedAuthV2Control)
-          {
-            proxyControl = (ProxiedAuthV2Control) c;
-          }
-          else
-          {
-            try
-            {
-              proxyControl = ProxiedAuthV2Control.decodeControl(c);
-            }
-            catch (LDAPException le)
-            {
-              if (debugEnabled())
-              {
-                TRACER.debugCaught(DebugLogLevel.ERROR, le);
-              }
-
-              throw new DirectoryException(
-                             ResultCode.valueOf(le.getResultCode()),
-                             le.getMessageObject());
-            }
-          }
-
+          ProxiedAuthV2Control proxyControl =
+              getRequestControl(ProxiedAuthV2Control.DECODER);
 
           Entry authorizationEntry = proxyControl.getAuthorizationEntry();
           setAuthorizationEntry(authorizationEntry);
diff --git a/opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendDeleteOperation.java b/opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendDeleteOperation.java
index 152baef..424a1cf 100644
--- a/opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendDeleteOperation.java
+++ b/opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendDeleteOperation.java
@@ -38,11 +38,7 @@
 import org.opends.server.api.ClientConnection;
 import org.opends.server.api.SynchronizationProvider;
 import org.opends.server.api.plugin.PluginResult;
-import org.opends.server.controls.LDAPAssertionRequestControl;
-import org.opends.server.controls.LDAPPreReadRequestControl;
-import org.opends.server.controls.LDAPPreReadResponseControl;
-import org.opends.server.controls.ProxiedAuthV1Control;
-import org.opends.server.controls.ProxiedAuthV2Control;
+import org.opends.server.controls.*;
 import org.opends.server.core.AccessControlConfigManager;
 import org.opends.server.core.DeleteOperationWrapper;
 import org.opends.server.core.DeleteOperation;
@@ -57,7 +53,6 @@
 import org.opends.server.types.DirectoryException;
 import org.opends.server.types.DN;
 import org.opends.server.types.Entry;
-import org.opends.server.types.LDAPException;
 import org.opends.server.types.LockManager;
 import org.opends.server.types.Privilege;
 import org.opends.server.types.ResultCode;
@@ -513,30 +508,8 @@
 
         if (oid.equals(OID_LDAP_ASSERTION))
         {
-          LDAPAssertionRequestControl assertControl;
-          if (c instanceof LDAPAssertionRequestControl)
-          {
-            assertControl = (LDAPAssertionRequestControl) c;
-          }
-          else
-          {
-            try
-            {
-              assertControl = LDAPAssertionRequestControl.decodeControl(c);
-              requestControls.set(i, assertControl);
-            }
-            catch (LDAPException le)
-            {
-              if (debugEnabled())
-              {
-                TRACER.debugCaught(DebugLogLevel.ERROR, le);
-              }
-
-              throw new DirectoryException(
-                             ResultCode.valueOf(le.getResultCode()),
-                             le.getMessageObject());
-            }
-          }
+          LDAPAssertionRequestControl assertControl =
+                getRequestControl(LDAPAssertionRequestControl.DECODER);
 
           try
           {
@@ -574,29 +547,8 @@
         }
         else if (oid.equals(OID_LDAP_READENTRY_PREREAD))
         {
-          if (c instanceof LDAPPreReadRequestControl)
-          {
-            preReadRequest = (LDAPPreReadRequestControl) c;
-          }
-          else
-          {
-            try
-            {
-              preReadRequest = LDAPPreReadRequestControl.decodeControl(c);
-              requestControls.set(i, preReadRequest);
-            }
-            catch (LDAPException le)
-            {
-              if (debugEnabled())
-              {
-                TRACER.debugCaught(DebugLogLevel.ERROR, le);
-              }
-
-              throw new DirectoryException(
-                             ResultCode.valueOf(le.getResultCode()),
-                             le.getMessageObject());
-            }
-          }
+          preReadRequest =
+                getRequestControl(LDAPPreReadRequestControl.DECODER);
         }
         else if (oid.equals(OID_PROXIED_AUTH_V1))
         {
@@ -608,31 +560,8 @@
                            ERR_PROXYAUTH_INSUFFICIENT_PRIVILEGES.get());
           }
 
-
-          ProxiedAuthV1Control proxyControl;
-          if (c instanceof ProxiedAuthV1Control)
-          {
-            proxyControl = (ProxiedAuthV1Control) c;
-          }
-          else
-          {
-            try
-            {
-              proxyControl = ProxiedAuthV1Control.decodeControl(c);
-            }
-            catch (LDAPException le)
-            {
-              if (debugEnabled())
-              {
-                TRACER.debugCaught(DebugLogLevel.ERROR, le);
-              }
-
-              throw new DirectoryException(
-                             ResultCode.valueOf(le.getResultCode()),
-                             le.getMessageObject());
-            }
-          }
-
+          ProxiedAuthV1Control proxyControl =
+              getRequestControl(ProxiedAuthV1Control.DECODER);
 
           Entry authorizationEntry = proxyControl.getAuthorizationEntry();
           setAuthorizationEntry(authorizationEntry);
@@ -655,31 +584,8 @@
                            ERR_PROXYAUTH_INSUFFICIENT_PRIVILEGES.get());
           }
 
-
-          ProxiedAuthV2Control proxyControl;
-          if (c instanceof ProxiedAuthV2Control)
-          {
-            proxyControl = (ProxiedAuthV2Control) c;
-          }
-          else
-          {
-            try
-            {
-              proxyControl = ProxiedAuthV2Control.decodeControl(c);
-            }
-            catch (LDAPException le)
-            {
-              if (debugEnabled())
-              {
-                TRACER.debugCaught(DebugLogLevel.ERROR, le);
-              }
-
-              throw new DirectoryException(
-                             ResultCode.valueOf(le.getResultCode()),
-                             le.getMessageObject());
-            }
-          }
-
+          ProxiedAuthV2Control proxyControl =
+              getRequestControl(ProxiedAuthV2Control.DECODER);
 
           Entry authorizationEntry = proxyControl.getAuthorizationEntry();
           setAuthorizationEntry(authorizationEntry);
@@ -760,8 +666,7 @@
       //          out..
       SearchResultEntry searchEntry = new SearchResultEntry(entryCopy);
       LDAPPreReadResponseControl responseControl =
-           new LDAPPreReadResponseControl(preReadRequest.getOID(),
-                                          preReadRequest.isCritical(),
+           new LDAPPreReadResponseControl(preReadRequest.isCritical(),
                                           searchEntry);
       addResponseControl(responseControl);
     }
diff --git a/opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendModifyDNOperation.java b/opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendModifyDNOperation.java
index 1a73ca0..29bfde0 100644
--- a/opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendModifyDNOperation.java
+++ b/opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendModifyDNOperation.java
@@ -64,7 +64,6 @@
 import org.opends.server.types.DirectoryException;
 import org.opends.server.types.DN;
 import org.opends.server.types.Entry;
-import org.opends.server.types.LDAPException;
 import org.opends.server.types.LockManager;
 import org.opends.server.types.Modification;
 import org.opends.server.types.ModificationType;
@@ -156,6 +155,7 @@
    * @return  The current entry, or <CODE>null</CODE> if it is not yet
    *           available.
    */
+  @Override
   public final Entry getOriginalEntry()
   {
     return currentEntry;
@@ -171,6 +171,7 @@
    * @return  The updated entry, or <CODE>null</CODE> if it is not yet
    *           available.
    */
+  @Override
   public final Entry getUpdatedEntry()
   {
     return newEntry;
@@ -703,30 +704,8 @@
 
         if (oid.equals(OID_LDAP_ASSERTION))
         {
-          LDAPAssertionRequestControl assertControl;
-          if (c instanceof LDAPAssertionRequestControl)
-          {
-            assertControl = (LDAPAssertionRequestControl) c;
-          }
-          else
-          {
-            try
-            {
-              assertControl = LDAPAssertionRequestControl.decodeControl(c);
-              requestControls.set(i, assertControl);
-            }
-            catch (LDAPException le)
-            {
-              if (debugEnabled())
-              {
-                TRACER.debugCaught(DebugLogLevel.ERROR, le);
-              }
-
-              throw new DirectoryException(
-                             ResultCode.valueOf(le.getResultCode()),
-                             le.getMessageObject());
-            }
-          }
+          LDAPAssertionRequestControl assertControl =
+                getRequestControl(LDAPAssertionRequestControl.DECODER);
 
           try
           {
@@ -764,29 +743,9 @@
         }
         else if (oid.equals(OID_LDAP_READENTRY_PREREAD))
         {
-          if (c instanceof LDAPPreReadRequestControl)
-          {
-            preReadRequest = (LDAPPreReadRequestControl) c;
-          }
-          else
-          {
-            try
-            {
-              preReadRequest = LDAPPreReadRequestControl.decodeControl(c);
-              requestControls.set(i, preReadRequest);
-            }
-            catch (LDAPException le)
-            {
-              if (debugEnabled())
-              {
-                TRACER.debugCaught(DebugLogLevel.ERROR, le);
-              }
-
-              throw new DirectoryException(
-                             ResultCode.valueOf(le.getResultCode()),
-                             le.getMessageObject());
-            }
-          }
+          preReadRequest =
+                getRequestControl(LDAPPreReadRequestControl.DECODER);
+          requestControls.set(i, preReadRequest);
         }
         else if (oid.equals(OID_LDAP_READENTRY_POSTREAD))
         {
@@ -796,22 +755,9 @@
           }
           else
           {
-            try
-            {
-              postReadRequest = LDAPPostReadRequestControl.decodeControl(c);
-              requestControls.set(i, postReadRequest);
-            }
-            catch (LDAPException le)
-            {
-              if (debugEnabled())
-              {
-                TRACER.debugCaught(DebugLogLevel.ERROR, le);
-              }
-
-              throw new DirectoryException(
-                             ResultCode.valueOf(le.getResultCode()),
-                             le.getMessageObject());
-            }
+            postReadRequest =
+                  getRequestControl(LDAPPostReadRequestControl.DECODER);
+            requestControls.set(i, postReadRequest);
           }
         }
         else if (oid.equals(OID_PROXIED_AUTH_V1))
@@ -824,31 +770,8 @@
                            ERR_PROXYAUTH_INSUFFICIENT_PRIVILEGES.get());
           }
 
-
-          ProxiedAuthV1Control proxyControl;
-          if (c instanceof ProxiedAuthV1Control)
-          {
-            proxyControl = (ProxiedAuthV1Control) c;
-          }
-          else
-          {
-            try
-            {
-              proxyControl = ProxiedAuthV1Control.decodeControl(c);
-            }
-            catch (LDAPException le)
-            {
-              if (debugEnabled())
-              {
-                TRACER.debugCaught(DebugLogLevel.ERROR, le);
-              }
-
-              throw new DirectoryException(
-                             ResultCode.valueOf(le.getResultCode()),
-                             le.getMessageObject());
-            }
-          }
-
+          ProxiedAuthV1Control proxyControl =
+              getRequestControl(ProxiedAuthV1Control.DECODER);
 
           Entry authorizationEntry = proxyControl.getAuthorizationEntry();
           setAuthorizationEntry(authorizationEntry);
@@ -871,31 +794,8 @@
                            ERR_PROXYAUTH_INSUFFICIENT_PRIVILEGES.get());
           }
 
-
-          ProxiedAuthV2Control proxyControl;
-          if (c instanceof ProxiedAuthV2Control)
-          {
-            proxyControl = (ProxiedAuthV2Control) c;
-          }
-          else
-          {
-            try
-            {
-              proxyControl = ProxiedAuthV2Control.decodeControl(c);
-            }
-            catch (LDAPException le)
-            {
-              if (debugEnabled())
-              {
-                TRACER.debugCaught(DebugLogLevel.ERROR, le);
-              }
-
-              throw new DirectoryException(
-                             ResultCode.valueOf(le.getResultCode()),
-                             le.getMessageObject());
-            }
-          }
-
+          ProxiedAuthV2Control proxyControl =
+              getRequestControl(ProxiedAuthV2Control.DECODER);
 
           Entry authorizationEntry = proxyControl.getAuthorizationEntry();
           setAuthorizationEntry(authorizationEntry);
@@ -1153,8 +1053,7 @@
       //          out..
       SearchResultEntry searchEntry = new SearchResultEntry(entry);
       LDAPPreReadResponseControl responseControl =
-           new LDAPPreReadResponseControl(preReadRequest.getOID(),
-                                          preReadRequest.isCritical(),
+           new LDAPPreReadResponseControl(preReadRequest.isCritical(),
                                           searchEntry);
 
       addResponseControl(responseControl);
@@ -1204,9 +1103,7 @@
       //          out..
       SearchResultEntry searchEntry = new SearchResultEntry(entry);
       LDAPPostReadResponseControl responseControl =
-           new LDAPPostReadResponseControl(postReadRequest.getOID(),
-                                           postReadRequest.isCritical(),
-                                           searchEntry);
+           new LDAPPostReadResponseControl(searchEntry);
 
       addResponseControl(responseControl);
     }
diff --git a/opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendModifyOperation.java b/opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendModifyOperation.java
index d57b74d..dec33a3 100644
--- a/opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendModifyOperation.java
+++ b/opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendModifyOperation.java
@@ -35,7 +35,6 @@
 import static org.opends.server.util.ServerConstants.*;
 import static org.opends.server.util.StaticUtils.*;
 
-import java.util.Arrays;
 import java.util.HashSet;
 import java.util.Iterator;
 import java.util.LinkedList;
@@ -68,36 +67,10 @@
 import org.opends.server.core.PersistentSearch;
 import org.opends.server.core.PluginConfigManager;
 import org.opends.server.loggers.debug.DebugTracer;
-import org.opends.server.protocols.asn1.ASN1OctetString;
 import org.opends.server.schema.AuthPasswordSyntax;
 import org.opends.server.schema.BooleanSyntax;
 import org.opends.server.schema.UserPasswordSyntax;
-import org.opends.server.types.AcceptRejectWarn;
-import org.opends.server.types.AccountStatusNotification;
-import org.opends.server.types.AccountStatusNotificationType;
-import org.opends.server.types.Attribute;
-import org.opends.server.types.AttributeBuilder;
-import org.opends.server.types.AttributeType;
-import org.opends.server.types.AttributeValue;
-import org.opends.server.types.AuthenticationInfo;
-import org.opends.server.types.ByteString;
-import org.opends.server.types.CanceledOperationException;
-import org.opends.server.types.Control;
-import org.opends.server.types.DN;
-import org.opends.server.types.DebugLogLevel;
-import org.opends.server.types.DirectoryException;
-import org.opends.server.types.Entry;
-import org.opends.server.types.LDAPException;
-import org.opends.server.types.LockManager;
-import org.opends.server.types.Modification;
-import org.opends.server.types.ModificationType;
-import org.opends.server.types.ObjectClass;
-import org.opends.server.types.Privilege;
-import org.opends.server.types.RDN;
-import org.opends.server.types.ResultCode;
-import org.opends.server.types.SearchFilter;
-import org.opends.server.types.SearchResultEntry;
-import org.opends.server.types.SynchronizationProviderResult;
+import org.opends.server.types.*;
 import org.opends.server.types.operation.PostOperationModifyOperation;
 import org.opends.server.types.operation.PostResponseModifyOperation;
 import org.opends.server.types.operation.PostSynchronizationModifyOperation;
@@ -767,30 +740,8 @@
 
         if (oid.equals(OID_LDAP_ASSERTION))
         {
-          LDAPAssertionRequestControl assertControl;
-          if (c instanceof LDAPAssertionRequestControl)
-          {
-            assertControl = (LDAPAssertionRequestControl) c;
-          }
-          else
-          {
-            try
-            {
-              assertControl = LDAPAssertionRequestControl.decodeControl(c);
-              requestControls.set(i, assertControl);
-            }
-            catch (LDAPException le)
-            {
-              if (debugEnabled())
-              {
-                TRACER.debugCaught(DebugLogLevel.ERROR, le);
-              }
-
-              throw new DirectoryException(
-                             ResultCode.valueOf(le.getResultCode()),
-                             le.getMessageObject());
-            }
-          }
+          LDAPAssertionRequestControl assertControl =
+                getRequestControl(LDAPAssertionRequestControl.DECODER);
 
           try
           {
@@ -828,29 +779,8 @@
         }
         else if (oid.equals(OID_LDAP_READENTRY_PREREAD))
         {
-          if (c instanceof LDAPPreReadRequestControl)
-          {
-            preReadRequest = (LDAPPreReadRequestControl) c;
-          }
-          else
-          {
-            try
-            {
-              preReadRequest = LDAPPreReadRequestControl.decodeControl(c);
-              requestControls.set(i, preReadRequest);
-            }
-            catch (LDAPException le)
-            {
-              if (debugEnabled())
-              {
-                TRACER.debugCaught(DebugLogLevel.ERROR, le);
-              }
-
-              throw new DirectoryException(
-                             ResultCode.valueOf(le.getResultCode()),
-                             le.getMessageObject());
-            }
-          }
+          preReadRequest =
+                getRequestControl(LDAPPreReadRequestControl.DECODER);
         }
         else if (oid.equals(OID_LDAP_READENTRY_POSTREAD))
         {
@@ -860,22 +790,9 @@
           }
           else
           {
-            try
-            {
-              postReadRequest = LDAPPostReadRequestControl.decodeControl(c);
-              requestControls.set(i, postReadRequest);
-            }
-            catch (LDAPException le)
-            {
-              if (debugEnabled())
-              {
-                TRACER.debugCaught(DebugLogLevel.ERROR, le);
-              }
-
-              throw new DirectoryException(
-                             ResultCode.valueOf(le.getResultCode()),
-                             le.getMessageObject());
-            }
+            postReadRequest =
+                getRequestControl(LDAPPostReadRequestControl.DECODER);
+            requestControls.set(i, postReadRequest);
           }
         }
         else if (oid.equals(OID_PROXIED_AUTH_V1))
@@ -888,31 +805,8 @@
                            ERR_PROXYAUTH_INSUFFICIENT_PRIVILEGES.get());
           }
 
-
-          ProxiedAuthV1Control proxyControl;
-          if (c instanceof ProxiedAuthV1Control)
-          {
-            proxyControl = (ProxiedAuthV1Control) c;
-          }
-          else
-          {
-            try
-            {
-              proxyControl = ProxiedAuthV1Control.decodeControl(c);
-            }
-            catch (LDAPException le)
-            {
-              if (debugEnabled())
-              {
-                TRACER.debugCaught(DebugLogLevel.ERROR, le);
-              }
-
-              throw new DirectoryException(
-                             ResultCode.valueOf(le.getResultCode()),
-                             le.getMessageObject());
-            }
-          }
-
+          ProxiedAuthV1Control proxyControl =
+                  getRequestControl(ProxiedAuthV1Control.DECODER);
 
           Entry authorizationEntry = proxyControl.getAuthorizationEntry();
           setAuthorizationEntry(authorizationEntry);
@@ -935,31 +829,8 @@
                            ERR_PROXYAUTH_INSUFFICIENT_PRIVILEGES.get());
           }
 
-
-          ProxiedAuthV2Control proxyControl;
-          if (c instanceof ProxiedAuthV2Control)
-          {
-            proxyControl = (ProxiedAuthV2Control) c;
-          }
-          else
-          {
-            try
-            {
-              proxyControl = ProxiedAuthV2Control.decodeControl(c);
-            }
-            catch (LDAPException le)
-            {
-              if (debugEnabled())
-              {
-                TRACER.debugCaught(DebugLogLevel.ERROR, le);
-              }
-
-              throw new DirectoryException(
-                             ResultCode.valueOf(le.getResultCode()),
-                             le.getMessageObject());
-            }
-          }
-
+          ProxiedAuthV2Control proxyControl =
+              getRequestControl(ProxiedAuthV2Control.DECODER);
 
           Entry authorizationEntry = proxyControl.getAuthorizationEntry();
           setAuthorizationEntry(authorizationEntry);
@@ -1071,7 +942,7 @@
             try
             {
               isEnabled =
-                  (! BooleanSyntax.decodeBooleanValue(v.getNormalizedValue()));
+                  (! BooleanSyntax.DECODER.decode(v));
             }
             catch (DirectoryException de)
             {
@@ -1349,7 +1220,8 @@
 
         for (ByteString s : pwPolicyState.encodePassword(v.getValue()))
         {
-          builder.add(new AttributeValue(pwAttr.getAttributeType(), s));
+          builder.add(AttributeValues.create(
+              pwAttr.getAttributeType(), s));
         }
       }
     }
@@ -1412,7 +1284,7 @@
               if (AuthPasswordSyntax.isEncoded(av.getValue()))
               {
                 StringBuilder[] components = AuthPasswordSyntax
-                    .decodeAuthPassword(av.getStringValue());
+                    .decodeAuthPassword(av.getValue().toString());
                 PasswordStorageScheme<?> scheme = DirectoryServer
                     .getAuthPasswordStorageScheme(components[0].toString());
                 if (scheme != null)
@@ -1439,12 +1311,12 @@
               if (UserPasswordSyntax.isEncoded(av.getValue()))
               {
                 String[] components = UserPasswordSyntax.decodeUserPassword(av
-                    .getStringValue());
+                    .getValue().toString());
                 PasswordStorageScheme<?> scheme = DirectoryServer
                     .getPasswordStorageScheme(toLowerCase(components[0]));
                 if (scheme != null)
                 {
-                  if (scheme.passwordMatches(v.getValue(), new ASN1OctetString(
+                  if (scheme.passwordMatches(v.getValue(), ByteString.valueOf(
                       components[1])))
                   {
                     builder.add(av);
@@ -1528,7 +1400,7 @@
           {
             throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX,
                 ERR_MODIFY_ADD_INVALID_SYNTAX.get(String.valueOf(entryDN), attr
-                    .getName(), v.getStringValue(), invalidReason));
+                    .getName(), v.getValue().toString(), invalidReason));
           }
         }
       }
@@ -1541,7 +1413,7 @@
           {
             setResultCode(ResultCode.INVALID_ATTRIBUTE_SYNTAX);
             logError(ERR_MODIFY_ADD_INVALID_SYNTAX.get(String.valueOf(entryDN),
-                attr.getName(), v.getStringValue(), invalidReason));
+                attr.getName(), v.getValue().toString(), invalidReason));
             invalidReason = new MessageBuilder();
           }
         }
@@ -1566,11 +1438,11 @@
     {
       StringBuilder buffer = new StringBuilder();
       Iterator<AttributeValue> iterator = duplicateValues.iterator();
-      buffer.append(iterator.next().getStringValue());
+      buffer.append(iterator.next().getValue().toString());
       while (iterator.hasNext())
       {
         buffer.append(", ");
-        buffer.append(iterator.next().getStringValue());
+        buffer.append(iterator.next().getValue().toString());
       }
 
       throw new DirectoryException(ResultCode.ATTRIBUTE_OR_VALUE_EXISTS,
@@ -1596,12 +1468,12 @@
     Validator.ensureTrue(attr.getAttributeType().isObjectClassType());
     for (AttributeValue v : attr)
     {
-      String name = v.getStringValue();
+      String name = v.getValue().toString();
 
       String lowerName;
       try
       {
-        lowerName = v.getNormalizedStringValue();
+        lowerName = v.getNormalizedValue().toString();
       }
       catch (Exception e)
       {
@@ -1610,7 +1482,7 @@
           TRACER.debugCaught(DebugLogLevel.ERROR, e);
         }
 
-        lowerName = toLowerCase(v.getStringValue());
+        lowerName = toLowerCase(v.getValue().toString());
       }
 
       ObjectClass oc = DirectoryServer.getObjectClass(lowerName);
@@ -1672,11 +1544,11 @@
       {
         StringBuilder buffer = new StringBuilder();
         Iterator<AttributeValue> iterator = missingValues.iterator();
-        buffer.append(iterator.next().getStringValue());
+        buffer.append(iterator.next().getValue().toString());
         while (iterator.hasNext())
         {
           buffer.append(", ");
-          buffer.append(iterator.next().getStringValue());
+          buffer.append(iterator.next().getValue().toString());
         }
 
         throw new DirectoryException(ResultCode.NO_SUCH_ATTRIBUTE,
@@ -1725,7 +1597,7 @@
           {
             throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX,
                 ERR_MODIFY_REPLACE_INVALID_SYNTAX.get(String.valueOf(entryDN),
-                    attr.getName(), v.getStringValue(), invalidReason));
+                    attr.getName(), v.getValue().toString(), invalidReason));
           }
         }
       }
@@ -1738,7 +1610,7 @@
           {
             setResultCode(ResultCode.INVALID_ATTRIBUTE_SYNTAX);
             logError(ERR_MODIFY_REPLACE_INVALID_SYNTAX.get(String
-                .valueOf(entryDN), attr.getName(), v.getStringValue(),
+                .valueOf(entryDN), attr.getName(), v.getValue().toString(),
                 invalidReason));
             invalidReason = new MessageBuilder();
           }
@@ -1817,7 +1689,7 @@
     long incrementValue;
     try
     {
-      incrementValue = Long.parseLong(v.getNormalizedStringValue());
+      incrementValue = Long.parseLong(v.getNormalizedValue().toString());
     }
     catch (Exception e)
     {
@@ -1828,7 +1700,7 @@
 
       throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX,
           ERR_MODIFY_INCREMENT_PROVIDED_VALUE_NOT_INTEGER.get(String
-              .valueOf(entryDN), attr.getName(), v.getStringValue()), e);
+              .valueOf(entryDN), attr.getName(), v.getValue().toString()), e);
     }
 
     // Get the attribute that is to be incremented.
@@ -1844,7 +1716,7 @@
     AttributeBuilder builder = new AttributeBuilder(a, true);
     for (AttributeValue existingValue : a)
     {
-      String s = existingValue.getStringValue();
+      String s = existingValue.getValue().toString();
       long currentValue;
       try
       {
@@ -1860,12 +1732,13 @@
         throw new DirectoryException(
             ResultCode.INVALID_ATTRIBUTE_SYNTAX,
             ERR_MODIFY_INCREMENT_REQUIRES_INTEGER_VALUE.get(String
-                .valueOf(entryDN), a.getName(), existingValue.getStringValue()),
+                .valueOf(entryDN), a.getName(),
+                existingValue.getValue().toString()),
             e);
       }
 
       long newValue = currentValue + incrementValue;
-      builder.add(new AttributeValue(t, String.valueOf(newValue)));
+      builder.add(AttributeValues.create(t, String.valueOf(newValue)));
     }
 
     // Replace the existing attribute with the incremented version.
@@ -1942,7 +1815,7 @@
               boolean found = false;
               for (ByteString s : clearPasswords)
               {
-                if (Arrays.equals(s.value(), pw.value()))
+                if (s.equals(pw))
                 {
                   found = true;
                   break;
@@ -2209,8 +2082,7 @@
       //          returned or if any attributes need to be stripped out..
       SearchResultEntry searchEntry = new SearchResultEntry(entry);
       LDAPPreReadResponseControl responseControl =
-           new LDAPPreReadResponseControl(preReadRequest.getOID(),
-                                          preReadRequest.isCritical(),
+           new LDAPPreReadResponseControl(preReadRequest.isCritical(),
                                           searchEntry);
       getResponseControls().add(responseControl);
     }
@@ -2258,9 +2130,7 @@
       //          returned or if any attributes need to be stripped out..
       SearchResultEntry searchEntry = new SearchResultEntry(entry);
       LDAPPostReadResponseControl responseControl =
-           new LDAPPostReadResponseControl(postReadRequest.getOID(),
-                                           postReadRequest.isCritical(),
-                                           searchEntry);
+           new LDAPPostReadResponseControl(searchEntry);
 
       getResponseControls().add(responseControl);
     }
diff --git a/opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendSearchOperation.java b/opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendSearchOperation.java
index a3334cd..6c85d95 100644
--- a/opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendSearchOperation.java
+++ b/opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendSearchOperation.java
@@ -51,7 +51,6 @@
 import org.opends.server.types.DirectoryException;
 import org.opends.server.types.DN;
 import org.opends.server.types.Entry;
-import org.opends.server.types.LDAPException;
 import org.opends.server.types.Privilege;
 import org.opends.server.types.ResultCode;
 import org.opends.server.types.SearchFilter;
@@ -336,30 +335,8 @@
 
         if (oid.equals(OID_LDAP_ASSERTION))
         {
-          LDAPAssertionRequestControl assertControl;
-          if (c instanceof LDAPAssertionRequestControl)
-          {
-            assertControl = (LDAPAssertionRequestControl) c;
-          }
-          else
-          {
-            try
-            {
-              assertControl = LDAPAssertionRequestControl.decodeControl(c);
-              requestControls.set(i, assertControl);
-            }
-            catch (LDAPException le)
-            {
-              if (debugEnabled())
-              {
-                TRACER.debugCaught(DebugLogLevel.ERROR, le);
-              }
-
-              throw new DirectoryException(
-                             ResultCode.valueOf(le.getResultCode()),
-                             le.getMessageObject(), le);
-            }
-          }
+          LDAPAssertionRequestControl assertControl =
+                getRequestControl(LDAPAssertionRequestControl.DECODER);
 
           try
           {
@@ -422,31 +399,8 @@
                            ERR_PROXYAUTH_INSUFFICIENT_PRIVILEGES.get());
           }
 
-
-          ProxiedAuthV1Control proxyControl;
-          if (c instanceof ProxiedAuthV1Control)
-          {
-            proxyControl = (ProxiedAuthV1Control) c;
-          }
-          else
-          {
-            try
-            {
-              proxyControl = ProxiedAuthV1Control.decodeControl(c);
-            }
-            catch (LDAPException le)
-            {
-              if (debugEnabled())
-              {
-                TRACER.debugCaught(DebugLogLevel.ERROR, le);
-              }
-
-              throw new DirectoryException(
-                             ResultCode.valueOf(le.getResultCode()),
-                             le.getMessageObject(), le);
-            }
-          }
-
+          ProxiedAuthV1Control proxyControl =
+              getRequestControl(ProxiedAuthV1Control.DECODER);
 
           Entry authorizationEntry = proxyControl.getAuthorizationEntry();
           setAuthorizationEntry(authorizationEntry);
@@ -469,31 +423,8 @@
                            ERR_PROXYAUTH_INSUFFICIENT_PRIVILEGES.get());
           }
 
-
-          ProxiedAuthV2Control proxyControl;
-          if (c instanceof ProxiedAuthV2Control)
-          {
-            proxyControl = (ProxiedAuthV2Control) c;
-          }
-          else
-          {
-            try
-            {
-              proxyControl = ProxiedAuthV2Control.decodeControl(c);
-            }
-            catch (LDAPException le)
-            {
-              if (debugEnabled())
-              {
-                TRACER.debugCaught(DebugLogLevel.ERROR, le);
-              }
-
-              throw new DirectoryException(
-                             ResultCode.valueOf(le.getResultCode()),
-                             le.getMessageObject(), le);
-            }
-          }
-
+          ProxiedAuthV2Control proxyControl =
+              getRequestControl(ProxiedAuthV2Control.DECODER);
 
           Entry authorizationEntry = proxyControl.getAuthorizationEntry();
           setAuthorizationEntry(authorizationEntry);
@@ -508,29 +439,8 @@
         }
         else if (oid.equals(OID_PERSISTENT_SEARCH))
         {
-          PersistentSearchControl psearchControl;
-          if (c instanceof PersistentSearchControl)
-          {
-            psearchControl = (PersistentSearchControl) c;
-          }
-          else
-          {
-            try
-            {
-              psearchControl = PersistentSearchControl.decodeControl(c);
-            }
-            catch (LDAPException le)
-            {
-              if (debugEnabled())
-              {
-                TRACER.debugCaught(DebugLogLevel.ERROR, le);
-              }
-
-              throw new DirectoryException(
-                             ResultCode.valueOf(le.getResultCode()),
-                             le.getMessageObject(), le);
-            }
-          }
+          PersistentSearchControl psearchControl =
+            getRequestControl(PersistentSearchControl.DECODER);
 
           persistentSearch = new PersistentSearch(this,
                                       psearchControl.getChangeTypes(),
@@ -549,30 +459,9 @@
         }
         else if (oid.equals(OID_MATCHED_VALUES))
         {
-          if (c instanceof MatchedValuesControl)
-          {
-            setMatchedValuesControl((MatchedValuesControl) c);
-          }
-          else
-          {
-            try
-            {
-              MatchedValuesControl matchedValuesControl =
-                MatchedValuesControl.decodeControl(c);
-              setMatchedValuesControl(matchedValuesControl);
-            }
-            catch (LDAPException le)
-            {
-              if (debugEnabled())
-              {
-                TRACER.debugCaught(DebugLogLevel.ERROR, le);
-              }
-
-              throw new DirectoryException(
-                             ResultCode.valueOf(le.getResultCode()),
-                             le.getMessageObject(), le);
-            }
-          }
+          MatchedValuesControl matchedValuesControl =
+                getRequestControl(MatchedValuesControl.DECODER);
+          setMatchedValuesControl(matchedValuesControl);
         }
         else if (oid.equals(OID_ACCOUNT_USABLE_CONTROL))
         {
diff --git a/opends/tests/staf-tests/functional-tests/testcases/aci/aci_targetattr.xml b/opends/tests/staf-tests/functional-tests/testcases/aci/aci_targetattr.xml
index 6befd22..e797458 100755
--- a/opends/tests/staf-tests/functional-tests/testcases/aci/aci_targetattr.xml
+++ b/opends/tests/staf-tests/functional-tests/testcases/aci/aci_targetattr.xml
@@ -23,7 +23,7 @@
  !
  ! CDDL HEADER END
  !
- !      Copyright 2008 Sun Microsystems, Inc.
+ !      Copyright 2008-2009 Sun Microsystems, Inc.
  ! -->
 <stax>
 
diff --git a/opends/tests/staf-tests/functional-tests/testcases/aci/aci_targetfilter.xml b/opends/tests/staf-tests/functional-tests/testcases/aci/aci_targetfilter.xml
index f4bdcc0..28d481e 100755
--- a/opends/tests/staf-tests/functional-tests/testcases/aci/aci_targetfilter.xml
+++ b/opends/tests/staf-tests/functional-tests/testcases/aci/aci_targetfilter.xml
@@ -23,7 +23,7 @@
  !
  ! CDDL HEADER END
  !
- !      Copyright 2008 Sun Microsystems, Inc.
+ !      Copyright 2008-2009 Sun Microsystems, Inc.
  ! -->
 <stax>
 
diff --git a/opends/tests/staf-tests/functional-tests/testcases/aci/multiple_aci_tests.xml b/opends/tests/staf-tests/functional-tests/testcases/aci/multiple_aci_tests.xml
index ecdfa33..4670c5b 100644
--- a/opends/tests/staf-tests/functional-tests/testcases/aci/multiple_aci_tests.xml
+++ b/opends/tests/staf-tests/functional-tests/testcases/aci/multiple_aci_tests.xml
@@ -23,7 +23,7 @@
  !
  ! CDDL HEADER END
  !
- !      Copyright 2008 Sun Microsystems, Inc.
+ !      Copyright 2008-2009 Sun Microsystems, Inc.
  ! -->
 <stax>
 
diff --git a/opends/tests/staf-tests/functional-tests/testcases/dsml/dsml_test.xml b/opends/tests/staf-tests/functional-tests/testcases/dsml/dsml_test.xml
index 4cb9ee5..56a336b 100755
--- a/opends/tests/staf-tests/functional-tests/testcases/dsml/dsml_test.xml
+++ b/opends/tests/staf-tests/functional-tests/testcases/dsml/dsml_test.xml
@@ -23,7 +23,7 @@
  !
  ! CDDL HEADER END
  !
- !      Portions Copyright 2008 Sun Microsystems, Inc.
+ !      Portions Copyright 2008-2009 Sun Microsystems, Inc.
  ! -->
 <stax>
   <defaultcall function="dsml_test" />
diff --git a/opends/tests/staf-tests/functional-tests/testcases/replication/changelog/changelog.xml b/opends/tests/staf-tests/functional-tests/testcases/replication/changelog/changelog.xml
index 383bcbc..92bc116 100644
--- a/opends/tests/staf-tests/functional-tests/testcases/replication/changelog/changelog.xml
+++ b/opends/tests/staf-tests/functional-tests/testcases/replication/changelog/changelog.xml
@@ -23,7 +23,7 @@
  !
  ! CDDL HEADER END
  !
- !      Copyright 2008 Sun Microsystems, Inc.
+ !      Copyright 2008-2009 Sun Microsystems, Inc.
  ! -->
 <stax>
     
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/quicksetup/TestUtilities.java b/opends/tests/unit-tests-testng/src/server/org/opends/quicksetup/TestUtilities.java
index 4c78b84..75a6b03 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/quicksetup/TestUtilities.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/quicksetup/TestUtilities.java
@@ -22,7 +22,7 @@
  * CDDL HEADER END
  *
  *
- *      Copyright 2008 Sun Microsystems, Inc.
+ *      Copyright 2009 Sun Microsystems, Inc.
  */
 
 package org.opends.quicksetup;
@@ -32,6 +32,7 @@
 import org.opends.quicksetup.util.FileManager;
 import org.opends.server.TestCaseUtils;
 import org.opends.server.types.OperatingSystem;
+import org.opends.server.types.ByteStringBuilder;
 
 import java.io.BufferedReader;
 import java.io.File;
@@ -114,7 +115,15 @@
     
     Process p = pb.start();
     if (p.waitFor() != 0) {
-      throw new IllegalStateException("setup server failed");
+      ByteStringBuilder stdOut = new ByteStringBuilder();
+      ByteStringBuilder stdErr = new ByteStringBuilder();
+      while(stdOut.append(p.getInputStream(), 512) > 0);
+      while(stdErr.append(p.getErrorStream(), 512) > 0);
+      throw new IllegalStateException(
+          "setup server process failed:\n" +
+          "exit value: " + p.exitValue() + "\n" +
+          "stdout contents: " + stdOut.toString() + "\n" +
+          "stderr contents: " + stdErr.toString());
     }
   }
 
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/TestCaseUtils.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/TestCaseUtils.java
index 09bb550..5506fd4 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/TestCaseUtils.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/TestCaseUtils.java
@@ -81,15 +81,17 @@
 import org.opends.server.loggers.debug.TextDebugLogPublisher;
 import org.opends.server.loggers.debug.DebugLogger;
 import org.opends.server.plugins.InvocationCounterPlugin;
-import org.opends.server.protocols.asn1.ASN1OctetString;
+import org.opends.server.protocols.asn1.ASN1;
 import org.opends.server.protocols.asn1.ASN1Reader;
 import org.opends.server.protocols.asn1.ASN1Writer;
 import org.opends.server.protocols.internal.InternalClientConnection;
 import org.opends.server.protocols.ldap.BindRequestProtocolOp;
 import org.opends.server.protocols.ldap.BindResponseProtocolOp;
 import org.opends.server.protocols.ldap.LDAPMessage;
+import org.opends.server.protocols.ldap.LDAPReader;
 import org.opends.server.tools.LDAPModify;
 import org.opends.server.tools.dsconfig.DSConfig;
+import org.opends.server.types.ByteString;
 import org.opends.server.types.DN;
 import org.opends.server.types.DirectoryEnvironmentConfig;
 import org.opends.server.types.DirectoryException;
@@ -1250,19 +1252,19 @@
     Socket s = null;
     try {
       s = new Socket("127.0.0.1", TestCaseUtils.getServerLdapPort());
-      ASN1Reader r = new ASN1Reader(s);
-      ASN1Writer w = new ASN1Writer(s);
-      r.setIOTimeout(3000);
+      s.setSoTimeout(3000);
+      ASN1Reader r = ASN1.getReader(s.getInputStream());
+      ASN1Writer w = ASN1.getWriter(s.getOutputStream());
 
       BindRequestProtocolOp bindRequest =
         new BindRequestProtocolOp(
-                 new ASN1OctetString(dn),
+                 ByteString.valueOf(dn),
                  3,
-                new ASN1OctetString(pw));
+                 ByteString.valueOf(pw));
       LDAPMessage message = new LDAPMessage(1, bindRequest);
-      w.writeElement(message.encode());
+      message.write(w);
 
-      message = LDAPMessage.decode(r.readElement().decodeAsSequence());
+      message = LDAPReader.readMessage(r);
       BindResponseProtocolOp bindResponse = message.getBindResponseProtocolOp();
       if (bindResponse.getResultCode() == 0) {
         return true;
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/RelativeInheritedDefaultBehaviorProviderTest.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/RelativeInheritedDefaultBehaviorProviderTest.java
index add6746..2c91c71 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/RelativeInheritedDefaultBehaviorProviderTest.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/RelativeInheritedDefaultBehaviorProviderTest.java
@@ -53,7 +53,9 @@
     try
     {
       TestCaseUtils.startServer();
-    } catch (Exception e) {}
+    } catch (Exception e) {
+      e.printStackTrace();
+    }
     d = TestParentCfgDefn.getInstance();
   }
 
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/TestCfg.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/TestCfg.java
index 490f2c2..e9b8b14 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/TestCfg.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/TestCfg.java
@@ -34,7 +34,6 @@
 import org.opends.server.core.DirectoryServer;
 import org.opends.server.schema.ObjectClassSyntax;
 import org.opends.server.types.ByteString;
-import org.opends.server.types.ByteStringFactory;
 import org.opends.server.types.ObjectClass;
 
 
@@ -100,7 +99,7 @@
           + "MAY ( ds-cfg-base-dn $ ds-cfg-group-dn $ "
           + "ds-cfg-filter $ ds-cfg-conflict-behavior ) "
           + "X-ORIGIN 'OpenDS Directory Server' )";
-      ByteString b = ByteStringFactory.create(ocd);
+      ByteString b = ByteString.valueOf(ocd);
 
       TEST_PARENT_OCD = ObjectClassSyntax.decodeObjectClass(b, DirectoryServer
           .getSchema(), false);
@@ -115,7 +114,7 @@
           + "MAY ( ds-cfg-base-dn $ ds-cfg-group-dn $ "
           + "ds-cfg-filter $ ds-cfg-conflict-behavior $"
           + "ds-cfg-rotation-policy) " + "X-ORIGIN 'OpenDS Directory Server' )";
-      ByteString b = ByteStringFactory.create(ocd);
+      ByteString b = ByteString.valueOf(ocd);
 
       TEST_CHILD_OCD = ObjectClassSyntax.decodeObjectClass(b, DirectoryServer
           .getSchema(), false);
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/client/ldap/MockLDAPConnection.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/client/ldap/MockLDAPConnection.java
index 714e1f3..2fba588 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/client/ldap/MockLDAPConnection.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/client/ldap/MockLDAPConnection.java
@@ -317,7 +317,7 @@
     for (org.opends.server.types.Attribute attribute : entry.getAttributes()) {
       BasicAttribute ba = new BasicAttribute(attribute.getName());
       for (AttributeValue value : attribute) {
-        ba.add(value.getStringValue());
+        ba.add(value.getValue().toString());
       }
       attributes.put(ba);
     }
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/server/DefaultBehaviorTest.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/server/DefaultBehaviorTest.java
index c6ad397..7fb3b6f 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/server/DefaultBehaviorTest.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/server/DefaultBehaviorTest.java
@@ -98,7 +98,7 @@
     public TestChildCfg getChild(String expectedName) {
       Assert.assertNotNull(child);
       Assert.assertEquals(child.dn().getRDN().getAttributeValue(0)
-          .getStringValue(), expectedName);
+          .getValue().toString(), expectedName);
       return child;
     }
 
@@ -158,7 +158,7 @@
     public TestChildCfg getChild(String expectedName) {
       Assert.assertNotNull(child);
       Assert.assertEquals(child.dn().getRDN().getAttributeValue(0)
-          .getStringValue(), expectedName);
+          .getValue().toString(), expectedName);
       return child;
     }
 
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/api/PasswordValidatorTestCase.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/api/PasswordValidatorTestCase.java
index b5e120b..e075cd5 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/api/PasswordValidatorTestCase.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/api/PasswordValidatorTestCase.java
@@ -39,10 +39,6 @@
 import org.opends.server.TestCaseUtils;
 import org.opends.server.core.AddOperation;
 import org.opends.server.extensions.TestPasswordValidator;
-import org.opends.server.protocols.asn1.ASN1OctetString;
-import org.opends.server.protocols.asn1.ASN1Reader;
-import org.opends.server.protocols.asn1.ASN1Sequence;
-import org.opends.server.protocols.asn1.ASN1Writer;
 import org.opends.server.protocols.internal.InternalClientConnection;
 import org.opends.server.protocols.ldap.BindRequestProtocolOp;
 import org.opends.server.protocols.ldap.BindResponseProtocolOp;
@@ -52,6 +48,7 @@
 import org.opends.server.protocols.ldap.ModifyRequestProtocolOp;
 import org.opends.server.protocols.ldap.ModifyResponseProtocolOp;
 import org.opends.server.tools.LDAPPasswordModify;
+import org.opends.server.tools.LDAPWriter;
 import org.opends.server.types.Attribute;
 import org.opends.server.types.ByteString;
 import org.opends.server.types.DN;
@@ -157,8 +154,8 @@
     assertEquals(LDAPPasswordModify.mainPasswordModify(args, false, null, null),
                  0);
 
-    assertEquals(TestPasswordValidator.getLastNewPassword().value(),
-                 new ASN1OctetString("newPassword").value());
+    assertEquals(TestPasswordValidator.getLastNewPassword(),
+                 ByteString.valueOf("newPassword"));
     assertFalse(TestPasswordValidator.getLastCurrentPasswords().isEmpty());
   }
 
@@ -218,8 +215,8 @@
                                                            null);
     assertFalse(returnCode == 0);
 
-    assertEquals(TestPasswordValidator.getLastNewPassword().value(),
-                 new ASN1OctetString("newPassword").value());
+    assertEquals(TestPasswordValidator.getLastNewPassword(),
+                 ByteString.valueOf("newPassword"));
     assertFalse(TestPasswordValidator.getLastCurrentPasswords().isEmpty());
 
     TestPasswordValidator.setNextReturnValue(true);
@@ -339,8 +336,8 @@
          TestPasswordValidator.getLastCurrentPasswords();
     assertFalse(currentPasswords.isEmpty());
     assertEquals(currentPasswords.size(), 1);
-    assertEquals(currentPasswords.iterator().next().value(),
-                 new ASN1OctetString("password").value());
+    assertEquals(currentPasswords.iterator().next(),
+                 ByteString.valueOf("password"));
   }
 
 
@@ -401,8 +398,8 @@
          TestPasswordValidator.getLastCurrentPasswords();
     assertFalse(currentPasswords.isEmpty());
     assertEquals(currentPasswords.size(), 1);
-    assertEquals(currentPasswords.iterator().next().value(),
-                 new ASN1OctetString("password").value());
+    assertEquals(currentPasswords.iterator().next(),
+                 ByteString.valueOf("password"));
   }
 
 
@@ -464,8 +461,8 @@
          TestPasswordValidator.getLastCurrentPasswords();
     assertFalse(currentPasswords.isEmpty());
     assertEquals(currentPasswords.size(), 1);
-    assertEquals(currentPasswords.iterator().next().value(),
-                 new ASN1OctetString("password").value());
+    assertEquals(currentPasswords.iterator().next(),
+                 ByteString.valueOf("password"));
   }
 
 
@@ -509,40 +506,40 @@
 
 
     Socket s = new Socket("127.0.0.1", TestCaseUtils.getServerLdapPort());
-    ASN1Reader r = new ASN1Reader(s);
-    ASN1Writer w = new ASN1Writer(s);
-    r.setIOTimeout(3000);
+    org.opends.server.tools.LDAPReader r = new org.opends.server.tools.LDAPReader(s);
+    LDAPWriter w = new LDAPWriter(s);
+    s.setSoTimeout(3000);
 
     BindRequestProtocolOp bindRequest =
       new BindRequestProtocolOp(
-               new ASN1OctetString("uid=test.user,o=test"),
-                                3, new ASN1OctetString("password"));
+               ByteString.valueOf("uid=test.user,o=test"),
+                                3, ByteString.valueOf("password"));
     LDAPMessage message = new LDAPMessage(1, bindRequest);
-    w.writeElement(message.encode());
+    w.writeMessage(message);
 
-    message = LDAPMessage.decode(r.readElement().decodeAsSequence());
+    message = r.readMessage();
     BindResponseProtocolOp bindResponse = message.getBindResponseProtocolOp();
     assertEquals(bindResponse.getResultCode(), 0);
 
     ArrayList<RawModification> mods = new ArrayList<RawModification>();
-    ArrayList<ASN1OctetString> values = new ArrayList<ASN1OctetString>();
-    values.add(new ASN1OctetString("newPassword"));
+    ArrayList<ByteString> values = new ArrayList<ByteString>();
+    values.add(ByteString.valueOf("newPassword"));
     LDAPAttribute attr = new LDAPAttribute("userPassword", values);
     mods.add(new LDAPModification(ModificationType.REPLACE, attr));
 
     ModifyRequestProtocolOp modifyRequest =
          new ModifyRequestProtocolOp(
-                  new ASN1OctetString("uid=test.user,o=test"), mods);
+                  ByteString.valueOf("uid=test.user,o=test"), mods);
     message = new LDAPMessage(2, modifyRequest);
-    w.writeElement(message.encode());
+    w.writeMessage(message);
 
-    message = LDAPMessage.decode(r.readElement().decodeAsSequence());
+    message = r.readMessage();
     ModifyResponseProtocolOp modifyResponse =
          message.getModifyResponseProtocolOp();
     assertEquals(modifyResponse.getResultCode(), 0);
 
-    assertEquals(TestPasswordValidator.getLastNewPassword().value(),
-                 new ASN1OctetString("newPassword").value());
+    assertEquals(TestPasswordValidator.getLastNewPassword(),
+                 ByteString.valueOf("newPassword"));
     assertTrue(TestPasswordValidator.getLastCurrentPasswords().isEmpty());
   }
 
@@ -587,41 +584,41 @@
 
 
     Socket s = new Socket("127.0.0.1", TestCaseUtils.getServerLdapPort());
-    ASN1Reader r = new ASN1Reader(s);
-    ASN1Writer w = new ASN1Writer(s);
-    r.setIOTimeout(3000);
+    org.opends.server.tools.LDAPReader r = new org.opends.server.tools.LDAPReader(s);
+    LDAPWriter w = new LDAPWriter(s);
+    s.setSoTimeout(3000);
 
     BindRequestProtocolOp bindRequest =
       new BindRequestProtocolOp(
-               new ASN1OctetString("uid=test.user,o=test"),
-                                3, new ASN1OctetString("password"));
+               ByteString.valueOf("uid=test.user,o=test"),
+                                3, ByteString.valueOf("password"));
     LDAPMessage message = new LDAPMessage(1, bindRequest);
-    w.writeElement(message.encode());
+    w.writeMessage(message);
 
-    message = LDAPMessage.decode(r.readElement().decodeAsSequence());
+    message = r.readMessage();
     BindResponseProtocolOp bindResponse = message.getBindResponseProtocolOp();
     assertEquals(bindResponse.getResultCode(), 0);
 
     ArrayList<RawModification> mods = new ArrayList<RawModification>();
-    ArrayList<ASN1OctetString> values = new ArrayList<ASN1OctetString>();
-    values.add(new ASN1OctetString("newPassword"));
+    ArrayList<ByteString> values = new ArrayList<ByteString>();
+    values.add(ByteString.valueOf("newPassword"));
     LDAPAttribute attr = new LDAPAttribute("userPassword", values);
     mods.add(new LDAPModification(ModificationType.REPLACE, attr));
 
     TestPasswordValidator.setNextReturnValue(false);
     ModifyRequestProtocolOp modifyRequest =
          new ModifyRequestProtocolOp(
-                  new ASN1OctetString("uid=test.user,o=test"), mods);
+                  ByteString.valueOf("uid=test.user,o=test"), mods);
     message = new LDAPMessage(2, modifyRequest);
-    w.writeElement(message.encode());
+    w.writeMessage(message);
 
-    message = LDAPMessage.decode(r.readElement().decodeAsSequence());
+    message = r.readMessage();
     ModifyResponseProtocolOp modifyResponse =
          message.getModifyResponseProtocolOp();
     assertFalse(modifyResponse.getResultCode() == 0);
 
-    assertEquals(TestPasswordValidator.getLastNewPassword().value(),
-                 new ASN1OctetString("newPassword").value());
+    assertEquals(TestPasswordValidator.getLastNewPassword(),
+                 ByteString.valueOf("newPassword"));
     assertTrue(TestPasswordValidator.getLastCurrentPasswords().isEmpty());
 
     TestPasswordValidator.setNextReturnValue(true);
@@ -669,39 +666,39 @@
 
 
     Socket s = new Socket("127.0.0.1", TestCaseUtils.getServerLdapPort());
-    ASN1Reader r = new ASN1Reader(s);
-    ASN1Writer w = new ASN1Writer(s);
-    r.setIOTimeout(3000);
+    org.opends.server.tools.LDAPReader r = new org.opends.server.tools.LDAPReader(s);
+    LDAPWriter w = new LDAPWriter(s);
+    s.setSoTimeout(3000);
 
     BindRequestProtocolOp bindRequest =
       new BindRequestProtocolOp(
-               new ASN1OctetString("uid=test.user,o=test"),
-                                3, new ASN1OctetString("password"));
+               ByteString.valueOf("uid=test.user,o=test"),
+                                3, ByteString.valueOf("password"));
     LDAPMessage message = new LDAPMessage(1, bindRequest);
-    w.writeElement(message.encode());
+    w.writeMessage(message);
 
-    message = LDAPMessage.decode(r.readElement().decodeAsSequence());
+    message = r.readMessage();
     BindResponseProtocolOp bindResponse = message.getBindResponseProtocolOp();
     assertEquals(bindResponse.getResultCode(), 0);
 
     ArrayList<RawModification> mods = new ArrayList<RawModification>();
-    ArrayList<ASN1OctetString> values = new ArrayList<ASN1OctetString>();
-    values.add(new ASN1OctetString("password"));
+    ArrayList<ByteString> values = new ArrayList<ByteString>();
+    values.add(ByteString.valueOf("password"));
     LDAPAttribute attr = new LDAPAttribute("userPassword", values);
     mods.add(new LDAPModification(ModificationType.DELETE, attr));
 
-    values = new ArrayList<ASN1OctetString>();
-    values.add(new ASN1OctetString("newPassword"));
+    values = new ArrayList<ByteString>();
+    values.add(ByteString.valueOf("newPassword"));
     attr = new LDAPAttribute("userPassword", values);
     mods.add(new LDAPModification(ModificationType.ADD, attr));
 
     ModifyRequestProtocolOp modifyRequest =
          new ModifyRequestProtocolOp(
-                  new ASN1OctetString("uid=test.user,o=test"), mods);
+                  ByteString.valueOf("uid=test.user,o=test"), mods);
     message = new LDAPMessage(2, modifyRequest);
-    w.writeElement(message.encode());
+    w.writeMessage(message);
 
-    message = LDAPMessage.decode(r.readElement().decodeAsSequence());
+    message = r.readMessage();
     ModifyResponseProtocolOp modifyResponse =
          message.getModifyResponseProtocolOp();
     assertEquals(modifyResponse.getResultCode(), 0);
@@ -710,8 +707,8 @@
          TestPasswordValidator.getLastCurrentPasswords();
     assertFalse(currentPasswords.isEmpty());
     assertEquals(currentPasswords.size(), 1);
-    assertEquals(currentPasswords.iterator().next().value(),
-                 new ASN1OctetString("password").value());
+    assertEquals(currentPasswords.iterator().next(),
+                 ByteString.valueOf("password"));
   }
 
 
@@ -758,34 +755,34 @@
 
 
     Socket s = new Socket("127.0.0.1", TestCaseUtils.getServerLdapPort());
-    ASN1Reader r = new ASN1Reader(s);
-    ASN1Writer w = new ASN1Writer(s);
-    r.setIOTimeout(3000);
+    org.opends.server.tools.LDAPReader r = new org.opends.server.tools.LDAPReader(s);
+    LDAPWriter w = new LDAPWriter(s);
+    s.setSoTimeout(3000);
 
     BindRequestProtocolOp bindRequest =
       new BindRequestProtocolOp(
-               new ASN1OctetString("uid=test.user,o=test"),
-                                3, new ASN1OctetString("password"));
+               ByteString.valueOf("uid=test.user,o=test"),
+                                3, ByteString.valueOf("password"));
     LDAPMessage message = new LDAPMessage(1, bindRequest);
-    w.writeElement(message.encode());
+    w.writeMessage(message);
 
-    message = LDAPMessage.decode(r.readElement().decodeAsSequence());
+    message = r.readMessage();
     BindResponseProtocolOp bindResponse = message.getBindResponseProtocolOp();
     assertEquals(bindResponse.getResultCode(), 0);
 
     ArrayList<RawModification> mods = new ArrayList<RawModification>();
-    ArrayList<ASN1OctetString> values = new ArrayList<ASN1OctetString>();
-    values.add(new ASN1OctetString("newPassword"));
+    ArrayList<ByteString> values = new ArrayList<ByteString>();
+    values.add(ByteString.valueOf("newPassword"));
     LDAPAttribute attr = new LDAPAttribute("userPassword", values);
     mods.add(new LDAPModification(ModificationType.REPLACE, attr));
 
     ModifyRequestProtocolOp modifyRequest =
          new ModifyRequestProtocolOp(
-                  new ASN1OctetString("uid=test.user,o=test"), mods);
+                  ByteString.valueOf("uid=test.user,o=test"), mods);
     message = new LDAPMessage(2, modifyRequest);
-    w.writeElement(message.encode());
+    w.writeMessage(message);
 
-    message = LDAPMessage.decode(r.readElement().decodeAsSequence());
+    message = r.readMessage();
     ModifyResponseProtocolOp modifyResponse =
          message.getModifyResponseProtocolOp();
     assertEquals(modifyResponse.getResultCode(), 0);
@@ -794,8 +791,8 @@
          TestPasswordValidator.getLastCurrentPasswords();
     assertFalse(currentPasswords.isEmpty());
     assertEquals(currentPasswords.size(), 1);
-    assertEquals(currentPasswords.iterator().next().value(),
-                 new ASN1OctetString("password").value());
+    assertEquals(currentPasswords.iterator().next(),
+                 ByteString.valueOf("password"));
   }
 
 
@@ -842,39 +839,39 @@
 
 
     Socket s = new Socket("127.0.0.1", TestCaseUtils.getServerLdapPort());
-    ASN1Reader r = new ASN1Reader(s);
-    ASN1Writer w = new ASN1Writer(s);
-    r.setIOTimeout(3000);
+    org.opends.server.tools.LDAPReader r = new org.opends.server.tools.LDAPReader(s);
+    LDAPWriter w = new LDAPWriter(s);
+    s.setSoTimeout(3000);
 
     BindRequestProtocolOp bindRequest =
       new BindRequestProtocolOp(
-               new ASN1OctetString("uid=test.user,o=test"),
-                                3, new ASN1OctetString("password"));
+               ByteString.valueOf("uid=test.user,o=test"),
+                                3, ByteString.valueOf("password"));
     LDAPMessage message = new LDAPMessage(1, bindRequest);
-    w.writeElement(message.encode());
+    w.writeMessage(message);
 
-    message = LDAPMessage.decode(r.readElement().decodeAsSequence());
+    message = r.readMessage();
     BindResponseProtocolOp bindResponse = message.getBindResponseProtocolOp();
     assertEquals(bindResponse.getResultCode(), 0);
 
     ArrayList<RawModification> mods = new ArrayList<RawModification>();
-    ArrayList<ASN1OctetString> values = new ArrayList<ASN1OctetString>();
-    values.add(new ASN1OctetString("password"));
+    ArrayList<ByteString> values = new ArrayList<ByteString>();
+    values.add(ByteString.valueOf("password"));
     LDAPAttribute attr = new LDAPAttribute("userPassword", values);
     mods.add(new LDAPModification(ModificationType.DELETE, attr));
 
-    values = new ArrayList<ASN1OctetString>();
-    values.add(new ASN1OctetString("newPassword"));
+    values = new ArrayList<ByteString>();
+    values.add(ByteString.valueOf("newPassword"));
     attr = new LDAPAttribute("userPassword", values);
     mods.add(new LDAPModification(ModificationType.ADD, attr));
 
     ModifyRequestProtocolOp modifyRequest =
          new ModifyRequestProtocolOp(
-                  new ASN1OctetString("uid=test.user,o=test"), mods);
+                  ByteString.valueOf("uid=test.user,o=test"), mods);
     message = new LDAPMessage(2, modifyRequest);
-    w.writeElement(message.encode());
+    w.writeMessage(message);
 
-    message = LDAPMessage.decode(r.readElement().decodeAsSequence());
+    message = r.readMessage();
     ModifyResponseProtocolOp modifyResponse =
          message.getModifyResponseProtocolOp();
     assertEquals(modifyResponse.getResultCode(), 0);
@@ -883,8 +880,8 @@
          TestPasswordValidator.getLastCurrentPasswords();
     assertFalse(currentPasswords.isEmpty());
     assertEquals(currentPasswords.size(), 1);
-    assertEquals(currentPasswords.iterator().next().value(),
-                 new ASN1OctetString("password").value());
+    assertEquals(currentPasswords.iterator().next(),
+                 ByteString.valueOf("password"));
   }
 }
 
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/authorization/dseecompat/TargetTestCase.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/authorization/dseecompat/TargetTestCase.java
index 6c6f5f0..c0c3bfd 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/authorization/dseecompat/TargetTestCase.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/authorization/dseecompat/TargetTestCase.java
@@ -29,9 +29,9 @@
 
 import org.opends.server.DirectoryServerTestCase;
 import org.opends.server.TestCaseUtils;
-import org.opends.server.protocols.asn1.ASN1OctetString;
 import org.opends.server.types.DN;
 import org.opends.server.types.DirectoryException;
+import org.opends.server.types.ByteString;
 import static org.testng.Assert.assertTrue;
 import static org.testng.Assert.fail;
 import org.testng.annotations.DataProvider;
@@ -412,7 +412,7 @@
   public void applicableTargets(String aciDN, String aciString, String entryDN)
        throws Exception
   {
-    Aci aci = Aci.decode(new ASN1OctetString(aciString), DN.decode(aciDN));
+    Aci aci = Aci.decode(ByteString.valueOf(aciString), DN.decode(aciDN));
     boolean match = AciTargets.isTargetApplicable(aci,
                                                   aci.getTargets(),
                                                   DN.decode(entryDN));
@@ -426,7 +426,7 @@
                                    String entryDN)
        throws Exception
   {
-    Aci aci = Aci.decode(new ASN1OctetString(aciString), DN.decode(aciDN));
+    Aci aci = Aci.decode(ByteString.valueOf(aciString), DN.decode(aciDN));
     boolean match = AciTargets.isTargetApplicable(aci,
                                                   aci.getTargets(),
                                                   DN.decode(entryDN));
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/backends/GenericBackendTestCase.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/backends/GenericBackendTestCase.java
index edf4fe6..c9b5752 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/backends/GenericBackendTestCase.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/backends/GenericBackendTestCase.java
@@ -36,24 +36,11 @@
 
 import org.opends.server.TestCaseUtils;
 import org.opends.server.api.Backend;
-import org.opends.server.core.AddOperation;
-import org.opends.server.core.DeleteOperation;
 import org.opends.server.core.DirectoryServer;
-import org.opends.server.core.ModifyOperation;
-import org.opends.server.core.ModifyDNOperationBasis;
-import org.opends.server.protocols.internal.InternalClientConnection;
-import org.opends.server.types.AttributeType;
-import org.opends.server.types.ByteStringFactory;
-import org.opends.server.types.DirectoryException;
 import org.opends.server.types.DN;
-import org.opends.server.types.Entry;
-import org.opends.server.types.RDN;
 
 import static org.testng.Assert.*;
 
-import static org.opends.server.util.StaticUtils.*;
-
-
 
 /**
  * A set of generic test cases that apply to all Directory Server backends.
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/backends/SchemaTestMatchingRule.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/backends/SchemaTestMatchingRule.java
index eeed142..3cf0393 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/backends/SchemaTestMatchingRule.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/backends/SchemaTestMatchingRule.java
@@ -30,14 +30,14 @@
 
 import java.util.Collection;
 import java.util.Collections;
+
 import org.opends.server.api.EqualityMatchingRule;
-import org.opends.server.api.MatchingRule;
 import org.opends.server.schema.CaseIgnoreEqualityMatchingRuleFactory;
+import org.opends.server.types.ByteSequence;
 import org.opends.server.types.ByteString;
 import org.opends.server.types.DirectoryException;
 
 
-
 /**
  * This class implements an equality matching rule that is intended for testing
  * purposes within the server (e.g., in conjunction with matching rule uses).
@@ -48,16 +48,16 @@
        extends EqualityMatchingRule
 {
   // Indicates whether this matching rule should be considered OBSOLETE.
-  private boolean isObsolete;
+  private final boolean isObsolete;
 
   // The matching rule that will do all the real work behind the scenes.
-  private EqualityMatchingRule caseIgnoreMatchingRule;
+  private final EqualityMatchingRule caseIgnoreMatchingRule;
 
   // The name for this matching rule.
-  private String name;
+  private final String name;
 
   // The OID for this matching rule.
-  private String oid;
+  private final String oid;
 
 
 
@@ -118,6 +118,7 @@
   /**
    * {@inheritDoc}
    */
+  @Override
   public Collection<String> getAllNames()
   {
     return Collections.singleton(getName());
@@ -131,6 +132,7 @@
    * @return  The common name for this matching rule, or <CODE>null</CODE> if
    * it does not have a name.
    */
+  @Override
   public String getName()
   {
     return name;
@@ -143,6 +145,7 @@
    *
    * @return  The OID for this matching rule.
    */
+  @Override
   public String getOID()
   {
     return oid;
@@ -156,6 +159,7 @@
    * @return  The description for this matching rule, or <CODE>null</CODE> if
    *          there is none.
    */
+  @Override
   public String getDescription()
   {
     return null;
@@ -169,6 +173,7 @@
    *
    * @return  The OID of the syntax with which this matching rule is associated.
    */
+  @Override
   public String getSyntaxOID()
   {
     return caseIgnoreMatchingRule.getSyntaxOID();
@@ -179,6 +184,7 @@
   /**
    * {@inheritDoc}
    */
+  @Override
   public boolean isObsolete()
   {
     return isObsolete;
@@ -197,7 +203,8 @@
    * @throws  DirectoryException  If the provided value is invalid according to
    *                              the associated attribute syntax.
    */
-  public ByteString normalizeValue(ByteString value)
+  @Override
+  public ByteString normalizeValue(ByteSequence value)
          throws DirectoryException
   {
     return caseIgnoreMatchingRule.normalizeValue(value);
@@ -215,7 +222,8 @@
    * @return  <CODE>true</CODE> if the provided values are equal, or
    *          <CODE>false</CODE> if not.
    */
-  public boolean areEqual(ByteString value1, ByteString value2)
+  @Override
+  public boolean areEqual(ByteSequence value1, ByteSequence value2)
   {
     return caseIgnoreMatchingRule.areEqual(value1, value2);
   }
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/backends/jeb/TestBackendImpl.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/backends/jeb/TestBackendImpl.java
index 8b41fb9..8303be6 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/backends/jeb/TestBackendImpl.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/backends/jeb/TestBackendImpl.java
@@ -32,6 +32,7 @@
 import org.opends.server.admin.std.server.LocalDBBackendCfg;
 import org.opends.server.admin.std.meta.LocalDBBackendCfgDefn;
 import org.opends.server.admin.server.AdminTestCaseUtils;
+import org.opends.server.controls.SubtreeDeleteControl;
 import org.opends.server.core.ModifyDNOperationBasis;
 import org.opends.server.core.DirectoryServer;
 import org.opends.server.protocols.internal.InternalClientConnection;
@@ -39,9 +40,6 @@
 import org.opends.server.protocols.ldap.LDAPFilter;
 import org.opends.server.types.*;
 import org.opends.server.util.Base64;
-import static
-    org.opends.server.util.ServerConstants.OID_SUBTREE_DELETE_CONTROL;
-
 import org.testng.annotations.DataProvider;
 import org.testng.annotations.Test;
 import org.testng.annotations.BeforeClass;
@@ -764,7 +762,7 @@
       "testMatchedDN", "testNumSubordinates",
       "testNumSubordinatesIndexEntryLimitExceeded"})
   public void testDeleteSubtree() throws Exception {
-    Control control = new Control(OID_SUBTREE_DELETE_CONTROL, false);
+    Control control = new SubtreeDeleteControl(false);
     ArrayList<Control> deleteSubTreeControl = new ArrayList<Control>();
     deleteSubTreeControl.add(control);
     InternalClientConnection conn =
@@ -923,16 +921,16 @@
 
       assertNotNull(entry);
       for (AttributeValue value : entry.getAttribute("cn").get(0)) {
-        assertEquals(value.getStringValue(), "Testing Test");
+        assertEquals(value.getValue().toString(), "Testing Test");
       }
       for (AttributeValue value : entry.getAttribute("sn").get(0)) {
-        assertEquals(value.getStringValue(), "Test");
+        assertEquals(value.getValue().toString(), "Test");
       }
       for (AttributeValue value : entry.getAttribute("givenname").get(0)) {
-        assertEquals(value.getStringValue(), "Testing");
+        assertEquals(value.getValue().toString(), "Testing");
       }
       for (AttributeValue value : entry.getAttribute("employeenumber").get(0)) {
-        assertEquals(value.getStringValue(), "777");
+        assertEquals(value.getValue().toString(), "777");
       }
 
       attribute = entry.getAttribute("cn").get(0).getAttributeType();
@@ -1123,20 +1121,20 @@
 
       assertTrue(entry.getAttribute("cn").get(0)
           .contains(
-              new AttributeValue(entry.getAttribute("cn").get(0)
+          AttributeValues.create(entry.getAttribute("cn").get(0)
                   .getAttributeType(), "Aaren Rigor")));
       assertTrue(entry.getAttribute("cn").get(0).contains(
-          new AttributeValue(
+          AttributeValues.create(
               entry.getAttribute("cn").get(0).getAttributeType(),
               "Aarenister Rigor")));
       assertFalse(entry.getAttribute("cn").get(0).contains(
-          new AttributeValue(
+          AttributeValues.create(
               entry.getAttribute("cn").get(0).getAttributeType(), "Aaren Atp")));
 
       Set<String> options = new LinkedHashSet<String>();
       options.add("lang-de");
       assertTrue(entry.getAttribute("givenname", options).get(0).contains(
-          new AttributeValue(entry.getAttribute("givenname", options).get(0)
+          AttributeValues.create(entry.getAttribute("givenname", options).get(0)
               .getAttributeType(), "test")));
       options = new LinkedHashSet<String>();
       options.add("lang-cn");
@@ -1144,12 +1142,12 @@
       options = new LinkedHashSet<String>();
       options.add("lang-es");
       assertTrue(entry.getAttribute("givenname", options).get(0).contains(
-          new AttributeValue(entry.getAttribute("givenname", options).get(0)
+          AttributeValues.create(entry.getAttribute("givenname", options).get(0)
               .getAttributeType(), "newtest3")));
       options = new LinkedHashSet<String>();
       options.add("lang-fr");
       assertTrue(entry.getAttribute("givenname", options).get(0).contains(
-          new AttributeValue(entry.getAttribute("givenname", options).get(0)
+          AttributeValues.create(entry.getAttribute("givenname", options).get(0)
               .getAttributeType(), "test2")));
 
       assertTrue(entry.getAttribute("employeenumber").contains(
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/backends/jeb/TestImportJob.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/backends/jeb/TestImportJob.java
index f6ba336..96b9b79 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/backends/jeb/TestImportJob.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/backends/jeb/TestImportJob.java
@@ -28,12 +28,7 @@
 
 import org.opends.server.TestCaseUtils;
 import org.opends.server.tasks.TaskUtils;
-import org.opends.server.admin.std.server.LocalDBBackendCfg;
-import org.opends.server.admin.std.meta.LocalDBBackendCfgDefn;
-import org.opends.server.admin.server.AdminTestCaseUtils;
 import org.opends.server.core.DirectoryServer;
-import org.opends.server.config.ConfigEntry;
-import org.opends.server.util.Base64;
 import static org.opends.server.util.ServerConstants.OC_TOP;
 import static org.opends.server.util.ServerConstants.OC_EXTENSIBLE_OBJECT;
 import org.opends.server.types.*;
@@ -495,7 +490,7 @@
 
       AttributeType attribute = entry.getAttribute("cn").get(0).getAttributeType();
 
-      assertTrue(entry.hasValue(attribute, null, new AttributeValue(attribute,"Annalee Bogard")));
+      assertTrue(entry.hasValue(attribute, null, AttributeValues.create(attribute,"Annalee Bogard")));
 
       VerifyConfig verifyConfig = new VerifyConfig();
       verifyConfig.setBaseDN(DN.decode("dc=importtest1,dc=com"));
@@ -697,7 +692,7 @@
     		attrType = DirectoryServer.getDefaultAttributeType(type);
     	List<Attribute> attrList = e.getAttribute(attrType, null);
     	AttributeValue v = attrList.get(0).iterator().next();
-    	long retVal = Long.parseLong(v.getStringValue());
+    	long retVal = Long.parseLong(v.getValue().toString());
     	return (retVal);
     }
 }
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/backends/jeb/TestJebFormat.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/backends/jeb/TestJebFormat.java
index 1b24c89..360e037 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/backends/jeb/TestJebFormat.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/backends/jeb/TestJebFormat.java
@@ -22,7 +22,7 @@
  * CDDL HEADER END
  *
  *
- *      Copyright 2006-2008 Sun Microsystems, Inc.
+ *      Copyright 2006-2009 Sun Microsystems, Inc.
  */
 package org.opends.server.backends.jeb;
 
@@ -32,17 +32,14 @@
 import java.io.ByteArrayInputStream;
 import java.util.Arrays;
 import java.util.List;
+import java.util.Map;
 
 import org.opends.server.TestCaseUtils;
 import org.opends.server.core.DirectoryServer;
-import org.opends.server.types.Attribute;
-import org.opends.server.types.AttributeType;
-import org.opends.server.types.Entry;
-import org.opends.server.types.EntryEncodeConfig;
-import org.opends.server.types.LDIFImportConfig;
-import org.opends.server.types.ObjectClass;
+import org.opends.server.types.*;
 import org.opends.server.util.LDIFReader;
 import org.opends.server.util.StaticUtils;
+import static org.opends.server.util.StaticUtils.getBytes;
 
 import org.testng.annotations.DataProvider;
 import org.testng.annotations.Test;
@@ -187,6 +184,237 @@
   }
 
   /**
+   * Encodes this entry using the V3 encoding.
+   *
+   * @param  buffer  The buffer to encode into.
+   *
+   * @throws  DirectoryException  If a problem occurs while attempting
+   *                              to encode the entry.
+   */
+  private void encodeV1(Entry entry, ByteStringBuilder buffer)
+         throws DirectoryException
+  {
+    // The version number will be one byte.
+    buffer.append((byte)0x01);
+
+    // TODO: Can we encode the DN directly into buffer?
+    byte[] dnBytes  = getBytes(entry.getDN().toString());
+    buffer.appendBERLength(dnBytes.length);
+    buffer.append(dnBytes);
+
+
+    // Encode number of OCs and 0 terminated names.
+    int i = 1;
+    ByteStringBuilder bsb = new ByteStringBuilder();
+    for (String ocName : entry.getObjectClasses().values())
+    {
+      bsb.append(ocName);
+      if(i < entry.getObjectClasses().values().size())
+      {
+        bsb.append((byte)0x00);
+      }
+      i++;
+    }
+    buffer.appendBERLength(bsb.length());
+    buffer.append(bsb);
+
+
+    // Encode the user attributes in the appropriate manner.
+    encodeV1Attributes(buffer, entry.getUserAttributes());
+
+
+    // The operational attributes will be encoded in the same way as
+    // the user attributes.
+    encodeV1Attributes(buffer, entry.getOperationalAttributes());
+  }
+
+  private void encodeV1Attributes(ByteStringBuilder buffer,
+                                Map<AttributeType,List<Attribute>> attributes)
+      throws DirectoryException
+  {
+    int numAttributes = 0;
+
+    // First count how many attributes are there to encode.
+    for (List<Attribute> attrList : attributes.values())
+    {
+      for (Attribute a : attrList)
+      {
+        if (a.isVirtual() || a.isEmpty())
+        {
+          continue;
+        }
+
+        numAttributes++;
+      }
+    }
+
+    // Encoded one-to-five byte number of attributes
+    buffer.appendBERLength(numAttributes);
+
+
+    // The attributes will be encoded as a sequence of:
+    // - A UTF-8 byte representation of the attribute name.
+    // - A zero delimiter
+    // - A one-to-five byte number of values for the attribute
+    // - A sequence of:
+    //   - A one-to-five byte length for the value
+    //   - A UTF-8 byte representation for the value
+    for (List<Attribute> attrList : attributes.values())
+    {
+      for (Attribute a : attrList)
+      {
+        byte[] nameBytes = getBytes(a.getNameWithOptions());
+        buffer.append(nameBytes);
+        buffer.append((byte)0x00);
+
+        buffer.appendBERLength(a.size());
+        for(AttributeValue v : a)
+        {
+          buffer.appendBERLength(v.getValue().length());
+          buffer.append(v.getValue());
+        }
+      }
+    }
+  }
+
+    /**
+   * Encodes this entry using the V3 encoding.
+   *
+   * @param  buffer  The buffer to encode into.
+   *
+   * @throws  DirectoryException  If a problem occurs while attempting
+   *                              to encode the entry.
+   */
+  private void encodeV2(Entry entry, ByteStringBuilder buffer,
+                        EntryEncodeConfig config)
+         throws DirectoryException
+  {
+    // The version number will be one byte.
+    buffer.append((byte)0x02);
+
+    // Get the encoded respresentation of the config.
+    config.encode(buffer);
+
+    // If we should include the DN, then it will be encoded as a
+    // one-to-five byte length followed by the UTF-8 byte
+    // representation.
+    if (! config.excludeDN())
+    {
+      // TODO: Can we encode the DN directly into buffer?
+      byte[] dnBytes  = getBytes(entry.getDN().toString());
+      buffer.appendBERLength(dnBytes.length);
+      buffer.append(dnBytes);
+    }
+
+
+    // Encode the object classes in the appropriate manner.
+    if (config.compressObjectClassSets())
+    {
+      ByteStringBuilder bsb = new ByteStringBuilder();
+      config.getCompressedSchema().encodeObjectClasses(bsb,
+          entry.getObjectClasses());
+      buffer.appendBERLength(bsb.length());
+      buffer.append(bsb);
+    }
+    else
+    {
+      // Encode number of OCs and 0 terminated names.
+      int i = 1;
+      ByteStringBuilder bsb = new ByteStringBuilder();
+      for (String ocName : entry.getObjectClasses().values())
+      {
+        bsb.append(ocName);
+        if(i < entry.getObjectClasses().values().size())
+        {
+          bsb.append((byte)0x00);
+        }
+        i++;
+      }
+      buffer.appendBERLength(bsb.length());
+      buffer.append(bsb);
+    }
+
+
+    // Encode the user attributes in the appropriate manner.
+    encodeV2Attributes(buffer, entry.getUserAttributes(), config);
+
+
+    // The operational attributes will be encoded in the same way as
+    // the user attributes.
+    encodeV2Attributes(buffer, entry.getOperationalAttributes(), config);
+  }
+
+  private void encodeV2Attributes(ByteStringBuilder buffer,
+                                Map<AttributeType,List<Attribute>> attributes,
+                                EntryEncodeConfig config)
+      throws DirectoryException
+  {
+    int numAttributes = 0;
+
+    // First count how many attributes are there to encode.
+    for (List<Attribute> attrList : attributes.values())
+    {
+      for (Attribute a : attrList)
+      {
+        if (a.isVirtual() || a.isEmpty())
+        {
+          continue;
+        }
+
+        numAttributes++;
+      }
+    }
+
+    // Encoded one-to-five byte number of attributes
+    buffer.appendBERLength(numAttributes);
+
+    if (config.compressAttributeDescriptions())
+    {
+      for (List<Attribute> attrList : attributes.values())
+      {
+        for (Attribute a : attrList)
+        {
+          if (a.isVirtual() || a.isEmpty())
+          {
+            continue;
+          }
+
+          ByteStringBuilder bsb = new ByteStringBuilder();
+          config.getCompressedSchema().encodeAttribute(bsb, a);
+          buffer.appendBERLength(bsb.length());
+          buffer.append(bsb);
+        }
+      }
+    }
+    else
+    {
+      // The attributes will be encoded as a sequence of:
+      // - A UTF-8 byte representation of the attribute name.
+      // - A zero delimiter
+      // - A one-to-five byte number of values for the attribute
+      // - A sequence of:
+      //   - A one-to-five byte length for the value
+      //   - A UTF-8 byte representation for the value
+      for (List<Attribute> attrList : attributes.values())
+      {
+        for (Attribute a : attrList)
+        {
+          byte[] nameBytes = getBytes(a.getNameWithOptions());
+          buffer.append(nameBytes);
+          buffer.append((byte)0x00);
+
+          buffer.appendBERLength(a.size());
+          for(AttributeValue v : a)
+          {
+            buffer.appendBERLength(v.getValue().length());
+            buffer.append(v.getValue());
+          }
+        }
+      }
+    }
+  }
+
+  /**
    * Test entry.
    *
    * @throws Exception
@@ -205,9 +433,10 @@
 
     Entry entryBefore, entryAfter;
     while ((entryBefore = reader.readEntry(false)) != null) {
-      byte[] bytes = JebFormat.entryToDatabase(entryBefore);
+      ByteString bytes = ID2Entry.entryToDatabase(entryBefore,
+          new DataConfig(false, false, null));
 
-      entryAfter = JebFormat.entryFromDatabase(bytes,
+      entryAfter = ID2Entry.entryFromDatabase(bytes,
                         DirectoryServer.getDefaultCompressedSchema());
 
       // check DN and number of attributes
@@ -274,16 +503,13 @@
     LDIFReader reader = new LDIFReader(new LDIFImportConfig(
         new ByteArrayInputStream(originalLDIFBytes)));
 
-    Entry entryBefore, entryAfterGeneric, entryAfterV1;
+    Entry entryBefore, entryAfterV1;
     while ((entryBefore = reader.readEntry(false)) != null) {
-      byte[] entryBytes = entryBefore.encodeV1();
-      entryAfterGeneric = Entry.decode(entryBytes);
-      assertEquals(entryBefore, entryAfterGeneric);
+      ByteStringBuilder bsb = new ByteStringBuilder();
+      encodeV1(entryBefore, bsb);
+      entryAfterV1 = Entry.decode(bsb.asReader());
 
-      entryAfterV1 = Entry.decodeV1(entryBytes);
       assertEquals(entryBefore, entryAfterV1);
-
-      assertEquals(entryAfterGeneric, entryAfterV1);
     }
     reader.close();
   }
@@ -327,25 +553,48 @@
     LDIFReader reader = new LDIFReader(new LDIFImportConfig(
         new ByteArrayInputStream(originalLDIFBytes)));
 
-    Entry entryBefore, entryAfterGeneric, entryAfterV2;
+    Entry entryBefore, entryAfterV2;
     while ((entryBefore = reader.readEntry(false)) != null) {
-      byte[] entryBytes = entryBefore.encodeV2(config);
-      entryAfterGeneric = Entry.decode(entryBytes,
-                                       config.getCompressedSchema());
-      if (config.excludeDN())
-      {
-        entryAfterGeneric.setDN(entryBefore.getDN());
-      }
-      assertEquals(entryBefore, entryAfterGeneric);
-
-      entryAfterV2 = Entry.decodeV2(entryBytes, config.getCompressedSchema());
+      ByteStringBuilder bsb = new ByteStringBuilder();
+      encodeV2(entryBefore, bsb, config);
+      entryAfterV2 = Entry.decode(bsb.asReader());
       if (config.excludeDN())
       {
         entryAfterV2.setDN(entryBefore.getDN());
       }
       assertEquals(entryBefore, entryAfterV2);
+    }
+    reader.close();
+  }
 
-      assertEquals(entryAfterGeneric, entryAfterV2);
+  /**
+   * Tests the entry encoding and decoding process the version 1 encoding.
+   *
+   * @throws Exception
+   *           If the test failed unexpectedly.
+   */
+  @Test(dataProvider = "encodeConfigs")
+  public void testEntryToAndFromDatabaseV3(EntryEncodeConfig config)
+         throws Exception {
+    // Make sure that the server is up and running.
+    TestCaseUtils.startServer();
+
+    // Convert the test LDIF string to a byte array
+    byte[] originalLDIFBytes = StaticUtils.getBytes(ldifString);
+
+    LDIFReader reader = new LDIFReader(new LDIFImportConfig(
+        new ByteArrayInputStream(originalLDIFBytes)));
+
+    Entry entryBefore, entryAfterV3;
+    while ((entryBefore = reader.readEntry(false)) != null) {
+      ByteStringBuilder bsb = new ByteStringBuilder();
+      entryBefore.encode(bsb, config);
+      entryAfterV3 = Entry.decode(bsb.asReader());
+      if (config.excludeDN())
+      {
+        entryAfterV3.setDN(entryBefore.getDN());
+      }
+      assertEquals(entryBefore, entryAfterV3);
     }
     reader.close();
   }
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/backends/jeb/TestRebuildJob.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/backends/jeb/TestRebuildJob.java
index ee50903..353a67e 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/backends/jeb/TestRebuildJob.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/backends/jeb/TestRebuildJob.java
@@ -339,7 +339,7 @@
       attrType = DirectoryServer.getDefaultAttributeType(type);
     List<Attribute> attrList = e.getAttribute(attrType, null);
     AttributeValue v = attrList.get(0).iterator().next();
-    long retVal = Long.parseLong(v.getStringValue());
+    long retVal = Long.parseLong(v.getValue().toString());
     return (retVal);
   }
 }
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/backends/jeb/TestVLVIndex.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/backends/jeb/TestVLVIndex.java
index 451e81a..66531b4 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/backends/jeb/TestVLVIndex.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/backends/jeb/TestVLVIndex.java
@@ -36,11 +36,9 @@
 import org.opends.server.controls.VLVResponseControl;
 import org.opends.server.protocols.internal.InternalClientConnection;
 import org.opends.server.protocols.internal.InternalSearchOperation;
-import org.opends.server.protocols.ldap.LDAPFilter;
 import org.opends.server.protocols.ldap.LDAPResultCode;
-import org.opends.server.protocols.asn1.ASN1OctetString;
+import org.opends.server.protocols.ldap.LDAPControl;
 import org.opends.server.core.DirectoryServer;
-import org.opends.server.core.SearchOperation;
 import org.opends.server.types.*;
 import org.testng.annotations.BeforeClass;
 import org.testng.annotations.Test;
@@ -337,7 +335,7 @@
         {
           for(int j = 0; j < values.getValues().length; j++)
           {
-            byte[] value;
+            ByteString value;
             if(i < 4)
             {
               value = svs1.getValue(i * 3 + j);
@@ -346,10 +344,10 @@
             {
               value = svs2.getValue((i - 4) * 3 + j);
             }
-            byte[] oValue = null;
+            ByteString oValue = null;
             if(values.getValues()[j] != null)
             {
-              oValue = values.getValues()[j].getNormalizedValueBytes();
+              oValue = values.getValues()[j].getNormalizedValue();
             }
             assertEquals(value, oValue);
           }
@@ -411,11 +409,25 @@
     {
       if (c.getOID().equals(OID_SERVER_SIDE_SORT_RESPONSE_CONTROL))
       {
-        sortResponse = ServerSideSortResponseControl.decodeControl(c);
+        if(c instanceof LDAPControl)
+        {
+          sortResponse = ServerSideSortResponseControl.DECODER.decode(c.isCritical(), ((LDAPControl)c).getValue());
+        }
+        else
+        {
+          sortResponse = (ServerSideSortResponseControl)c;
+        }
       }
       else if (c.getOID().equals(OID_VLV_RESPONSE_CONTROL))
       {
-        vlvResponse = VLVResponseControl.decodeControl(c);
+        if(c instanceof LDAPControl)
+        {
+          vlvResponse = VLVResponseControl.DECODER.decode(c.isCritical(), ((LDAPControl)c).getValue());
+        }
+        else
+        {
+          vlvResponse = (VLVResponseControl)c;
+        }
       }
       else
       {
@@ -485,11 +497,25 @@
     {
       if (c.getOID().equals(OID_SERVER_SIDE_SORT_RESPONSE_CONTROL))
       {
-        sortResponse = ServerSideSortResponseControl.decodeControl(c);
+        if(c instanceof LDAPControl)
+        {
+          sortResponse = ServerSideSortResponseControl.DECODER.decode(c.isCritical(), ((LDAPControl)c).getValue());
+        }
+        else
+        {
+          sortResponse = (ServerSideSortResponseControl)c;
+        }
       }
       else if (c.getOID().equals(OID_VLV_RESPONSE_CONTROL))
       {
-        vlvResponse = VLVResponseControl.decodeControl(c);
+        if(c instanceof LDAPControl)
+        {
+          vlvResponse = VLVResponseControl.DECODER.decode(c.isCritical(), ((LDAPControl)c).getValue());
+        }
+        else
+        {
+          vlvResponse = (VLVResponseControl)c;
+        }
       }
       else
       {
@@ -559,11 +585,25 @@
     {
       if (c.getOID().equals(OID_SERVER_SIDE_SORT_RESPONSE_CONTROL))
       {
-        sortResponse = ServerSideSortResponseControl.decodeControl(c);
+        if(c instanceof LDAPControl)
+        {
+          sortResponse = ServerSideSortResponseControl.DECODER.decode(c.isCritical(), ((LDAPControl)c).getValue());
+        }
+        else
+        {
+          sortResponse = (ServerSideSortResponseControl)c;
+        }
       }
       else if (c.getOID().equals(OID_VLV_RESPONSE_CONTROL))
       {
-        vlvResponse = VLVResponseControl.decodeControl(c);
+        if(c instanceof LDAPControl)
+        {
+          vlvResponse = VLVResponseControl.DECODER.decode(c.isCritical(), ((LDAPControl)c).getValue());
+        }
+        else
+        {
+          vlvResponse = (VLVResponseControl)c;
+        }
       }
       else
       {
@@ -618,7 +658,14 @@
     {
       if (c.getOID().equals(OID_VLV_RESPONSE_CONTROL))
       {
-        vlvResponse = VLVResponseControl.decodeControl(c);
+        if(c instanceof LDAPControl)
+        {
+          vlvResponse = VLVResponseControl.DECODER.decode(c.isCritical(), ((LDAPControl)c).getValue());
+        }
+        else
+        {
+          vlvResponse = (VLVResponseControl)c;
+        }
       }
     }
 
@@ -665,7 +712,14 @@
     {
       if (c.getOID().equals(OID_VLV_RESPONSE_CONTROL))
       {
-        vlvResponse = VLVResponseControl.decodeControl(c);
+        if(c instanceof LDAPControl)
+        {
+          vlvResponse = VLVResponseControl.DECODER.decode(c.isCritical(), ((LDAPControl)c).getValue());
+        }
+        else
+        {
+          vlvResponse = (VLVResponseControl)c;
+        }
       }
     }
 
@@ -723,7 +777,14 @@
     {
       if (c.getOID().equals(OID_VLV_RESPONSE_CONTROL))
       {
-        vlvResponse = VLVResponseControl.decodeControl(c);
+        if(c instanceof LDAPControl)
+        {
+          vlvResponse = VLVResponseControl.DECODER.decode(c.isCritical(), ((LDAPControl)c).getValue());
+        }
+        else
+        {
+          vlvResponse = (VLVResponseControl)c;
+        }
       }
     }
 
@@ -786,11 +847,25 @@
     {
       if (c.getOID().equals(OID_SERVER_SIDE_SORT_RESPONSE_CONTROL))
       {
-        sortResponse = ServerSideSortResponseControl.decodeControl(c);
+        if(c instanceof LDAPControl)
+        {
+          sortResponse = ServerSideSortResponseControl.DECODER.decode(c.isCritical(), ((LDAPControl)c).getValue());
+        }
+        else
+        {
+          sortResponse = (ServerSideSortResponseControl)c;
+        }
       }
       else if (c.getOID().equals(OID_VLV_RESPONSE_CONTROL))
       {
-        vlvResponse = VLVResponseControl.decodeControl(c);
+        if(c instanceof LDAPControl)
+        {
+          vlvResponse = VLVResponseControl.DECODER.decode(c.isCritical(), ((LDAPControl)c).getValue());
+        }
+        else
+        {
+          vlvResponse = (VLVResponseControl)c;
+        }
       }
       else
       {
@@ -823,7 +898,7 @@
 
     ArrayList<Control> requestControls = new ArrayList<Control>();
     requestControls.add(new ServerSideSortRequestControl(sortOrder));
-    requestControls.add(new VLVRequestControl(0, 3, new ASN1OctetString("a")));
+    requestControls.add(new VLVRequestControl(0, 3, ByteString.valueOf("a")));
 
     InternalSearchOperation internalSearch =
         new InternalSearchOperation(conn, conn.nextOperationID(),
@@ -860,11 +935,25 @@
     {
       if (c.getOID().equals(OID_SERVER_SIDE_SORT_RESPONSE_CONTROL))
       {
-        sortResponse = ServerSideSortResponseControl.decodeControl(c);
+        if(c instanceof LDAPControl)
+        {
+          sortResponse = ServerSideSortResponseControl.DECODER.decode(c.isCritical(), ((LDAPControl)c).getValue());
+        }
+        else
+        {
+          sortResponse = (ServerSideSortResponseControl)c;
+        }
       }
       else if (c.getOID().equals(OID_VLV_RESPONSE_CONTROL))
       {
-        vlvResponse = VLVResponseControl.decodeControl(c);
+        if(c instanceof LDAPControl)
+        {
+          vlvResponse = VLVResponseControl.DECODER.decode(c.isCritical(), ((LDAPControl)c).getValue());
+        }
+        else
+        {
+          vlvResponse = (VLVResponseControl)c;
+        }
       }
       else
       {
@@ -898,7 +987,7 @@
     ArrayList<Control> requestControls = new ArrayList<Control>();
     requestControls.add(new ServerSideSortRequestControl(sortOrder));
     requestControls.add(new VLVRequestControl(0, 3,
-                                              new ASN1OctetString("aaccf")));
+                                              ByteString.valueOf("aaccf")));
 
     InternalSearchOperation internalSearch =
         new InternalSearchOperation(conn, conn.nextOperationID(),
@@ -935,11 +1024,25 @@
     {
       if (c.getOID().equals(OID_SERVER_SIDE_SORT_RESPONSE_CONTROL))
       {
-        sortResponse = ServerSideSortResponseControl.decodeControl(c);
+        if(c instanceof LDAPControl)
+        {
+          sortResponse = ServerSideSortResponseControl.DECODER.decode(c.isCritical(), ((LDAPControl)c).getValue());
+        }
+        else
+        {
+          sortResponse = (ServerSideSortResponseControl)c;
+        }
       }
       else if (c.getOID().equals(OID_VLV_RESPONSE_CONTROL))
       {
-        vlvResponse = VLVResponseControl.decodeControl(c);
+        if(c instanceof LDAPControl)
+        {
+          vlvResponse = VLVResponseControl.DECODER.decode(c.isCritical(), ((LDAPControl)c).getValue());
+        }
+        else
+        {
+          vlvResponse = (VLVResponseControl)c;
+        }
       }
       else
       {
@@ -973,7 +1076,7 @@
     ArrayList<Control> requestControls = new ArrayList<Control>();
     requestControls.add(new ServerSideSortRequestControl(sortOrder));
     requestControls.add(new VLVRequestControl(0, 3,
-                                              new ASN1OctetString("albert")));
+                                              ByteString.valueOf("albert")));
 
     InternalSearchOperation internalSearch =
         new InternalSearchOperation(conn, conn.nextOperationID(),
@@ -1010,11 +1113,25 @@
     {
       if (c.getOID().equals(OID_SERVER_SIDE_SORT_RESPONSE_CONTROL))
       {
-        sortResponse = ServerSideSortResponseControl.decodeControl(c);
+        if(c instanceof LDAPControl)
+        {
+          sortResponse = ServerSideSortResponseControl.DECODER.decode(c.isCritical(), ((LDAPControl)c).getValue());
+        }
+        else
+        {
+          sortResponse = (ServerSideSortResponseControl)c;
+        }
       }
       else if (c.getOID().equals(OID_VLV_RESPONSE_CONTROL))
       {
-        vlvResponse = VLVResponseControl.decodeControl(c);
+        if(c instanceof LDAPControl)
+        {
+          vlvResponse = VLVResponseControl.DECODER.decode(c.isCritical(), ((LDAPControl)c).getValue());
+        }
+        else
+        {
+          vlvResponse = (VLVResponseControl)c;
+        }
       }
       else
       {
@@ -1048,7 +1165,7 @@
     ArrayList<Control> requestControls = new ArrayList<Control>();
     requestControls.add(new ServerSideSortRequestControl(sortOrder));
     requestControls.add(new VLVRequestControl(1, 3,
-                                              new ASN1OctetString("albert")));
+                                              ByteString.valueOf("albert")));
 
     InternalSearchOperation internalSearch =
         new InternalSearchOperation(conn, conn.nextOperationID(),
@@ -1086,11 +1203,25 @@
     {
       if (c.getOID().equals(OID_SERVER_SIDE_SORT_RESPONSE_CONTROL))
       {
-        sortResponse = ServerSideSortResponseControl.decodeControl(c);
+        if(c instanceof LDAPControl)
+        {
+          sortResponse = ServerSideSortResponseControl.DECODER.decode(c.isCritical(), ((LDAPControl)c).getValue());
+        }
+        else
+        {
+          sortResponse = (ServerSideSortResponseControl)c;
+        }
       }
       else if (c.getOID().equals(OID_VLV_RESPONSE_CONTROL))
       {
-        vlvResponse = VLVResponseControl.decodeControl(c);
+        if(c instanceof LDAPControl)
+        {
+          vlvResponse = VLVResponseControl.DECODER.decode(c.isCritical(), ((LDAPControl)c).getValue());
+        }
+        else
+        {
+          vlvResponse = (VLVResponseControl)c;
+        }
       }
       else
       {
@@ -1123,7 +1254,7 @@
 
     ArrayList<Control> requestControls = new ArrayList<Control>();
     requestControls.add(new ServerSideSortRequestControl(sortOrder));
-    requestControls.add(new VLVRequestControl(0, 3, new ASN1OctetString("zz")));
+    requestControls.add(new VLVRequestControl(0, 3, ByteString.valueOf("zz")));
 
     InternalSearchOperation internalSearch =
         new InternalSearchOperation(conn, conn.nextOperationID(),
@@ -1159,7 +1290,14 @@
     {
       if (c.getOID().equals(OID_VLV_RESPONSE_CONTROL))
       {
-        vlvResponse = VLVResponseControl.decodeControl(c);
+        if(c instanceof LDAPControl)
+        {
+          vlvResponse = VLVResponseControl.DECODER.decode(c.isCritical(), ((LDAPControl)c).getValue());
+        }
+        else
+        {
+          vlvResponse = (VLVResponseControl)c;
+        }
       }
     }
 
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/backends/jeb/TestVerifyJob.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/backends/jeb/TestVerifyJob.java
index c0ced3f..b912076 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/backends/jeb/TestVerifyJob.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/backends/jeb/TestVerifyJob.java
@@ -441,10 +441,10 @@
       byte[] shortBytes = new byte[3];
       DatabaseEntry key= new DatabaseEntry(shortBytes);
       Entry testEntry=bldStatEntry(junkDN);
-      byte []entryBytes =
-           JebFormat.entryToDatabase(testEntry,
+      ByteString entryBytes =
+           ID2Entry.entryToDatabase(testEntry,
                                      new DataConfig(false, false, null));
-      DatabaseEntry data= new DatabaseEntry(entryBytes);
+      DatabaseEntry data= new DatabaseEntry(entryBytes.toByteArray());
       assertTrue(id2entry.putRaw(txn, key, data));
 
       //add entry with ramdom bytes
@@ -773,8 +773,8 @@
     DatabaseEntry key= new EntryID(id).getDatabaseEntry();
     Entry testEntry=bldStatEntry(dn);
     byte []entryBytes =
-         JebFormat.entryToDatabase(testEntry,
-                                   new DataConfig(false, false, null));
+         ID2Entry.entryToDatabase(testEntry,
+                                   new DataConfig(false, false, null)).toByteArray();
     if(trashFormat)
       entryBytes[0] = 0x67;
     DatabaseEntry data= new DatabaseEntry(entryBytes);
@@ -876,7 +876,7 @@
       attrType = DirectoryServer.getDefaultAttributeType(type);
     List<Attribute> attrList = e.getAttribute(attrType, null);
     AttributeValue v = attrList.get(0).iterator().next();
-    long retVal = Long.parseLong(v.getStringValue());
+    long retVal = Long.parseLong(v.getValue().toString());
     return (retVal);
   }
 
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/controls/MatchedValuesControlTest.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/controls/MatchedValuesControlTest.java
index 7b51bb0..8d6f678 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/controls/MatchedValuesControlTest.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/controls/MatchedValuesControlTest.java
@@ -32,15 +32,12 @@
 import org.opends.server.api.MatchingRuleFactory;
 import org.opends.server.api.MatchingRule;
 import org.opends.server.core.DirectoryServer;
-import org.opends.server.protocols.asn1.ASN1Element;
-import org.opends.server.protocols.asn1.ASN1OctetString;
 import org.opends.server.schema.BooleanEqualityMatchingRuleFactory;
 import org.opends.server.schema.DistinguishedNameEqualityMatchingRuleFactory;
 import org.opends.server.schema.IntegerEqualityMatchingRuleFactory;
-import org.opends.server.types.AttributeType;
-import org.opends.server.types.AttributeValue;
-import org.opends.server.types.ByteString;
-import org.opends.server.types.LDAPException;
+import org.opends.server.types.*;
+import org.opends.server.protocols.asn1.ASN1Writer;
+import org.opends.server.protocols.asn1.ASN1;
 import org.testng.annotations.DataProvider;
 import org.testng.annotations.Test;
 
@@ -93,7 +90,7 @@
     try
     {
       mvf = MatchedValuesFilter.createEqualityFilter((String) null,
-          (ASN1OctetString) null);
+          (ByteString) null);
       assertTrue(false, "Expected NullPointerException");
     }
     catch (NullPointerException e)
@@ -109,7 +106,7 @@
     try
     {
       mvf = MatchedValuesFilter.createEqualityFilter(type,
-          (ASN1OctetString) null);
+          (ByteString) null);
       assertTrue(false, "Expected NullPointerException");
     }
     catch (NullPointerException e)
@@ -121,11 +118,11 @@
       // excepted behavior
     }
 
-    mvf = MatchedValuesFilter.createEqualityFilter(type, new ASN1OctetString(
+    mvf = MatchedValuesFilter.createEqualityFilter(type, ByteString.valueOf(
         value));
     assertNotNull(mvf);
     assertEquals(mvf.getRawAttributeType(), type);
-    assertEquals(mvf.getRawAssertionValue(), new ASN1OctetString(value));
+    assertEquals(mvf.getRawAssertionValue(), ByteString.valueOf(value));
     assertEquals(mvf.getMatchType(), MatchedValuesFilter.EQUALITY_MATCH_TYPE);
     checkEncodeDecode(mvf);
 
@@ -133,7 +130,7 @@
     try
     {
       mvf = MatchedValuesFilter.createEqualityFilter((String) null,
-          new ASN1OctetString(value));
+          ByteString.valueOf(value));
       assertTrue(false, "Expected NullPointerException");
     }
     catch (NullPointerException e)
@@ -152,7 +149,7 @@
     AttributeValue attVal = null;
     if (attType != null)
     {
-      attVal = new AttributeValue(attType, value);
+      attVal = AttributeValues.create(attType, value);
     }
 
     // Check null, null
@@ -245,14 +242,14 @@
     // input parameter
     String             rawAttTypeTest = type;
     AttributeType         attTypeTest = DirectoryServer.getAttributeType(type);
-    ASN1OctetString       subInitialTest = new ASN1OctetString(subInitial);
+    ByteString            subInitialTest = ByteString.valueOf(subInitial);
     List<ByteString> subAnyTest =
       new ArrayList<ByteString>(subAny.size());
     for (String s : subAny)
     {
-      subAnyTest.add(new ASN1OctetString(s));
+      subAnyTest.add(ByteString.valueOf(s));
     }
-    ByteString subFinalTest = new ASN1OctetString(subFinal);
+    ByteString subFinalTest = ByteString.valueOf(subFinal);
 
     // test parameter
     AttributeType    attTypeCurrent;
@@ -389,7 +386,7 @@
     {
 
       mvf = MatchedValuesFilter.createGreaterOrEqualFilter((String) null,
-          (ASN1OctetString) null);
+          (ByteString) null);
       assertTrue(false, "Expected NullPointerException");
     }
     catch (NullPointerException e)
@@ -405,7 +402,7 @@
     try
     {
       mvf = MatchedValuesFilter.createGreaterOrEqualFilter(type,
-          (ASN1OctetString) null);
+          (ByteString) null);
       assertTrue(false, "Expected NullPointerException");
     }
     catch (NullPointerException e)
@@ -424,10 +421,10 @@
     if ((type != null) && (value != null))
     {
       mvf = MatchedValuesFilter.createGreaterOrEqualFilter(type,
-          new ASN1OctetString(value));
+          ByteString.valueOf(value));
       assertNotNull(mvf);
       assertEquals(mvf.getRawAttributeType(), type);
-      assertEquals(mvf.getRawAssertionValue(), new ASN1OctetString(value));
+      assertEquals(mvf.getRawAssertionValue(), ByteString.valueOf(value));
       assertEquals(mvf.getMatchType(),
           MatchedValuesFilter.GREATER_OR_EQUAL_TYPE);
     }
@@ -436,7 +433,7 @@
     try
     {
       mvf = MatchedValuesFilter.createGreaterOrEqualFilter((String) null,
-          new ASN1OctetString(value));
+          ByteString.valueOf(value));
       assertTrue(false, "Expected NullPointerException");
     }
     catch (NullPointerException e)
@@ -455,7 +452,7 @@
     AttributeValue attVal = null;
     if (attType != null)
     {
-      attVal = new AttributeValue(attType, value);
+      attVal = AttributeValues.create(attType, value);
     }
 
     // Check null, null
@@ -533,7 +530,7 @@
     try
     {
       mvf = MatchedValuesFilter.createLessOrEqualFilter((String) null,
-          (ASN1OctetString) null);
+          (ByteString) null);
     }
     catch (NullPointerException e)
     {
@@ -548,7 +545,7 @@
     try
     {
       mvf = MatchedValuesFilter.createLessOrEqualFilter(type,
-          (ASN1OctetString) null);
+          (ByteString) null);
     }
     catch (NullPointerException e)
     {
@@ -561,17 +558,17 @@
 
     // Check type, value
     mvf = MatchedValuesFilter.createLessOrEqualFilter(type,
-        new ASN1OctetString(value));
+        ByteString.valueOf(value));
     assertNotNull(mvf);
     assertEquals(mvf.getRawAttributeType(), type);
-    assertEquals(mvf.getRawAssertionValue(), new ASN1OctetString(value));
+    assertEquals(mvf.getRawAssertionValue(), ByteString.valueOf(value));
     assertEquals(mvf.getMatchType(), MatchedValuesFilter.LESS_OR_EQUAL_TYPE);
 
     // Check null, value
     try
     {
       mvf = MatchedValuesFilter.createLessOrEqualFilter((String) null,
-          new ASN1OctetString(value));
+          ByteString.valueOf(value));
     }
     catch (NullPointerException e)
     {
@@ -590,7 +587,7 @@
     AttributeValue attVal = null ;
     if (attType != null)
     {
-      new AttributeValue(attType, value);
+      AttributeValues.create(attType, value);
     }
 
     // Check null, null
@@ -729,7 +726,7 @@
     try
     {
       mvf = MatchedValuesFilter.createApproximateFilter((String) null,
-          (ASN1OctetString) null);
+          (ByteString) null);
       assertTrue(false, "Expected NullPointerException");
     }
     catch (NullPointerException e)
@@ -745,7 +742,7 @@
     try
     {
       mvf = MatchedValuesFilter.createApproximateFilter(type,
-          (ASN1OctetString) null);
+          (ByteString) null);
       assertTrue(false, "Expected NullPointerException");
     }
     catch (NullPointerException e)
@@ -759,17 +756,17 @@
 
     // Check type, value
     mvf = MatchedValuesFilter.createApproximateFilter(type,
-        new ASN1OctetString(value));
+        ByteString.valueOf(value));
     assertNotNull(mvf);
     assertEquals(mvf.getRawAttributeType(), type);
-    assertEquals(mvf.getRawAssertionValue(), new ASN1OctetString(value));
+    assertEquals(mvf.getRawAssertionValue(), ByteString.valueOf(value));
     assertEquals(mvf.getMatchType(), MatchedValuesFilter.APPROXIMATE_MATCH_TYPE);
 
     // Check null, value
     try
     {
       mvf = MatchedValuesFilter.createApproximateFilter((String) null,
-          new ASN1OctetString(value));
+          ByteString.valueOf(value));
       assertTrue(false, "Expected NullPointerException");
     }
     catch (NullPointerException e)
@@ -788,7 +785,7 @@
     AttributeValue attVal = null ;
     if (attType != null)
     {
-      attVal = new AttributeValue(attType, value);
+      attVal = AttributeValues.create(attType, value);
     }
 
     // Check null, null
@@ -886,15 +883,15 @@
     String          rawAttTypeTest = type ;
     AttributeType      attTypeTest = DirectoryServer.getAttributeType(type) ;
     String             matchingRuleIdTest = matchingRule.getOID() ;
-    ASN1OctetString rawAttValueTest = (attTypeTest == null) ? null : new ASN1OctetString(value);
-    AttributeValue     attValueTest = (attTypeTest == null) ? null : new AttributeValue(attTypeTest, value);
+    ByteString rawAttValueTest = (attTypeTest == null) ? null : ByteString.valueOf(value);
+    AttributeValue     attValueTest = (attTypeTest == null) ? null : AttributeValues.create(attTypeTest, value);
     //
     // parameter used for the test.
     String          rawAttTypeTestCurrent;
     AttributeType      attTypeTestCurrent ;
     String          rawMatchingRuleidTestCurrent ;
     MatchingRule        matchingRuleidTestCurrent ;
-    ASN1OctetString rawAttValueTestCurrent;
+    ByteString      rawAttValueTestCurrent;
     AttributeValue     attValueTestCurrent;
 
 
@@ -959,13 +956,16 @@
    */
   private void checkEncodeDecode(MatchedValuesFilter mvf)
   {
-    ASN1Element asn1Elt = mvf.encode() ;
+    ByteStringBuilder bsb = new ByteStringBuilder();
+    ASN1Writer writer = ASN1.getWriter(bsb);
     try
     {
-      MatchedValuesFilter newMvf = MatchedValuesFilter.decode(asn1Elt) ;
+      mvf.encode(writer);
+      MatchedValuesFilter newMvf = MatchedValuesFilter.decode(ASN1
+          .getReader(bsb));
       assertEquals(newMvf.toString(), mvf.toString());
     }
-    catch (LDAPException e)
+    catch (Exception e)
     {
       assertTrue(false, "Unexpected LDAPException ; msg=" + e.getMessage());
     }
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/controls/PasswordControlTest.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/controls/PasswordControlTest.java
index e4bcb6c..cae98e3 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/controls/PasswordControlTest.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/controls/PasswordControlTest.java
@@ -31,10 +31,11 @@
 import java.util.HashMap;
 import java.util.Set;
 
-import org.opends.server.protocols.asn1.ASN1Boolean;
-import org.opends.server.protocols.asn1.ASN1OctetString;
-import org.opends.server.types.Control;
-import org.opends.server.types.LDAPException;
+import org.opends.server.types.*;
+import org.opends.server.protocols.ldap.LDAPControl;
+import org.opends.server.protocols.ldap.LDAPReader;
+import org.opends.server.protocols.asn1.ASN1;
+import org.opends.server.protocols.asn1.ASN1Writer;
 import org.testng.annotations.DataProvider;
 import org.testng.annotations.Test;
 
@@ -199,17 +200,15 @@
   }
 
   /**
-   * Create values for PasswordControl
+   * Create values for PasswordExpiredControl
    */
-  @DataProvider(name = "passwordControlData")
+  @DataProvider(name = "passwordExpiredControlData")
   public Object[][] createPasswordExpiredControlData()
   {
 
     return new Object[][] {
-     { OID_NS_PASSWORD_EXPIRED, true , -1},
-     { OID_NS_PASSWORD_EXPIRED, false , 0},
-     { OID_NS_PASSWORD_EXPIRING, true,  1},
-     { OID_NS_PASSWORD_EXPIRING, false, 2},
+     { true },
+     { false },
     };
   }
 
@@ -227,9 +226,9 @@
   /**
    * Test "Netscape password expired control" implementation
    */
-  @Test(dataProvider = "passwordControlData")
+  @Test(dataProvider = "passwordExpiredControlData")
   public void passwordExpiredControlTest(
-      String oid, boolean isCritical, int sec) throws Exception
+      boolean isCritical) throws Exception
   {
     // Check default constructor
     PasswordExpiredControl pec = new PasswordExpiredControl();
@@ -238,26 +237,27 @@
     assertEquals(pec.getOID(),OID_NS_PASSWORD_EXPIRED);
 
     // Check constructor with oid and boolean
-    pec = new PasswordExpiredControl(oid, isCritical);
+    pec = new PasswordExpiredControl(isCritical);
     assertNotNull(pec);
     assertEquals(pec.isCritical(),isCritical);
-    assertEquals(pec.getOID(),oid);
+    assertEquals(pec.getOID(),OID_NS_PASSWORD_EXPIRED);
 
     // Check the decode
-    Control control = new Control(oid,isCritical);
-    pec = PasswordExpiredControl.decodeControl(control);
+    LDAPControl control = new LDAPControl(OID_NS_PASSWORD_EXPIRED,isCritical);
+    pec = PasswordExpiredControl.DECODER.decode(control.isCritical(), control.getValue());
     assertNotNull(pec);
     assertEquals(pec.isCritical(),isCritical);
-    assertEquals(pec.getOID(),oid);
+    assertEquals(pec.getOID(),OID_NS_PASSWORD_EXPIRED);
 
-    control.setValue(new ASN1Boolean(true).decodeAsOctetString());
+    control = new LDAPControl(OID_NS_PASSWORD_EXPIRED, isCritical,
+        ByteString.valueOf("value"));
     try
     {
-      pec = PasswordExpiredControl.decodeControl(control);
+      pec = PasswordExpiredControl.DECODER.decode(control.isCritical(), control.getValue());
       assertTrue(false,
           "should be allow to create a passwordExpiredControl with value");
     }
-    catch (LDAPException e)
+    catch (DirectoryException e)
     {
       // Normal case
       assertTrue(true,
@@ -266,14 +266,39 @@
 
     // Check toString
     assertEquals("PasswordExpiredControl()", pec.toString());
+
+    // Check encode
+    ByteStringBuilder bsb = new ByteStringBuilder();
+    ASN1Writer writer = ASN1.getWriter(bsb);
+    pec = new PasswordExpiredControl(isCritical);
+    pec.write(writer);
+    control = LDAPReader.readControl(ASN1.getReader(bsb));
+    PasswordExpiredControl newPec =
+        PasswordExpiredControl.DECODER.decode(control.isCritical(), control.getValue());
+    assertNotNull(newPec);
+    assertEquals(newPec.isCritical(), isCritical);
+    assertEquals(pec.getOID(),OID_NS_PASSWORD_EXPIRED);
+  }
+
+  /**
+   * Create values for PasswordControl
+   */
+  @DataProvider(name = "passwordExpiringControlData")
+  public Object[][] createPasswordExpiringControlData()
+  {
+
+    return new Object[][] {
+     { true,  1},
+     { false, 2},
+    };
   }
 
   /**
    * Test "Netscape password expired control" implementation
    */
-  @Test(dataProvider = "passwordControlData")
+  @Test(dataProvider = "passwordExpiringControlData")
   public void passwordExpiringControlTest(
-      String oid, boolean isCritical, int sec) throws Exception
+      boolean isCritical, int sec) throws Exception
   {
     // Check constructor with int
     PasswordExpiringControl pec = new PasswordExpiringControl(sec);
@@ -284,56 +309,74 @@
     assertEquals(pec.getSecondsUntilExpiration(), sec);
 
     // Check constructor with oid, boolean and int
-    pec = new PasswordExpiringControl(oid, isCritical, sec);
+    pec = new PasswordExpiringControl(isCritical, sec);
     assertNotNull(pec);
     assertEquals(pec.isCritical(),isCritical);
-    assertEquals(pec.getOID(),oid);
+    assertEquals(pec.getOID(),OID_NS_PASSWORD_EXPIRING);
     assertEquals(pec.getSecondsUntilExpiration(), sec);
 
     // Check the decode
-    Control control = new Control(oid,isCritical);
+    LDAPControl control = new LDAPControl(OID_NS_PASSWORD_EXPIRING,isCritical);
     try
     {
-      pec = PasswordExpiringControl.decodeControl(control);
+      pec = PasswordExpiringControl.DECODER.decode(control.isCritical(), control.getValue());
       assertTrue(false,
           "shouldn't be allow to create PasswordExpiringControl without value");
     }
-    catch (LDAPException e)
+    catch (DirectoryException e)
     {
       // Normal case
       assertTrue(true,
           "shouldn't be allow to create PasswordExpiringControl without value");
     }
 
-    control.setValue(new ASN1OctetString("invalid value"));
+    control = new LDAPControl(OID_NS_PASSWORD_EXPIRING, isCritical,
+        ByteString.valueOf("Wrong value"));
     try
     {
-      pec = PasswordExpiringControl.decodeControl(control);
+      pec = PasswordExpiringControl.DECODER.decode(control.isCritical(), control.getValue());
       assertTrue(false,
       "shouldn't be allow to create PasswordExpiringControl with a wrong value");
     }
-    catch (LDAPException e)
+    catch (DirectoryException e)
     {
       // Normal case
       assertTrue(true,
       "shouldn't be allow to create PasswordExpiringControl with a wrong value");
     }
 
-    pec = new PasswordExpiringControl(oid, isCritical, sec);
-    control= new Control(oid,isCritical,pec.getValue());
-    PasswordExpiringControl newPec = PasswordExpiringControl.decodeControl(control);
-    assertNotNull(newPec);
-    assertEquals(newPec.isCritical(), isCritical);
-    assertEquals(newPec.getOID(), oid);
-    assertEquals(newPec.getSecondsUntilExpiration(), sec);
+    // Check encode/decode
+    ByteStringBuilder bsb = new ByteStringBuilder();
+    ASN1Writer writer = ASN1.getWriter(bsb);
+    pec = new PasswordExpiringControl(isCritical, sec);
+    pec.write(writer);
+    control = LDAPReader.readControl(ASN1.getReader(bsb));
+    pec = PasswordExpiringControl.DECODER.decode(control.isCritical(), control.getValue());
+    assertNotNull(pec);
+    assertEquals(pec.isCritical(), isCritical);
+    assertEquals(pec.getOID(),OID_NS_PASSWORD_EXPIRING);
+    assertEquals(pec.getSecondsUntilExpiration(), sec);
+  }
+
+  /**
+   * Create values for PasswordControl
+   */
+  @DataProvider(name = "passwordPolicyRequestControlData")
+  public Object[][] createPasswordPolicyRequestControlData()
+  {
+
+    return new Object[][] {
+     { true},
+     { false},
+    };
   }
 
   /**
    * Test PasswordPolicyRequestControl
    */
-  @Test(dataProvider = "passwordControlData")
+  @Test(dataProvider = "passwordPolicyRequestControlData")
   public void passwordPolicyRequestControlTest(
-      String oid, boolean isCritical, int sec) throws Exception
+      boolean isCritical) throws Exception
   {
     // Check default constructor
     PasswordPolicyRequestControl pec = new PasswordPolicyRequestControl();
@@ -342,26 +385,32 @@
     assertEquals(pec.getOID(),OID_PASSWORD_POLICY_CONTROL);
 
     // Check constructor with oid and boolean
-    pec = new PasswordPolicyRequestControl(oid, isCritical);
+    pec = new PasswordPolicyRequestControl(isCritical);
     assertNotNull(pec);
     assertEquals(pec.isCritical(),isCritical);
-    assertEquals(pec.getOID(),oid);
+    assertEquals(pec.getOID(),OID_PASSWORD_POLICY_CONTROL);
 
-    // Check the decode
-    Control control = new Control(oid,isCritical);
-    pec = PasswordPolicyRequestControl.decodeControl(control);
+    // Check the encode/decode
+    ByteStringBuilder bsb = new ByteStringBuilder();
+    ASN1Writer writer = ASN1.getWriter(bsb);
+    pec = new PasswordPolicyRequestControl(isCritical);
+    pec.write(writer);
+    LDAPControl control = LDAPReader
+        .readControl(ASN1.getReader(bsb));
+    pec = PasswordPolicyRequestControl.DECODER.decode(control.isCritical(), control.getValue());
     assertNotNull(pec);
     assertEquals(pec.isCritical(),isCritical);
-    assertEquals(pec.getOID(),oid);
+    assertEquals(pec.getOID(),OID_PASSWORD_POLICY_CONTROL);
 
-    control.setValue(new ASN1Boolean(true).decodeAsOctetString());
+    control = new LDAPControl(OID_PASSWORD_POLICY_CONTROL,
+        isCritical, ByteString.valueOf("value"));
     try
     {
-      pec = PasswordPolicyRequestControl.decodeControl(control);
+      pec = PasswordPolicyRequestControl.DECODER.decode(control.isCritical(), control.getValue());
       assertTrue(false,
           "should be allow to create a PasswordPolicyRequestControl with value");
     }
-    catch (LDAPException e)
+    catch (DirectoryException e)
     {
       // Normal case
       assertTrue(true,
@@ -381,12 +430,10 @@
   {
 
     return new Object[][] {
-     { OID_PASSWORD_POLICY_CONTROL, true , -1},
-     { OID_PASSWORD_POLICY_CONTROL, false , -1},
-     { OID_PASSWORD_POLICY_CONTROL, true , 0},
-     { OID_PASSWORD_POLICY_CONTROL, false , 0},
-     { OID_NS_PASSWORD_EXPIRING, true,      1},
-     { OID_NS_PASSWORD_EXPIRING, false,     2}
+     { true , -1},
+     { false , -1},
+     { true , 0},
+     { false , 0}
     };
   }
 
@@ -395,7 +442,7 @@
    */
    @Test(dataProvider = "passwordPolicyResponseControl")
   public void passwordPolicyResponseControlTest(
-      String oid, boolean isCritical, int warningValue)
+      boolean isCritical, int warningValue)
       throws Exception
   {
     // Check default constructor
@@ -420,6 +467,7 @@
         assertEquals(warningType, pprc.getWarningType());
         assertEquals(errorType, pprc.getErrorType());
         assertEquals(pprc.getWarningValue(),warningValue);
+        assertEquals(pprc.getOID(), OID_PASSWORD_POLICY_CONTROL);
       }
     }
 
@@ -433,30 +481,37 @@
       for (PasswordPolicyWarningType warningType : PasswordPolicyWarningType
           .values())
       {
-        pprc = new PasswordPolicyResponseControl(oid, isCritical,
+        pprc = new PasswordPolicyResponseControl(isCritical,
             warningType, warningValue, errorType);
         assertNotNull(pprc);
         assertEquals(warningType, pprc.getWarningType());
         assertEquals(errorType, pprc.getErrorType());
         assertEquals(pprc.getWarningValue(), warningValue);
+        assertEquals(pprc.getOID(), OID_PASSWORD_POLICY_CONTROL);
       }
     }
 
 
-    // check decode
-    Control control ;
+    // check encode/decode
+    PasswordPolicyResponseControl control ;
+    ByteStringBuilder bsb = new ByteStringBuilder();
+    ASN1Writer writer = ASN1.getWriter(bsb);
     for (PasswordPolicyErrorType errorType : PasswordPolicyErrorType.values())
     {
       for (PasswordPolicyWarningType warningType : PasswordPolicyWarningType
           .values())
       {
-        control = new PasswordPolicyResponseControl(oid, isCritical,
+        bsb.clear();
+        control = new PasswordPolicyResponseControl(isCritical,
             warningType, warningValue, errorType);
-        pprc = PasswordPolicyResponseControl.decodeControl(control);
+        control.write(writer);
+        LDAPControl c = LDAPReader.readControl(ASN1.getReader(bsb));
+        pprc = PasswordPolicyResponseControl.DECODER.decode(c.isCritical(), c.getValue());
         assertNotNull(pprc);
         assertEquals(warningType, pprc.getWarningType());
         assertEquals(errorType, pprc.getErrorType());
         assertEquals(pprc.getWarningValue(), warningValue);
+        assertEquals(pprc.getOID(), OID_PASSWORD_POLICY_CONTROL);
 
         // check to String
         String toString =
@@ -473,11 +528,11 @@
         // check null value for the control
         try
         {
-          control.setValue(null);
-          pprc = PasswordPolicyResponseControl.decodeControl(control);
+          c = new LDAPControl(OID_PASSWORD_POLICY_CONTROL, isCritical);
+          pprc = PasswordPolicyResponseControl.DECODER.decode(c.isCritical(), c.getValue());
           assertTrue(false,"the control should have a value");
         }
-        catch (LDAPException e)
+        catch (DirectoryException e)
         {
           // normal case
           assertTrue(true,"the control should have a value");
@@ -485,27 +540,33 @@
 
 
         // check null warning type
-        control = new PasswordPolicyResponseControl(oid, isCritical,
+        bsb.clear();
+        control = new PasswordPolicyResponseControl(isCritical,
             null, warningValue, errorType);
+        control.write(writer);
+        c = LDAPReader.readControl(ASN1.getReader(bsb));
         try
         {
-          pprc = PasswordPolicyResponseControl.decodeControl(control);
+          pprc = PasswordPolicyResponseControl.DECODER.decode(c.isCritical(), c.getValue());
           assertNull(pprc.getWarningType());
         }
-        catch (LDAPException e)
+        catch (DirectoryException e)
         {
           assertTrue(false,"We should be able to decode the control");
         }
 
         // check null error type
-        control = new PasswordPolicyResponseControl(oid, isCritical,
+        bsb.clear();
+        control = new PasswordPolicyResponseControl(isCritical,
             warningType, warningValue, null);
+        control.write(writer);
+        c = LDAPReader.readControl(ASN1.getReader(bsb));
         try
         {
-          pprc = PasswordPolicyResponseControl.decodeControl(control);
+          pprc = PasswordPolicyResponseControl.DECODER.decode(c.isCritical(), c.getValue());
           assertNull(pprc.getErrorType());
         }
-        catch (LDAPException e)
+        catch (DirectoryException e)
         {
           assertTrue(false,"We should be able to decode the control");
         }
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/controls/PasswordPolicyControlTestCase.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/controls/PasswordPolicyControlTestCase.java
index d54e352..a05b24b 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/controls/PasswordPolicyControlTestCase.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/controls/PasswordPolicyControlTestCase.java
@@ -31,13 +31,13 @@
 import java.net.Socket;
 import java.util.ArrayList;
 import java.util.LinkedHashSet;
+import java.util.List;
 
 import org.testng.annotations.BeforeClass;
 import org.testng.annotations.DataProvider;
 import org.testng.annotations.Test;
 
 import org.opends.server.TestCaseUtils;
-import org.opends.server.protocols.asn1.*;
 import org.opends.server.protocols.ldap.*;
 import org.opends.server.types.*;
 
@@ -102,21 +102,21 @@
       "ds-privilege-name: bypass-acl");
 
     Socket s = new Socket("127.0.0.1", TestCaseUtils.getServerLdapPort());
-    ASN1Reader r = new ASN1Reader(s);
-    ASN1Writer w = new ASN1Writer(s);
+    org.opends.server.tools.LDAPReader r = new org.opends.server.tools.LDAPReader(s);
+    org.opends.server.tools.LDAPWriter w = new org.opends.server.tools.LDAPWriter(s);
 
     try
     {
-      ArrayList<LDAPControl> controls = new ArrayList<LDAPControl>();
+      List<Control> controls = new ArrayList<Control>();
       controls.add(new LDAPControl(OID_PASSWORD_POLICY_CONTROL, true));
 
       BindRequestProtocolOp bindRequest = new BindRequestProtocolOp(
-           new ASN1OctetString("uid=test.user,o=test"), 3,
-           new ASN1OctetString("password"));
+           ByteString.valueOf("uid=test.user,o=test"), 3,
+           ByteString.valueOf("password"));
       LDAPMessage message = new LDAPMessage(1, bindRequest, controls);
-      w.writeElement(message.encode());
+      w.writeMessage(message);
 
-      message = LDAPMessage.decode(r.readElement().decodeAsSequence());
+      message = r.readMessage();
       BindResponseProtocolOp bindResponse = message.getBindResponseProtocolOp();
       assertEquals(bindResponse.getResultCode(), LDAPResultCode.SUCCESS);
 
@@ -125,12 +125,20 @@
       assertFalse(controls.isEmpty());
 
       boolean found = false;
-      for (LDAPControl c : controls)
+      for (Control c : controls)
       {
         if (c.getOID().equals(OID_PASSWORD_POLICY_CONTROL))
         {
-          PasswordPolicyResponseControl pwpControl =
-               PasswordPolicyResponseControl.decodeControl(c.getControl());
+          PasswordPolicyResponseControl pwpControl;
+          if(c instanceof LDAPControl)
+          {
+            pwpControl =
+                PasswordPolicyResponseControl.DECODER.decode(c.isCritical(), ((LDAPControl)c).getValue());
+          }
+          else
+          {
+            pwpControl = (PasswordPolicyResponseControl)c;
+          }
           assertEquals(pwpControl.getErrorType(),
                        PasswordPolicyErrorType.CHANGE_AFTER_RESET);
           found = true;
@@ -144,15 +152,15 @@
       rawAttrs.add(RawAttribute.create("ou", "People"));
 
       AddRequestProtocolOp addRequest = new AddRequestProtocolOp(
-           new ASN1OctetString("ou=People,o=test"), rawAttrs);
+           ByteString.valueOf("ou=People,o=test"), rawAttrs);
 
-      controls = new ArrayList<LDAPControl>();
+      controls = new ArrayList<Control>();
       controls.add(new LDAPControl(OID_PASSWORD_POLICY_CONTROL, true));
 
       message = new LDAPMessage(2, addRequest, controls);
-      w.writeElement(message.encode());
+      w.writeMessage(message);
 
-      message = LDAPMessage.decode(r.readElement().decodeAsSequence());
+      message = r.readMessage();
       AddResponseProtocolOp addResponse = message.getAddResponseProtocolOp();
       assertFalse(addResponse.getResultCode() == LDAPResultCode.SUCCESS);
 
@@ -161,12 +169,20 @@
       assertFalse(controls.isEmpty());
 
       found = false;
-      for (LDAPControl c : controls)
+      for (Control c : controls)
       {
         if (c.getOID().equals(OID_PASSWORD_POLICY_CONTROL))
         {
-          PasswordPolicyResponseControl pwpControl =
-               PasswordPolicyResponseControl.decodeControl(c.getControl());
+          PasswordPolicyResponseControl pwpControl;
+          if(c instanceof LDAPControl)
+          {
+            pwpControl =
+                PasswordPolicyResponseControl.DECODER.decode(c.isCritical(), ((LDAPControl)c).getValue());
+          }
+          else
+          {
+            pwpControl = (PasswordPolicyResponseControl)c;
+          }
           assertEquals(pwpControl.getErrorType(),
                        PasswordPolicyErrorType.CHANGE_AFTER_RESET);
           found = true;
@@ -203,18 +219,18 @@
     TestCaseUtils.initializeTestBackend(true);
 
     Socket s = new Socket("127.0.0.1", TestCaseUtils.getServerLdapPort());
-    ASN1Reader r = new ASN1Reader(s);
-    ASN1Writer w = new ASN1Writer(s);
+    org.opends.server.tools.LDAPReader r = new org.opends.server.tools.LDAPReader(s);
+    org.opends.server.tools.LDAPWriter w = new org.opends.server.tools.LDAPWriter(s);
 
     try
     {
       BindRequestProtocolOp bindRequest = new BindRequestProtocolOp(
-           new ASN1OctetString("cn=Directory Manager"), 3,
-           new ASN1OctetString("password"));
+           ByteString.valueOf("cn=Directory Manager"), 3,
+           ByteString.valueOf("password"));
       LDAPMessage message = new LDAPMessage(1, bindRequest);
-      w.writeElement(message.encode());
+      w.writeMessage(message);
 
-      message = LDAPMessage.decode(r.readElement().decodeAsSequence());
+      message = r.readMessage();
       BindResponseProtocolOp bindResponse = message.getBindResponseProtocolOp();
       assertEquals(bindResponse.getResultCode(), LDAPResultCode.SUCCESS);
 
@@ -229,15 +245,15 @@
                         "{SSHA}0pZPpMIm6xSBIW4hGvR/72fjO4M9p3Ff1g7QFw=="));
 
       AddRequestProtocolOp addRequest = new AddRequestProtocolOp(
-           new ASN1OctetString("ou=uid=test.user,o=test"), rawAttrs);
+           ByteString.valueOf("ou=uid=test.user,o=test"), rawAttrs);
 
-      ArrayList<LDAPControl> controls = new ArrayList<LDAPControl>();
+      List<Control> controls = new ArrayList<Control>();
       controls.add(new LDAPControl(OID_PASSWORD_POLICY_CONTROL, true));
 
       message = new LDAPMessage(2, addRequest, controls);
-      w.writeElement(message.encode());
+      w.writeMessage(message);
 
-      message = LDAPMessage.decode(r.readElement().decodeAsSequence());
+      message = r.readMessage();
       AddResponseProtocolOp addResponse = message.getAddResponseProtocolOp();
       assertFalse(addResponse.getResultCode() == LDAPResultCode.SUCCESS);
 
@@ -246,12 +262,20 @@
       assertFalse(controls.isEmpty());
 
       boolean found = false;
-      for (LDAPControl c : controls)
+      for(Control c : controls)
       {
         if (c.getOID().equals(OID_PASSWORD_POLICY_CONTROL))
         {
-          PasswordPolicyResponseControl pwpControl =
-               PasswordPolicyResponseControl.decodeControl(c.getControl());
+          PasswordPolicyResponseControl pwpControl;
+          if(c instanceof LDAPControl)
+          {
+            pwpControl =
+                PasswordPolicyResponseControl.DECODER.decode(c.isCritical(), ((LDAPControl)c).getValue());
+          }
+          else
+          {
+            pwpControl = (PasswordPolicyResponseControl)c;
+          }
           assertEquals(pwpControl.getErrorType(),
                        PasswordPolicyErrorType.INSUFFICIENT_PASSWORD_QUALITY);
           found = true;
@@ -288,18 +312,18 @@
       "--add", "password-validator:Length-Based Password Validator");
 
     Socket s = new Socket("127.0.0.1", TestCaseUtils.getServerLdapPort());
-    ASN1Reader r = new ASN1Reader(s);
-    ASN1Writer w = new ASN1Writer(s);
+    org.opends.server.tools.LDAPReader r = new org.opends.server.tools.LDAPReader(s);
+    org.opends.server.tools.LDAPWriter w = new org.opends.server.tools.LDAPWriter(s);
 
     try
     {
       BindRequestProtocolOp bindRequest = new BindRequestProtocolOp(
-           new ASN1OctetString("cn=Directory Manager"), 3,
-           new ASN1OctetString("password"));
+           ByteString.valueOf("cn=Directory Manager"), 3,
+           ByteString.valueOf("password"));
       LDAPMessage message = new LDAPMessage(1, bindRequest);
-      w.writeElement(message.encode());
+      w.writeMessage(message);
 
-      message = LDAPMessage.decode(r.readElement().decodeAsSequence());
+      message = r.readMessage();
       BindResponseProtocolOp bindResponse = message.getBindResponseProtocolOp();
       assertEquals(bindResponse.getResultCode(), LDAPResultCode.SUCCESS);
 
@@ -313,15 +337,15 @@
       rawAttrs.add(RawAttribute.create("userPassword", "short"));
 
       AddRequestProtocolOp addRequest = new AddRequestProtocolOp(
-           new ASN1OctetString("ou=uid=test.user,o=test"), rawAttrs);
+           ByteString.valueOf("ou=uid=test.user,o=test"), rawAttrs);
 
-      ArrayList<LDAPControl> controls = new ArrayList<LDAPControl>();
+      List<Control> controls = new ArrayList<Control>();
       controls.add(new LDAPControl(OID_PASSWORD_POLICY_CONTROL, true));
 
       message = new LDAPMessage(2, addRequest, controls);
-      w.writeElement(message.encode());
+      w.writeMessage(message);
 
-      message = LDAPMessage.decode(r.readElement().decodeAsSequence());
+      message = r.readMessage();
       AddResponseProtocolOp addResponse = message.getAddResponseProtocolOp();
       assertFalse(addResponse.getResultCode() == LDAPResultCode.SUCCESS);
 
@@ -330,12 +354,20 @@
       assertFalse(controls.isEmpty());
 
       boolean found = false;
-      for (LDAPControl c : controls)
+      for(Control c : controls)
       {
         if (c.getOID().equals(OID_PASSWORD_POLICY_CONTROL))
         {
-          PasswordPolicyResponseControl pwpControl =
-               PasswordPolicyResponseControl.decodeControl(c.getControl());
+          PasswordPolicyResponseControl pwpControl;
+          if(c instanceof LDAPControl)
+          {
+            pwpControl =
+                PasswordPolicyResponseControl.DECODER.decode(c.isCritical(), ((LDAPControl)c).getValue());
+          }
+          else
+          {
+            pwpControl = (PasswordPolicyResponseControl)c;
+          }
           assertEquals(pwpControl.getErrorType(),
                        PasswordPolicyErrorType.INSUFFICIENT_PASSWORD_QUALITY);
           found = true;
@@ -391,36 +423,36 @@
       "ds-privilege-name: bypass-acl");
 
     Socket s = new Socket("127.0.0.1", TestCaseUtils.getServerLdapPort());
-    ASN1Reader r = new ASN1Reader(s);
-    ASN1Writer w = new ASN1Writer(s);
+    org.opends.server.tools.LDAPReader r = new org.opends.server.tools.LDAPReader(s);
+    org.opends.server.tools.LDAPWriter w = new org.opends.server.tools.LDAPWriter(s);
 
     try
     {
       BindRequestProtocolOp bindRequest = new BindRequestProtocolOp(
-           new ASN1OctetString("uid=test.user,o=test"), 3,
-           new ASN1OctetString("wrong"));
+           ByteString.valueOf("uid=test.user,o=test"), 3,
+           ByteString.valueOf("wrong"));
 
       for (int i=1; i <= 3; i++)
       {
         LDAPMessage message = new LDAPMessage(1, bindRequest);
-        w.writeElement(message.encode());
+        w.writeMessage(message);
 
-        message = LDAPMessage.decode(r.readElement().decodeAsSequence());
+        message = r.readMessage();
         BindResponseProtocolOp bindResponse = message.getBindResponseProtocolOp();
         assertFalse(bindResponse.getResultCode() == LDAPResultCode.SUCCESS);
       }
 
       bindRequest = new BindRequestProtocolOp(
-           new ASN1OctetString("uid=test.user,o=test"), 3,
-           new ASN1OctetString("password"));
+           ByteString.valueOf("uid=test.user,o=test"), 3,
+           ByteString.valueOf("password"));
 
-      ArrayList<LDAPControl> controls = new ArrayList<LDAPControl>();
+      List<Control> controls = new ArrayList<Control>();
       controls.add(new LDAPControl(OID_PASSWORD_POLICY_CONTROL, true));
 
       LDAPMessage message = new LDAPMessage(4, bindRequest, controls);
-      w.writeElement(message.encode());
+      w.writeMessage(message);
 
-      message = LDAPMessage.decode(r.readElement().decodeAsSequence());
+      message = r.readMessage();
       BindResponseProtocolOp bindResponse = message.getBindResponseProtocolOp();
       assertFalse(bindResponse.getResultCode() == LDAPResultCode.SUCCESS);
 
@@ -429,12 +461,20 @@
       assertFalse(controls.isEmpty());
 
       boolean found = false;
-      for (LDAPControl c : controls)
+      for(Control c : controls)
       {
         if (c.getOID().equals(OID_PASSWORD_POLICY_CONTROL))
         {
-          PasswordPolicyResponseControl pwpControl =
-               PasswordPolicyResponseControl.decodeControl(c.getControl());
+          PasswordPolicyResponseControl pwpControl;
+          if(c instanceof LDAPControl)
+          {
+            pwpControl =
+                PasswordPolicyResponseControl.DECODER.decode(c.isCritical(), ((LDAPControl)c).getValue());
+          }
+          else
+          {
+            pwpControl = (PasswordPolicyResponseControl)c;
+          }
           assertEquals(pwpControl.getErrorType(),
                        PasswordPolicyErrorType.ACCOUNT_LOCKED);
           found = true;
@@ -489,33 +529,33 @@
       "ds-privilege-name: bypass-acl");
 
     Socket s = new Socket("127.0.0.1", TestCaseUtils.getServerLdapPort());
-    ASN1Reader r = new ASN1Reader(s);
-    ASN1Writer w = new ASN1Writer(s);
+    org.opends.server.tools.LDAPReader r = new org.opends.server.tools.LDAPReader(s);
+    org.opends.server.tools.LDAPWriter w = new org.opends.server.tools.LDAPWriter(s);
 
     try
     {
       BindRequestProtocolOp bindRequest = new BindRequestProtocolOp(
-           new ASN1OctetString("uid=test.user,o=test"), 3,
-           new ASN1OctetString("password"));
+           ByteString.valueOf("uid=test.user,o=test"), 3,
+           ByteString.valueOf("password"));
       LDAPMessage message = new LDAPMessage(1, bindRequest);
-      w.writeElement(message.encode());
+      w.writeMessage(message);
 
-      message = LDAPMessage.decode(r.readElement().decodeAsSequence());
+      message = r.readMessage();
       BindResponseProtocolOp bindResponse = message.getBindResponseProtocolOp();
       assertEquals(bindResponse.getResultCode(), LDAPResultCode.SUCCESS);
 
 
       CompareRequestProtocolOp compareRequest =
-           new CompareRequestProtocolOp(new ASN1OctetString("o=test"), "o",
-                                        new ASN1OctetString("test"));
+           new CompareRequestProtocolOp(ByteString.valueOf("o=test"), "o",
+                                        ByteString.valueOf("test"));
 
-      ArrayList<LDAPControl> controls = new ArrayList<LDAPControl>();
+      List<Control> controls = new ArrayList<Control>();
       controls.add(new LDAPControl(OID_PASSWORD_POLICY_CONTROL, true));
 
       message = new LDAPMessage(2, compareRequest, controls);
-      w.writeElement(message.encode());
+      w.writeMessage(message);
 
-      message = LDAPMessage.decode(r.readElement().decodeAsSequence());
+      message = r.readMessage();
       CompareResponseProtocolOp compareResponse =
            message.getCompareResponseProtocolOp();
       assertFalse(compareResponse.getResultCode() == LDAPResultCode.SUCCESS);
@@ -525,12 +565,20 @@
       assertFalse(controls.isEmpty());
 
       boolean found = false;
-      for (LDAPControl c : controls)
+      for(Control c : controls)
       {
         if (c.getOID().equals(OID_PASSWORD_POLICY_CONTROL))
         {
-          PasswordPolicyResponseControl pwpControl =
-               PasswordPolicyResponseControl.decodeControl(c.getControl());
+          PasswordPolicyResponseControl pwpControl;
+          if(c instanceof LDAPControl)
+          {
+            pwpControl =
+                PasswordPolicyResponseControl.DECODER.decode(c.isCritical(), ((LDAPControl)c).getValue());
+          }
+          else
+          {
+            pwpControl = (PasswordPolicyResponseControl)c;
+          }
           assertEquals(pwpControl.getErrorType(),
                        PasswordPolicyErrorType.CHANGE_AFTER_RESET);
           found = true;
@@ -590,32 +638,32 @@
       "ou: People");
 
     Socket s = new Socket("127.0.0.1", TestCaseUtils.getServerLdapPort());
-    ASN1Reader r = new ASN1Reader(s);
-    ASN1Writer w = new ASN1Writer(s);
+    org.opends.server.tools.LDAPReader r = new org.opends.server.tools.LDAPReader(s);
+    org.opends.server.tools.LDAPWriter w = new org.opends.server.tools.LDAPWriter(s);
 
     try
     {
       BindRequestProtocolOp bindRequest = new BindRequestProtocolOp(
-           new ASN1OctetString("uid=test.user,o=test"), 3,
-           new ASN1OctetString("password"));
+           ByteString.valueOf("uid=test.user,o=test"), 3,
+           ByteString.valueOf("password"));
       LDAPMessage message = new LDAPMessage(1, bindRequest);
-      w.writeElement(message.encode());
+      w.writeMessage(message);
 
-      message = LDAPMessage.decode(r.readElement().decodeAsSequence());
+      message = r.readMessage();
       BindResponseProtocolOp bindResponse = message.getBindResponseProtocolOp();
       assertEquals(bindResponse.getResultCode(), LDAPResultCode.SUCCESS);
 
 
       DeleteRequestProtocolOp deleteRequest =
-           new DeleteRequestProtocolOp(new ASN1OctetString("ou=People,o=test"));
+           new DeleteRequestProtocolOp(ByteString.valueOf("ou=People,o=test"));
 
-      ArrayList<LDAPControl> controls = new ArrayList<LDAPControl>();
+      List<Control> controls = new ArrayList<Control>();
       controls.add(new LDAPControl(OID_PASSWORD_POLICY_CONTROL, true));
 
       message = new LDAPMessage(2, deleteRequest, controls);
-      w.writeElement(message.encode());
+      w.writeMessage(message);
 
-      message = LDAPMessage.decode(r.readElement().decodeAsSequence());
+      message = r.readMessage();
       DeleteResponseProtocolOp deleteResponse =
            message.getDeleteResponseProtocolOp();
       assertFalse(deleteResponse.getResultCode() == LDAPResultCode.SUCCESS);
@@ -625,12 +673,20 @@
       assertFalse(controls.isEmpty());
 
       boolean found = false;
-      for (LDAPControl c : controls)
+      for(Control c : controls)
       {
         if (c.getOID().equals(OID_PASSWORD_POLICY_CONTROL))
         {
-          PasswordPolicyResponseControl pwpControl =
-               PasswordPolicyResponseControl.decodeControl(c.getControl());
+          PasswordPolicyResponseControl pwpControl;
+          if(c instanceof LDAPControl)
+          {
+            pwpControl =
+                PasswordPolicyResponseControl.DECODER.decode(c.isCritical(), ((LDAPControl)c).getValue());
+          }
+          else
+          {
+            pwpControl = (PasswordPolicyResponseControl)c;
+          }
           assertEquals(pwpControl.getErrorType(),
                        PasswordPolicyErrorType.CHANGE_AFTER_RESET);
           found = true;
@@ -732,18 +788,18 @@
       "ds-privilege-name: bypass-acl");
 
     Socket s = new Socket("127.0.0.1", TestCaseUtils.getServerLdapPort());
-    ASN1Reader r = new ASN1Reader(s);
-    ASN1Writer w = new ASN1Writer(s);
+    org.opends.server.tools.LDAPReader r = new org.opends.server.tools.LDAPReader(s);
+    org.opends.server.tools.LDAPWriter w = new org.opends.server.tools.LDAPWriter(s);
 
     try
     {
       BindRequestProtocolOp bindRequest = new BindRequestProtocolOp(
-           new ASN1OctetString(userDN), 3,
-           new ASN1OctetString("password"));
+           ByteString.valueOf(userDN), 3,
+           ByteString.valueOf("password"));
       LDAPMessage message = new LDAPMessage(1, bindRequest);
-      w.writeElement(message.encode());
+      w.writeMessage(message);
 
-      message = LDAPMessage.decode(r.readElement().decodeAsSequence());
+      message = r.readMessage();
       BindResponseProtocolOp bindResponse = message.getBindResponseProtocolOp();
       assertEquals(bindResponse.getResultCode(), LDAPResultCode.SUCCESS);
 
@@ -753,15 +809,15 @@
                                       "foo"));
 
       ModifyRequestProtocolOp modifyRequest =
-           new ModifyRequestProtocolOp(new ASN1OctetString(entryDN), mods);
+           new ModifyRequestProtocolOp(ByteString.valueOf(entryDN), mods);
 
-      ArrayList<LDAPControl> controls = new ArrayList<LDAPControl>();
+      List<Control> controls = new ArrayList<Control>();
       controls.add(new LDAPControl(OID_PASSWORD_POLICY_CONTROL, true));
 
       message = new LDAPMessage(2, modifyRequest, controls);
-      w.writeElement(message.encode());
+      w.writeMessage(message);
 
-      message = LDAPMessage.decode(r.readElement().decodeAsSequence());
+      message = r.readMessage();
       ModifyResponseProtocolOp modifyResponse =
            message.getModifyResponseProtocolOp();
 
@@ -781,12 +837,20 @@
       assertFalse(controls.isEmpty());
 
       boolean found = false;
-      for (LDAPControl c : controls)
+      for(Control c : controls)
       {
         if (c.getOID().equals(OID_PASSWORD_POLICY_CONTROL))
         {
-          PasswordPolicyResponseControl pwpControl =
-               PasswordPolicyResponseControl.decodeControl(c.getControl());
+          PasswordPolicyResponseControl pwpControl;
+          if(c instanceof LDAPControl)
+          {
+            pwpControl =
+                PasswordPolicyResponseControl.DECODER.decode(c.isCritical(), ((LDAPControl)c).getValue());
+          }
+          else
+          {
+            pwpControl = (PasswordPolicyResponseControl)c;
+          }
           if (changeAfterReset) {
             assertEquals(pwpControl.getErrorType(),
                          PasswordPolicyErrorType.CHANGE_AFTER_RESET);
@@ -846,18 +910,18 @@
       "ds-privilege-name: bypass-acl");
 
     Socket s = new Socket("127.0.0.1", TestCaseUtils.getServerLdapPort());
-    ASN1Reader r = new ASN1Reader(s);
-    ASN1Writer w = new ASN1Writer(s);
+    org.opends.server.tools.LDAPReader r = new org.opends.server.tools.LDAPReader(s);
+    org.opends.server.tools.LDAPWriter w = new org.opends.server.tools.LDAPWriter(s);
 
     try
     {
       BindRequestProtocolOp bindRequest = new BindRequestProtocolOp(
-           new ASN1OctetString("uid=test.user,o=test"), 3,
-           new ASN1OctetString("password"));
+           ByteString.valueOf("uid=test.user,o=test"), 3,
+           ByteString.valueOf("password"));
       LDAPMessage message = new LDAPMessage(1, bindRequest);
-      w.writeElement(message.encode());
+      w.writeMessage(message);
 
-      message = LDAPMessage.decode(r.readElement().decodeAsSequence());
+      message = r.readMessage();
       BindResponseProtocolOp bindResponse = message.getBindResponseProtocolOp();
       assertEquals(bindResponse.getResultCode(), LDAPResultCode.SUCCESS);
 
@@ -868,15 +932,15 @@
 
       ModifyRequestProtocolOp modifyRequest =
            new ModifyRequestProtocolOp(
-                    new ASN1OctetString("uid=test.user,o=test"), mods);
+                    ByteString.valueOf("uid=test.user,o=test"), mods);
 
-      ArrayList<LDAPControl> controls = new ArrayList<LDAPControl>();
+      List<Control> controls = new ArrayList<Control>();
       controls.add(new LDAPControl(OID_PASSWORD_POLICY_CONTROL, true));
 
       message = new LDAPMessage(2, modifyRequest, controls);
-      w.writeElement(message.encode());
+      w.writeMessage(message);
 
-      message = LDAPMessage.decode(r.readElement().decodeAsSequence());
+      message = r.readMessage();
       ModifyResponseProtocolOp modifyResponse =
            message.getModifyResponseProtocolOp();
       assertFalse(modifyResponse.getResultCode() == LDAPResultCode.SUCCESS);
@@ -886,12 +950,20 @@
       assertFalse(controls.isEmpty());
 
       boolean found = false;
-      for (LDAPControl c : controls)
+      for(Control c : controls)
       {
         if (c.getOID().equals(OID_PASSWORD_POLICY_CONTROL))
         {
-          PasswordPolicyResponseControl pwpControl =
-               PasswordPolicyResponseControl.decodeControl(c.getControl());
+          PasswordPolicyResponseControl pwpControl;
+          if(c instanceof LDAPControl)
+          {
+            pwpControl =
+                PasswordPolicyResponseControl.DECODER.decode(c.isCritical(), ((LDAPControl)c).getValue());
+          }
+          else
+          {
+            pwpControl = (PasswordPolicyResponseControl)c;
+          }
           assertEquals(pwpControl.getErrorType(),
                        PasswordPolicyErrorType.PASSWORD_MOD_NOT_ALLOWED);
           found = true;
@@ -947,18 +1019,18 @@
       "ds-privilege-name: bypass-acl");
 
     Socket s = new Socket("127.0.0.1", TestCaseUtils.getServerLdapPort());
-    ASN1Reader r = new ASN1Reader(s);
-    ASN1Writer w = new ASN1Writer(s);
+    org.opends.server.tools.LDAPReader r = new org.opends.server.tools.LDAPReader(s);
+    org.opends.server.tools.LDAPWriter w = new org.opends.server.tools.LDAPWriter(s);
 
     try
     {
       BindRequestProtocolOp bindRequest = new BindRequestProtocolOp(
-           new ASN1OctetString("uid=test.user,o=test"), 3,
-           new ASN1OctetString("password"));
+           ByteString.valueOf("uid=test.user,o=test"), 3,
+           ByteString.valueOf("password"));
       LDAPMessage message = new LDAPMessage(1, bindRequest);
-      w.writeElement(message.encode());
+      w.writeMessage(message);
 
-      message = LDAPMessage.decode(r.readElement().decodeAsSequence());
+      message = r.readMessage();
       BindResponseProtocolOp bindResponse = message.getBindResponseProtocolOp();
       assertEquals(bindResponse.getResultCode(), LDAPResultCode.SUCCESS);
 
@@ -969,15 +1041,15 @@
 
       ModifyRequestProtocolOp modifyRequest =
            new ModifyRequestProtocolOp(
-                    new ASN1OctetString("uid=test.user,o=test"), mods);
+                    ByteString.valueOf("uid=test.user,o=test"), mods);
 
-      ArrayList<LDAPControl> controls = new ArrayList<LDAPControl>();
+      List<Control> controls = new ArrayList<Control>();
       controls.add(new LDAPControl(OID_PASSWORD_POLICY_CONTROL, true));
 
       message = new LDAPMessage(2, modifyRequest, controls);
-      w.writeElement(message.encode());
+      w.writeMessage(message);
 
-      message = LDAPMessage.decode(r.readElement().decodeAsSequence());
+      message = r.readMessage();
       ModifyResponseProtocolOp modifyResponse =
            message.getModifyResponseProtocolOp();
       assertFalse(modifyResponse.getResultCode() == LDAPResultCode.SUCCESS);
@@ -987,12 +1059,20 @@
       assertFalse(controls.isEmpty());
 
       boolean found = false;
-      for (LDAPControl c : controls)
+      for(Control c : controls)
       {
         if (c.getOID().equals(OID_PASSWORD_POLICY_CONTROL))
         {
-          PasswordPolicyResponseControl pwpControl =
-               PasswordPolicyResponseControl.decodeControl(c.getControl());
+          PasswordPolicyResponseControl pwpControl;
+          if(c instanceof LDAPControl)
+          {
+            pwpControl =
+                PasswordPolicyResponseControl.DECODER.decode(c.isCritical(), ((LDAPControl)c).getValue());
+          }
+          else
+          {
+            pwpControl = (PasswordPolicyResponseControl)c;
+          }
           assertEquals(pwpControl.getErrorType(),
                        PasswordPolicyErrorType.PASSWORD_IN_HISTORY);
           found = true;
@@ -1048,18 +1128,18 @@
       "ds-privilege-name: bypass-acl");
 
     Socket s = new Socket("127.0.0.1", TestCaseUtils.getServerLdapPort());
-    ASN1Reader r = new ASN1Reader(s);
-    ASN1Writer w = new ASN1Writer(s);
+    org.opends.server.tools.LDAPReader r = new org.opends.server.tools.LDAPReader(s);
+    org.opends.server.tools.LDAPWriter w = new org.opends.server.tools.LDAPWriter(s);
 
     try
     {
       BindRequestProtocolOp bindRequest = new BindRequestProtocolOp(
-           new ASN1OctetString("uid=test.user,o=test"), 3,
-           new ASN1OctetString("password"));
+           ByteString.valueOf("uid=test.user,o=test"), 3,
+           ByteString.valueOf("password"));
       LDAPMessage message = new LDAPMessage(1, bindRequest);
-      w.writeElement(message.encode());
+      w.writeMessage(message);
 
-      message = LDAPMessage.decode(r.readElement().decodeAsSequence());
+      message = r.readMessage();
       BindResponseProtocolOp bindResponse = message.getBindResponseProtocolOp();
       assertEquals(bindResponse.getResultCode(), LDAPResultCode.SUCCESS);
 
@@ -1070,15 +1150,15 @@
 
       ModifyRequestProtocolOp modifyRequest =
            new ModifyRequestProtocolOp(
-                    new ASN1OctetString("uid=test.user,o=test"), mods);
+                    ByteString.valueOf("uid=test.user,o=test"), mods);
 
-      ArrayList<LDAPControl> controls = new ArrayList<LDAPControl>();
+      List<Control> controls = new ArrayList<Control>();
       controls.add(new LDAPControl(OID_PASSWORD_POLICY_CONTROL, true));
 
       message = new LDAPMessage(2, modifyRequest, controls);
-      w.writeElement(message.encode());
+      w.writeMessage(message);
 
-      message = LDAPMessage.decode(r.readElement().decodeAsSequence());
+      message = r.readMessage();
       ModifyResponseProtocolOp modifyResponse =
            message.getModifyResponseProtocolOp();
       assertFalse(modifyResponse.getResultCode() == LDAPResultCode.SUCCESS);
@@ -1088,12 +1168,20 @@
       assertFalse(controls.isEmpty());
 
       boolean found = false;
-      for (LDAPControl c : controls)
+      for(Control c : controls)
       {
         if (c.getOID().equals(OID_PASSWORD_POLICY_CONTROL))
         {
-          PasswordPolicyResponseControl pwpControl =
-               PasswordPolicyResponseControl.decodeControl(c.getControl());
+          PasswordPolicyResponseControl pwpControl;
+          if(c instanceof LDAPControl)
+          {
+            pwpControl =
+                PasswordPolicyResponseControl.DECODER.decode(c.isCritical(), ((LDAPControl)c).getValue());
+          }
+          else
+          {
+            pwpControl = (PasswordPolicyResponseControl)c;
+          }
           assertEquals(pwpControl.getErrorType(),
                        PasswordPolicyErrorType.MUST_SUPPLY_OLD_PASSWORD);
           found = true;
@@ -1149,18 +1237,18 @@
       "ds-privilege-name: bypass-acl");
 
     Socket s = new Socket("127.0.0.1", TestCaseUtils.getServerLdapPort());
-    ASN1Reader r = new ASN1Reader(s);
-    ASN1Writer w = new ASN1Writer(s);
+    org.opends.server.tools.LDAPReader r = new org.opends.server.tools.LDAPReader(s);
+    org.opends.server.tools.LDAPWriter w = new org.opends.server.tools.LDAPWriter(s);
 
     try
     {
       BindRequestProtocolOp bindRequest = new BindRequestProtocolOp(
-           new ASN1OctetString("uid=test.user,o=test"), 3,
-           new ASN1OctetString("password"));
+           ByteString.valueOf("uid=test.user,o=test"), 3,
+           ByteString.valueOf("password"));
       LDAPMessage message = new LDAPMessage(1, bindRequest);
-      w.writeElement(message.encode());
+      w.writeMessage(message);
 
-      message = LDAPMessage.decode(r.readElement().decodeAsSequence());
+      message = r.readMessage();
       BindResponseProtocolOp bindResponse = message.getBindResponseProtocolOp();
       assertEquals(bindResponse.getResultCode(), LDAPResultCode.SUCCESS);
 
@@ -1171,15 +1259,15 @@
 
       ModifyRequestProtocolOp modifyRequest =
            new ModifyRequestProtocolOp(
-                    new ASN1OctetString("uid=test.user,o=test"), mods);
+                    ByteString.valueOf("uid=test.user,o=test"), mods);
 
-      ArrayList<LDAPControl> controls = new ArrayList<LDAPControl>();
+      List<Control> controls = new ArrayList<Control>();
       controls.add(new LDAPControl(OID_PASSWORD_POLICY_CONTROL, true));
 
       message = new LDAPMessage(2, modifyRequest, controls);
-      w.writeElement(message.encode());
+      w.writeMessage(message);
 
-      message = LDAPMessage.decode(r.readElement().decodeAsSequence());
+      message = r.readMessage();
       ModifyResponseProtocolOp modifyResponse =
            message.getModifyResponseProtocolOp();
       assertFalse(modifyResponse.getResultCode() == LDAPResultCode.SUCCESS);
@@ -1189,12 +1277,20 @@
       assertFalse(controls.isEmpty());
 
       boolean found = false;
-      for (LDAPControl c : controls)
+      for(Control c : controls)
       {
         if (c.getOID().equals(OID_PASSWORD_POLICY_CONTROL))
         {
-          PasswordPolicyResponseControl pwpControl =
-               PasswordPolicyResponseControl.decodeControl(c.getControl());
+          PasswordPolicyResponseControl pwpControl;
+          if(c instanceof LDAPControl)
+          {
+            pwpControl =
+                PasswordPolicyResponseControl.DECODER.decode(c.isCritical(), ((LDAPControl)c).getValue());
+          }
+          else
+          {
+            pwpControl = (PasswordPolicyResponseControl)c;
+          }
           assertEquals(pwpControl.getErrorType(),
                        PasswordPolicyErrorType.PASSWORD_TOO_YOUNG);
           found = true;
@@ -1254,34 +1350,34 @@
       "ou: People");
 
     Socket s = new Socket("127.0.0.1", TestCaseUtils.getServerLdapPort());
-    ASN1Reader r = new ASN1Reader(s);
-    ASN1Writer w = new ASN1Writer(s);
+    org.opends.server.tools.LDAPReader r = new org.opends.server.tools.LDAPReader(s);
+    org.opends.server.tools.LDAPWriter w = new org.opends.server.tools.LDAPWriter(s);
 
     try
     {
       BindRequestProtocolOp bindRequest = new BindRequestProtocolOp(
-           new ASN1OctetString("uid=test.user,o=test"), 3,
-           new ASN1OctetString("password"));
+           ByteString.valueOf("uid=test.user,o=test"), 3,
+           ByteString.valueOf("password"));
       LDAPMessage message = new LDAPMessage(1, bindRequest);
-      w.writeElement(message.encode());
+      w.writeMessage(message);
 
-      message = LDAPMessage.decode(r.readElement().decodeAsSequence());
+      message = r.readMessage();
       BindResponseProtocolOp bindResponse = message.getBindResponseProtocolOp();
       assertEquals(bindResponse.getResultCode(), LDAPResultCode.SUCCESS);
 
 
       ModifyDNRequestProtocolOp modifyDNRequest =
            new ModifyDNRequestProtocolOp(
-                    new ASN1OctetString("ou=People,o=test"),
-                    new ASN1OctetString("ou=Users"), true);
+                    ByteString.valueOf("ou=People,o=test"),
+                    ByteString.valueOf("ou=Users"), true);
 
-      ArrayList<LDAPControl> controls = new ArrayList<LDAPControl>();
+      List<Control> controls = new ArrayList<Control>();
       controls.add(new LDAPControl(OID_PASSWORD_POLICY_CONTROL, true));
 
       message = new LDAPMessage(2, modifyDNRequest, controls);
-      w.writeElement(message.encode());
+      w.writeMessage(message);
 
-      message = LDAPMessage.decode(r.readElement().decodeAsSequence());
+      message = r.readMessage();
       ModifyDNResponseProtocolOp modifyDNResponse =
            message.getModifyDNResponseProtocolOp();
       assertFalse(modifyDNResponse.getResultCode() == LDAPResultCode.SUCCESS);
@@ -1291,12 +1387,20 @@
       assertFalse(controls.isEmpty());
 
       boolean found = false;
-      for (LDAPControl c : controls)
+      for(Control c : controls)
       {
         if (c.getOID().equals(OID_PASSWORD_POLICY_CONTROL))
         {
-          PasswordPolicyResponseControl pwpControl =
-               PasswordPolicyResponseControl.decodeControl(c.getControl());
+          PasswordPolicyResponseControl pwpControl;
+          if(c instanceof LDAPControl)
+          {
+            pwpControl =
+                PasswordPolicyResponseControl.DECODER.decode(c.isCritical(), ((LDAPControl)c).getValue());
+          }
+          else
+          {
+            pwpControl = (PasswordPolicyResponseControl)c;
+          }
           assertEquals(pwpControl.getErrorType(),
                        PasswordPolicyErrorType.CHANGE_AFTER_RESET);
           found = true;
@@ -1351,37 +1455,37 @@
       "ds-privilege-name: bypass-acl");
 
     Socket s = new Socket("127.0.0.1", TestCaseUtils.getServerLdapPort());
-    ASN1Reader r = new ASN1Reader(s);
-    ASN1Writer w = new ASN1Writer(s);
+    org.opends.server.tools.LDAPReader r = new org.opends.server.tools.LDAPReader(s);
+    org.opends.server.tools.LDAPWriter w = new org.opends.server.tools.LDAPWriter(s);
 
     try
     {
       BindRequestProtocolOp bindRequest = new BindRequestProtocolOp(
-           new ASN1OctetString("uid=test.user,o=test"), 3,
-           new ASN1OctetString("password"));
+           ByteString.valueOf("uid=test.user,o=test"), 3,
+           ByteString.valueOf("password"));
       LDAPMessage message = new LDAPMessage(1, bindRequest);
-      w.writeElement(message.encode());
+      w.writeMessage(message);
 
-      message = LDAPMessage.decode(r.readElement().decodeAsSequence());
+      message = r.readMessage();
       BindResponseProtocolOp bindResponse = message.getBindResponseProtocolOp();
       assertEquals(bindResponse.getResultCode(), LDAPResultCode.SUCCESS);
 
 
       SearchRequestProtocolOp searchRequest =
-           new SearchRequestProtocolOp(new ASN1OctetString("o=test"),
+           new SearchRequestProtocolOp(ByteString.valueOf("o=test"),
                                        SearchScope.BASE_OBJECT,
                                        DereferencePolicy.NEVER_DEREF_ALIASES, 0,
                                        0, false,
                                        LDAPFilter.decode("(objectClass=*)"),
                                        new LinkedHashSet<String>());
 
-      ArrayList<LDAPControl> controls = new ArrayList<LDAPControl>();
+      List<Control> controls = new ArrayList<Control>();
       controls.add(new LDAPControl(OID_PASSWORD_POLICY_CONTROL, true));
 
       message = new LDAPMessage(2, searchRequest, controls);
-      w.writeElement(message.encode());
+      w.writeMessage(message);
 
-      message = LDAPMessage.decode(r.readElement().decodeAsSequence());
+      message = r.readMessage();
       SearchResultDoneProtocolOp searchDone =
            message.getSearchResultDoneProtocolOp();
       assertFalse(searchDone.getResultCode() == LDAPResultCode.SUCCESS);
@@ -1391,12 +1495,20 @@
       assertFalse(controls.isEmpty());
 
       boolean found = false;
-      for (LDAPControl c : controls)
+      for(Control c : controls)
       {
         if (c.getOID().equals(OID_PASSWORD_POLICY_CONTROL))
         {
-          PasswordPolicyResponseControl pwpControl =
-               PasswordPolicyResponseControl.decodeControl(c.getControl());
+          PasswordPolicyResponseControl pwpControl;
+          if(c instanceof LDAPControl)
+          {
+            pwpControl =
+                PasswordPolicyResponseControl.DECODER.decode(c.isCritical(), ((LDAPControl)c).getValue());
+          }
+          else
+          {
+            pwpControl = (PasswordPolicyResponseControl)c;
+          }
           assertEquals(pwpControl.getErrorType(),
                        PasswordPolicyErrorType.CHANGE_AFTER_RESET);
           found = true;
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/controls/PersistentSearchControlTest.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/controls/PersistentSearchControlTest.java
index aba735f..96f01fc 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/controls/PersistentSearchControlTest.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/controls/PersistentSearchControlTest.java
@@ -34,12 +34,13 @@
 import org.testng.annotations.DataProvider;
 import org.testng.annotations.Test;
 
-import static org.opends.server.util.ServerConstants.OID_NS_PASSWORD_EXPIRED;
 import static org.testng.Assert.*;
 
-import org.opends.server.types.Control;
-import org.opends.server.types.DN;
-import org.opends.server.types.LDAPException;
+import org.opends.server.types.*;
+import org.opends.server.protocols.asn1.ASN1;
+import org.opends.server.protocols.asn1.ASN1Writer;
+import org.opends.server.protocols.ldap.LDAPReader;
+import org.opends.server.protocols.ldap.LDAPControl;
 
 /**
  * Test ChangeNumber and ChangeNumberGenerator
@@ -229,10 +230,8 @@
 
     return new Object[][]
     {
-    { OID_NS_PASSWORD_EXPIRED, true , true, true },
-    { OID_NS_PASSWORD_EXPIRED, false  ,true, false },
-    {OID_PERSISTENT_SEARCH , true,  false, true },
-    {OID_PERSISTENT_SEARCH ,  false, false, false }, };
+    {true,  false, true },
+    {false, false, false }, };
   }
 
   /**
@@ -240,7 +239,7 @@
    */
   @Test(dataProvider = "persistentSearchControl")
   public void checkPersistentSearchControlTest(
-      String oid, boolean isCritical, boolean changesOnly, boolean returnECs)
+      boolean isCritical, boolean changesOnly, boolean returnECs)
       throws Exception
   {
     // Test contructor
@@ -267,51 +266,36 @@
     for (int i = 1; i <= 15; i++)
     {
       returnTypes = PersistentSearchChangeType.intToTypes(i);
-      PersistentSearchControl psc = new PersistentSearchControl(oid,
+      PersistentSearchControl psc = new PersistentSearchControl(
           isCritical, returnTypes, changesOnly, returnECs);
       assertNotNull(psc);
       assertEquals(isCritical, psc.isCritical());
-      assertEquals(oid, psc.getOID());
+      assertEquals(OID_PERSISTENT_SEARCH, psc.getOID());
       assertEquals(changesOnly, psc.getChangesOnly());
       assertEquals(returnECs, psc.getReturnECs());
       assertEquals(returnTypes.size(), psc.getChangeTypes().size());
     }
 
 
-    // Test decodeControl
+    // Test encode/decode
+    ByteStringBuilder bsb = new ByteStringBuilder();
+    ASN1Writer writer = ASN1.getWriter(bsb);
     for (int i = 1; i <= 15; i++)
     {
+      bsb.clear();
       returnTypes = PersistentSearchChangeType.intToTypes(i);
-      Control control = new PersistentSearchControl(oid,
+      PersistentSearchControl psc = new PersistentSearchControl(
           isCritical, returnTypes, changesOnly, returnECs);
-      PersistentSearchControl psc = PersistentSearchControl.decodeControl(control);
+      psc.write(writer);
+      LDAPControl control = LDAPReader.readControl(ASN1.getReader(bsb));
+      psc = PersistentSearchControl.DECODER.decode(control.isCritical(), control.getValue());
       assertNotNull(psc);
       assertEquals(isCritical, psc.isCritical());
-      assertEquals(oid, psc.getOID());
+      assertEquals(OID_PERSISTENT_SEARCH, psc.getOID());
       assertEquals(changesOnly, psc.getChangesOnly());
       assertEquals(returnECs, psc.getReturnECs());
       assertEquals(returnTypes.size(), psc.getChangeTypes().size());
 
-      // Check setChangeTypes
-      Set<PersistentSearchChangeType> newChangetype =
-        new HashSet<PersistentSearchChangeType>();
-      psc.setChangeTypes(newChangetype);
-      assertEquals(0, psc.getChangeTypes().size());
-      psc.setChangeTypes(returnTypes);
-      assertEquals(returnTypes.size(), psc.getChangeTypes().size());
-
-      // Check setChangesOnly
-      psc.setChangesOnly(!psc.getChangesOnly());
-      assertEquals(!changesOnly,psc.getChangesOnly());
-      psc.setChangesOnly(!psc.getChangesOnly());
-      assertEquals(changesOnly,psc.getChangesOnly());
-
-      // Check setReturnECs
-      psc.setReturnECs(!psc.getReturnECs());
-      assertEquals(!returnECs,psc.getReturnECs());
-      psc.setReturnECs(!psc.getReturnECs());
-      assertEquals(returnECs,psc.getReturnECs());
-
       // Check the toString
       String toString = "PersistentSearchControl(changeTypes=\"" +
       PersistentSearchChangeType.changeTypesToString(psc.getChangeTypes()) +
@@ -323,27 +307,25 @@
       // check null value for the control
       try
       {
-        control.setValue(null);
-        psc = PersistentSearchControl.decodeControl(control);
+        control = new LDAPControl(OID_PERSISTENT_SEARCH, isCritical);
+        psc = PersistentSearchControl.DECODER.decode(control.isCritical(), control.getValue());
         assertTrue(false,"the control should have a value");
       }
-      catch (LDAPException e)
+      catch (DirectoryException e)
       {
         // normal case
         assertTrue(true,"the control should have a value");
       }
 
       // check invalid value for the control
-      control = new PasswordPolicyResponseControl(oid, isCritical,
-          PasswordPolicyWarningType.GRACE_LOGINS_REMAINING, 2,
-          PasswordPolicyErrorType.ACCOUNT_LOCKED);
-
       try
       {
-        psc = PersistentSearchControl.decodeControl(control);
+        control = new LDAPControl(OID_PERSISTENT_SEARCH, isCritical,
+            ByteString.valueOf("invalid value"));
+        psc = PersistentSearchControl.DECODER.decode(control.isCritical(), control.getValue());
         assertTrue(false, "the control should have a value");
       }
-      catch (LDAPException e)
+      catch (DirectoryException e)
       {
         // normal case
         assertTrue(true, "the control should have a value");
@@ -361,17 +343,17 @@
   {
     return new Object[][]
     {
-    { OID_NS_PASSWORD_EXPIRED, true, 1, "cn=test" },
-    { OID_NS_PASSWORD_EXPIRED, false, 2, "dc=example,dc=com" },
-    { OID_PERSISTENT_SEARCH, true, 3, "cn=test, dc=example,dc=com" },
-    { OID_PERSISTENT_SEARCH, false, 4, "cn= new test, dc=example,dc=com" } };
+    { true, 1, "cn=test" },
+    { false, 2, "dc=example,dc=com" },
+    { true, 3, "cn=test, dc=example,dc=com" },
+    { false, 4, "cn= new test, dc=example,dc=com" } };
   }
   /**
    * Test EntryChangeNotificationControl
    */
   @Test(dataProvider = "entryChangeNotificationControl")
   public void checkEntryChangeNotificationControlTest(
-      String oid, boolean isCritical, long changeNumber, String dnString)
+      boolean isCritical, long changeNumber, String dnString)
       throws Exception
   {
     // Test contructor EntryChangeNotificationControl
@@ -379,6 +361,8 @@
     PersistentSearchChangeType[] types = PersistentSearchChangeType.values();
     EntryChangeNotificationControl ecnc = null ;
     EntryChangeNotificationControl newEcnc ;
+    ByteStringBuilder bsb = new ByteStringBuilder();
+    ASN1Writer writer = ASN1.getWriter(bsb);
     for (PersistentSearchChangeType type : types)
     {
       ecnc = new EntryChangeNotificationControl(type, changeNumber);
@@ -390,10 +374,13 @@
       assertEquals(false, ecnc.isCritical()) ;
       checkEntryChangeNotificationControlToString(ecnc);
 
-      // also check encode
+      // also check encode/decode
       try
       {
-        newEcnc = EntryChangeNotificationControl.decodeControl(ecnc);
+        bsb.clear();
+        ecnc.write(writer);
+        LDAPControl control = LDAPReader.readControl(ASN1.getReader(bsb));
+        newEcnc = EntryChangeNotificationControl.DECODER.decode(control.isCritical(), control.getValue());
         assertNotNull(newEcnc);
         assertEquals(ecnc.getOID(), newEcnc.getOID());
         assertEquals(ecnc.getChangeNumber(), newEcnc.getChangeNumber());
@@ -401,7 +388,7 @@
         assertNull(newEcnc.getPreviousDN());
         assertEquals(ecnc.isCritical(), newEcnc.isCritical());
       }
-      catch (LDAPException e)
+      catch (DirectoryException e)
       {
         if (type.compareTo(PersistentSearchChangeType.MODIFY_DN) == 0)
         {
@@ -431,10 +418,13 @@
       assertEquals(false, ecnc.isCritical()) ;
       checkEntryChangeNotificationControlToString(ecnc);
 
-      // also check encode
+      // also check encode/decode
       try
       {
-        newEcnc = EntryChangeNotificationControl.decodeControl(ecnc);
+        bsb.clear();
+        ecnc.write(writer);
+        LDAPControl control = LDAPReader.readControl(ASN1.getReader(bsb));
+        newEcnc = EntryChangeNotificationControl.DECODER.decode(control.isCritical(), control.getValue());
         assertNotNull(newEcnc);
         assertEquals(ecnc.getOID(),newEcnc.getOID());
         assertEquals(ecnc.getChangeNumber(),newEcnc.getChangeNumber());
@@ -442,7 +432,7 @@
         assertEquals(ecnc.getPreviousDN(),newEcnc.getPreviousDN());
         assertEquals(ecnc.isCritical(),newEcnc.isCritical()) ;
       }
-      catch (LDAPException e)
+      catch (DirectoryException e)
       {
         if (type.compareTo(PersistentSearchChangeType.MODIFY_DN) == 0)
         {
@@ -458,25 +448,28 @@
     }
 
 
-    // Test contructor EntryChangeNotificationControl(String oid, boolean
+    // Test contructor EntryChangeNotificationControl(boolean
     // isCritical, PersistentSearchChangeType changeType,
     // DN previousDN, long changeNumber)
     for (PersistentSearchChangeType type : types)
     {
-      ecnc = new EntryChangeNotificationControl(oid, isCritical, type, dn,
+      ecnc = new EntryChangeNotificationControl(isCritical, type, dn,
           changeNumber);
       assertNotNull(ecnc);
-      assertEquals(oid, ecnc.getOID());
+      assertEquals(OID_ENTRY_CHANGE_NOTIFICATION, ecnc.getOID());
       assertEquals(changeNumber, ecnc.getChangeNumber());
       assertEquals(type, ecnc.getChangeType());
       assertEquals(dn, ecnc.getPreviousDN());
       assertEquals(isCritical, ecnc.isCritical()) ;
       checkEntryChangeNotificationControlToString(ecnc);
 
-      // also check encode
+      // also check encode/decode
       try
       {
-        newEcnc = EntryChangeNotificationControl.decodeControl(ecnc);
+        bsb.clear();
+        ecnc.write(writer);
+        LDAPControl control = LDAPReader.readControl(ASN1.getReader(bsb));
+        newEcnc = EntryChangeNotificationControl.DECODER.decode(control.isCritical(), control.getValue());
         assertNotNull(newEcnc);
         assertEquals(ecnc.getOID(),newEcnc.getOID());
         assertEquals(ecnc.getChangeNumber(),newEcnc.getChangeNumber());
@@ -484,7 +477,7 @@
         assertEquals(ecnc.getPreviousDN(),newEcnc.getPreviousDN());
         assertEquals(ecnc.isCritical(),newEcnc.isCritical()) ;
       }
-      catch (LDAPException e)
+      catch (DirectoryException e)
       {
         if (type.compareTo(PersistentSearchChangeType.MODIFY_DN) == 0)
         {
@@ -499,31 +492,15 @@
       }
     }
 
-    // check setPreviousDN
-    ecnc.setPreviousDN(null) ;
-    assertNull(ecnc.getPreviousDN()) ;
-    ecnc.setPreviousDN(dn) ;
-    assertEquals(dn, ecnc.getPreviousDN());
-
-    // Check setChangeNumber
-    ecnc.setChangeNumber(changeNumber +1) ;
-    assertEquals(changeNumber +1, ecnc.getChangeNumber());
-
-    // Check setChangeType
-    for (PersistentSearchChangeType type : types)
-    {
-      ecnc.setChangeType(type) ;
-      assertEquals(type, ecnc.getChangeType());
-    }
-
     // Check error on decode
     try
     {
-      ecnc.setValue(null) ;
-      newEcnc = EntryChangeNotificationControl.decodeControl(ecnc);
+      LDAPControl control =
+          new LDAPControl(OID_ENTRY_CHANGE_NOTIFICATION, isCritical);
+      newEcnc = EntryChangeNotificationControl.DECODER.decode(control.isCritical(), control.getValue());
       assertTrue(false,"couldn't decode a control with null");
     }
-    catch (LDAPException e)
+    catch (DirectoryException e)
     {
       assertTrue(true,"couldn't decode a control with null");
     }
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/controls/ProxiedAuthV1ControlTestCase.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/controls/ProxiedAuthV1ControlTestCase.java
index 08b8638..23cc4fe 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/controls/ProxiedAuthV1ControlTestCase.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/controls/ProxiedAuthV1ControlTestCase.java
@@ -28,19 +28,14 @@
 
 
 
-import java.util.ArrayList;
-
 import org.testng.annotations.BeforeClass;
 import org.testng.annotations.Test;
 
 import org.opends.server.TestCaseUtils;
-import org.opends.server.protocols.asn1.ASN1Element;
-import org.opends.server.protocols.asn1.ASN1OctetString;
-import org.opends.server.protocols.asn1.ASN1Sequence;
-import org.opends.server.types.Control;
-import org.opends.server.types.DirectoryException;
-import org.opends.server.types.DN;
-import org.opends.server.types.LDAPException;
+import org.opends.server.protocols.ldap.LDAPControl;
+import org.opends.server.protocols.asn1.ASN1Writer;
+import org.opends.server.protocols.asn1.ASN1;
+import org.opends.server.types.*;
 
 import static org.testng.Assert.*;
 
@@ -84,36 +79,33 @@
     ProxiedAuthV1Control proxyControl;
     try
     {
-      proxyControl = new ProxiedAuthV1Control((ASN1OctetString) null);
+      proxyControl = new ProxiedAuthV1Control((ByteString) null);
       throw new AssertionError("Expected a failure when creating a proxied " +
                                "auth V1 control with a null octet string.");
     } catch (Throwable t) {}
 
 
     // Try an empty DN, which is acceptable.
-    proxyControl = new ProxiedAuthV1Control(new ASN1OctetString(""));
+    proxyControl = new ProxiedAuthV1Control(ByteString.valueOf(""));
     assertTrue(proxyControl.getOID().equals(OID_PROXIED_AUTH_V1));
     assertTrue(proxyControl.isCritical());
-    assertTrue(proxyControl.hasValue());
     assertTrue(proxyControl.getAuthorizationDN().isNullDN());
 
 
     // Try a valid DN, which is acceptable.
     proxyControl =
-         new ProxiedAuthV1Control(new ASN1OctetString("uid=test,o=test"));
+         new ProxiedAuthV1Control(ByteString.valueOf("uid=test,o=test"));
     assertTrue(proxyControl.getOID().equals(OID_PROXIED_AUTH_V1));
     assertTrue(proxyControl.isCritical());
-    assertTrue(proxyControl.hasValue());
     assertEquals(proxyControl.getAuthorizationDN(),
                  DN.decode("uid=test,o=test"));
 
 
     // Try an invalid DN, which will be initally accepted but will fail when
     // attempting to get the authorization DN.
-    proxyControl = new ProxiedAuthV1Control(new ASN1OctetString("invalid"));
+    proxyControl = new ProxiedAuthV1Control(ByteString.valueOf("invalid"));
     assertTrue(proxyControl.getOID().equals(OID_PROXIED_AUTH_V1));
     assertTrue(proxyControl.isCritical());
-    assertTrue(proxyControl.hasValue());
     try
     {
       proxyControl.getAuthorizationDN();
@@ -149,7 +141,6 @@
     proxyControl = new ProxiedAuthV1Control(DN.nullDN());
     assertTrue(proxyControl.getOID().equals(OID_PROXIED_AUTH_V1));
     assertTrue(proxyControl.isCritical());
-    assertTrue(proxyControl.hasValue());
     assertTrue(proxyControl.getAuthorizationDN().isNullDN());
 
 
@@ -158,7 +149,6 @@
          new ProxiedAuthV1Control(DN.decode("uid=test,o=test"));
     assertTrue(proxyControl.getOID().equals(OID_PROXIED_AUTH_V1));
     assertTrue(proxyControl.isCritical());
-    assertTrue(proxyControl.hasValue());
     assertEquals(proxyControl.getAuthorizationDN(),
                  DN.decode("uid=test,o=test"));
   }
@@ -166,37 +156,24 @@
 
 
   /**
-   * Tests the {@code decodeControl} method when the provided control is
-   * {@code null}.
-   *
-   * @throws  Exception  If an unexpected problem occurs.
-   */
-  @Test(expectedExceptions = { AssertionError.class })
-  public void testDecodeControlNull()
-         throws Exception
-  {
-    ProxiedAuthV1Control.decodeControl(null);
-  }
-
-
-
-  /**
    * Tests the {@code decodeControl} method when the provided control has a
    * criticality of "false".
    *
    * @throws  Exception  If an unexpected problem occurs.
    */
-  @Test(expectedExceptions = { LDAPException.class })
+  @Test(expectedExceptions = { DirectoryException.class })
   public void testDecodeControlNotCritical()
          throws Exception
   {
-    ArrayList<ASN1Element> elements = new ArrayList<ASN1Element>(1);
-    elements.add(new ASN1OctetString("uid=test,o=test"));
-    ASN1Sequence valueSequence = new ASN1Sequence(elements);
-    ASN1OctetString value = new ASN1OctetString(valueSequence.encode());
-    Control c = new Control(OID_PROXIED_AUTH_V1, false, value);
+    ByteStringBuilder bsb = new ByteStringBuilder();
+    ASN1Writer writer = ASN1.getWriter(bsb);
+    writer.writeStartSequence();
+    writer.writeOctetString("uid=test,o=test");
+    writer.writeEndSequence();
+    LDAPControl c =
+        new LDAPControl(OID_PROXIED_AUTH_V1, false, bsb.toByteString());
 
-    ProxiedAuthV1Control.decodeControl(c);
+    ProxiedAuthV1Control.DECODER.decode(c.isCritical(), c.getValue());
   }
 
 
@@ -207,13 +184,13 @@
    *
    * @throws  Exception  If an unexpected problem occurs.
    */
-  @Test(expectedExceptions = { LDAPException.class })
+  @Test(expectedExceptions = { DirectoryException.class })
   public void testDecodeControlNoValue()
          throws Exception
   {
-    Control c = new Control(OID_PROXIED_AUTH_V1, true, null);
+    LDAPControl c = new LDAPControl(OID_PROXIED_AUTH_V1, true);
 
-    ProxiedAuthV1Control.decodeControl(c);
+    ProxiedAuthV1Control.DECODER.decode(c.isCritical(), c.getValue());
   }
 
 
@@ -224,14 +201,15 @@
    *
    * @throws  Exception  If an unexpected problem occurs.
    */
-  @Test(expectedExceptions = { LDAPException.class })
+  @Test(expectedExceptions = { DirectoryException.class })
   public void testDecodeControlValueNotSequence()
          throws Exception
   {
-    ASN1OctetString value = new ASN1OctetString("uid=test,o=test");
-    Control c = new Control(OID_PROXIED_AUTH_V1, true, value);
+    LDAPControl c =
+        new LDAPControl(OID_PROXIED_AUTH_V1, true,
+            ByteString.valueOf("uid=test,o=test"));
 
-    ProxiedAuthV1Control.decodeControl(c);
+    ProxiedAuthV1Control.DECODER.decode(c.isCritical(), c.getValue());
   }
 
 
@@ -242,16 +220,18 @@
    *
    * @throws  Exception  If an unexpected problem occurs.
    */
-  @Test(expectedExceptions = { LDAPException.class })
+  @Test(expectedExceptions = { DirectoryException.class })
   public void testDecodeControlValueEmptySequence()
          throws Exception
   {
-    ArrayList<ASN1Element> elements = new ArrayList<ASN1Element>(0);
-    ASN1Sequence valueSequence = new ASN1Sequence(elements);
-    ASN1OctetString value = new ASN1OctetString(valueSequence.encode());
-    Control c = new Control(OID_PROXIED_AUTH_V1, true, value);
+    ByteStringBuilder bsb = new ByteStringBuilder();
+    ASN1Writer writer = ASN1.getWriter(bsb);
+    writer.writeStartSequence();
+    writer.writeEndSequence();
+    LDAPControl c =
+        new LDAPControl(OID_PROXIED_AUTH_V1, true, bsb.toByteString());
 
-    ProxiedAuthV1Control.decodeControl(c);
+    ProxiedAuthV1Control.DECODER.decode(c.isCritical(), c.getValue());
   }
 
 
@@ -262,18 +242,20 @@
    *
    * @throws  Exception  If an unexpected problem occurs.
    */
-  @Test(expectedExceptions = { LDAPException.class })
+  @Test(expectedExceptions = { DirectoryException.class })
   public void testDecodeControlValueMultiElementSequence()
          throws Exception
   {
-    ArrayList<ASN1Element> elements = new ArrayList<ASN1Element>(2);
-    elements.add(new ASN1OctetString("uid=element1,o=test"));
-    elements.add(new ASN1OctetString("uid=element2,o=test"));
-    ASN1Sequence valueSequence = new ASN1Sequence(elements);
-    ASN1OctetString value = new ASN1OctetString(valueSequence.encode());
-    Control c = new Control(OID_PROXIED_AUTH_V1, true, value);
+    ByteStringBuilder bsb = new ByteStringBuilder();
+    ASN1Writer writer = ASN1.getWriter(bsb);
+    writer.writeStartSequence();
+    writer.writeOctetString("uid=element1,o=test");
+    writer.writeOctetString("uid=element2,o=test");
+    writer.writeEndSequence();
+    LDAPControl c =
+        new LDAPControl(OID_PROXIED_AUTH_V1, true, bsb.toByteString());
 
-    ProxiedAuthV1Control.decodeControl(c);
+    ProxiedAuthV1Control.DECODER.decode(c.isCritical(), c.getValue());
   }
 
 
@@ -288,14 +270,15 @@
   public void testDecodeControlValueInvalidDN()
          throws Exception
   {
-    ArrayList<ASN1Element> elements = new ArrayList<ASN1Element>(1);
-    elements.add(new ASN1OctetString("invaliddn"));
-    ASN1Sequence valueSequence = new ASN1Sequence(elements);
-    ASN1OctetString value = new ASN1OctetString(valueSequence.encode());
-    Control c = new Control(OID_PROXIED_AUTH_V1, true, value);
+    ByteStringBuilder bsb = new ByteStringBuilder();
+    ASN1Writer writer = ASN1.getWriter(bsb);
+    writer.writeStartSequence();
+    writer.writeOctetString("invaliddn");
+    writer.writeEndSequence();
+    LDAPControl c =
+        new LDAPControl(OID_PROXIED_AUTH_V1, true, bsb.toByteString());
 
-    ProxiedAuthV1Control proxyControl = ProxiedAuthV1Control.decodeControl(c);
-    proxyControl.getAuthorizationDN();
+    ProxiedAuthV1Control.DECODER.decode(c.isCritical(), c.getValue());
   }
 
 
@@ -310,13 +293,15 @@
   public void testDecodeControlValueEmptyDN()
          throws Exception
   {
-    ArrayList<ASN1Element> elements = new ArrayList<ASN1Element>(1);
-    elements.add(new ASN1OctetString(""));
-    ASN1Sequence valueSequence = new ASN1Sequence(elements);
-    ASN1OctetString value = new ASN1OctetString(valueSequence.encode());
-    Control c = new Control(OID_PROXIED_AUTH_V1, true, value);
+    ByteStringBuilder bsb = new ByteStringBuilder();
+    ASN1Writer writer = ASN1.getWriter(bsb);
+    writer.writeStartSequence();
+    writer.writeOctetString("");
+    writer.writeEndSequence();
+    LDAPControl c =
+        new LDAPControl(OID_PROXIED_AUTH_V1, true, bsb.toByteString());
 
-    ProxiedAuthV1Control proxyControl = ProxiedAuthV1Control.decodeControl(c);
+    ProxiedAuthV1Control proxyControl = ProxiedAuthV1Control.DECODER.decode(c.isCritical(), c.getValue());
     assertTrue(proxyControl.getAuthorizationDN().isNullDN());
   }
 
@@ -332,13 +317,15 @@
   public void testDecodeControlValueNonEmptyDN()
          throws Exception
   {
-    ArrayList<ASN1Element> elements = new ArrayList<ASN1Element>(1);
-    elements.add(new ASN1OctetString("uid=test,o=test"));
-    ASN1Sequence valueSequence = new ASN1Sequence(elements);
-    ASN1OctetString value = new ASN1OctetString(valueSequence.encode());
-    Control c = new Control(OID_PROXIED_AUTH_V1, true, value);
+    ByteStringBuilder bsb = new ByteStringBuilder();
+    ASN1Writer writer = ASN1.getWriter(bsb);
+    writer.writeStartSequence();
+    writer.writeOctetString("uid=test,o=test");
+    writer.writeEndSequence();
+    LDAPControl c =
+        new LDAPControl(OID_PROXIED_AUTH_V1, true, bsb.toByteString());
 
-    ProxiedAuthV1Control proxyControl = ProxiedAuthV1Control.decodeControl(c);
+    ProxiedAuthV1Control proxyControl = ProxiedAuthV1Control.DECODER.decode(c.isCritical(), c.getValue());
     assertEquals(proxyControl.getAuthorizationDN(),
                  DN.decode("uid=test,o=test"));
   }
@@ -356,12 +343,13 @@
          throws Exception
   {
     ProxiedAuthV1Control proxyControl =
-         new ProxiedAuthV1Control(new ASN1OctetString(""));
-    assertEquals(proxyControl.getRawAuthorizationDN(), new ASN1OctetString(""));
+         new ProxiedAuthV1Control(ByteString.valueOf(""));
+    assertEquals(proxyControl.getRawAuthorizationDN(), ByteString.valueOf(""));
 
-    proxyControl.setRawAuthorizationDN(new ASN1OctetString("uid=test,o=test"));
+    proxyControl =
+         new ProxiedAuthV1Control(ByteString.valueOf("uid=test,o=test"));
     assertEquals(proxyControl.getRawAuthorizationDN(),
-                 new ASN1OctetString("uid=test,o=test"));
+        ByteString.valueOf("uid=test,o=test"));
   }
 
 
@@ -378,12 +366,13 @@
   {
     ProxiedAuthV1Control proxyControl =
          new ProxiedAuthV1Control(DN.nullDN());
-    assertEquals(proxyControl.getRawAuthorizationDN(), new ASN1OctetString(""));
+    assertEquals(proxyControl.getRawAuthorizationDN(), ByteString.valueOf(""));
     assertEquals(proxyControl.getAuthorizationDN(), DN.nullDN());
 
-    proxyControl.setAuthorizationDN(DN.decode("uid=test,o=test"));
+    proxyControl =
+         new ProxiedAuthV1Control(DN.decode("uid=test,o=test"));
     assertEquals(proxyControl.getRawAuthorizationDN(),
-                 new ASN1OctetString("uid=test,o=test"));
+                 ByteString.valueOf("uid=test,o=test"));
     assertEquals(proxyControl.getAuthorizationDN(),
                  DN.decode("uid=test,o=test"));
   }
@@ -391,23 +380,6 @@
 
 
   /**
-   * Tests the {@code setRawAuthorizationDN} method when providing an
-   * authorization DN that is {@code null}.
-   *
-   * @throws  Exception  If an unexpected problem occurs.
-   */
-  @Test(expectedExceptions = { AssertionError.class })
-  public void testSetNullAuthorizationDN()
-         throws Exception
-  {
-    ProxiedAuthV1Control proxyControl =
-         new ProxiedAuthV1Control(DN.nullDN());
-    proxyControl.setAuthorizationDN(null);
-  }
-
-
-
-  /**
    * Tests the {@code getValidatedAuthorizationDN} method for the null DN.
    *
    * @throws  Exception  If an unexpected problem occurs.
@@ -518,7 +490,7 @@
     // The default toString() calls the version that takes a string builder
     // argument, so we only need to use the default version to cover both cases.
     ProxiedAuthV1Control proxyControl =
-         new ProxiedAuthV1Control(new ASN1OctetString("uid=test,o=test"));
+         new ProxiedAuthV1Control(ByteString.valueOf("uid=test,o=test"));
     proxyControl.toString();
 
     proxyControl = new ProxiedAuthV1Control(DN.decode("uid=test,o=test"));
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/controls/ProxiedAuthV2ControlTestCase.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/controls/ProxiedAuthV2ControlTestCase.java
index 1fe2600..58d85b9 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/controls/ProxiedAuthV2ControlTestCase.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/controls/ProxiedAuthV2ControlTestCase.java
@@ -32,11 +32,10 @@
 import org.testng.annotations.Test;
 
 import org.opends.server.TestCaseUtils;
-import org.opends.server.protocols.asn1.ASN1OctetString;
-import org.opends.server.types.Control;
-import org.opends.server.types.DirectoryException;
-import org.opends.server.types.DN;
-import org.opends.server.types.LDAPException;
+import org.opends.server.protocols.ldap.LDAPControl;
+import org.opends.server.protocols.asn1.ASN1;
+import org.opends.server.protocols.asn1.ASN1Writer;
+import org.opends.server.types.*;
 
 import static org.testng.Assert.*;
 
@@ -71,7 +70,7 @@
   @Test(expectedExceptions = { AssertionError.class })
   public void testConstructorNullAuthzID()
   {
-    ProxiedAuthV2Control proxyControl = new ProxiedAuthV2Control(null);
+    new ProxiedAuthV2Control(null);
   }
 
 
@@ -83,8 +82,8 @@
   public void testConstructorEmptyAuthzID()
   {
     ProxiedAuthV2Control proxyControl =
-         new ProxiedAuthV2Control(new ASN1OctetString(""));
-    assertEquals(proxyControl.getAuthorizationID(), new ASN1OctetString(""));
+         new ProxiedAuthV2Control(ByteString.valueOf(""));
+    assertEquals(proxyControl.getAuthorizationID(), ByteString.valueOf(""));
   }
 
 
@@ -97,9 +96,9 @@
   public void testConstructorNonEmptyAuthzIDDN()
   {
     ProxiedAuthV2Control proxyControl =
-         new ProxiedAuthV2Control(new ASN1OctetString("dn:uid=test,o=test"));
+         new ProxiedAuthV2Control(ByteString.valueOf("dn:uid=test,o=test"));
     assertEquals(proxyControl.getAuthorizationID(),
-                 new ASN1OctetString("dn:uid=test,o=test"));
+                 ByteString.valueOf("dn:uid=test,o=test"));
   }
 
 
@@ -112,23 +111,9 @@
   public void testConstructorNonEmptyAuthzIDUsername()
   {
     ProxiedAuthV2Control proxyControl =
-         new ProxiedAuthV2Control(new ASN1OctetString("u:test"));
+         new ProxiedAuthV2Control(ByteString.valueOf("u:test"));
     assertEquals(proxyControl.getAuthorizationID(),
-                 new ASN1OctetString("u:test"));
-  }
-
-
-
-  /**
-   * Tests the {@code decodeControl} method with a {@code null} argument.
-   *
-   * @throws  Exception  If an unexpected problem occurs.
-   */
-  @Test(expectedExceptions = { AssertionError.class })
-  public void testDecodeControlNull()
-         throws Exception
-  {
-    ProxiedAuthV2Control.decodeControl(null);
+                 ByteString.valueOf("u:test"));
   }
 
 
@@ -139,13 +124,13 @@
    *
    * @throws  Exception  If an unexpected problem occurs.
    */
-  @Test(expectedExceptions = { LDAPException.class })
+  @Test(expectedExceptions = { DirectoryException.class })
   public void testDecodeControlNotCritical()
          throws Exception
   {
-    Control c = new Control(OID_PROXIED_AUTH_V2, false,
-                            new ASN1OctetString("u:test"));
-    ProxiedAuthV2Control.decodeControl(c);
+    LDAPControl c = new LDAPControl(OID_PROXIED_AUTH_V2, false,
+                            ByteString.valueOf("u:test"));
+    ProxiedAuthV2Control.DECODER.decode(c.isCritical(), c.getValue());
   }
 
 
@@ -156,12 +141,12 @@
    *
    * @throws  Exception  If an unexpected problem occurs.
    */
-  @Test(expectedExceptions = { LDAPException.class })
+  @Test(expectedExceptions = { DirectoryException.class })
   public void testDecodeControlNoValue()
          throws Exception
   {
-    Control c = new Control(OID_PROXIED_AUTH_V2, true);
-    ProxiedAuthV2Control.decodeControl(c);
+    LDAPControl c = new LDAPControl(OID_PROXIED_AUTH_V2, true);
+    ProxiedAuthV2Control.DECODER.decode(c.isCritical(), c.getValue());
   }
 
 
@@ -176,10 +161,10 @@
   public void testDecodeControlDNValue()
          throws Exception
   {
-    ASN1OctetString authzID = new ASN1OctetString("dn:uid=test,o=test");
+    ByteString authzID = ByteString.valueOf("dn:uid=test,o=test");
 
-    Control c = new Control(OID_PROXIED_AUTH_V2, true, authzID);
-    ProxiedAuthV2Control proxyControl = ProxiedAuthV2Control.decodeControl(c);
+    LDAPControl c = new LDAPControl(OID_PROXIED_AUTH_V2, true, authzID);
+    ProxiedAuthV2Control proxyControl = ProxiedAuthV2Control.DECODER.decode(c.isCritical(), c.getValue());
     assertEquals(proxyControl.getAuthorizationID(), authzID);
   }
 
@@ -195,10 +180,10 @@
   public void testDecodeControlUsernameValue()
          throws Exception
   {
-    ASN1OctetString authzID = new ASN1OctetString("u:test");
+    ByteString authzID = ByteString.valueOf("u:test");
 
-    Control c = new Control(OID_PROXIED_AUTH_V2, true, authzID);
-    ProxiedAuthV2Control proxyControl = ProxiedAuthV2Control.decodeControl(c);
+    LDAPControl c = new LDAPControl(OID_PROXIED_AUTH_V2, true, authzID);
+    ProxiedAuthV2Control proxyControl = ProxiedAuthV2Control.DECODER.decode(c.isCritical(), c.getValue());
     assertEquals(proxyControl.getAuthorizationID(), authzID);
   }
 
@@ -210,14 +195,14 @@
    *
    * @throws  Exception  If an unexpected problem occurs.
    */
-  @Test(expectedExceptions = { LDAPException.class })
+  @Test(expectedExceptions = { DirectoryException.class })
   public void testDecodeControlInvalidValue()
          throws Exception
   {
-    ASN1OctetString authzID = new ASN1OctetString("invalid");
+    ByteString authzID = ByteString.valueOf("invalid");
 
-    Control c = new Control(OID_PROXIED_AUTH_V2, true, authzID);
-    ProxiedAuthV2Control proxyControl = ProxiedAuthV2Control.decodeControl(c);
+    LDAPControl c = new LDAPControl(OID_PROXIED_AUTH_V2, true, authzID);
+    ProxiedAuthV2Control proxyControl = ProxiedAuthV2Control.DECODER.decode(c.isCritical(), c.getValue());
     assertEquals(proxyControl.getAuthorizationID(), authzID);
   }
 
@@ -234,11 +219,14 @@
   public void testDecodeControlLegacyDNValue()
          throws Exception
   {
-    ASN1OctetString innerValue = new ASN1OctetString("dn:uid=test,o=test");
-    ASN1OctetString outerValue = new ASN1OctetString(innerValue.encode());
+    ByteString innerValue = ByteString.valueOf("dn:uid=test,o=test");
+    ByteStringBuilder bsb = new ByteStringBuilder();
+    ASN1Writer writer = ASN1.getWriter(bsb);
+    writer.writeOctetString(innerValue);
+    ByteString outerValue = bsb.toByteString();
 
-    Control c = new Control(OID_PROXIED_AUTH_V2, true, outerValue);
-    ProxiedAuthV2Control proxyControl = ProxiedAuthV2Control.decodeControl(c);
+    LDAPControl c = new LDAPControl(OID_PROXIED_AUTH_V2, true, outerValue);
+    ProxiedAuthV2Control proxyControl = ProxiedAuthV2Control.DECODER.decode(c.isCritical(), c.getValue());
     assertEquals(proxyControl.getAuthorizationID(), innerValue);
   }
 
@@ -255,49 +243,20 @@
   public void testDecodeControlLegacyUsernameValue()
          throws Exception
   {
-    ASN1OctetString innerValue = new ASN1OctetString("u:test");
-    ASN1OctetString outerValue = new ASN1OctetString(innerValue.encode());
+    ByteString innerValue = ByteString.valueOf("u:test");
+    ByteStringBuilder bsb = new ByteStringBuilder();
+    ASN1Writer writer = ASN1.getWriter(bsb);
+    writer.writeOctetString(innerValue);
+    ByteString outerValue = bsb.toByteString();
 
-    Control c = new Control(OID_PROXIED_AUTH_V2, true, outerValue);
-    ProxiedAuthV2Control proxyControl = ProxiedAuthV2Control.decodeControl(c);
+    LDAPControl c = new LDAPControl(OID_PROXIED_AUTH_V2, true, outerValue);
+    ProxiedAuthV2Control proxyControl = ProxiedAuthV2Control.DECODER.decode(c.isCritical(), c.getValue());
     assertEquals(proxyControl.getAuthorizationID(), innerValue);
   }
 
 
 
   /**
-   * Tests the {@code getAuthorizationID} and {@code setAuthorizationID}
-   * methods.
-   *
-   * @throws  Exception  If an unexpected problem occurs.
-   */
-  @Test()
-  public void testGetAndSetAuthorizationID()
-         throws Exception
-  {
-    ProxiedAuthV2Control proxyControl =
-         new ProxiedAuthV2Control(new ASN1OctetString("dn:uid=test,o=test"));
-    assertEquals(proxyControl.getAuthorizationID(),
-                 new ASN1OctetString("dn:uid=test,o=test"));
-
-    proxyControl.setAuthorizationID(null);
-    assertEquals(proxyControl.getAuthorizationID(), new ASN1OctetString(""));
-
-    proxyControl.setAuthorizationID(new ASN1OctetString(""));
-    assertEquals(proxyControl.getAuthorizationID(), new ASN1OctetString(""));
-
-    proxyControl.setAuthorizationID(new ASN1OctetString("u:test"));
-    assertEquals(proxyControl.getAuthorizationID(),
-                 new ASN1OctetString("u:test"));
-
-    proxyControl.setAuthorizationID(new ASN1OctetString("dn:uid=test,o=test"));
-    assertEquals(proxyControl.getAuthorizationID(),
-                 new ASN1OctetString("dn:uid=test,o=test"));
-  }
-
-
-
-  /**
    * Tests the {@code getValidatedAuthorizationDN} method with an empty
    * authorization ID string.
    *
@@ -308,7 +267,7 @@
          throws Exception
   {
     ProxiedAuthV2Control proxyControl =
-         new ProxiedAuthV2Control(new ASN1OctetString(""));
+         new ProxiedAuthV2Control(ByteString.valueOf(""));
     assertNull(proxyControl.getAuthorizationEntry());
   }
 
@@ -325,7 +284,7 @@
          throws Exception
   {
     ProxiedAuthV2Control proxyControl =
-         new ProxiedAuthV2Control(new ASN1OctetString("dn:"));
+         new ProxiedAuthV2Control(ByteString.valueOf("dn:"));
     assertNull(proxyControl.getAuthorizationEntry());
   }
 
@@ -354,7 +313,7 @@
       "cn: Test User");
 
     ProxiedAuthV2Control proxyControl =
-         new ProxiedAuthV2Control(new ASN1OctetString("dn:uid=test,o=test"));
+         new ProxiedAuthV2Control(ByteString.valueOf("dn:uid=test,o=test"));
     assertEquals(proxyControl.getAuthorizationEntry().getDN(),
                  DN.decode("uid=test,o=test"));
   }
@@ -374,7 +333,7 @@
     TestCaseUtils.initializeTestBackend(true);
 
     ProxiedAuthV2Control proxyControl =
-         new ProxiedAuthV2Control(new ASN1OctetString("dn:uid=test,o=test"));
+         new ProxiedAuthV2Control(ByteString.valueOf("dn:uid=test,o=test"));
     proxyControl.getAuthorizationEntry();
   }
 
@@ -405,7 +364,7 @@
       "ds-pwp-account-disabled: true");
 
     ProxiedAuthV2Control proxyControl =
-         new ProxiedAuthV2Control(new ASN1OctetString("dn:uid=test,o=test"));
+         new ProxiedAuthV2Control(ByteString.valueOf("dn:uid=test,o=test"));
     proxyControl.getAuthorizationEntry();
   }
 
@@ -422,7 +381,7 @@
          throws Exception
   {
     ProxiedAuthV2Control proxyControl =
-         new ProxiedAuthV2Control(new ASN1OctetString("u:"));
+         new ProxiedAuthV2Control(ByteString.valueOf("u:"));
     assertNull(proxyControl.getAuthorizationEntry());
   }
 
@@ -451,7 +410,7 @@
       "cn: Test User");
 
     ProxiedAuthV2Control proxyControl =
-         new ProxiedAuthV2Control(new ASN1OctetString("u:test"));
+         new ProxiedAuthV2Control(ByteString.valueOf("u:test"));
     assertEquals(proxyControl.getAuthorizationEntry().getDN(),
                  DN.decode("uid=test,o=test"));
   }
@@ -471,7 +430,7 @@
     TestCaseUtils.initializeTestBackend(true);
 
     ProxiedAuthV2Control proxyControl =
-         new ProxiedAuthV2Control(new ASN1OctetString("u:test"));
+         new ProxiedAuthV2Control(ByteString.valueOf("u:test"));
     proxyControl.getAuthorizationEntry();
   }
 
@@ -502,7 +461,7 @@
       "ds-pwp-account-disabled: true");
 
     ProxiedAuthV2Control proxyControl =
-         new ProxiedAuthV2Control(new ASN1OctetString("u:test"));
+         new ProxiedAuthV2Control(ByteString.valueOf("u:test"));
     proxyControl.getAuthorizationEntry();
   }
 
@@ -519,7 +478,7 @@
          throws Exception
   {
     ProxiedAuthV2Control proxyControl =
-         new ProxiedAuthV2Control(new ASN1OctetString("invalid"));
+         new ProxiedAuthV2Control(ByteString.valueOf("invalid"));
     proxyControl.getAuthorizationEntry();
   }
 
@@ -537,10 +496,10 @@
     // The default toString() calls the version that takes a string builder
     // argument, so we only need to use the default version to cover both cases.
     ProxiedAuthV2Control proxyControl =
-         new ProxiedAuthV2Control(new ASN1OctetString("dn:uid=test,o=test"));
+         new ProxiedAuthV2Control(ByteString.valueOf("dn:uid=test,o=test"));
     proxyControl.toString();
 
-    proxyControl = new ProxiedAuthV2Control(new ASN1OctetString("u:test"));
+    proxyControl = new ProxiedAuthV2Control(ByteString.valueOf("u:test"));
     proxyControl.toString();
   }
 }
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/controls/ServerSideSortControlTestCase.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/controls/ServerSideSortControlTestCase.java
index 775dc54..46fe9e0 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/controls/ServerSideSortControlTestCase.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/controls/ServerSideSortControlTestCase.java
@@ -40,6 +40,7 @@
 import org.opends.server.core.DirectoryServer;
 import org.opends.server.protocols.internal.InternalClientConnection;
 import org.opends.server.protocols.internal.InternalSearchOperation;
+import org.opends.server.protocols.ldap.LDAPControl;
 import org.opends.server.types.AttributeType;
 import org.opends.server.types.Control;
 import org.opends.server.types.DN;
@@ -350,8 +351,16 @@
     assertNotNull(responseControls);
     assertEquals(responseControls.size(), 1);
 
-    ServerSideSortResponseControl responseControl =
-         ServerSideSortResponseControl.decodeControl(responseControls.get(0));
+    ServerSideSortResponseControl responseControl;
+    Control c = responseControls.get(0);
+    if(c instanceof ServerSideSortResponseControl)
+    {
+      responseControl = (ServerSideSortResponseControl)c;
+    }
+    else
+    {
+      responseControl = ServerSideSortResponseControl.DECODER.decode(c.isCritical(), ((LDAPControl)c).getValue());
+    }
     assertEquals(responseControl.getResultCode(), 0);
     assertNull(responseControl.getAttributeType());
     responseControl.toString();
@@ -413,8 +422,16 @@
     assertNotNull(responseControls);
     assertEquals(responseControls.size(), 1);
 
-    ServerSideSortResponseControl responseControl =
-         ServerSideSortResponseControl.decodeControl(responseControls.get(0));
+    ServerSideSortResponseControl responseControl;
+    Control c = responseControls.get(0);
+    if(c instanceof ServerSideSortResponseControl)
+    {
+      responseControl = (ServerSideSortResponseControl)c;
+    }
+    else
+    {
+      responseControl = ServerSideSortResponseControl.DECODER.decode(c.isCritical(), ((LDAPControl)c).getValue());
+    }
     assertEquals(responseControl.getResultCode(), 0);
     assertNull(responseControl.getAttributeType());
     responseControl.toString();
@@ -474,8 +491,16 @@
     assertNotNull(responseControls);
     assertEquals(responseControls.size(), 1);
 
-    ServerSideSortResponseControl responseControl =
-         ServerSideSortResponseControl.decodeControl(responseControls.get(0));
+    ServerSideSortResponseControl responseControl;
+    Control c = responseControls.get(0);
+    if(c instanceof ServerSideSortResponseControl)
+    {
+      responseControl = (ServerSideSortResponseControl)c;
+    }
+    else
+    {
+      responseControl = ServerSideSortResponseControl.DECODER.decode(c.isCritical(), ((LDAPControl)c).getValue());
+    }
     assertEquals(responseControl.getResultCode(), 0);
     assertNull(responseControl.getAttributeType());
     responseControl.toString();
@@ -537,8 +562,16 @@
     assertNotNull(responseControls);
     assertEquals(responseControls.size(), 1);
 
-    ServerSideSortResponseControl responseControl =
-         ServerSideSortResponseControl.decodeControl(responseControls.get(0));
+    ServerSideSortResponseControl responseControl;
+    Control c = responseControls.get(0);
+    if(c instanceof ServerSideSortResponseControl)
+    {
+      responseControl = (ServerSideSortResponseControl)c;
+    }
+    else
+    {
+      responseControl = ServerSideSortResponseControl.DECODER.decode(c.isCritical(), ((LDAPControl)c).getValue());
+    }
     assertEquals(responseControl.getResultCode(), 0);
     assertNull(responseControl.getAttributeType());
     responseControl.toString();
@@ -598,8 +631,16 @@
     assertNotNull(responseControls);
     assertEquals(responseControls.size(), 1);
 
-    ServerSideSortResponseControl responseControl =
-         ServerSideSortResponseControl.decodeControl(responseControls.get(0));
+    ServerSideSortResponseControl responseControl;
+    Control c = responseControls.get(0);
+    if(c instanceof ServerSideSortResponseControl)
+    {
+      responseControl = (ServerSideSortResponseControl)c;
+    }
+    else
+    {
+      responseControl = ServerSideSortResponseControl.DECODER.decode(c.isCritical(), ((LDAPControl)c).getValue());
+    }
     assertEquals(responseControl.getResultCode(), 0);
     assertNull(responseControl.getAttributeType());
     responseControl.toString();
@@ -659,8 +700,16 @@
     assertNotNull(responseControls);
     assertEquals(responseControls.size(), 1);
 
-    ServerSideSortResponseControl responseControl =
-         ServerSideSortResponseControl.decodeControl(responseControls.get(0));
+    ServerSideSortResponseControl responseControl;
+    Control c = responseControls.get(0);
+    if(c instanceof ServerSideSortResponseControl)
+    {
+      responseControl = (ServerSideSortResponseControl)c;
+    }
+    else
+    {
+      responseControl = ServerSideSortResponseControl.DECODER.decode(c.isCritical(), ((LDAPControl)c).getValue());
+    }
     assertEquals(responseControl.getResultCode(), 0);
     assertNull(responseControl.getAttributeType());
     responseControl.toString();
@@ -684,7 +733,7 @@
          InternalClientConnection.getRootConnection();
 
     ArrayList<Control> requestControls = new ArrayList<Control>();
-    requestControls.add(new ServerSideSortRequestControl("undefined"));
+    requestControls.add(new ServerSideSortRequestControl(true, "undefined"));
 
     InternalSearchOperation internalSearch =
          new InternalSearchOperation(conn, conn.nextOperationID(),
@@ -716,7 +765,7 @@
          InternalClientConnection.getRootConnection();
 
     ArrayList<Control> requestControls = new ArrayList<Control>();
-    requestControls.add(new ServerSideSortRequestControl(
+    requestControls.add(new ServerSideSortRequestControl(true,
                                  "givenName:undefinedOrderingMatch"));
 
     InternalSearchOperation internalSearch =
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/controls/VLVControlTestCase.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/controls/VLVControlTestCase.java
index 14115d8..e48897d 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/controls/VLVControlTestCase.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/controls/VLVControlTestCase.java
@@ -40,18 +40,11 @@
 
 import org.opends.server.TestCaseUtils;
 import org.opends.server.core.DirectoryServer;
-import org.opends.server.protocols.asn1.ASN1OctetString;
 import org.opends.server.protocols.internal.InternalClientConnection;
 import org.opends.server.protocols.internal.InternalSearchOperation;
 import org.opends.server.protocols.ldap.LDAPResultCode;
-import org.opends.server.types.AttributeType;
-import org.opends.server.types.Control;
-import org.opends.server.types.DN;
-import org.opends.server.types.DereferencePolicy;
-import org.opends.server.types.Entry;
-import org.opends.server.types.ResultCode;
-import org.opends.server.types.SearchFilter;
-import org.opends.server.types.SearchScope;
+import org.opends.server.protocols.ldap.LDAPControl;
+import org.opends.server.types.*;
 import org.testng.annotations.BeforeClass;
 import org.testng.annotations.Test;
 
@@ -247,6 +240,7 @@
   {
     VLVRequestControl vlvRequest = new VLVRequestControl(0, 9, 1, 0);
 
+    assertEquals(vlvRequest.isCritical(), false);
     assertEquals(vlvRequest.getBeforeCount(), 0);
     assertEquals(vlvRequest.getAfterCount(), 9);
     assertEquals(vlvRequest.getOffset(), 1);
@@ -256,8 +250,6 @@
                  VLVRequestControl.TYPE_TARGET_BYOFFSET);
     assertNull(vlvRequest.getGreaterThanOrEqualAssertion());
     assertNotNull(vlvRequest.toString());
-
-    assertNotNull(vlvRequest.decodeControl(vlvRequest));
   }
 
 
@@ -272,8 +264,9 @@
   public void testRequestConstructor2NullContextID()
               throws Exception
   {
-    VLVRequestControl vlvRequest = new VLVRequestControl(0, 9, 1, 0, null);
+    VLVRequestControl vlvRequest = new VLVRequestControl(true, 0, 9, 1, 0, null);
 
+    assertEquals(vlvRequest.isCritical(), true);
     assertEquals(vlvRequest.getBeforeCount(), 0);
     assertEquals(vlvRequest.getAfterCount(), 9);
     assertEquals(vlvRequest.getOffset(), 1);
@@ -283,8 +276,6 @@
                  VLVRequestControl.TYPE_TARGET_BYOFFSET);
     assertNull(vlvRequest.getGreaterThanOrEqualAssertion());
     assertNotNull(vlvRequest.toString());
-
-    assertNotNull(vlvRequest.decodeControl(vlvRequest));
   }
 
 
@@ -300,8 +291,9 @@
               throws Exception
   {
     VLVRequestControl vlvRequest =
-         new VLVRequestControl(0, 9, 1, 0, new ASN1OctetString("foo"));
+         new VLVRequestControl(true, 0, 9, 1, 0, ByteString.valueOf("foo"));
 
+    assertEquals(vlvRequest.isCritical(), true);
     assertEquals(vlvRequest.getBeforeCount(), 0);
     assertEquals(vlvRequest.getAfterCount(), 9);
     assertEquals(vlvRequest.getOffset(), 1);
@@ -311,8 +303,6 @@
                  VLVRequestControl.TYPE_TARGET_BYOFFSET);
     assertNull(vlvRequest.getGreaterThanOrEqualAssertion());
     assertNotNull(vlvRequest.toString());
-
-    assertNotNull(vlvRequest.decodeControl(vlvRequest));
   }
 
 
@@ -327,18 +317,17 @@
               throws Exception
   {
     VLVRequestControl vlvRequest =
-         new VLVRequestControl(0, 9, new ASN1OctetString("a"));
+         new VLVRequestControl(0, 9, ByteString.valueOf("a"));
 
+    assertEquals(vlvRequest.isCritical(), false);
     assertEquals(vlvRequest.getBeforeCount(), 0);
     assertEquals(vlvRequest.getAfterCount(), 9);
-    assertEquals(vlvRequest.getGreaterThanOrEqualAssertion().stringValue(),
+    assertEquals(vlvRequest.getGreaterThanOrEqualAssertion().toString(),
                  "a");
     assertNull(vlvRequest.getContextID());
     assertEquals(vlvRequest.getTargetType(),
                  VLVRequestControl.TYPE_TARGET_GREATERTHANOREQUAL);
     assertNotNull(vlvRequest.toString());
-
-    assertNotNull(vlvRequest.decodeControl(vlvRequest));
   }
 
 
@@ -354,18 +343,17 @@
               throws Exception
   {
     VLVRequestControl vlvRequest =
-         new VLVRequestControl(0, 9, new ASN1OctetString("a"), null);
+         new VLVRequestControl(true, 0, 9, ByteString.valueOf("a"), null);
 
+    assertEquals(vlvRequest.isCritical(), true);
     assertEquals(vlvRequest.getBeforeCount(), 0);
     assertEquals(vlvRequest.getAfterCount(), 9);
-    assertEquals(vlvRequest.getGreaterThanOrEqualAssertion().stringValue(),
+    assertEquals(vlvRequest.getGreaterThanOrEqualAssertion().toString(),
                  "a");
     assertNull(vlvRequest.getContextID());
     assertEquals(vlvRequest.getTargetType(),
                  VLVRequestControl.TYPE_TARGET_GREATERTHANOREQUAL);
     assertNotNull(vlvRequest.toString());
-
-    assertNotNull(vlvRequest.decodeControl(vlvRequest));
   }
 
 
@@ -381,19 +369,18 @@
               throws Exception
   {
     VLVRequestControl vlvRequest =
-         new VLVRequestControl(0, 9, new ASN1OctetString("a"),
-                               new ASN1OctetString("foo"));
+         new VLVRequestControl(true, 0, 9, ByteString.valueOf("a"),
+                               ByteString.valueOf("foo"));
 
+    assertEquals(vlvRequest.isCritical(), true);
     assertEquals(vlvRequest.getBeforeCount(), 0);
     assertEquals(vlvRequest.getAfterCount(), 9);
-    assertEquals(vlvRequest.getGreaterThanOrEqualAssertion().stringValue(),
+    assertEquals(vlvRequest.getGreaterThanOrEqualAssertion().toString(),
                  "a");
     assertNotNull(vlvRequest.getContextID());
     assertEquals(vlvRequest.getTargetType(),
                  VLVRequestControl.TYPE_TARGET_GREATERTHANOREQUAL);
     assertNotNull(vlvRequest.toString());
-
-    assertNotNull(vlvRequest.decodeControl(vlvRequest));
   }
 
 
@@ -409,13 +396,12 @@
   {
     VLVResponseControl vlvResponse = new VLVResponseControl(0, 15, 0);
 
+    assertEquals(vlvResponse.isCritical(), false);
     assertEquals(vlvResponse.getTargetPosition(), 0);
     assertEquals(vlvResponse.getContentCount(), 15);
     assertEquals(vlvResponse.getVLVResultCode(), 0);
     assertNull(vlvResponse.getContextID());
     assertNotNull(vlvResponse.toString());
-
-    assertNotNull(vlvResponse.decodeControl(vlvResponse));
   }
 
 
@@ -430,15 +416,14 @@
   public void testResponseConstructor2NullContextID()
          throws Exception
   {
-    VLVResponseControl vlvResponse = new VLVResponseControl(0, 15, 0, null);
+    VLVResponseControl vlvResponse = new VLVResponseControl(true, 0, 15, 0, null);
 
+    assertEquals(vlvResponse.isCritical(), true);
     assertEquals(vlvResponse.getTargetPosition(), 0);
     assertEquals(vlvResponse.getContentCount(), 15);
     assertEquals(vlvResponse.getVLVResultCode(), 0);
     assertNull(vlvResponse.getContextID());
     assertNotNull(vlvResponse.toString());
-
-    assertNotNull(vlvResponse.decodeControl(vlvResponse));
   }
 
 
@@ -454,15 +439,14 @@
          throws Exception
   {
     VLVResponseControl vlvResponse =
-         new VLVResponseControl(0, 15, 0, new ASN1OctetString("foo"));
+         new VLVResponseControl(true, 0, 15, 0, ByteString.valueOf("foo"));
 
+    assertEquals(vlvResponse.isCritical(), true);
     assertEquals(vlvResponse.getTargetPosition(), 0);
     assertEquals(vlvResponse.getContentCount(), 15);
     assertEquals(vlvResponse.getVLVResultCode(), 0);
     assertNotNull(vlvResponse.getContextID());
     assertNotNull(vlvResponse.toString());
-
-    assertNotNull(vlvResponse.decodeControl(vlvResponse));
   }
 
 
@@ -521,11 +505,26 @@
     {
       if (c.getOID().equals(OID_SERVER_SIDE_SORT_RESPONSE_CONTROL))
       {
-        sortResponse = ServerSideSortResponseControl.decodeControl(c);
+        if(c instanceof LDAPControl)
+        {
+          sortResponse =
+              ServerSideSortResponseControl.DECODER.decode(c.isCritical(), ((LDAPControl)c).getValue());
+        }
+        else
+        {
+          sortResponse = (ServerSideSortResponseControl)c;
+        }
       }
       else if (c.getOID().equals(OID_VLV_RESPONSE_CONTROL))
       {
-        vlvResponse = VLVResponseControl.decodeControl(c);
+        if(c instanceof LDAPControl)
+        {
+          vlvResponse = VLVResponseControl.DECODER.decode(c.isCritical(), ((LDAPControl)c).getValue());
+        }
+        else
+        {
+          vlvResponse = (VLVResponseControl)c;
+        }
       }
       else
       {
@@ -599,11 +598,26 @@
     {
       if (c.getOID().equals(OID_SERVER_SIDE_SORT_RESPONSE_CONTROL))
       {
-        sortResponse = ServerSideSortResponseControl.decodeControl(c);
+        if(c instanceof LDAPControl)
+        {
+          sortResponse =
+              ServerSideSortResponseControl.DECODER.decode(c.isCritical(), ((LDAPControl)c).getValue());
+        }
+        else
+        {
+          sortResponse = (ServerSideSortResponseControl)c;
+        }
       }
       else if (c.getOID().equals(OID_VLV_RESPONSE_CONTROL))
       {
-        vlvResponse = VLVResponseControl.decodeControl(c);
+        if(c instanceof LDAPControl)
+        {
+          vlvResponse = VLVResponseControl.DECODER.decode(c.isCritical(), ((LDAPControl)c).getValue());
+        }
+        else
+        {
+          vlvResponse = (VLVResponseControl)c;
+        }
       }
       else
       {
@@ -677,11 +691,26 @@
     {
       if (c.getOID().equals(OID_SERVER_SIDE_SORT_RESPONSE_CONTROL))
       {
-        sortResponse = ServerSideSortResponseControl.decodeControl(c);
+        if(c instanceof LDAPControl)
+        {
+          sortResponse =
+              ServerSideSortResponseControl.DECODER.decode(c.isCritical(), ((LDAPControl)c).getValue());
+        }
+        else
+        {
+          sortResponse = (ServerSideSortResponseControl)c;
+        }
       }
       else if (c.getOID().equals(OID_VLV_RESPONSE_CONTROL))
       {
-        vlvResponse = VLVResponseControl.decodeControl(c);
+        if(c instanceof LDAPControl)
+        {
+          vlvResponse = VLVResponseControl.DECODER.decode(c.isCritical(), ((LDAPControl)c).getValue());
+        }
+        else
+        {
+          vlvResponse = (VLVResponseControl)c;
+        }
       }
       else
       {
@@ -740,7 +769,14 @@
     {
       if (c.getOID().equals(OID_VLV_RESPONSE_CONTROL))
       {
-        vlvResponse = VLVResponseControl.decodeControl(c);
+        if(c instanceof LDAPControl)
+        {
+          vlvResponse = VLVResponseControl.DECODER.decode(c.isCritical(), ((LDAPControl)c).getValue());
+        }
+        else
+        {
+          vlvResponse = (VLVResponseControl)c;
+        }
       }
     }
 
@@ -791,7 +827,14 @@
     {
       if (c.getOID().equals(OID_VLV_RESPONSE_CONTROL))
       {
-        vlvResponse = VLVResponseControl.decodeControl(c);
+        if(c instanceof LDAPControl)
+        {
+          vlvResponse = VLVResponseControl.DECODER.decode(c.isCritical(), ((LDAPControl)c).getValue());
+        }
+        else
+        {
+          vlvResponse = (VLVResponseControl)c;
+        }
       }
     }
 
@@ -853,7 +896,14 @@
     {
       if (c.getOID().equals(OID_VLV_RESPONSE_CONTROL))
       {
-        vlvResponse = VLVResponseControl.decodeControl(c);
+        if(c instanceof LDAPControl)
+        {
+          vlvResponse = VLVResponseControl.DECODER.decode(c.isCritical(), ((LDAPControl)c).getValue());
+        }
+        else
+        {
+          vlvResponse = (VLVResponseControl)c;
+        }
       }
     }
 
@@ -919,11 +969,26 @@
     {
       if (c.getOID().equals(OID_SERVER_SIDE_SORT_RESPONSE_CONTROL))
       {
-        sortResponse = ServerSideSortResponseControl.decodeControl(c);
+        if(c instanceof LDAPControl)
+        {
+          sortResponse =
+              ServerSideSortResponseControl.DECODER.decode(c.isCritical(), ((LDAPControl)c).getValue());
+        }
+        else
+        {
+          sortResponse = (ServerSideSortResponseControl)c;
+        }
       }
       else if (c.getOID().equals(OID_VLV_RESPONSE_CONTROL))
       {
-        vlvResponse = VLVResponseControl.decodeControl(c);
+        if(c instanceof LDAPControl)
+        {
+          vlvResponse = VLVResponseControl.DECODER.decode(c.isCritical(), ((LDAPControl)c).getValue());
+        }
+        else
+        {
+          vlvResponse = (VLVResponseControl)c;
+        }
       }
       else
       {
@@ -960,7 +1025,7 @@
 
     ArrayList<Control> requestControls = new ArrayList<Control>();
     requestControls.add(new ServerSideSortRequestControl("givenName"));
-    requestControls.add(new VLVRequestControl(0, 3, new ASN1OctetString("a")));
+    requestControls.add(new VLVRequestControl(0, 3, ByteString.valueOf("a")));
 
     InternalSearchOperation internalSearch =
          new InternalSearchOperation(conn, conn.nextOperationID(),
@@ -997,11 +1062,26 @@
     {
       if (c.getOID().equals(OID_SERVER_SIDE_SORT_RESPONSE_CONTROL))
       {
-        sortResponse = ServerSideSortResponseControl.decodeControl(c);
+        if(c instanceof LDAPControl)
+        {
+          sortResponse =
+              ServerSideSortResponseControl.DECODER.decode(c.isCritical(), ((LDAPControl)c).getValue());
+        }
+        else
+        {
+          sortResponse = (ServerSideSortResponseControl)c;
+        }
       }
       else if (c.getOID().equals(OID_VLV_RESPONSE_CONTROL))
       {
-        vlvResponse = VLVResponseControl.decodeControl(c);
+        if(c instanceof LDAPControl)
+        {
+          vlvResponse = VLVResponseControl.DECODER.decode(c.isCritical(), ((LDAPControl)c).getValue());
+        }
+        else
+        {
+          vlvResponse = (VLVResponseControl)c;
+        }
       }
       else
       {
@@ -1039,7 +1119,7 @@
     ArrayList<Control> requestControls = new ArrayList<Control>();
     requestControls.add(new ServerSideSortRequestControl("givenName"));
     requestControls.add(new VLVRequestControl(0, 3,
-                                              new ASN1OctetString("aaccf")));
+                                              ByteString.valueOf("aaccf")));
 
     InternalSearchOperation internalSearch =
          new InternalSearchOperation(conn, conn.nextOperationID(),
@@ -1076,11 +1156,26 @@
     {
       if (c.getOID().equals(OID_SERVER_SIDE_SORT_RESPONSE_CONTROL))
       {
-        sortResponse = ServerSideSortResponseControl.decodeControl(c);
+        if(c instanceof LDAPControl)
+        {
+          sortResponse =
+              ServerSideSortResponseControl.DECODER.decode(c.isCritical(), ((LDAPControl)c).getValue());
+        }
+        else
+        {
+          sortResponse = (ServerSideSortResponseControl)c;
+        }
       }
       else if (c.getOID().equals(OID_VLV_RESPONSE_CONTROL))
       {
-        vlvResponse = VLVResponseControl.decodeControl(c);
+        if(c instanceof LDAPControl)
+        {
+          vlvResponse = VLVResponseControl.DECODER.decode(c.isCritical(), ((LDAPControl)c).getValue());
+        }
+        else
+        {
+          vlvResponse = (VLVResponseControl)c;
+        }
       }
       else
       {
@@ -1118,7 +1213,7 @@
     ArrayList<Control> requestControls = new ArrayList<Control>();
     requestControls.add(new ServerSideSortRequestControl("givenName"));
     requestControls.add(new VLVRequestControl(0, 3,
-                                              new ASN1OctetString("albert")));
+                                              ByteString.valueOf("albert")));
 
     InternalSearchOperation internalSearch =
          new InternalSearchOperation(conn, conn.nextOperationID(),
@@ -1155,11 +1250,26 @@
     {
       if (c.getOID().equals(OID_SERVER_SIDE_SORT_RESPONSE_CONTROL))
       {
-        sortResponse = ServerSideSortResponseControl.decodeControl(c);
+        if(c instanceof LDAPControl)
+        {
+          sortResponse =
+              ServerSideSortResponseControl.DECODER.decode(c.isCritical(), ((LDAPControl)c).getValue());
+        }
+        else
+        {
+          sortResponse = (ServerSideSortResponseControl)c;
+        }
       }
       else if (c.getOID().equals(OID_VLV_RESPONSE_CONTROL))
       {
-        vlvResponse = VLVResponseControl.decodeControl(c);
+        if(c instanceof LDAPControl)
+        {
+          vlvResponse = VLVResponseControl.DECODER.decode(c.isCritical(), ((LDAPControl)c).getValue());
+        }
+        else
+        {
+          vlvResponse = (VLVResponseControl)c;
+        }
       }
       else
       {
@@ -1197,7 +1307,7 @@
     ArrayList<Control> requestControls = new ArrayList<Control>();
     requestControls.add(new ServerSideSortRequestControl("givenName"));
     requestControls.add(new VLVRequestControl(1, 3,
-                                              new ASN1OctetString("albert")));
+                                              ByteString.valueOf("albert")));
 
     InternalSearchOperation internalSearch =
          new InternalSearchOperation(conn, conn.nextOperationID(),
@@ -1235,11 +1345,26 @@
     {
       if (c.getOID().equals(OID_SERVER_SIDE_SORT_RESPONSE_CONTROL))
       {
-        sortResponse = ServerSideSortResponseControl.decodeControl(c);
+        if(c instanceof LDAPControl)
+        {
+          sortResponse =
+              ServerSideSortResponseControl.DECODER.decode(c.isCritical(), ((LDAPControl)c).getValue());
+        }
+        else
+        {
+          sortResponse = (ServerSideSortResponseControl)c;
+        }
       }
       else if (c.getOID().equals(OID_VLV_RESPONSE_CONTROL))
       {
-        vlvResponse = VLVResponseControl.decodeControl(c);
+        if(c instanceof LDAPControl)
+        {
+          vlvResponse = VLVResponseControl.DECODER.decode(c.isCritical(), ((LDAPControl)c).getValue());
+        }
+        else
+        {
+          vlvResponse = (VLVResponseControl)c;
+        }
       }
       else
       {
@@ -1276,7 +1401,7 @@
 
     ArrayList<Control> requestControls = new ArrayList<Control>();
     requestControls.add(new ServerSideSortRequestControl("sn"));
-    requestControls.add(new VLVRequestControl(0, 3, new ASN1OctetString("zz")));
+    requestControls.add(new VLVRequestControl(0, 3, ByteString.valueOf("zz")));
 
     InternalSearchOperation internalSearch =
          new InternalSearchOperation(conn, conn.nextOperationID(),
@@ -1299,7 +1424,14 @@
     {
       if (c.getOID().equals(OID_VLV_RESPONSE_CONTROL))
       {
-        vlvResponse = VLVResponseControl.decodeControl(c);
+        if(c instanceof LDAPControl)
+        {
+          vlvResponse = VLVResponseControl.DECODER.decode(c.isCritical(), ((LDAPControl)c).getValue());
+        }
+        else
+        {
+          vlvResponse = (VLVResponseControl)c;
+        }
       }
     }
 
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/core/AbandonOperationTestCase.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/core/AbandonOperationTestCase.java
index 6232bba..1e6cf60 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/core/AbandonOperationTestCase.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/core/AbandonOperationTestCase.java
@@ -39,10 +39,11 @@
 import java.util.LinkedHashSet;
 
 import org.opends.server.TestCaseUtils;
+import org.opends.server.tools.LDAPWriter;
+import org.opends.server.tools.LDAPReader;
 import org.opends.messages.Message;
 import org.opends.server.plugins.DelayPreOpPlugin;
 import org.opends.server.plugins.DisconnectClientPlugin;
-import org.opends.server.protocols.asn1.ASN1OctetString;
 import org.opends.server.protocols.asn1.ASN1Reader;
 import org.opends.server.protocols.asn1.ASN1Writer;
 import org.opends.server.protocols.internal.InternalClientConnection;
@@ -68,17 +69,7 @@
 import org.opends.server.protocols.ldap.ModifyResponseProtocolOp;
 import org.opends.server.protocols.ldap.SearchRequestProtocolOp;
 import org.opends.server.protocols.ldap.SearchResultDoneProtocolOp;
-import org.opends.server.types.CancelRequest;
-import org.opends.server.types.CancelResult;
-import org.opends.server.types.Control;
-import org.opends.server.types.DereferencePolicy;
-import org.opends.server.types.Entry;
-import org.opends.server.types.ModificationType;
-import org.opends.server.types.Operation;
-import org.opends.server.types.RawAttribute;
-import org.opends.server.types.RawModification;
-import org.opends.server.types.ResultCode;
-import org.opends.server.types.SearchScope;
+import org.opends.server.types.*;
 import org.testng.annotations.Test;
 import org.testng.annotations.BeforeClass;
 
@@ -223,15 +214,15 @@
     // Establish a connection to the server.  It can be unauthenticated for the
     // purpose of this test.
     Socket s = new Socket("127.0.0.1", TestCaseUtils.getServerLdapPort());
-    ASN1Writer w = new ASN1Writer(s);
+    LDAPWriter w = new LDAPWriter(s);
 
 
     // Send the abandon request to the server and wait a few seconds to ensure
     // it has completed before closing the connection.
     AbandonRequestProtocolOp abandonRequest = new AbandonRequestProtocolOp(1);
     LDAPMessage message = new LDAPMessage(2, abandonRequest,
-         DisconnectClientPlugin.createDisconnectLDAPControlList("PreParse"));
-    w.writeElement(message.encode());
+         DisconnectClientPlugin.createDisconnectControlList("PreParse"));
+    w.writeMessage(message);
 
     Thread.sleep(3000);
 
@@ -261,13 +252,13 @@
     // Establish a connection to the server.  It can be unauthenticated for the
     // purpose of this test.
     Socket s = new Socket("127.0.0.1", TestCaseUtils.getServerLdapPort());
-    ASN1Writer w = new ASN1Writer(s);
+    LDAPWriter w = new LDAPWriter(s);
 
 
     // Send the abandon request to the server and wait a few seconds to ensure
     // it has completed before closing the connection.
     AbandonRequestProtocolOp abandonRequest = new AbandonRequestProtocolOp(1);
-    w.writeElement(new LDAPMessage(2, abandonRequest).encode());
+    w.writeMessage(new LDAPMessage(2, abandonRequest));
 
     Thread.sleep(3000);
 
@@ -290,17 +281,17 @@
 
     // Establish a connection to the server and bind as a root user.
     Socket s = new Socket("127.0.0.1", TestCaseUtils.getServerLdapPort());
-    ASN1Reader r = new ASN1Reader(s);
-    ASN1Writer w = new ASN1Writer(s);
-    r.setIOTimeout(6000);
+    LDAPReader r = new LDAPReader(s);
+    LDAPWriter w = new LDAPWriter(s);
+    s.setSoTimeout(6000);
 
     BindRequestProtocolOp bindRequest =
-         new BindRequestProtocolOp(new ASN1OctetString("cn=Directory Manager"),
-                                   3, new ASN1OctetString("password"));
+         new BindRequestProtocolOp(ByteString.valueOf("cn=Directory Manager"),
+                                   3, ByteString.valueOf("password"));
     LDAPMessage message = new LDAPMessage(1, bindRequest);
-    w.writeElement(message.encode());
+    w.writeMessage(message);
 
-    message = LDAPMessage.decode(r.readElement().decodeAsSequence());
+    message = r.readMessage();
     BindResponseProtocolOp bindResponse = message.getBindResponseProtocolOp();
     assertEquals(bindResponse.getResultCode(), LDAPResultCode.SUCCESS);
 
@@ -314,33 +305,33 @@
     // abandon request.
     ArrayList<RawAttribute> attributes = new ArrayList<RawAttribute>();
 
-    ArrayList<ASN1OctetString> values = new ArrayList<ASN1OctetString>(2);
-    values.add(new ASN1OctetString("top"));
-    values.add(new ASN1OctetString("organizationalUnit"));
+    ArrayList<ByteString> values = new ArrayList<ByteString>(2);
+    values.add(ByteString.valueOf("top"));
+    values.add(ByteString.valueOf("organizationalUnit"));
     attributes.add(new LDAPAttribute("objectClass", values));
 
-    values = new ArrayList<ASN1OctetString>(1);
-    values.add(new ASN1OctetString("People"));
+    values = new ArrayList<ByteString>(1);
+    values.add(ByteString.valueOf("People"));
     attributes.add(new LDAPAttribute("ou", values));
 
     AddRequestProtocolOp addRequest =
-         new AddRequestProtocolOp(new ASN1OctetString("ou=People,o=test"),
+         new AddRequestProtocolOp(ByteString.valueOf("ou=People,o=test"),
                                   attributes);
     message = new LDAPMessage(2, addRequest,
-                       DelayPreOpPlugin.createDelayLDAPControlList(5000));
-    w.writeElement(message.encode());
+                       DelayPreOpPlugin.createDelayControlList(5000));
+    w.writeMessage(message);
 
 
     // Send the abandon request to the server.
     AbandonRequestProtocolOp abandonRequest = new AbandonRequestProtocolOp(2);
-    w.writeElement(new LDAPMessage(3, abandonRequest).encode());
+    w.writeMessage(new LDAPMessage(3, abandonRequest));
 
 
     // Normally, abandoned operations don't receive a response.  However, the
     // testing configuration has been updated to ensure that if an operation
     // does get abandoned, the server will return a response for it with a
     // result code of "cancelled".
-    message = LDAPMessage.decode(r.readElement().decodeAsSequence());
+    message = r.readMessage();
     AddResponseProtocolOp addResponse = message.getAddResponseProtocolOp();
     assertEquals(addResponse.getResultCode(), LDAPResultCode.CANCELED);
 
@@ -366,17 +357,17 @@
 
     // Establish a connection to the server and bind as a root user.
     Socket s = new Socket("127.0.0.1", TestCaseUtils.getServerLdapPort());
-    ASN1Reader r = new ASN1Reader(s);
-    ASN1Writer w = new ASN1Writer(s);
-    r.setIOTimeout(6000);
+    LDAPReader r = new LDAPReader(s);
+    LDAPWriter w = new LDAPWriter(s);
+    s.setSoTimeout(6000);
 
     BindRequestProtocolOp bindRequest =
-         new BindRequestProtocolOp(new ASN1OctetString("cn=Directory Manager"),
-                                   3, new ASN1OctetString("password"));
+         new BindRequestProtocolOp(ByteString.valueOf("cn=Directory Manager"),
+                                   3, ByteString.valueOf("password"));
     LDAPMessage message = new LDAPMessage(1, bindRequest);
-    w.writeElement(message.encode());
+    w.writeMessage(message);
 
-    message = LDAPMessage.decode(r.readElement().decodeAsSequence());
+    message = r.readMessage();
     BindResponseProtocolOp bindResponse = message.getBindResponseProtocolOp();
     assertEquals(bindResponse.getResultCode(), LDAPResultCode.SUCCESS);
 
@@ -389,24 +380,24 @@
     // the delay request control so it won't complete before we can send the
     // abandon request.
     CompareRequestProtocolOp compareRequest =
-      new CompareRequestProtocolOp(new ASN1OctetString("o=test"), "o",
-                                   new ASN1OctetString("test"));
+      new CompareRequestProtocolOp(ByteString.valueOf("o=test"), "o",
+                                   ByteString.valueOf("test"));
     message = new LDAPMessage(2, compareRequest,
-                       DelayPreOpPlugin.createDelayLDAPControlList(5000));
-    w.writeElement(message.encode());
+                       DelayPreOpPlugin.createDelayControlList(5000));
+    w.writeMessage(message);
 
 
     // Send the abandon request to the server and wait a few seconds to ensure
     // it has completed before closing the connection.
     AbandonRequestProtocolOp abandonRequest = new AbandonRequestProtocolOp(2);
-    w.writeElement(new LDAPMessage(3, abandonRequest).encode());
+    w.writeMessage(new LDAPMessage(3, abandonRequest));
 
 
     // Normally, abandoned operations don't receive a response.  However, the
     // testing configuration has been updated to ensure that if an operation
     // does get abandoned, the server will return a response for it with a
     // result code of "cancelled".
-    message = LDAPMessage.decode(r.readElement().decodeAsSequence());
+    message = r.readMessage();
     CompareResponseProtocolOp compareResponse =
          message.getCompareResponseProtocolOp();
     assertEquals(compareResponse.getResultCode(), LDAPResultCode.CANCELED);
@@ -447,17 +438,17 @@
 
     // Establish a connection to the server and bind as a root user.
     Socket s = new Socket("127.0.0.1", TestCaseUtils.getServerLdapPort());
-    ASN1Reader r = new ASN1Reader(s);
-    ASN1Writer w = new ASN1Writer(s);
-    r.setIOTimeout(6000);
+    LDAPReader r = new LDAPReader(s);
+    LDAPWriter w = new LDAPWriter(s);
+    s.setSoTimeout(6000);
 
     BindRequestProtocolOp bindRequest =
-         new BindRequestProtocolOp(new ASN1OctetString("cn=Directory Manager"),
-                                   3, new ASN1OctetString("password"));
+         new BindRequestProtocolOp(ByteString.valueOf("cn=Directory Manager"),
+                                   3, ByteString.valueOf("password"));
     LDAPMessage message = new LDAPMessage(1, bindRequest);
-    w.writeElement(message.encode());
+    w.writeMessage(message);
 
-    message = LDAPMessage.decode(r.readElement().decodeAsSequence());
+    message = r.readMessage();
     BindResponseProtocolOp bindResponse = message.getBindResponseProtocolOp();
     assertEquals(bindResponse.getResultCode(), LDAPResultCode.SUCCESS);
 
@@ -470,23 +461,23 @@
     // the delay request control so it won't complete before we can send the
     // abandon request.
     DeleteRequestProtocolOp deleteRequest =
-         new DeleteRequestProtocolOp(new ASN1OctetString("cn=test,o=test"));
+         new DeleteRequestProtocolOp(ByteString.valueOf("cn=test,o=test"));
     message = new LDAPMessage(2, deleteRequest,
-                       DelayPreOpPlugin.createDelayLDAPControlList(5000));
-    w.writeElement(message.encode());
+                       DelayPreOpPlugin.createDelayControlList(5000));
+    w.writeMessage(message);
 
 
     // Send the abandon request to the server and wait a few seconds to ensure
     // it has completed before closing the connection.
     AbandonRequestProtocolOp abandonRequest = new AbandonRequestProtocolOp(2);
-    w.writeElement(new LDAPMessage(3, abandonRequest).encode());
+    w.writeMessage(new LDAPMessage(3, abandonRequest));
 
 
     // Normally, abandoned operations don't receive a response.  However, the
     // testing configuration has been updated to ensure that if an operation
     // does get abandoned, the server will return a response for it with a
     // result code of "cancelled".
-    message = LDAPMessage.decode(r.readElement().decodeAsSequence());
+    message = r.readMessage();
     DeleteResponseProtocolOp deleteResponse =
          message.getDeleteResponseProtocolOp();
     assertEquals(deleteResponse.getResultCode(), LDAPResultCode.CANCELED);
@@ -513,17 +504,17 @@
 
     // Establish a connection to the server and bind as a root user.
     Socket s = new Socket("127.0.0.1", TestCaseUtils.getServerLdapPort());
-    ASN1Reader r = new ASN1Reader(s);
-    ASN1Writer w = new ASN1Writer(s);
-    r.setIOTimeout(6000);
+    LDAPReader r = new LDAPReader(s);
+    LDAPWriter w = new LDAPWriter(s);
+    s.setSoTimeout(6000);
 
     BindRequestProtocolOp bindRequest =
-         new BindRequestProtocolOp(new ASN1OctetString("cn=Directory Manager"),
-                                   3, new ASN1OctetString("password"));
+         new BindRequestProtocolOp(ByteString.valueOf("cn=Directory Manager"),
+                                   3, ByteString.valueOf("password"));
     LDAPMessage message = new LDAPMessage(1, bindRequest);
-    w.writeElement(message.encode());
+    w.writeMessage(message);
 
-    message = LDAPMessage.decode(r.readElement().decodeAsSequence());
+    message = r.readMessage();
     BindResponseProtocolOp bindResponse = message.getBindResponseProtocolOp();
     assertEquals(bindResponse.getResultCode(), LDAPResultCode.SUCCESS);
 
@@ -538,21 +529,21 @@
     ExtendedRequestProtocolOp whoAmIRequest =
          new ExtendedRequestProtocolOp(OID_WHO_AM_I_REQUEST, null);
     message = new LDAPMessage(2, whoAmIRequest,
-                       DelayPreOpPlugin.createDelayLDAPControlList(5000));
-    w.writeElement(message.encode());
+                       DelayPreOpPlugin.createDelayControlList(5000));
+    w.writeMessage(message);
 
 
     // Send the abandon request to the server and wait a few seconds to ensure
     // it has completed before closing the connection.
     AbandonRequestProtocolOp abandonRequest = new AbandonRequestProtocolOp(2);
-    w.writeElement(new LDAPMessage(3, abandonRequest).encode());
+    w.writeMessage(new LDAPMessage(3, abandonRequest));
 
 
     // Normally, abandoned operations don't receive a response.  However, the
     // testing configuration has been updated to ensure that if an operation
     // does get abandoned, the server will return a response for it with a
     // result code of "cancelled".
-    message = LDAPMessage.decode(r.readElement().decodeAsSequence());
+    message = r.readMessage();
     ExtendedResponseProtocolOp extendedResponse =
          message.getExtendedResponseProtocolOp();
     assertEquals(extendedResponse.getResultCode(), LDAPResultCode.CANCELED);
@@ -579,17 +570,17 @@
 
     // Establish a connection to the server and bind as a root user.
     Socket s = new Socket("127.0.0.1", TestCaseUtils.getServerLdapPort());
-    ASN1Reader r = new ASN1Reader(s);
-    ASN1Writer w = new ASN1Writer(s);
-    r.setIOTimeout(6000);
+    LDAPReader r = new LDAPReader(s);
+    LDAPWriter w = new LDAPWriter(s);
+    s.setSoTimeout(6000);
 
     BindRequestProtocolOp bindRequest =
-         new BindRequestProtocolOp(new ASN1OctetString("cn=Directory Manager"),
-                                   3, new ASN1OctetString("password"));
+         new BindRequestProtocolOp(ByteString.valueOf("cn=Directory Manager"),
+                                   3, ByteString.valueOf("password"));
     LDAPMessage message = new LDAPMessage(1, bindRequest);
-    w.writeElement(message.encode());
+    w.writeMessage(message);
 
-    message = LDAPMessage.decode(r.readElement().decodeAsSequence());
+    message = r.readMessage();
     BindResponseProtocolOp bindResponse = message.getBindResponseProtocolOp();
     assertEquals(bindResponse.getResultCode(), LDAPResultCode.SUCCESS);
 
@@ -601,31 +592,31 @@
     // Create a modify request and send it to the server.  Make sure to include
     // the delay request control so it won't complete before we can send the
     // abandon request.
-    ArrayList<ASN1OctetString> values = new ArrayList<ASN1OctetString>(1);
-    values.add(new ASN1OctetString("foo"));
+    ArrayList<ByteString> values = new ArrayList<ByteString>(1);
+    values.add(ByteString.valueOf("foo"));
 
     ArrayList<RawModification> mods = new ArrayList<RawModification>(1);
     mods.add(new LDAPModification(ModificationType.REPLACE,
                                   new LDAPAttribute("description", values)));
 
     ModifyRequestProtocolOp modifyRequest =
-         new ModifyRequestProtocolOp(new ASN1OctetString("o=test"), mods);
+         new ModifyRequestProtocolOp(ByteString.valueOf("o=test"), mods);
     message = new LDAPMessage(2, modifyRequest,
-                       DelayPreOpPlugin.createDelayLDAPControlList(5000));
-    w.writeElement(message.encode());
+                       DelayPreOpPlugin.createDelayControlList(5000));
+    w.writeMessage(message);
 
 
     // Send the abandon request to the server and wait a few seconds to ensure
     // it has completed before closing the connection.
     AbandonRequestProtocolOp abandonRequest = new AbandonRequestProtocolOp(2);
-    w.writeElement(new LDAPMessage(3, abandonRequest).encode());
+    w.writeMessage(new LDAPMessage(3, abandonRequest));
 
 
     // Normally, abandoned operations don't receive a response.  However, the
     // testing configuration has been updated to ensure that if an operation
     // does get abandoned, the server will return a response for it with a
     // result code of "cancelled".
-    message = LDAPMessage.decode(r.readElement().decodeAsSequence());
+    message = r.readMessage();
     ModifyResponseProtocolOp modifyResponse =
          message.getModifyResponseProtocolOp();
     assertEquals(modifyResponse.getResultCode(), LDAPResultCode.CANCELED);
@@ -666,17 +657,17 @@
 
     // Establish a connection to the server and bind as a root user.
     Socket s = new Socket("127.0.0.1", TestCaseUtils.getServerLdapPort());
-    ASN1Reader r = new ASN1Reader(s);
-    ASN1Writer w = new ASN1Writer(s);
-    r.setIOTimeout(6000);
+    LDAPReader r = new LDAPReader(s);
+    LDAPWriter w = new LDAPWriter(s);
+    s.setSoTimeout(6000);
 
     BindRequestProtocolOp bindRequest =
-         new BindRequestProtocolOp(new ASN1OctetString("cn=Directory Manager"),
-                                   3, new ASN1OctetString("password"));
+         new BindRequestProtocolOp(ByteString.valueOf("cn=Directory Manager"),
+                                   3, ByteString.valueOf("password"));
     LDAPMessage message = new LDAPMessage(1, bindRequest);
-    w.writeElement(message.encode());
+    w.writeMessage(message);
 
-    message = LDAPMessage.decode(r.readElement().decodeAsSequence());
+    message = r.readMessage();
     BindResponseProtocolOp bindResponse = message.getBindResponseProtocolOp();
     assertEquals(bindResponse.getResultCode(), LDAPResultCode.SUCCESS);
 
@@ -689,24 +680,24 @@
     // include the delay request control so it won't complete before we can send
     // the abandon request.
     ModifyDNRequestProtocolOp modifyDNRequest =
-         new ModifyDNRequestProtocolOp(new ASN1OctetString("cn=test,o=test"),
-                                       new ASN1OctetString("cn=test2"), true);
+         new ModifyDNRequestProtocolOp(ByteString.valueOf("cn=test,o=test"),
+                                       ByteString.valueOf("cn=test2"), true);
     message = new LDAPMessage(2, modifyDNRequest,
-                       DelayPreOpPlugin.createDelayLDAPControlList(5000));
-    w.writeElement(message.encode());
+                       DelayPreOpPlugin.createDelayControlList(5000));
+    w.writeMessage(message);
 
 
     // Send the abandon request to the server and wait a few seconds to ensure
     // it has completed before closing the connection.
     AbandonRequestProtocolOp abandonRequest = new AbandonRequestProtocolOp(2);
-    w.writeElement(new LDAPMessage(3, abandonRequest).encode());
+    w.writeMessage(new LDAPMessage(3, abandonRequest));
 
 
     // Normally, abandoned operations don't receive a response.  However, the
     // testing configuration has been updated to ensure that if an operation
     // does get abandoned, the server will return a response for it with a
     // result code of "cancelled".
-    message = LDAPMessage.decode(r.readElement().decodeAsSequence());
+    message = r.readMessage();
     ModifyDNResponseProtocolOp modifyDNResponse =
          message.getModifyDNResponseProtocolOp();
     assertEquals(modifyDNResponse.getResultCode(), LDAPResultCode.CANCELED);
@@ -733,17 +724,17 @@
 
     // Establish a connection to the server and bind as a root user.
     Socket s = new Socket("127.0.0.1", TestCaseUtils.getServerLdapPort());
-    ASN1Reader r = new ASN1Reader(s);
-    ASN1Writer w = new ASN1Writer(s);
-    r.setIOTimeout(6000);
+    LDAPReader r = new LDAPReader(s);
+    LDAPWriter w = new LDAPWriter(s);
+    s.setSoTimeout(6000);
 
     BindRequestProtocolOp bindRequest =
-         new BindRequestProtocolOp(new ASN1OctetString("cn=Directory Manager"),
-                                   3, new ASN1OctetString("password"));
+         new BindRequestProtocolOp(ByteString.valueOf("cn=Directory Manager"),
+                                   3, ByteString.valueOf("password"));
     LDAPMessage message = new LDAPMessage(1, bindRequest);
-    w.writeElement(message.encode());
+    w.writeMessage(message);
 
-    message = LDAPMessage.decode(r.readElement().decodeAsSequence());
+    message = r.readMessage();
     BindResponseProtocolOp bindResponse = message.getBindResponseProtocolOp();
     assertEquals(bindResponse.getResultCode(), LDAPResultCode.SUCCESS);
 
@@ -756,28 +747,28 @@
     // the delay request control so it won't complete before we can send the
     // abandon request.
     SearchRequestProtocolOp searchRequest =
-         new SearchRequestProtocolOp(new ASN1OctetString("o=test"),
+         new SearchRequestProtocolOp(ByteString.valueOf("o=test"),
                                      SearchScope.BASE_OBJECT,
                                      DereferencePolicy.NEVER_DEREF_ALIASES, 0,
                                      0, false,
                                      LDAPFilter.decode("(match=false)"),
                                      new LinkedHashSet<String>());
     message = new LDAPMessage(2, searchRequest,
-                       DelayPreOpPlugin.createDelayLDAPControlList(5000));
-    w.writeElement(message.encode());
+                       DelayPreOpPlugin.createDelayControlList(5000));
+    w.writeMessage(message);
 
 
     // Send the abandon request to the server and wait a few seconds to ensure
     // it has completed before closing the connection.
     AbandonRequestProtocolOp abandonRequest = new AbandonRequestProtocolOp(2);
-    w.writeElement(new LDAPMessage(3, abandonRequest).encode());
+    w.writeMessage(new LDAPMessage(3, abandonRequest));
 
 
     // Normally, abandoned operations don't receive a response.  However, the
     // testing configuration has been updated to ensure that if an operation
     // does get abandoned, the server will return a response for it with a
     // result code of "cancelled".
-    message = LDAPMessage.decode(r.readElement().decodeAsSequence());
+    message = r.readMessage();
     SearchResultDoneProtocolOp searchDone =
          message.getSearchResultDoneProtocolOp();
     assertEquals(searchDone.getResultCode(), LDAPResultCode.CANCELED);
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/core/AddOperationTestCase.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/core/AddOperationTestCase.java
index 763bc9c..6185c79 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/core/AddOperationTestCase.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/core/AddOperationTestCase.java
@@ -43,8 +43,6 @@
 import org.opends.server.plugins.DisconnectClientPlugin;
 import org.opends.server.plugins.ShortCircuitPlugin;
 import org.opends.server.plugins.UpdatePreOpPlugin;
-import org.opends.server.protocols.asn1.ASN1Element;
-import org.opends.server.protocols.asn1.ASN1OctetString;
 import org.opends.server.protocols.asn1.ASN1Reader;
 import org.opends.server.protocols.asn1.ASN1Writer;
 import org.opends.server.protocols.internal.InternalClientConnection;
@@ -55,23 +53,9 @@
 import org.opends.server.protocols.ldap.LDAPAttribute;
 import org.opends.server.protocols.ldap.LDAPMessage;
 import org.opends.server.tools.LDAPModify;
-import org.opends.server.types.Attribute;
-import org.opends.server.types.AttributeType;
-import org.opends.server.types.AttributeValue;
-import org.opends.server.types.Attributes;
-import org.opends.server.types.ByteString;
-import org.opends.server.types.CancelRequest;
-import org.opends.server.types.CancelResult;
-import org.opends.server.types.Control;
-import org.opends.server.types.DN;
-import org.opends.server.types.DirectoryException;
-import org.opends.server.types.Entry;
-import org.opends.server.types.LockManager;
-import org.opends.server.types.ObjectClass;
-import org.opends.server.types.Operation;
-import org.opends.server.types.RawAttribute;
-import org.opends.server.types.ResultCode;
-import org.opends.server.types.WritabilityMode;
+import org.opends.server.tools.LDAPReader;
+import org.opends.server.tools.LDAPWriter;
+import org.opends.server.types.*;
 import org.testng.annotations.AfterMethod;
 import org.testng.annotations.DataProvider;
 import org.testng.annotations.Test;
@@ -110,13 +94,13 @@
 
     ArrayList<RawAttribute> ldapAttrList = new ArrayList<RawAttribute>();
 
-    ArrayList<ASN1OctetString> values = new ArrayList<ASN1OctetString>();
-    values.add(new ASN1OctetString("top"));
-    values.add(new ASN1OctetString("organizationalUnit"));
+    ArrayList<ByteString> values = new ArrayList<ByteString>();
+    values.add(ByteString.valueOf("top"));
+    values.add(ByteString.valueOf("organizationalUnit"));
     ldapAttrList.add(new LDAPAttribute("objectclass", values));
 
     values.clear();
-    values.add(new ASN1OctetString("People"));
+    values.add(ByteString.valueOf("People"));
     ldapAttrList.add(new LDAPAttribute("ou", values));
 
     Entry entry = TestCaseUtils.makeEntry(
@@ -128,10 +112,10 @@
     Operation[] opArray = new Operation[]
     {
       new AddOperationBasis(conn, conn.nextOperationID(), conn.nextMessageID(),
-                       null, new ASN1OctetString("ou=People,o=test"),
+                       null, ByteString.valueOf("ou=People,o=test"),
                        ldapAttrList),
       new AddOperationBasis(conn, conn.nextOperationID(), conn.nextMessageID(),
-                       noControls, new ASN1OctetString("ou=People,o=test"),
+                       noControls, ByteString.valueOf("ou=People,o=test"),
                        ldapAttrList),
       new AddOperationBasis(conn, conn.nextOperationID(), conn.nextMessageID(),
                        null, entry.getDN(), entry.getObjectClasses(),
@@ -186,10 +170,10 @@
     ByteString originalDN = addOperation.getRawEntryDN();
     assertNotNull(originalDN);
 
-    addOperation.setRawEntryDN(new ASN1OctetString("uid=test,o=test"));
+    addOperation.setRawEntryDN(ByteString.valueOf("uid=test,o=test"));
     assertNotNull(addOperation.getRawEntryDN());
     assertEquals(addOperation.getRawEntryDN(),
-                 new ASN1OctetString("uid=test,o=test"));
+                 ByteString.valueOf("uid=test,o=test"));
 
     addOperation.setRawEntryDN(originalDN);
     assertNotNull(addOperation.getRawEntryDN());
@@ -210,18 +194,18 @@
 
     ArrayList<RawAttribute> ldapAttrList = new ArrayList<RawAttribute>();
 
-    ArrayList<ASN1OctetString> values = new ArrayList<ASN1OctetString>();
-    values.add(new ASN1OctetString("top"));
-    values.add(new ASN1OctetString("organizationalUnit"));
+    ArrayList<ByteString> values = new ArrayList<ByteString>();
+    values.add(ByteString.valueOf("top"));
+    values.add(ByteString.valueOf("organizationalUnit"));
     ldapAttrList.add(new LDAPAttribute("objectclass", values));
 
     values.clear();
-    values.add(new ASN1OctetString("People"));
+    values.add(ByteString.valueOf("People"));
     ldapAttrList.add(new LDAPAttribute("ou", values));
 
     AddOperationBasis addOperation =
          new AddOperationBasis(conn, conn.nextOperationID(), conn.nextMessageID(),
-                          null, new ASN1OctetString("ou=People,o=test"),
+                          null, ByteString.valueOf("ou=People,o=test"),
                           ldapAttrList);
     assertNotNull(addOperation.getEntryDN());
   }
@@ -284,7 +268,7 @@
                           entry.getOperationalAttributes());
     assertNotNull(addOperation.getEntryDN());
 
-    addOperation.setRawEntryDN(new ASN1OctetString("ou=Users,o=test"));
+    addOperation.setRawEntryDN(ByteString.valueOf("ou=Users,o=test"));
     assertNotNull(addOperation.getEntryDN());
   }
 
@@ -307,8 +291,8 @@
       new ArrayList<RawAttribute>(rawAttrs);
     addOperation.setRawAttributes(copiedAttrs);
 
-    ArrayList<ASN1OctetString> values = new ArrayList<ASN1OctetString>();
-    values.add(new ASN1OctetString("foo"));
+    ArrayList<ByteString> values = new ArrayList<ByteString>();
+    values.add(ByteString.valueOf("foo"));
     addOperation.addRawAttribute(new LDAPAttribute("description", values));
 
     boolean found = false;
@@ -462,14 +446,14 @@
     boolean foundBar = false;
     for (Attribute attr : attrList)
     {
-      if (attr.contains(new AttributeValue(a.getAttributeType(),
-                                           new ASN1OctetString("foo"))))
+      if (attr.contains(AttributeValues.create(a.getAttributeType(),
+                                           ByteString.valueOf("foo"))))
       {
         foundFoo = true;
       }
 
-      if (attr.contains(new AttributeValue(a.getAttributeType(),
-                                                new ASN1OctetString("bar"))))
+      if (attr.contains(AttributeValues.create(a.getAttributeType(),
+                                                ByteString.valueOf("bar"))))
       {
         foundBar = true;
       }
@@ -604,20 +588,20 @@
 
     ArrayList<RawAttribute> attrs = new ArrayList<RawAttribute>();
 
-    ArrayList<ASN1OctetString> values = new ArrayList<ASN1OctetString>();
-    values.add(new ASN1OctetString("top"));
-    values.add(new ASN1OctetString("organizationalUnit"));
+    ArrayList<ByteString> values = new ArrayList<ByteString>();
+    values.add(ByteString.valueOf("top"));
+    values.add(ByteString.valueOf("organizationalUnit"));
     attrs.add(new LDAPAttribute("objectClass", values));
 
-    values = new ArrayList<ASN1OctetString>();
-    values.add(new ASN1OctetString("People"));
+    values = new ArrayList<ByteString>();
+    values.add(ByteString.valueOf("People"));
     attrs.add(new LDAPAttribute("ou", values));
 
     InternalClientConnection conn =
          InternalClientConnection.getRootConnection();
 
     AddOperation addOperation =
-         conn.processAdd(new ASN1OctetString("ou=People,o=test"), attrs);
+         conn.processAdd(ByteString.valueOf("ou=People,o=test"), attrs);
     assertEquals(addOperation.getResultCode(), ResultCode.SUCCESS);
     retrieveCompletedOperationElements(addOperation);
   }
@@ -669,20 +653,20 @@
 
     ArrayList<RawAttribute> attrs = new ArrayList<RawAttribute>();
 
-    ArrayList<ASN1OctetString> values = new ArrayList<ASN1OctetString>();
-    values.add(new ASN1OctetString("top"));
-    values.add(new ASN1OctetString("organizationalUnit"));
+    ArrayList<ByteString> values = new ArrayList<ByteString>();
+    values.add(ByteString.valueOf("top"));
+    values.add(ByteString.valueOf("organizationalUnit"));
     attrs.add(new LDAPAttribute("objectClass", values));
 
-    values = new ArrayList<ASN1OctetString>();
-    values.add(new ASN1OctetString("People"));
+    values = new ArrayList<ByteString>();
+    values.add(ByteString.valueOf("People"));
     attrs.add(new LDAPAttribute("ou", values));
 
     InternalClientConnection conn =
          InternalClientConnection.getRootConnection();
 
     AddOperation addOperation =
-         conn.processAdd(new ASN1OctetString("invalid"), attrs);
+         conn.processAdd(ByteString.valueOf("invalid"), attrs);
     assertFalse(addOperation.getResultCode() == ResultCode.SUCCESS);
   }
 
@@ -702,20 +686,20 @@
 
     ArrayList<RawAttribute> attrs = new ArrayList<RawAttribute>();
 
-    ArrayList<ASN1OctetString> values = new ArrayList<ASN1OctetString>();
-    values.add(new ASN1OctetString("top"));
-    values.add(new ASN1OctetString("organization"));
+    ArrayList<ByteString> values = new ArrayList<ByteString>();
+    values.add(ByteString.valueOf("top"));
+    values.add(ByteString.valueOf("organization"));
     attrs.add(new LDAPAttribute("objectClass", values));
 
-    values = new ArrayList<ASN1OctetString>();
-    values.add(new ASN1OctetString("test"));
+    values = new ArrayList<ByteString>();
+    values.add(ByteString.valueOf("test"));
     attrs.add(new LDAPAttribute("o", values));
 
     InternalClientConnection conn =
          InternalClientConnection.getRootConnection();
 
     AddOperation addOperation =
-         conn.processAdd(new ASN1OctetString("o=test"), attrs);
+         conn.processAdd(ByteString.valueOf("o=test"), attrs);
     assertFalse(addOperation.getResultCode() == ResultCode.SUCCESS);
   }
 
@@ -735,20 +719,20 @@
 
     ArrayList<RawAttribute> attrs = new ArrayList<RawAttribute>();
 
-    ArrayList<ASN1OctetString> values = new ArrayList<ASN1OctetString>();
-    values.add(new ASN1OctetString("top"));
-    values.add(new ASN1OctetString("organization"));
+    ArrayList<ByteString> values = new ArrayList<ByteString>();
+    values.add(ByteString.valueOf("top"));
+    values.add(ByteString.valueOf("organization"));
     attrs.add(new LDAPAttribute("objectClass", values));
 
-    values = new ArrayList<ASN1OctetString>();
-    values.add(new ASN1OctetString("undefined"));
+    values = new ArrayList<ByteString>();
+    values.add(ByteString.valueOf("undefined"));
     attrs.add(new LDAPAttribute("o", values));
 
     InternalClientConnection conn =
          InternalClientConnection.getRootConnection();
 
     AddOperation addOperation =
-         conn.processAdd(new ASN1OctetString("o=undefined"), attrs);
+         conn.processAdd(ByteString.valueOf("o=undefined"), attrs);
     assertFalse(addOperation.getResultCode() == ResultCode.SUCCESS);
   }
 
@@ -768,20 +752,20 @@
 
     ArrayList<RawAttribute> attrs = new ArrayList<RawAttribute>();
 
-    ArrayList<ASN1OctetString> values = new ArrayList<ASN1OctetString>();
-    values.add(new ASN1OctetString("top"));
-    values.add(new ASN1OctetString("organizationalUnit"));
+    ArrayList<ByteString> values = new ArrayList<ByteString>();
+    values.add(ByteString.valueOf("top"));
+    values.add(ByteString.valueOf("organizationalUnit"));
     attrs.add(new LDAPAttribute("objectClass", values));
 
-    values = new ArrayList<ASN1OctetString>();
-    values.add(new ASN1OctetString("People"));
+    values = new ArrayList<ByteString>();
+    values.add(ByteString.valueOf("People"));
     attrs.add(new LDAPAttribute("ou", values));
 
     InternalClientConnection conn =
          InternalClientConnection.getRootConnection();
 
     AddOperation addOperation =
-         conn.processAdd(new ASN1OctetString("ou=People,o=undefined"), attrs);
+         conn.processAdd(ByteString.valueOf("ou=People,o=undefined"), attrs);
     assertFalse(addOperation.getResultCode() == ResultCode.SUCCESS);
   }
 
@@ -801,20 +785,20 @@
 
     ArrayList<RawAttribute> attrs = new ArrayList<RawAttribute>();
 
-    ArrayList<ASN1OctetString> values = new ArrayList<ASN1OctetString>();
-    values.add(new ASN1OctetString("top"));
-    values.add(new ASN1OctetString("organizationalUnit"));
+    ArrayList<ByteString> values = new ArrayList<ByteString>();
+    values.add(ByteString.valueOf("top"));
+    values.add(ByteString.valueOf("organizationalUnit"));
     attrs.add(new LDAPAttribute("objectClass", values));
 
-    values = new ArrayList<ASN1OctetString>();
-    values.add(new ASN1OctetString("People"));
+    values = new ArrayList<ByteString>();
+    values.add(ByteString.valueOf("People"));
     attrs.add(new LDAPAttribute("ou", values));
 
     InternalClientConnection conn =
          InternalClientConnection.getRootConnection();
 
     AddOperation addOperation =
-         conn.processAdd(new ASN1OctetString("ou=People,o=missing,o=test"),
+         conn.processAdd(ByteString.valueOf("ou=People,o=missing,o=test"),
                          attrs);
     assertFalse(addOperation.getResultCode() == ResultCode.SUCCESS);
   }
@@ -834,50 +818,50 @@
     TestCaseUtils.initializeTestBackend(true);
 
     Socket s = new Socket("127.0.0.1", TestCaseUtils.getServerLdapPort());
-    ASN1Reader r = new ASN1Reader(s);
-    ASN1Writer w = new ASN1Writer(s);
-    r.setIOTimeout(3000);
+    LDAPReader r = new LDAPReader(s);
+    LDAPWriter w = new LDAPWriter(s);
+    s.setSoTimeout(3000);
 
     BindRequestProtocolOp bindRequest =
-         new BindRequestProtocolOp(new ASN1OctetString("cn=Directory Manager"),
-                                   3, new ASN1OctetString("password"));
+         new BindRequestProtocolOp(ByteString.valueOf("cn=Directory Manager"),
+                                   3, ByteString.valueOf("password"));
     LDAPMessage message = new LDAPMessage(1, bindRequest);
-    w.writeElement(message.encode());
+    w.writeMessage(message);
 
-    message = LDAPMessage.decode(r.readElement().decodeAsSequence());
+    message = r.readMessage();
     BindResponseProtocolOp bindResponse =
          message.getBindResponseProtocolOp();
     assertEquals(bindResponse.getResultCode(), 0);
 
 
     ArrayList<RawAttribute> attrs = new ArrayList<RawAttribute>();
-    ArrayList<ASN1OctetString> values = new ArrayList<ASN1OctetString>();
-    values.add(new ASN1OctetString("top"));
-    values.add(new ASN1OctetString("organizationalUnit"));
+    ArrayList<ByteString> values = new ArrayList<ByteString>();
+    values.add(ByteString.valueOf("top"));
+    values.add(ByteString.valueOf("organizationalUnit"));
     attrs.add(new LDAPAttribute("objectClass", values));
 
-    values = new ArrayList<ASN1OctetString>();
-    values.add(new ASN1OctetString("People"));
+    values = new ArrayList<ByteString>();
+    values.add(ByteString.valueOf("People"));
     attrs.add(new LDAPAttribute("ou", values));
 
-    values = new ArrayList<ASN1OctetString>();
-    values.add(new ASN1OctetString("cn=Directory Manager"));
+    values = new ArrayList<ByteString>();
+    values.add(ByteString.valueOf("cn=Directory Manager"));
     attrs.add(new LDAPAttribute("creatorsName", values));
 
-    values = new ArrayList<ASN1OctetString>();
-    values.add(new ASN1OctetString("20060101000000Z"));
+    values = new ArrayList<ByteString>();
+    values.add(ByteString.valueOf("20060101000000Z"));
     attrs.add(new LDAPAttribute("createTimestamp", values));
 
     long addRequests  = ldapStatistics.getAddRequests();
     long addResponses = ldapStatistics.getAddResponses();
 
     AddRequestProtocolOp addRequest =
-         new AddRequestProtocolOp(new ASN1OctetString("ou=People,o=test"),
+         new AddRequestProtocolOp(ByteString.valueOf("ou=People,o=test"),
                                   attrs);
     message = new LDAPMessage(2, addRequest);
-    w.writeElement(message.encode());
+    w.writeMessage(message);
 
-    message = LDAPMessage.decode(r.readElement().decodeAsSequence());
+    message = r.readMessage();
     AddResponseProtocolOp addResponse =
          message.getAddResponseProtocolOp();
     assertFalse(addResponse.getResultCode() == 0);
@@ -907,20 +891,20 @@
 
     ArrayList<RawAttribute> attrs = new ArrayList<RawAttribute>();
 
-    ArrayList<ASN1OctetString> values = new ArrayList<ASN1OctetString>();
-    values.add(new ASN1OctetString("top"));
-    values.add(new ASN1OctetString("undefined"));
+    ArrayList<ByteString> values = new ArrayList<ByteString>();
+    values.add(ByteString.valueOf("top"));
+    values.add(ByteString.valueOf("undefined"));
     attrs.add(new LDAPAttribute("objectClass", values));
 
-    values = new ArrayList<ASN1OctetString>();
-    values.add(new ASN1OctetString("People"));
+    values = new ArrayList<ByteString>();
+    values.add(ByteString.valueOf("People"));
     attrs.add(new LDAPAttribute("ou", values));
 
     InternalClientConnection conn =
          InternalClientConnection.getRootConnection();
 
     AddOperation addOperation =
-         conn.processAdd(new ASN1OctetString("ou=People,o=test"),
+         conn.processAdd(ByteString.valueOf("ou=People,o=test"),
                          attrs);
     assertFalse(addOperation.getResultCode() == ResultCode.SUCCESS);
   }
@@ -980,28 +964,28 @@
 
     ArrayList<RawAttribute> attrs = new ArrayList<RawAttribute>();
 
-    ArrayList<ASN1OctetString> values = new ArrayList<ASN1OctetString>();
-    values.add(new ASN1OctetString("top"));
-    values.add(new ASN1OctetString("organizationalUnit"));
+    ArrayList<ByteString> values = new ArrayList<ByteString>();
+    values.add(ByteString.valueOf("top"));
+    values.add(ByteString.valueOf("organizationalUnit"));
     attrs.add(new LDAPAttribute("objectClass", values));
 
-    values = new ArrayList<ASN1OctetString>();
-    values.add(new ASN1OctetString("foo"));
+    values = new ArrayList<ByteString>();
+    values.add(ByteString.valueOf("foo"));
     attrs.add(new LDAPAttribute("description", values));
 
-    values = new ArrayList<ASN1OctetString>();
-    values.add(new ASN1OctetString("People"));
+    values = new ArrayList<ByteString>();
+    values.add(ByteString.valueOf("People"));
     attrs.add(new LDAPAttribute("ou", values));
 
-    values = new ArrayList<ASN1OctetString>();
-    values.add(new ASN1OctetString("bar"));
+    values = new ArrayList<ByteString>();
+    values.add(ByteString.valueOf("bar"));
     attrs.add(new LDAPAttribute("description", values));
 
     InternalClientConnection conn =
          InternalClientConnection.getRootConnection();
 
     AddOperation addOperation =
-         conn.processAdd(new ASN1OctetString("ou=People,o=test"),
+         conn.processAdd(ByteString.valueOf("ou=People,o=test"),
                          attrs);
     assertEquals(addOperation.getResultCode(), ResultCode.SUCCESS);
   }
@@ -1022,28 +1006,28 @@
 
     ArrayList<RawAttribute> attrs = new ArrayList<RawAttribute>();
 
-    ArrayList<ASN1OctetString> values = new ArrayList<ASN1OctetString>();
-    values.add(new ASN1OctetString("top"));
-    values.add(new ASN1OctetString("organizationalUnit"));
+    ArrayList<ByteString> values = new ArrayList<ByteString>();
+    values.add(ByteString.valueOf("top"));
+    values.add(ByteString.valueOf("organizationalUnit"));
     attrs.add(new LDAPAttribute("objectClass", values));
 
-    values = new ArrayList<ASN1OctetString>();
-    values.add(new ASN1OctetString("foo"));
+    values = new ArrayList<ByteString>();
+    values.add(ByteString.valueOf("foo"));
     attrs.add(new LDAPAttribute("description", values));
 
-    values = new ArrayList<ASN1OctetString>();
-    values.add(new ASN1OctetString("People"));
+    values = new ArrayList<ByteString>();
+    values.add(ByteString.valueOf("People"));
     attrs.add(new LDAPAttribute("ou", values));
 
-    values = new ArrayList<ASN1OctetString>();
-    values.add(new ASN1OctetString("foo"));
+    values = new ArrayList<ByteString>();
+    values.add(ByteString.valueOf("foo"));
     attrs.add(new LDAPAttribute("description;lang-en-us", values));
 
     InternalClientConnection conn =
          InternalClientConnection.getRootConnection();
 
     AddOperation addOperation =
-         conn.processAdd(new ASN1OctetString("ou=People,o=test"),
+         conn.processAdd(ByteString.valueOf("ou=People,o=test"),
                          attrs);
     assertEquals(addOperation.getResultCode(), ResultCode.SUCCESS);
   }
@@ -1064,24 +1048,24 @@
 
     ArrayList<RawAttribute> attrs = new ArrayList<RawAttribute>();
 
-    ArrayList<ASN1OctetString> values = new ArrayList<ASN1OctetString>();
-    values.add(new ASN1OctetString("top"));
-    values.add(new ASN1OctetString("organizationalUnit"));
+    ArrayList<ByteString> values = new ArrayList<ByteString>();
+    values.add(ByteString.valueOf("top"));
+    values.add(ByteString.valueOf("organizationalUnit"));
     attrs.add(new LDAPAttribute("objectClass", values));
 
-    values = new ArrayList<ASN1OctetString>();
-    values.add(new ASN1OctetString("People"));
+    values = new ArrayList<ByteString>();
+    values.add(ByteString.valueOf("People"));
     attrs.add(new LDAPAttribute("ou", values));
 
-    values = new ArrayList<ASN1OctetString>();
-    values.add(new ASN1OctetString("foo"));
+    values = new ArrayList<ByteString>();
+    values.add(ByteString.valueOf("foo"));
     attrs.add(new LDAPAttribute("description;lang-en-us", values));
 
     InternalClientConnection conn =
          InternalClientConnection.getRootConnection();
 
     AddOperation addOperation =
-         conn.processAdd(new ASN1OctetString("ou=People,o=test"),
+         conn.processAdd(ByteString.valueOf("ou=People,o=test"),
                          attrs);
     assertEquals(addOperation.getResultCode(), ResultCode.SUCCESS);
   }
@@ -1143,21 +1127,21 @@
 
     ArrayList<RawAttribute> attrs = new ArrayList<RawAttribute>();
 
-    ArrayList<ASN1OctetString> values = new ArrayList<ASN1OctetString>();
-    values.add(new ASN1OctetString("top"));
-    values.add(new ASN1OctetString("ds-root-dse"));
-    values.add(new ASN1OctetString("extensibleObject"));
+    ArrayList<ByteString> values = new ArrayList<ByteString>();
+    values.add(ByteString.valueOf("top"));
+    values.add(ByteString.valueOf("ds-root-dse"));
+    values.add(ByteString.valueOf("extensibleObject"));
     attrs.add(new LDAPAttribute("objectClass", values));
 
-    values = new ArrayList<ASN1OctetString>();
-    values.add(new ASN1OctetString("Root DSE"));
+    values = new ArrayList<ByteString>();
+    values.add(ByteString.valueOf("Root DSE"));
     attrs.add(new LDAPAttribute("cn", values));
 
     InternalClientConnection conn =
          InternalClientConnection.getRootConnection();
 
     AddOperation addOperation =
-         conn.processAdd(new ASN1OctetString(), attrs);
+         conn.processAdd(ByteString.empty(), attrs);
     assertFalse(addOperation.getResultCode() == ResultCode.SUCCESS);
   }
 
@@ -1269,7 +1253,7 @@
     {
       for (AttributeValue v : a)
       {
-        if (v.getStringValue().equalsIgnoreCase("top"))
+        if (v.getValue().toString().equalsIgnoreCase("top"))
         {
           found = true;
           break;
@@ -1678,30 +1662,30 @@
     TestCaseUtils.initializeTestBackend(true);
 
     Socket s = new Socket("127.0.0.1", TestCaseUtils.getServerLdapPort());
-    ASN1Reader r = new ASN1Reader(s);
-    ASN1Writer w = new ASN1Writer(s);
-    r.setIOTimeout(3000);
+    LDAPReader r = new LDAPReader(s);
+    LDAPWriter w = new LDAPWriter(s);
+    s.setSoTimeout(3000);
 
     BindRequestProtocolOp bindRequest =
-         new BindRequestProtocolOp(new ASN1OctetString("cn=Directory Manager"),
-                                   3, new ASN1OctetString("password"));
+         new BindRequestProtocolOp(ByteString.valueOf("cn=Directory Manager"),
+                                   3, ByteString.valueOf("password"));
     LDAPMessage message = new LDAPMessage(1, bindRequest);
-    w.writeElement(message.encode());
+    w.writeMessage(message);
 
-    message = LDAPMessage.decode(r.readElement().decodeAsSequence());
+    message = r.readMessage();
     BindResponseProtocolOp bindResponse =
          message.getBindResponseProtocolOp();
     assertEquals(bindResponse.getResultCode(), 0);
 
 
     ArrayList<RawAttribute> attrs = new ArrayList<RawAttribute>();
-    ArrayList<ASN1OctetString> values = new ArrayList<ASN1OctetString>();
-    values.add(new ASN1OctetString("top"));
-    values.add(new ASN1OctetString("organizationalUnit"));
+    ArrayList<ByteString> values = new ArrayList<ByteString>();
+    values.add(ByteString.valueOf("top"));
+    values.add(ByteString.valueOf("organizationalUnit"));
     attrs.add(new LDAPAttribute("objectClass", values));
 
-    values = new ArrayList<ASN1OctetString>();
-    values.add(new ASN1OctetString("People"));
+    values = new ArrayList<ByteString>();
+    values.add(ByteString.valueOf("People"));
     attrs.add(new LDAPAttribute("ou", values));
 
     DirectoryServer.setWritabilityMode(WritabilityMode.INTERNAL_ONLY);
@@ -1710,12 +1694,12 @@
     long addResponses = ldapStatistics.getAddResponses();
 
     AddRequestProtocolOp addRequest =
-         new AddRequestProtocolOp(new ASN1OctetString("ou=People,o=test"),
+         new AddRequestProtocolOp(ByteString.valueOf("ou=People,o=test"),
                                   attrs);
     message = new LDAPMessage(2, addRequest);
-    w.writeElement(message.encode());
+    w.writeMessage(message);
 
-    message = LDAPMessage.decode(r.readElement().decodeAsSequence());
+    message = r.readMessage();
     AddResponseProtocolOp addResponse =
          message.getAddResponseProtocolOp();
     assertFalse(addResponse.getResultCode() == 0);
@@ -1829,30 +1813,30 @@
     TestCaseUtils.initializeTestBackend(true);
 
     Socket s = new Socket("127.0.0.1", TestCaseUtils.getServerLdapPort());
-    ASN1Reader r = new ASN1Reader(s);
-    ASN1Writer w = new ASN1Writer(s);
-    r.setIOTimeout(3000);
+    LDAPReader r = new LDAPReader(s);
+    LDAPWriter w = new LDAPWriter(s);
+    s.setSoTimeout(3000);
 
     BindRequestProtocolOp bindRequest =
-         new BindRequestProtocolOp(new ASN1OctetString("cn=Directory Manager"),
-                                   3, new ASN1OctetString("password"));
+         new BindRequestProtocolOp(ByteString.valueOf("cn=Directory Manager"),
+                                   3, ByteString.valueOf("password"));
     LDAPMessage message = new LDAPMessage(1, bindRequest);
-    w.writeElement(message.encode());
+    w.writeMessage(message);
 
-    message = LDAPMessage.decode(r.readElement().decodeAsSequence());
+    message = r.readMessage();
     BindResponseProtocolOp bindResponse =
          message.getBindResponseProtocolOp();
     assertEquals(bindResponse.getResultCode(), 0);
 
 
     ArrayList<RawAttribute> attrs = new ArrayList<RawAttribute>();
-    ArrayList<ASN1OctetString> values = new ArrayList<ASN1OctetString>();
-    values.add(new ASN1OctetString("top"));
-    values.add(new ASN1OctetString("organizationalUnit"));
+    ArrayList<ByteString> values = new ArrayList<ByteString>();
+    values.add(ByteString.valueOf("top"));
+    values.add(ByteString.valueOf("organizationalUnit"));
     attrs.add(new LDAPAttribute("objectClass", values));
 
-    values = new ArrayList<ASN1OctetString>();
-    values.add(new ASN1OctetString("People"));
+    values = new ArrayList<ByteString>();
+    values.add(ByteString.valueOf("People"));
     attrs.add(new LDAPAttribute("ou", values));
 
     Backend b = DirectoryServer.getBackend(DN.decode("o=test"));
@@ -1862,12 +1846,12 @@
     long addResponses = ldapStatistics.getAddResponses();
 
     AddRequestProtocolOp addRequest =
-         new AddRequestProtocolOp(new ASN1OctetString("ou=People,o=test"),
+         new AddRequestProtocolOp(ByteString.valueOf("ou=People,o=test"),
                                   attrs);
     message = new LDAPMessage(2, addRequest);
-    w.writeElement(message.encode());
+    w.writeMessage(message);
 
-    message = LDAPMessage.decode(r.readElement().decodeAsSequence());
+    message = r.readMessage();
     AddResponseProtocolOp addResponse =
          message.getAddResponseProtocolOp();
     assertFalse(addResponse.getResultCode() == 0);
@@ -2084,45 +2068,44 @@
     TestCaseUtils.initializeTestBackend(true);
 
     Socket s = new Socket("127.0.0.1", TestCaseUtils.getServerLdapPort());
-    ASN1Reader r = new ASN1Reader(s);
-    ASN1Writer w = new ASN1Writer(s);
-    r.setIOTimeout(5000);
+    LDAPReader r = new LDAPReader(s);
+    LDAPWriter w = new LDAPWriter(s);
+    s.setSoTimeout(5000);
 
     BindRequestProtocolOp bindRequest =
-         new BindRequestProtocolOp(new ASN1OctetString("cn=Directory Manager"),
-                                   3, new ASN1OctetString("password"));
+         new BindRequestProtocolOp(ByteString.valueOf("cn=Directory Manager"),
+                                   3, ByteString.valueOf("password"));
     LDAPMessage message = new LDAPMessage(1, bindRequest);
-    w.writeElement(message.encode());
+    w.writeMessage(message);
 
-    message = LDAPMessage.decode(r.readElement().decodeAsSequence());
+    message = r.readMessage();
     BindResponseProtocolOp bindResponse =
          message.getBindResponseProtocolOp();
     assertEquals(bindResponse.getResultCode(), 0);
 
 
     ArrayList<RawAttribute> attrs = new ArrayList<RawAttribute>();
-    ArrayList<ASN1OctetString> values = new ArrayList<ASN1OctetString>();
-    values.add(new ASN1OctetString("top"));
-    values.add(new ASN1OctetString("organizationalUnit"));
+    ArrayList<ByteString> values = new ArrayList<ByteString>();
+    values.add(ByteString.valueOf("top"));
+    values.add(ByteString.valueOf("organizationalUnit"));
     attrs.add(new LDAPAttribute("objectClass", values));
 
-    values = new ArrayList<ASN1OctetString>();
-    values.add(new ASN1OctetString("People"));
+    values = new ArrayList<ByteString>();
+    values.add(ByteString.valueOf("People"));
     attrs.add(new LDAPAttribute("ou", values));
 
     AddRequestProtocolOp addRequest =
-         new AddRequestProtocolOp(new ASN1OctetString("ou=People,o=test"),
+         new AddRequestProtocolOp(ByteString.valueOf("ou=People,o=test"),
                                   attrs);
     message = new LDAPMessage(2, addRequest,
-         DisconnectClientPlugin.createDisconnectLDAPControlList("PreParse"));
-    w.writeElement(message.encode());
+         DisconnectClientPlugin.createDisconnectControlList("PreParse"));
+    w.writeMessage(message);
 
-    ASN1Element element = r.readElement();
-    if (element != null)
+    message = r.readMessage();
+    if (message != null)
     {
       // If we got an element back, then it must be a notice of disconnect
       // unsolicited notification.
-      message = LDAPMessage.decode(element.decodeAsSequence());
       assertEquals(message.getProtocolOpType(), OP_TYPE_EXTENDED_RESPONSE);
     }
 
@@ -2147,46 +2130,45 @@
     TestCaseUtils.initializeTestBackend(true);
 
     Socket s = new Socket("127.0.0.1", TestCaseUtils.getServerLdapPort());
-    ASN1Reader r = new ASN1Reader(s);
-    ASN1Writer w = new ASN1Writer(s);
-    r.setIOTimeout(5000);
+    LDAPReader r = new LDAPReader(s);
+    LDAPWriter w = new LDAPWriter(s);
+    s.setSoTimeout(5000);
 
     BindRequestProtocolOp bindRequest =
-         new BindRequestProtocolOp(new ASN1OctetString("cn=Directory Manager"),
-                                   3, new ASN1OctetString("password"));
+         new BindRequestProtocolOp(ByteString.valueOf("cn=Directory Manager"),
+                                   3, ByteString.valueOf("password"));
     LDAPMessage message = new LDAPMessage(1, bindRequest);
-    w.writeElement(message.encode());
+    w.writeMessage(message);
 
-    message = LDAPMessage.decode(r.readElement().decodeAsSequence());
+    message = r.readMessage();
     BindResponseProtocolOp bindResponse =
          message.getBindResponseProtocolOp();
     assertEquals(bindResponse.getResultCode(), 0);
 
 
     ArrayList<RawAttribute> attrs = new ArrayList<RawAttribute>();
-    ArrayList<ASN1OctetString> values = new ArrayList<ASN1OctetString>();
-    values.add(new ASN1OctetString("top"));
-    values.add(new ASN1OctetString("organizationalUnit"));
+    ArrayList<ByteString> values = new ArrayList<ByteString>();
+    values.add(ByteString.valueOf("top"));
+    values.add(ByteString.valueOf("organizationalUnit"));
     attrs.add(new LDAPAttribute("objectClass", values));
 
-    values = new ArrayList<ASN1OctetString>();
-    values.add(new ASN1OctetString("People"));
+    values = new ArrayList<ByteString>();
+    values.add(ByteString.valueOf("People"));
     attrs.add(new LDAPAttribute("ou", values));
 
     AddRequestProtocolOp addRequest =
-         new AddRequestProtocolOp(new ASN1OctetString("ou=People,o=test"),
+         new AddRequestProtocolOp(ByteString.valueOf("ou=People,o=test"),
                                   attrs);
     message = new LDAPMessage(2, addRequest,
-         DisconnectClientPlugin.createDisconnectLDAPControlList(
+         DisconnectClientPlugin.createDisconnectControlList(
               "PreOperation"));
-    w.writeElement(message.encode());
+    w.writeMessage(message);
 
-    ASN1Element element = r.readElement();
-    if (element != null)
+    message = r.readMessage();
+    if (message != null)
     {
       // If we got an element back, then it must be a notice of disconnect
       // unsolicited notification.
-      message = LDAPMessage.decode(element.decodeAsSequence());
       assertEquals(message.getProtocolOpType(), OP_TYPE_EXTENDED_RESPONSE);
     }
 
@@ -2211,46 +2193,45 @@
     TestCaseUtils.initializeTestBackend(true);
 
     Socket s = new Socket("127.0.0.1", TestCaseUtils.getServerLdapPort());
-    ASN1Reader r = new ASN1Reader(s);
-    ASN1Writer w = new ASN1Writer(s);
-    r.setIOTimeout(5000);
+    LDAPReader r = new LDAPReader(s);
+    LDAPWriter w = new LDAPWriter(s);
+    s.setSoTimeout(5000);
 
     BindRequestProtocolOp bindRequest =
-         new BindRequestProtocolOp(new ASN1OctetString("cn=Directory Manager"),
-                                   3, new ASN1OctetString("password"));
+         new BindRequestProtocolOp(ByteString.valueOf("cn=Directory Manager"),
+                                   3, ByteString.valueOf("password"));
     LDAPMessage message = new LDAPMessage(1, bindRequest);
-    w.writeElement(message.encode());
+    w.writeMessage(message);
 
-    message = LDAPMessage.decode(r.readElement().decodeAsSequence());
+    message = r.readMessage();
     BindResponseProtocolOp bindResponse =
          message.getBindResponseProtocolOp();
     assertEquals(bindResponse.getResultCode(), 0);
 
 
     ArrayList<RawAttribute> attrs = new ArrayList<RawAttribute>();
-    ArrayList<ASN1OctetString> values = new ArrayList<ASN1OctetString>();
-    values.add(new ASN1OctetString("top"));
-    values.add(new ASN1OctetString("organizationalUnit"));
+    ArrayList<ByteString> values = new ArrayList<ByteString>();
+    values.add(ByteString.valueOf("top"));
+    values.add(ByteString.valueOf("organizationalUnit"));
     attrs.add(new LDAPAttribute("objectClass", values));
 
-    values = new ArrayList<ASN1OctetString>();
-    values.add(new ASN1OctetString("People"));
+    values = new ArrayList<ByteString>();
+    values.add(ByteString.valueOf("People"));
     attrs.add(new LDAPAttribute("ou", values));
 
     AddRequestProtocolOp addRequest =
-         new AddRequestProtocolOp(new ASN1OctetString("ou=People,o=test"),
+         new AddRequestProtocolOp(ByteString.valueOf("ou=People,o=test"),
                                   attrs);
     message = new LDAPMessage(2, addRequest,
-         DisconnectClientPlugin.createDisconnectLDAPControlList(
+         DisconnectClientPlugin.createDisconnectControlList(
               "PostOperation"));
-    w.writeElement(message.encode());
+    w.writeMessage(message);
 
-    ASN1Element element = r.readElement();
-    if (element != null)
+    message = r.readMessage();
+    if (message != null)
     {
       // If we got an element back, then it must be a notice of disconnect
       // unsolicited notification.
-      message = LDAPMessage.decode(element.decodeAsSequence());
       assertEquals(message.getProtocolOpType(), OP_TYPE_EXTENDED_RESPONSE);
     }
 
@@ -2275,51 +2256,50 @@
     TestCaseUtils.initializeTestBackend(true);
 
     Socket s = new Socket("127.0.0.1", TestCaseUtils.getServerLdapPort());
-    ASN1Reader r = new ASN1Reader(s);
-    ASN1Writer w = new ASN1Writer(s);
-    r.setIOTimeout(5000);
+    LDAPReader r = new LDAPReader(s);
+    LDAPWriter w = new LDAPWriter(s);
+    //s.setSoTimeout(5000);
 
     BindRequestProtocolOp bindRequest =
-         new BindRequestProtocolOp(new ASN1OctetString("cn=Directory Manager"),
-                                   3, new ASN1OctetString("password"));
+         new BindRequestProtocolOp(ByteString.valueOf("cn=Directory Manager"),
+                                   3, ByteString.valueOf("password"));
     LDAPMessage message = new LDAPMessage(1, bindRequest);
-    w.writeElement(message.encode());
+    w.writeMessage(message);
 
-    message = LDAPMessage.decode(r.readElement().decodeAsSequence());
+    message = r.readMessage();
     BindResponseProtocolOp bindResponse =
          message.getBindResponseProtocolOp();
     assertEquals(bindResponse.getResultCode(), 0);
 
 
     ArrayList<RawAttribute> attrs = new ArrayList<RawAttribute>();
-    ArrayList<ASN1OctetString> values = new ArrayList<ASN1OctetString>();
-    values.add(new ASN1OctetString("top"));
-    values.add(new ASN1OctetString("organizationalUnit"));
+    ArrayList<ByteString> values = new ArrayList<ByteString>();
+    values.add(ByteString.valueOf("top"));
+    values.add(ByteString.valueOf("organizationalUnit"));
     attrs.add(new LDAPAttribute("objectClass", values));
 
-    values = new ArrayList<ASN1OctetString>();
-    values.add(new ASN1OctetString("People"));
+    values = new ArrayList<ByteString>();
+    values.add(ByteString.valueOf("People"));
     attrs.add(new LDAPAttribute("ou", values));
 
     AddRequestProtocolOp addRequest =
-         new AddRequestProtocolOp(new ASN1OctetString("ou=People,o=test"),
+         new AddRequestProtocolOp(ByteString.valueOf("ou=People,o=test"),
                                   attrs);
     message = new LDAPMessage(2, addRequest,
-         DisconnectClientPlugin.createDisconnectLDAPControlList(
+         DisconnectClientPlugin.createDisconnectControlList(
               "PostResponse"));
-    w.writeElement(message.encode());
+    w.writeMessage(message);
 
 responseLoop:
     while (true)
     {
-      ASN1Element element = r.readElement();
-      if (element == null)
+      message = r.readMessage();
+      if (message == null)
       {
         // The connection has been closed.
         break responseLoop;
       }
 
-      message = LDAPMessage.decode(element.decodeAsSequence());
       switch (message.getProtocolOpType())
       {
         case OP_TYPE_ADD_RESPONSE:
@@ -2544,8 +2524,8 @@
          ShortCircuitPlugin.createShortCircuitControlList(0, "PreParse");
 
     ArrayList<ByteString> ocValues = new ArrayList<ByteString>();
-    ocValues.add(new ASN1OctetString("top"));
-    ocValues.add(new ASN1OctetString("organization"));
+    ocValues.add(ByteString.valueOf("top"));
+    ocValues.add(ByteString.valueOf("organization"));
 
     ArrayList<RawAttribute> rawAttrs = new ArrayList<RawAttribute>();
     rawAttrs.add(RawAttribute.create("objectClass", ocValues));
@@ -2553,7 +2533,7 @@
 
     AddOperationBasis addOperation =
          new AddOperationBasis(conn, conn.nextOperationID(), conn.nextMessageID(),
-                          controls, new ASN1OctetString("o=test"), rawAttrs);
+                          controls, ByteString.valueOf("o=test"), rawAttrs);
     addOperation.run();
     assertEquals(addOperation.getResultCode(), ResultCode.SUCCESS);
     assertFalse(DirectoryServer.entryExists(DN.decode("o=test")));
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/core/BindOperationTestCase.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/core/BindOperationTestCase.java
index 799dfba..b679ea9 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/core/BindOperationTestCase.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/core/BindOperationTestCase.java
@@ -39,16 +39,13 @@
 import org.opends.server.plugins.DisconnectClientPlugin;
 import org.opends.server.plugins.InvocationCounterPlugin;
 import org.opends.server.plugins.ShortCircuitPlugin;
-import org.opends.server.protocols.asn1.ASN1Element;
-import org.opends.server.protocols.asn1.ASN1OctetString;
 import org.opends.server.protocols.asn1.ASN1Reader;
 import org.opends.server.protocols.asn1.ASN1Writer;
 import org.opends.server.protocols.internal.InternalClientConnection;
-import org.opends.server.protocols.ldap.BindRequestProtocolOp;
-import org.opends.server.protocols.ldap.BindResponseProtocolOp;
-import org.opends.server.protocols.ldap.LDAPMessage;
-import org.opends.server.protocols.ldap.LDAPResultCode;
+import org.opends.server.protocols.ldap.*;
 import org.opends.server.tools.LDAPSearch;
+import org.opends.server.tools.LDAPReader;
+import org.opends.server.tools.LDAPWriter;
 import org.opends.server.types.*;
 
 import static org.testng.Assert.*;
@@ -77,41 +74,41 @@
     InternalClientConnection conn =
          InternalClientConnection.getRootConnection();
     ArrayList<Control> noControls = new ArrayList<Control>(0);
-    ASN1OctetString nullOS = null;
+    ByteString nullOS = null;
     DN nullDN = null;
 
     BindOperation[] simpleBinds = new BindOperation[]
     {
       new BindOperationBasis(conn, conn.nextOperationID(), conn.nextMessageID(),
-                        null, "3", new ASN1OctetString(),
-                        new ASN1OctetString()),
+                        null, "3", ByteString.empty(),
+                        ByteString.empty()),
       new BindOperationBasis(conn, conn.nextOperationID(), conn.nextMessageID(),
-                        noControls, "3", new ASN1OctetString(),
-                        new ASN1OctetString()),
+                        noControls, "3", ByteString.empty(),
+                        ByteString.empty()),
       new BindOperationBasis(conn, conn.nextOperationID(), conn.nextMessageID(),
-                        null, "3", nullOS, new ASN1OctetString()),
+                        null, "3", nullOS, ByteString.empty()),
       new BindOperationBasis(conn, conn.nextOperationID(), conn.nextMessageID(),
-                        noControls, "3", nullOS, new ASN1OctetString()),
+                        noControls, "3", nullOS, ByteString.empty()),
       new BindOperationBasis(conn, conn.nextOperationID(), conn.nextMessageID(),
-                        null, "3", new ASN1OctetString(), nullOS),
+                        null, "3", ByteString.empty(), nullOS),
       new BindOperationBasis(conn, conn.nextOperationID(), conn.nextMessageID(),
-                        noControls, "3", new ASN1OctetString(), nullOS),
+                        noControls, "3", ByteString.empty(), nullOS),
       new BindOperationBasis(conn, conn.nextOperationID(), conn.nextMessageID(),
                         null, "3", nullOS, nullOS),
       new BindOperationBasis(conn, conn.nextOperationID(), conn.nextMessageID(),
                         noControls, "3", nullOS, nullOS),
       new BindOperationBasis(conn, conn.nextOperationID(), conn.nextMessageID(),
                         noControls, "3",
-                        new ASN1OctetString("cn=Directory Manager"),
-                        new ASN1OctetString("password")),
+                        ByteString.valueOf("cn=Directory Manager"),
+                        ByteString.valueOf("password")),
       new BindOperationBasis(conn, conn.nextOperationID(), conn.nextMessageID(),
-                        null, "3", DN.nullDN(), new ASN1OctetString()),
+                        null, "3", DN.nullDN(), ByteString.empty()),
       new BindOperationBasis(conn, conn.nextOperationID(), conn.nextMessageID(),
-                        noControls, "3", DN.nullDN(), new ASN1OctetString()),
+                        noControls, "3", DN.nullDN(), ByteString.empty()),
       new BindOperationBasis(conn, conn.nextOperationID(), conn.nextMessageID(),
-                        null, "3", nullDN, new ASN1OctetString()),
+                        null, "3", nullDN, ByteString.empty()),
       new BindOperationBasis(conn, conn.nextOperationID(), conn.nextMessageID(),
-                        noControls, "3", nullDN, new ASN1OctetString()),
+                        noControls, "3", nullDN, ByteString.empty()),
       new BindOperationBasis(conn, conn.nextOperationID(), conn.nextMessageID(),
                         null, "3", DN.nullDN(), nullOS),
       new BindOperationBasis(conn, conn.nextOperationID(), conn.nextMessageID(),
@@ -122,7 +119,7 @@
                         noControls, "3", nullDN, nullOS),
       new BindOperationBasis(conn, conn.nextOperationID(), conn.nextMessageID(),
                         noControls, "3", DN.decode("cn=Directory Manager"),
-                        new ASN1OctetString("password"))
+                        ByteString.valueOf("password"))
     };
 
     Object[][] array = new Object[simpleBinds.length][1];
@@ -150,32 +147,32 @@
     InternalClientConnection conn =
          InternalClientConnection.getRootConnection();
     ArrayList<Control> noControls = new ArrayList<Control>(0);
-    ASN1OctetString nullOS = null;
+    ByteString nullOS = null;
     DN nullDN = null;
 
     BindOperation[] saslBinds = new BindOperation[]
     {
       new BindOperationBasis(conn, conn.nextOperationID(), conn.nextMessageID(),
-                        null, "3", new ASN1OctetString(), "EXTERNAL", null),
+                        null, "3", ByteString.empty(), "EXTERNAL", null),
       new BindOperationBasis(conn, conn.nextOperationID(), conn.nextMessageID(),
-                        noControls, "3", new ASN1OctetString(), "EXTERNAL",
+                        noControls, "3", ByteString.empty(), "EXTERNAL",
                         null),
       new BindOperationBasis(conn, conn.nextOperationID(), conn.nextMessageID(),
                         null, "3", nullOS, "EXTERNAL", null),
       new BindOperationBasis(conn, conn.nextOperationID(), conn.nextMessageID(),
                         noControls, "3", nullOS, "EXTERNAL", null),
       new BindOperationBasis(conn, conn.nextOperationID(), conn.nextMessageID(),
-                        null, "3", new ASN1OctetString(), "PLAIN",
-                        new ASN1OctetString("\u0000u:test.user\u0000password")),
+                        null, "3", ByteString.empty(), "PLAIN",
+                        ByteString.valueOf("\u0000u:test.user\u0000password")),
       new BindOperationBasis(conn, conn.nextOperationID(), conn.nextMessageID(),
-                        noControls, "3", new ASN1OctetString(), "PLAIN",
-                        new ASN1OctetString("\u0000u:test.user\u0000password")),
+                        noControls, "3", ByteString.empty(), "PLAIN",
+                        ByteString.valueOf("\u0000u:test.user\u0000password")),
       new BindOperationBasis(conn, conn.nextOperationID(), conn.nextMessageID(),
                         null, "3", nullOS, "PLAIN",
-                        new ASN1OctetString("\u0000u:test.user\u0000password")),
+                        ByteString.valueOf("\u0000u:test.user\u0000password")),
       new BindOperationBasis(conn, conn.nextOperationID(), conn.nextMessageID(),
                         noControls, "3", nullOS, "PLAIN",
-                        new ASN1OctetString("\u0000u:test.user\u0000password")),
+                        ByteString.valueOf("\u0000u:test.user\u0000password")),
       new BindOperationBasis(conn, conn.nextOperationID(), conn.nextMessageID(),
                         null, "3", DN.nullDN(), "EXTERNAL", null),
       new BindOperationBasis(conn, conn.nextOperationID(), conn.nextMessageID(),
@@ -186,16 +183,16 @@
                         noControls, "3", nullDN, "EXTERNAL", null),
       new BindOperationBasis(conn, conn.nextOperationID(), conn.nextMessageID(),
                         null, "3", DN.nullDN(), "PLAIN",
-                        new ASN1OctetString("\u0000u:test.user\u0000password")),
+                        ByteString.valueOf("\u0000u:test.user\u0000password")),
       new BindOperationBasis(conn, conn.nextOperationID(), conn.nextMessageID(),
                         noControls, "3", DN.nullDN(), "PLAIN",
-                        new ASN1OctetString("\u0000u:test.user\u0000password")),
+                        ByteString.valueOf("\u0000u:test.user\u0000password")),
       new BindOperationBasis(conn, conn.nextOperationID(), conn.nextMessageID(),
                         null, "3", nullDN, "PLAIN",
-                        new ASN1OctetString("\u0000u:test.user\u0000password")),
+                        ByteString.valueOf("\u0000u:test.user\u0000password")),
       new BindOperationBasis(conn, conn.nextOperationID(), conn.nextMessageID(),
                         noControls, "3", nullDN, "PLAIN",
-                        new ASN1OctetString("\u0000u:test.user\u0000password"))
+                        ByteString.valueOf("\u0000u:test.user\u0000password"))
     };
 
     Object[][] array = new Object[saslBinds.length][1];
@@ -332,13 +329,13 @@
     assertNotNull(originalRawBindDN);
 
     o.setRawBindDN(null);
-    assertEquals(o.getRawBindDN(), new ASN1OctetString());
+    assertEquals(o.getRawBindDN(), ByteString.empty());
 
-    o.setRawBindDN(new ASN1OctetString());
-    assertEquals(o.getRawBindDN(), new ASN1OctetString());
+    o.setRawBindDN(ByteString.empty());
+    assertEquals(o.getRawBindDN(), ByteString.empty());
 
-    o.setRawBindDN(new ASN1OctetString("cn=Directory Manager"));
-    assertEquals(o.getRawBindDN(), new ASN1OctetString("cn=Directory Manager"));
+    o.setRawBindDN(ByteString.valueOf("cn=Directory Manager"));
+    assertEquals(o.getRawBindDN(), ByteString.valueOf("cn=Directory Manager"));
 
     o.setRawBindDN(originalRawBindDN);
     assertEquals(o.getRawBindDN(), originalRawBindDN);
@@ -358,13 +355,13 @@
     assertNotNull(originalRawBindDN);
 
     o.setRawBindDN(null);
-    assertEquals(o.getRawBindDN(), new ASN1OctetString());
+    assertEquals(o.getRawBindDN(), ByteString.empty());
 
-    o.setRawBindDN(new ASN1OctetString());
-    assertEquals(o.getRawBindDN(), new ASN1OctetString());
+    o.setRawBindDN(ByteString.empty());
+    assertEquals(o.getRawBindDN(), ByteString.empty());
 
-    o.setRawBindDN(new ASN1OctetString("cn=Directory Manager"));
-    assertEquals(o.getRawBindDN(), new ASN1OctetString("cn=Directory Manager"));
+    o.setRawBindDN(ByteString.valueOf("cn=Directory Manager"));
+    assertEquals(o.getRawBindDN(), ByteString.valueOf("cn=Directory Manager"));
 
     o.setRawBindDN(originalRawBindDN);
     assertEquals(o.getRawBindDN(), originalRawBindDN);
@@ -502,7 +499,7 @@
     assertNull(o.getSASLCredentials());
 
     o.setSASLCredentials("PLAIN",
-         new ASN1OctetString("\u0000u:test.user\u0000password"));
+         ByteString.valueOf("\u0000u:test.user\u0000password"));
     assertEquals(o.getAuthenticationType(), AuthenticationType.SASL);
     assertNotNull(o.getSASLMechanism());
     assertNotNull(o.getSASLCredentials());
@@ -528,7 +525,7 @@
     assertNull(o.getSimplePassword());
 
     String          originalMech  = o.getSASLMechanism();
-    ASN1OctetString originalCreds = o.getSASLCredentials();
+    ByteString originalCreds = o.getSASLCredentials();
     assertNotNull(originalMech);
 
     o.setSimplePassword(null);
@@ -539,7 +536,7 @@
     assertEquals(o.getAuthenticationType(), AuthenticationType.SASL);
     assertNull(o.getSimplePassword());
 
-    o.setSimplePassword(new ASN1OctetString());
+    o.setSimplePassword(ByteString.empty());
     assertEquals(o.getAuthenticationType(), AuthenticationType.SIMPLE);
     assertNotNull(o.getSimplePassword());
 
@@ -547,7 +544,7 @@
     assertEquals(o.getAuthenticationType(), AuthenticationType.SASL);
     assertNull(o.getSimplePassword());
 
-    o.setSimplePassword(new ASN1OctetString("password"));
+    o.setSimplePassword(ByteString.valueOf("password"));
     assertEquals(o.getAuthenticationType(), AuthenticationType.SIMPLE);
     assertNotNull(o.getSimplePassword());
 
@@ -624,8 +621,8 @@
     InternalClientConnection conn =
          new InternalClientConnection(new AuthenticationInfo());
 
-    ASN1OctetString saslCreds =
-         new ASN1OctetString("\u0000dn:cn=Directory Manager\u0000password");
+    ByteString saslCreds =
+         ByteString.valueOf("\u0000dn:cn=Directory Manager\u0000password");
 
     BindOperation bindOperation =
                        conn.processSASLBind(DN.nullDN(), "PLAIN", saslCreds);
@@ -660,8 +657,8 @@
          new InternalClientConnection(new AuthenticationInfo());
 
     BindOperation bindOperation =
-         conn.processSimpleBind(new ASN1OctetString("cn=Directory Manager"),
-                                new ASN1OctetString("password"));
+         conn.processSimpleBind(ByteString.valueOf("cn=Directory Manager"),
+                                ByteString.valueOf("password"));
     assertEquals(bindOperation.getResultCode(), ResultCode.SUCCESS);
     assertNotNull(bindOperation.getUserEntryDN());
   }
@@ -692,8 +689,8 @@
     InternalClientConnection conn =
          new InternalClientConnection(new AuthenticationInfo());
 
-    ASN1OctetString saslCreds =
-         new ASN1OctetString("\u0000dn:cn=Directory Manager\u0000password");
+    ByteString saslCreds =
+         ByteString.valueOf("\u0000dn:cn=Directory Manager\u0000password");
 
     BindOperation bindOperation =
          conn.processSASLBind(DN.nullDN(), "PLAIN", saslCreds);
@@ -715,8 +712,8 @@
          new InternalClientConnection(new AuthenticationInfo());
 
     BindOperation bindOperation =
-         conn.processSimpleBind(new ASN1OctetString("cn=Directory Manager"),
-                                new ASN1OctetString("password"));
+         conn.processSimpleBind(ByteString.valueOf("cn=Directory Manager"),
+                                ByteString.valueOf("password"));
     assertEquals(bindOperation.getResultCode(), ResultCode.SUCCESS);
     assertTrue(bindOperation.getProcessingStartTime() > 0);
     assertTrue(bindOperation.getProcessingStopTime() >=
@@ -737,8 +734,8 @@
     InternalClientConnection conn =
          new InternalClientConnection(new AuthenticationInfo());
 
-    ASN1OctetString saslCreds =
-         new ASN1OctetString("\u0000dn:cn=Directory Manager\u0000password");
+    ByteString saslCreds =
+         ByteString.valueOf("\u0000dn:cn=Directory Manager\u0000password");
 
     BindOperation bindOperation =
          conn.processSASLBind(DN.nullDN(), "PLAIN", saslCreds);
@@ -790,8 +787,8 @@
          new InternalClientConnection(new AuthenticationInfo());
 
     BindOperation bindOperation =
-         conn.processSimpleBind(new ASN1OctetString("cn=Directory Manager"),
-                                new ASN1OctetString("password"));
+         conn.processSimpleBind(ByteString.valueOf("cn=Directory Manager"),
+                                ByteString.valueOf("password"));
     assertEquals(bindOperation.getResultCode(), ResultCode.SUCCESS);
     assertNotNull(bindOperation.getResponseLogElements());
     assertTrue(bindOperation.getResponseLogElements().length > 0);
@@ -809,8 +806,8 @@
     InternalClientConnection conn =
          new InternalClientConnection(new AuthenticationInfo());
 
-    ASN1OctetString saslCreds =
-         new ASN1OctetString("\u0000dn:cn=Directory Manager\u0000password");
+    ByteString saslCreds =
+         ByteString.valueOf("\u0000dn:cn=Directory Manager\u0000password");
 
     BindOperation bindOperation =
          conn.processSASLBind(DN.nullDN(), "PLAIN", saslCreds);
@@ -837,8 +834,8 @@
          new InternalClientConnection(new AuthenticationInfo());
 
     BindOperation bindOperation =
-         conn.processSimpleBind(new ASN1OctetString("uid=test,o=test"),
-                                new ASN1OctetString("password"));
+         conn.processSimpleBind(ByteString.valueOf("uid=test,o=test"),
+                                ByteString.valueOf("password"));
     assertEquals(bindOperation.getResultCode(), ResultCode.INVALID_CREDENTIALS);
     assertNotNull(bindOperation.getResponseLogElements());
     assertTrue(bindOperation.getResponseLogElements().length > 0);
@@ -859,8 +856,8 @@
          new InternalClientConnection(new AuthenticationInfo());
 
     BindOperation bindOperation =
-         conn.processSimpleBind(new ASN1OctetString("cn=Directory Manager"),
-                                new ASN1OctetString("password"));
+         conn.processSimpleBind(ByteString.valueOf("cn=Directory Manager"),
+                                ByteString.valueOf("password"));
     assertEquals(bindOperation.getResultCode(), ResultCode.SUCCESS);
 
 //    assertTrue(InvocationCounterPlugin.getPreParseCount() > 0);
@@ -884,8 +881,8 @@
     InternalClientConnection conn =
          new InternalClientConnection(new AuthenticationInfo());
 
-    ASN1OctetString saslCreds =
-         new ASN1OctetString("\u0000dn:cn=Directory Manager\u0000password");
+    ByteString saslCreds =
+         ByteString.valueOf("\u0000dn:cn=Directory Manager\u0000password");
 
     BindOperation bindOperation =
          conn.processSASLBind(DN.nullDN(), "PLAIN", saslCreds);
@@ -911,23 +908,22 @@
          throws Exception
   {
     Socket s = new Socket("127.0.0.1", TestCaseUtils.getServerLdapPort());
-    ASN1Reader r = new ASN1Reader(s);
-    ASN1Writer w = new ASN1Writer(s);
-    r.setIOTimeout(6000);
+    LDAPReader r = new LDAPReader(s);
+    LDAPWriter w = new LDAPWriter(s);
+    s.setSoTimeout(6000);
 
     BindRequestProtocolOp bindRequest =
-         new BindRequestProtocolOp(new ASN1OctetString(), 3,
-                                   new ASN1OctetString());
+         new BindRequestProtocolOp(ByteString.empty(), 3,
+                                   ByteString.empty());
     LDAPMessage message = new LDAPMessage(1, bindRequest,
-         DisconnectClientPlugin.createDisconnectLDAPControlList("PreParse"));
-    w.writeElement(message.encode());
+         DisconnectClientPlugin.createDisconnectControlList("PreParse"));
+    w.writeMessage(message);
 
-    ASN1Element element = r.readElement();
-    if (element != null)
+    message = r.readMessage();
+    if (message != null)
     {
       // If we got an element back, then it must be a notice of disconnect
       // unsolicited notification.
-      message = LDAPMessage.decode(element.decodeAsSequence());
       assertEquals(message.getProtocolOpType(), OP_TYPE_EXTENDED_RESPONSE);
     }
 
@@ -951,24 +947,23 @@
          throws Exception
   {
     Socket s = new Socket("127.0.0.1", TestCaseUtils.getServerLdapPort());
-    ASN1Reader r = new ASN1Reader(s);
-    ASN1Writer w = new ASN1Writer(s);
-    r.setIOTimeout(6000);
+    LDAPReader r = new LDAPReader(s);
+    LDAPWriter w = new LDAPWriter(s);
+    s.setSoTimeout(6000);
 
     BindRequestProtocolOp bindRequest =
-         new BindRequestProtocolOp(new ASN1OctetString(), 3,
-                                   new ASN1OctetString());
+         new BindRequestProtocolOp(ByteString.empty(), 3,
+                                   ByteString.empty());
     LDAPMessage message = new LDAPMessage(1, bindRequest,
-         DisconnectClientPlugin.createDisconnectLDAPControlList(
+         DisconnectClientPlugin.createDisconnectControlList(
               "PreOperation"));
-    w.writeElement(message.encode());
+    w.writeMessage(message);
 
-    ASN1Element element = r.readElement();
-    if (element != null)
+    message = r.readMessage();
+    if (message != null)
     {
       // If we got an element back, then it must be a notice of disconnect
       // unsolicited notification.
-      message = LDAPMessage.decode(element.decodeAsSequence());
       assertEquals(message.getProtocolOpType(), OP_TYPE_EXTENDED_RESPONSE);
     }
 
@@ -992,24 +987,23 @@
          throws Exception
   {
     Socket s = new Socket("127.0.0.1", TestCaseUtils.getServerLdapPort());
-    ASN1Reader r = new ASN1Reader(s);
-    ASN1Writer w = new ASN1Writer(s);
-    r.setIOTimeout(6000);
+    LDAPReader r = new LDAPReader(s);
+    LDAPWriter w = new LDAPWriter(s);
+    s.setSoTimeout(6000);
 
     BindRequestProtocolOp bindRequest =
-         new BindRequestProtocolOp(new ASN1OctetString(), 3,
-                                   new ASN1OctetString());
+         new BindRequestProtocolOp(ByteString.empty(), 3,
+                                   ByteString.empty());
     LDAPMessage message = new LDAPMessage(1, bindRequest,
-         DisconnectClientPlugin.createDisconnectLDAPControlList(
+         DisconnectClientPlugin.createDisconnectControlList(
               "PostOperation"));
-    w.writeElement(message.encode());
+    w.writeMessage(message);
 
-    ASN1Element element = r.readElement();
-    if (element != null)
+    message = r.readMessage();
+    if (message != null)
     {
       // If we got an element back, then it must be a notice of disconnect
       // unsolicited notification.
-      message = LDAPMessage.decode(element.decodeAsSequence());
       assertEquals(message.getProtocolOpType(), OP_TYPE_EXTENDED_RESPONSE);
     }
 
@@ -1033,25 +1027,24 @@
          throws Exception
   {
     Socket s = new Socket("127.0.0.1", TestCaseUtils.getServerLdapPort());
-    ASN1Reader r = new ASN1Reader(s);
-    ASN1Writer w = new ASN1Writer(s);
-    r.setIOTimeout(6000);
+    LDAPReader r = new LDAPReader(s);
+    LDAPWriter w = new LDAPWriter(s);
+    s.setSoTimeout(6000);
 
     BindRequestProtocolOp bindRequest =
-         new BindRequestProtocolOp(new ASN1OctetString(), 3,
-                                   new ASN1OctetString());
+         new BindRequestProtocolOp(ByteString.empty(), 3,
+                                   ByteString.empty());
     LDAPMessage message = new LDAPMessage(1, bindRequest,
-         DisconnectClientPlugin.createDisconnectLDAPControlList(
+         DisconnectClientPlugin.createDisconnectControlList(
               "PostResponse"));
-    w.writeElement(message.encode());
+    w.writeMessage(message);
 
-    ASN1Element element = r.readElement();
-    while (element != null)
+    message = r.readMessage();
+    while (message != null)
     {
-      message = LDAPMessage.decode(element.decodeAsSequence());
       assertTrue((message.getProtocolOpType() == OP_TYPE_BIND_RESPONSE) ||
                  (message.getProtocolOpType() == OP_TYPE_EXTENDED_RESPONSE));
-      element = r.readElement();
+      message = r.readMessage();
     }
 
     try
@@ -1073,23 +1066,22 @@
          throws Exception
   {
     Socket s = new Socket("127.0.0.1", TestCaseUtils.getServerLdapPort());
-    ASN1Reader r = new ASN1Reader(s);
-    ASN1Writer w = new ASN1Writer(s);
-    r.setIOTimeout(6000);
+    LDAPReader r = new LDAPReader(s);
+    LDAPWriter w = new LDAPWriter(s);
+    s.setSoTimeout(6000);
 
     BindRequestProtocolOp bindRequest =
-         new BindRequestProtocolOp(new ASN1OctetString("cn=Directory Manager"),
-                                   3, new ASN1OctetString("password"));
+         new BindRequestProtocolOp(ByteString.valueOf("cn=Directory Manager"),
+                                   3, ByteString.valueOf("password"));
     LDAPMessage message = new LDAPMessage(1, bindRequest,
-         DisconnectClientPlugin.createDisconnectLDAPControlList("PreParse"));
-    w.writeElement(message.encode());
+         DisconnectClientPlugin.createDisconnectControlList("PreParse"));
+    w.writeMessage(message);
 
-    ASN1Element element = r.readElement();
-    if (element != null)
+    message = r.readMessage();
+    if (message != null)
     {
       // If we got an element back, then it must be a notice of disconnect
       // unsolicited notification.
-      message = LDAPMessage.decode(element.decodeAsSequence());
       assertEquals(message.getProtocolOpType(), OP_TYPE_EXTENDED_RESPONSE);
     }
 
@@ -1113,24 +1105,23 @@
          throws Exception
   {
     Socket s = new Socket("127.0.0.1", TestCaseUtils.getServerLdapPort());
-    ASN1Reader r = new ASN1Reader(s);
-    ASN1Writer w = new ASN1Writer(s);
-    r.setIOTimeout(6000);
+    LDAPReader r = new LDAPReader(s);
+    LDAPWriter w = new LDAPWriter(s);
+    s.setSoTimeout(6000);
 
     BindRequestProtocolOp bindRequest =
-         new BindRequestProtocolOp(new ASN1OctetString("cn=Directory Manager"),
-                                   3, new ASN1OctetString("password"));
+         new BindRequestProtocolOp(ByteString.valueOf("cn=Directory Manager"),
+                                   3, ByteString.valueOf("password"));
     LDAPMessage message = new LDAPMessage(1, bindRequest,
-         DisconnectClientPlugin.createDisconnectLDAPControlList(
+         DisconnectClientPlugin.createDisconnectControlList(
               "PreOperation"));
-    w.writeElement(message.encode());
+    w.writeMessage(message);
 
-    ASN1Element element = r.readElement();
-    if (element != null)
+    message = r.readMessage();
+    if (message != null)
     {
       // If we got an element back, then it must be a notice of disconnect
       // unsolicited notification.
-      message = LDAPMessage.decode(element.decodeAsSequence());
       assertEquals(message.getProtocolOpType(), OP_TYPE_EXTENDED_RESPONSE);
     }
 
@@ -1154,24 +1145,23 @@
          throws Exception
   {
     Socket s = new Socket("127.0.0.1", TestCaseUtils.getServerLdapPort());
-    ASN1Reader r = new ASN1Reader(s);
-    ASN1Writer w = new ASN1Writer(s);
-    r.setIOTimeout(6000);
+    LDAPReader r = new LDAPReader(s);
+    LDAPWriter w = new LDAPWriter(s);
+    s.setSoTimeout(6000);
 
     BindRequestProtocolOp bindRequest =
-         new BindRequestProtocolOp(new ASN1OctetString("cn=Directory Manager"),
-                                   3, new ASN1OctetString("password"));
+         new BindRequestProtocolOp(ByteString.valueOf("cn=Directory Manager"),
+                                   3, ByteString.valueOf("password"));
     LDAPMessage message = new LDAPMessage(1, bindRequest,
-         DisconnectClientPlugin.createDisconnectLDAPControlList(
+         DisconnectClientPlugin.createDisconnectControlList(
               "PostOperation"));
-    w.writeElement(message.encode());
+    w.writeMessage(message);
 
-    ASN1Element element = r.readElement();
-    if (element != null)
+    message = r.readMessage();
+    if (message != null)
     {
       // If we got an element back, then it must be a notice of disconnect
       // unsolicited notification.
-      message = LDAPMessage.decode(element.decodeAsSequence());
       assertEquals(message.getProtocolOpType(), OP_TYPE_EXTENDED_RESPONSE);
     }
 
@@ -1195,25 +1185,24 @@
          throws Exception
   {
     Socket s = new Socket("127.0.0.1", TestCaseUtils.getServerLdapPort());
-    ASN1Reader r = new ASN1Reader(s);
-    ASN1Writer w = new ASN1Writer(s);
-    r.setIOTimeout(6000);
+    LDAPReader r = new LDAPReader(s);
+    LDAPWriter w = new LDAPWriter(s);
+    s.setSoTimeout(6000);
 
     BindRequestProtocolOp bindRequest =
-         new BindRequestProtocolOp(new ASN1OctetString("cn=Directory Manager"),
-                                   3, new ASN1OctetString("password"));
+         new BindRequestProtocolOp(ByteString.valueOf("cn=Directory Manager"),
+                                   3, ByteString.valueOf("password"));
     LDAPMessage message = new LDAPMessage(1, bindRequest,
-         DisconnectClientPlugin.createDisconnectLDAPControlList(
+         DisconnectClientPlugin.createDisconnectControlList(
               "PostResponse"));
-    w.writeElement(message.encode());
+    w.writeMessage(message);
 
-    ASN1Element element = r.readElement();
-    while (element != null)
+    message = r.readMessage();
+    while (message != null)
     {
-      message = LDAPMessage.decode(element.decodeAsSequence());
       assertTrue((message.getProtocolOpType() == OP_TYPE_BIND_RESPONSE) ||
                  (message.getProtocolOpType() == OP_TYPE_EXTENDED_RESPONSE));
-      element = r.readElement();
+      message = r.readMessage();
     }
 
     try
@@ -1235,25 +1224,24 @@
          throws Exception
   {
     Socket s = new Socket("127.0.0.1", TestCaseUtils.getServerLdapPort());
-    ASN1Reader r = new ASN1Reader(s);
-    ASN1Writer w = new ASN1Writer(s);
-    r.setIOTimeout(6000);
+    LDAPReader r = new LDAPReader(s);
+    LDAPWriter w = new LDAPWriter(s);
+    s.setSoTimeout(6000);
 
-    ASN1OctetString saslCreds =
-         new ASN1OctetString("\u0000dn:cn=Directory Manager\u0000password");
+    ByteString saslCreds =
+         ByteString.valueOf("\u0000dn:cn=Directory Manager\u0000password");
 
     BindRequestProtocolOp bindRequest =
-         new BindRequestProtocolOp(new ASN1OctetString(), "PLAIN", saslCreds);
+         new BindRequestProtocolOp(ByteString.empty(), "PLAIN", saslCreds);
     LDAPMessage message = new LDAPMessage(1, bindRequest,
-         DisconnectClientPlugin.createDisconnectLDAPControlList("PreParse"));
-    w.writeElement(message.encode());
+         DisconnectClientPlugin.createDisconnectControlList("PreParse"));
+    w.writeMessage(message);
 
-    ASN1Element element = r.readElement();
-    if (element != null)
+    message = r.readMessage();
+    if (message != null)
     {
       // If we got an element back, then it must be a notice of disconnect
       // unsolicited notification.
-      message = LDAPMessage.decode(element.decodeAsSequence());
       assertEquals(message.getProtocolOpType(), OP_TYPE_EXTENDED_RESPONSE);
     }
 
@@ -1276,26 +1264,25 @@
          throws Exception
   {
     Socket s = new Socket("127.0.0.1", TestCaseUtils.getServerLdapPort());
-    ASN1Reader r = new ASN1Reader(s);
-    ASN1Writer w = new ASN1Writer(s);
-    r.setIOTimeout(6000);
+    LDAPReader r = new LDAPReader(s);
+    LDAPWriter w = new LDAPWriter(s);
+    s.setSoTimeout(6000);
 
-    ASN1OctetString saslCreds =
-         new ASN1OctetString("\u0000dn:cn=Directory Manager\u0000password");
+    ByteString saslCreds =
+         ByteString.valueOf("\u0000dn:cn=Directory Manager\u0000password");
 
     BindRequestProtocolOp bindRequest =
-         new BindRequestProtocolOp(new ASN1OctetString(), "PLAIN", saslCreds);
+         new BindRequestProtocolOp(ByteString.empty(), "PLAIN", saslCreds);
     LDAPMessage message = new LDAPMessage(1, bindRequest,
-         DisconnectClientPlugin.createDisconnectLDAPControlList(
+         DisconnectClientPlugin.createDisconnectControlList(
               "PreOperation"));
-    w.writeElement(message.encode());
+    w.writeMessage(message);
 
-    ASN1Element element = r.readElement();
-    if (element != null)
+    message = r.readMessage();
+    if (message != null)
     {
       // If we got an element back, then it must be a notice of disconnect
       // unsolicited notification.
-      message = LDAPMessage.decode(element.decodeAsSequence());
       assertEquals(message.getProtocolOpType(), OP_TYPE_EXTENDED_RESPONSE);
     }
 
@@ -1318,26 +1305,25 @@
          throws Exception
   {
     Socket s = new Socket("127.0.0.1", TestCaseUtils.getServerLdapPort());
-    ASN1Reader r = new ASN1Reader(s);
-    ASN1Writer w = new ASN1Writer(s);
-    r.setIOTimeout(6000);
+    LDAPReader r = new LDAPReader(s);
+    LDAPWriter w = new LDAPWriter(s);
+    s.setSoTimeout(6000);
 
-    ASN1OctetString saslCreds =
-         new ASN1OctetString("\u0000dn:cn=Directory Manager\u0000password");
+    ByteString saslCreds =
+         ByteString.valueOf("\u0000dn:cn=Directory Manager\u0000password");
 
     BindRequestProtocolOp bindRequest =
-         new BindRequestProtocolOp(new ASN1OctetString(), "PLAIN", saslCreds);
+         new BindRequestProtocolOp(ByteString.empty(), "PLAIN", saslCreds);
     LDAPMessage message = new LDAPMessage(1, bindRequest,
-         DisconnectClientPlugin.createDisconnectLDAPControlList(
+         DisconnectClientPlugin.createDisconnectControlList(
               "PostOperation"));
-    w.writeElement(message.encode());
+    w.writeMessage(message);
 
-    ASN1Element element = r.readElement();
-    if (element != null)
+    message = r.readMessage();
+    if (message != null)
     {
       // If we got an element back, then it must be a notice of disconnect
       // unsolicited notification.
-      message = LDAPMessage.decode(element.decodeAsSequence());
       assertEquals(message.getProtocolOpType(), OP_TYPE_EXTENDED_RESPONSE);
     }
 
@@ -1360,27 +1346,26 @@
          throws Exception
   {
     Socket s = new Socket("127.0.0.1", TestCaseUtils.getServerLdapPort());
-    ASN1Reader r = new ASN1Reader(s);
-    ASN1Writer w = new ASN1Writer(s);
-    r.setIOTimeout(6000);
+    LDAPReader r = new LDAPReader(s);
+    LDAPWriter w = new LDAPWriter(s);
+    s.setSoTimeout(6000);
 
-    ASN1OctetString saslCreds =
-         new ASN1OctetString("\u0000dn:cn=Directory Manager\u0000password");
+    ByteString saslCreds =
+         ByteString.valueOf("\u0000dn:cn=Directory Manager\u0000password");
 
     BindRequestProtocolOp bindRequest =
-         new BindRequestProtocolOp(new ASN1OctetString(), "PLAIN", saslCreds);
+         new BindRequestProtocolOp(ByteString.empty(), "PLAIN", saslCreds);
     LDAPMessage message = new LDAPMessage(1, bindRequest,
-         DisconnectClientPlugin.createDisconnectLDAPControlList(
+         DisconnectClientPlugin.createDisconnectControlList(
               "PostResponse"));
-    w.writeElement(message.encode());
+    w.writeMessage(message);
 
-    ASN1Element element = r.readElement();
-    while (element != null)
+    message = r.readMessage();
+    while (message != null)
     {
-      message = LDAPMessage.decode(element.decodeAsSequence());
       assertTrue((message.getProtocolOpType() == OP_TYPE_BIND_RESPONSE) ||
                  (message.getProtocolOpType() == OP_TYPE_EXTENDED_RESPONSE));
-      element = r.readElement();
+      message = r.readMessage();
     }
 
     try
@@ -1403,18 +1388,18 @@
          throws Exception
   {
     Socket s = new Socket("127.0.0.1", TestCaseUtils.getServerLdapPort());
-    ASN1Reader r = new ASN1Reader(s);
-    ASN1Writer w = new ASN1Writer(s);
-    r.setIOTimeout(6000);
+    LDAPReader r = new LDAPReader(s);
+    LDAPWriter w = new LDAPWriter(s);
+    s.setSoTimeout(6000);
 
     BindRequestProtocolOp bindRequest =
-         new BindRequestProtocolOp(new ASN1OctetString(), 3,
-                                   new ASN1OctetString());
+         new BindRequestProtocolOp(ByteString.empty(), 3,
+                                   ByteString.empty());
     LDAPMessage message = new LDAPMessage(1, bindRequest,
-         ShortCircuitPlugin.createShortCircuitLDAPControlList(80, "PreParse"));
-    w.writeElement(message.encode());
+         ShortCircuitPlugin.createShortCircuitControlList(80, "PreParse"));
+    w.writeMessage(message);
 
-    message = LDAPMessage.decode(r.readElement().decodeAsSequence());
+    message = r.readMessage();
     BindResponseProtocolOp bindResponse = message.getBindResponseProtocolOp();
     assertEquals(bindResponse.getResultCode(), 80);
 
@@ -1438,19 +1423,19 @@
          throws Exception
   {
     Socket s = new Socket("127.0.0.1", TestCaseUtils.getServerLdapPort());
-    ASN1Reader r = new ASN1Reader(s);
-    ASN1Writer w = new ASN1Writer(s);
-    r.setIOTimeout(6000);
+    LDAPReader r = new LDAPReader(s);
+    LDAPWriter w = new LDAPWriter(s);
+    s.setSoTimeout(6000);
 
     BindRequestProtocolOp bindRequest =
-         new BindRequestProtocolOp(new ASN1OctetString(), 3,
-                                   new ASN1OctetString());
+         new BindRequestProtocolOp(ByteString.empty(), 3,
+                                   ByteString.empty());
     LDAPMessage message = new LDAPMessage(1, bindRequest,
-         ShortCircuitPlugin.createShortCircuitLDAPControlList(80,
+         ShortCircuitPlugin.createShortCircuitControlList(80,
                                                               "PreOperation"));
-    w.writeElement(message.encode());
+    w.writeMessage(message);
 
-    message = LDAPMessage.decode(r.readElement().decodeAsSequence());
+    message = r.readMessage();
     BindResponseProtocolOp bindResponse = message.getBindResponseProtocolOp();
     assertEquals(bindResponse.getResultCode(), 80);
 
@@ -1474,18 +1459,18 @@
          throws Exception
   {
     Socket s = new Socket("127.0.0.1", TestCaseUtils.getServerLdapPort());
-    ASN1Reader r = new ASN1Reader(s);
-    ASN1Writer w = new ASN1Writer(s);
-    r.setIOTimeout(6000);
+    LDAPReader r = new LDAPReader(s);
+    LDAPWriter w = new LDAPWriter(s);
+    s.setSoTimeout(6000);
 
     BindRequestProtocolOp bindRequest =
-         new BindRequestProtocolOp(new ASN1OctetString("cn=Directory Manager"),
-                                   3, new ASN1OctetString("password"));
+         new BindRequestProtocolOp(ByteString.valueOf("cn=Directory Manager"),
+                                   3, ByteString.valueOf("password"));
     LDAPMessage message = new LDAPMessage(1, bindRequest,
-         ShortCircuitPlugin.createShortCircuitLDAPControlList(80, "PreParse"));
-    w.writeElement(message.encode());
+         ShortCircuitPlugin.createShortCircuitControlList(80, "PreParse"));
+    w.writeMessage(message);
 
-    message = LDAPMessage.decode(r.readElement().decodeAsSequence());
+    message = r.readMessage();
     BindResponseProtocolOp bindResponse = message.getBindResponseProtocolOp();
     assertEquals(bindResponse.getResultCode(), 80);
 
@@ -1509,19 +1494,19 @@
          throws Exception
   {
     Socket s = new Socket("127.0.0.1", TestCaseUtils.getServerLdapPort());
-    ASN1Reader r = new ASN1Reader(s);
-    ASN1Writer w = new ASN1Writer(s);
-    r.setIOTimeout(6000);
+    LDAPReader r = new LDAPReader(s);
+    LDAPWriter w = new LDAPWriter(s);
+    s.setSoTimeout(6000);
 
     BindRequestProtocolOp bindRequest =
-         new BindRequestProtocolOp(new ASN1OctetString("cn=Directory Manager"),
-                                   3, new ASN1OctetString("password"));
+         new BindRequestProtocolOp(ByteString.valueOf("cn=Directory Manager"),
+                                   3, ByteString.valueOf("password"));
     LDAPMessage message = new LDAPMessage(1, bindRequest,
-         ShortCircuitPlugin.createShortCircuitLDAPControlList(80,
+         ShortCircuitPlugin.createShortCircuitControlList(80,
                                                               "PreOperation"));
-    w.writeElement(message.encode());
+    w.writeMessage(message);
 
-    message = LDAPMessage.decode(r.readElement().decodeAsSequence());
+    message = r.readMessage();
     BindResponseProtocolOp bindResponse = message.getBindResponseProtocolOp();
     assertEquals(bindResponse.getResultCode(), 80);
 
@@ -1544,20 +1529,20 @@
          throws Exception
   {
     Socket s = new Socket("127.0.0.1", TestCaseUtils.getServerLdapPort());
-    ASN1Reader r = new ASN1Reader(s);
-    ASN1Writer w = new ASN1Writer(s);
-    r.setIOTimeout(6000);
+    LDAPReader r = new LDAPReader(s);
+    LDAPWriter w = new LDAPWriter(s);
+    s.setSoTimeout(6000);
 
-    ASN1OctetString saslCreds =
-         new ASN1OctetString("\u0000dn:cn=Directory Manager\u0000password");
+    ByteString saslCreds =
+         ByteString.valueOf("\u0000dn:cn=Directory Manager\u0000password");
 
     BindRequestProtocolOp bindRequest =
-         new BindRequestProtocolOp(new ASN1OctetString(), "PLAIN", saslCreds);
+         new BindRequestProtocolOp(ByteString.empty(), "PLAIN", saslCreds);
     LDAPMessage message = new LDAPMessage(1, bindRequest,
-         ShortCircuitPlugin.createShortCircuitLDAPControlList(80, "PreParse"));
-    w.writeElement(message.encode());
+         ShortCircuitPlugin.createShortCircuitControlList(80, "PreParse"));
+    w.writeMessage(message);
 
-    message = LDAPMessage.decode(r.readElement().decodeAsSequence());
+    message = r.readMessage();
     BindResponseProtocolOp bindResponse = message.getBindResponseProtocolOp();
     assertEquals(bindResponse.getResultCode(), 80);
 
@@ -1580,21 +1565,21 @@
          throws Exception
   {
     Socket s = new Socket("127.0.0.1", TestCaseUtils.getServerLdapPort());
-    ASN1Reader r = new ASN1Reader(s);
-    ASN1Writer w = new ASN1Writer(s);
-    r.setIOTimeout(6000);
+    LDAPReader r = new LDAPReader(s);
+    LDAPWriter w = new LDAPWriter(s);
+    s.setSoTimeout(6000);
 
-    ASN1OctetString saslCreds =
-         new ASN1OctetString("\u0000dn:cn=Directory Manager\u0000password");
+    ByteString saslCreds =
+         ByteString.valueOf("\u0000dn:cn=Directory Manager\u0000password");
 
     BindRequestProtocolOp bindRequest =
-         new BindRequestProtocolOp(new ASN1OctetString(), "PLAIN", saslCreds);
+         new BindRequestProtocolOp(ByteString.empty(), "PLAIN", saslCreds);
     LDAPMessage message = new LDAPMessage(1, bindRequest,
-         ShortCircuitPlugin.createShortCircuitLDAPControlList(80,
+         ShortCircuitPlugin.createShortCircuitControlList(80,
                                                               "PreOperation"));
-    w.writeElement(message.encode());
+    w.writeMessage(message);
 
-    message = LDAPMessage.decode(r.readElement().decodeAsSequence());
+    message = r.readMessage();
     BindResponseProtocolOp bindResponse = message.getBindResponseProtocolOp();
     assertEquals(bindResponse.getResultCode(), 80);
 
@@ -1616,8 +1601,8 @@
          new InternalClientConnection(new AuthenticationInfo());
 
     BindOperation bindOperation =
-         conn.processSimpleBind(new ASN1OctetString("invaliddn"),
-                                new ASN1OctetString("password"));
+         conn.processSimpleBind(ByteString.valueOf("invaliddn"),
+                                ByteString.valueOf("password"));
     assertEquals(bindOperation.getResultCode(), ResultCode.INVALID_CREDENTIALS);
   }
 
@@ -1632,11 +1617,11 @@
     InternalClientConnection conn =
          new InternalClientConnection(new AuthenticationInfo());
 
-    ASN1OctetString saslCreds =
-         new ASN1OctetString("\u0000dn:cn=Directory Manager\u0000password");
+    ByteString saslCreds =
+         ByteString.valueOf("\u0000dn:cn=Directory Manager\u0000password");
 
     BindOperation bindOperation =
-         conn.processSASLBind(new ASN1OctetString("invaliddn"), "PLAIN",
+         conn.processSASLBind(ByteString.valueOf("invaliddn"), "PLAIN",
                               saslCreds);
     assertEquals(bindOperation.getResultCode(), ResultCode.INVALID_CREDENTIALS);
   }
@@ -1654,12 +1639,12 @@
          new InternalClientConnection(new AuthenticationInfo());
 
     ArrayList<Control> requestControls = new ArrayList<Control>(1);
-    requestControls.add(new Control("1.2.3.4", true));
+    requestControls.add(new LDAPControl("1.2.3.4", true));
 
     BindOperationBasis bindOperation =
          new BindOperationBasis(conn, conn.nextOperationID(), conn.nextMessageID(),
                            requestControls, "3", DN.nullDN(),
-                        new ASN1OctetString());
+                        ByteString.empty());
     bindOperation.run();
     assertEquals(bindOperation.getResultCode(),
                  ResultCode.UNAVAILABLE_CRITICAL_EXTENSION);
@@ -1678,10 +1663,10 @@
          new InternalClientConnection(new AuthenticationInfo());
 
     ArrayList<Control> requestControls = new ArrayList<Control>(1);
-    requestControls.add(new Control("1.2.3.4", true));
+    requestControls.add(new LDAPControl("1.2.3.4", true));
 
-    ASN1OctetString saslCreds =
-         new ASN1OctetString("\u0000dn:cn=Directory Manager\u0000password");
+    ByteString saslCreds =
+         ByteString.valueOf("\u0000dn:cn=Directory Manager\u0000password");
 
     BindOperationBasis bindOperation =
          new BindOperationBasis(conn, conn.nextOperationID(), conn.nextMessageID(),
@@ -1705,12 +1690,12 @@
          new InternalClientConnection(new AuthenticationInfo());
 
     ArrayList<Control> requestControls = new ArrayList<Control>(1);
-    requestControls.add(new Control("1.2.3.4", false));
+    requestControls.add(new LDAPControl("1.2.3.4", false));
 
     BindOperationBasis bindOperation =
          new BindOperationBasis(conn, conn.nextOperationID(), conn.nextMessageID(),
                            requestControls, "3", DN.nullDN(),
-                           new ASN1OctetString());
+                           ByteString.empty());
 
     bindOperation.run();
     assertEquals(bindOperation.getResultCode(), ResultCode.SUCCESS);
@@ -1729,10 +1714,10 @@
          new InternalClientConnection(new AuthenticationInfo());
 
     ArrayList<Control> requestControls = new ArrayList<Control>(1);
-    requestControls.add(new Control("1.2.3.4", false));
+    requestControls.add(new LDAPControl("1.2.3.4", false));
 
-    ASN1OctetString saslCreds =
-         new ASN1OctetString("\u0000dn:cn=Directory Manager\u0000password");
+    ByteString saslCreds =
+         ByteString.valueOf("\u0000dn:cn=Directory Manager\u0000password");
 
     BindOperationBasis bindOperation =
          new BindOperationBasis(conn, conn.nextOperationID(), conn.nextMessageID(),
@@ -1760,8 +1745,8 @@
          new InternalClientConnection(new AuthenticationInfo());
 
     BindOperation bindOperation =
-         conn.processSimpleBind(new ASN1OctetString("uid=test,o=test"),
-                                new ASN1OctetString("password"));
+         conn.processSimpleBind(ByteString.valueOf("uid=test,o=test"),
+                                ByteString.valueOf("password"));
     assertEquals(bindOperation.getResultCode(), ResultCode.INVALID_CREDENTIALS);
   }
 
@@ -1784,8 +1769,8 @@
          new InternalClientConnection(new AuthenticationInfo());
 
     BindOperation bindOperation =
-         conn.processSimpleBind(new ASN1OctetString("cn=Directory Manager"),
-                                new ASN1OctetString());
+         conn.processSimpleBind(ByteString.valueOf("cn=Directory Manager"),
+                                ByteString.empty());
     assertEquals(bindOperation.getResultCode(), ResultCode.UNWILLING_TO_PERFORM);
   }
 
@@ -1816,8 +1801,8 @@
     assertEquals(modifyOperation.getResultCode(), ResultCode.SUCCESS);
 
     BindOperation bindOperation =
-         conn.processSimpleBind(new ASN1OctetString("cn=Directory Manager"),
-                                new ASN1OctetString());
+         conn.processSimpleBind(ByteString.valueOf("cn=Directory Manager"),
+                                ByteString.empty());
     assertEquals(bindOperation.getResultCode(), ResultCode.SUCCESS);
 
     mods.clear();
@@ -1862,8 +1847,8 @@
     assertEquals(addOperation.getResultCode(), ResultCode.SUCCESS);
 
     BindOperation bindOperation =
-         conn.processSimpleBind(new ASN1OctetString("uid=test,o=test"),
-                                new ASN1OctetString("password"));
+         conn.processSimpleBind(ByteString.valueOf("uid=test,o=test"),
+                                ByteString.valueOf("password"));
     assertEquals(bindOperation.getResultCode(), ResultCode.INVALID_CREDENTIALS);
   }
 
@@ -1880,8 +1865,8 @@
          new InternalClientConnection(new AuthenticationInfo());
 
     BindOperation bindOperation =
-         conn.processSimpleBind(new ASN1OctetString("cn=Directory Manager"),
-                                new ASN1OctetString("wrongpassword"));
+         conn.processSimpleBind(ByteString.valueOf("cn=Directory Manager"),
+                                ByteString.valueOf("wrongpassword"));
     assertEquals(bindOperation.getResultCode(), ResultCode.INVALID_CREDENTIALS);
   }
 
@@ -1898,8 +1883,8 @@
          new InternalClientConnection(new AuthenticationInfo());
 
     BindOperation bindOperation =
-         conn.processSimpleBind(new ASN1OctetString("cn=Directory Manager"),
-                                new ASN1OctetString("wrongpassword"));
+         conn.processSimpleBind(ByteString.valueOf("cn=Directory Manager"),
+                                ByteString.valueOf("wrongpassword"));
     assertEquals(bindOperation.getResultCode(), ResultCode.INVALID_CREDENTIALS);
     assertTrue(((bindOperation.getErrorMessage() == null) ||
                 (bindOperation.getErrorMessage().length() == 0)),
@@ -1913,8 +1898,8 @@
       "--set", "return-bind-error-messages:true");
 
     bindOperation =
-         conn.processSimpleBind(new ASN1OctetString("cn=Directory Manager"),
-                                new ASN1OctetString("wrongpassword"));
+         conn.processSimpleBind(ByteString.valueOf("cn=Directory Manager"),
+                                ByteString.valueOf("wrongpassword"));
     assertEquals(bindOperation.getResultCode(), ResultCode.INVALID_CREDENTIALS);
     assertTrue(bindOperation.getErrorMessage().length() > 0);
 
@@ -1926,8 +1911,8 @@
       "--set", "return-bind-error-messages:false");
 
     bindOperation =
-         conn.processSimpleBind(new ASN1OctetString("cn=Directory Manager"),
-                                new ASN1OctetString("wrongpassword"));
+         conn.processSimpleBind(ByteString.valueOf("cn=Directory Manager"),
+                                ByteString.valueOf("wrongpassword"));
     assertEquals(bindOperation.getResultCode(), ResultCode.INVALID_CREDENTIALS);
     assertTrue(((bindOperation.getErrorMessage() == null) ||
                 (bindOperation.getErrorMessage().length() == 0)),
@@ -1963,17 +1948,17 @@
     DN userDN = DN.decode(dnString);
 
     Socket s = new Socket("127.0.0.1", TestCaseUtils.getServerLdapPort());
-    ASN1Reader r = new ASN1Reader(s);
-    ASN1Writer w = new ASN1Writer(s);
-    r.setIOTimeout(6000);
+    s.setSoTimeout(6000);
+    LDAPReader r = new LDAPReader(s);
+    LDAPWriter w = new LDAPWriter(s);
 
     BindRequestProtocolOp bindRequest =
-         new BindRequestProtocolOp(new ASN1OctetString(dnString),
-                                   3, new ASN1OctetString("password"));
+         new BindRequestProtocolOp(ByteString.valueOf(dnString),
+                                   3, ByteString.valueOf("password"));
     LDAPMessage message = new LDAPMessage(1, bindRequest);
-    w.writeElement(message.encode());
+    w.writeMessage(message);
 
-    message = LDAPMessage.decode(r.readElement().decodeAsSequence());
+    message = r.readMessage();
     BindResponseProtocolOp bindResponse = message.getBindResponseProtocolOp();
     assertEquals(bindResponse.getResultCode(), 0);
 
@@ -1986,12 +1971,12 @@
     // for previous ops to complete.
     TestCaseUtils.quiesceServer();
     bindRequest = new BindRequestProtocolOp(
-                           new ASN1OctetString("cn=Directory Manager"), 3,
-                           new ASN1OctetString("password"));
+                           ByteString.valueOf("cn=Directory Manager"), 3,
+                           ByteString.valueOf("password"));
     message = new LDAPMessage(1, bindRequest);
-    w.writeElement(message.encode());
+    w.writeMessage(message);
 
-    message = LDAPMessage.decode(r.readElement().decodeAsSequence());
+    message = r.readMessage();
     bindResponse = message.getBindResponseProtocolOp();
     assertEquals(bindResponse.getResultCode(), 0, message.toString());
 
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/core/CompareOperationTestCase.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/core/CompareOperationTestCase.java
index e998449..c9eb45c 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/core/CompareOperationTestCase.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/core/CompareOperationTestCase.java
@@ -28,18 +28,10 @@
 package org.opends.server.core;
 
 import org.opends.server.protocols.internal.InternalClientConnection;
-import org.opends.server.protocols.asn1.ASN1OctetString;
-import org.opends.server.protocols.asn1.ASN1Reader;
-import org.opends.server.protocols.asn1.ASN1Writer;
 import org.opends.server.protocols.ldap.*;
-import org.opends.server.types.AuthenticationInfo;
-import org.opends.server.types.Control;
-import org.opends.server.types.ResultCode;
-import org.opends.server.types.DN;
-import org.opends.server.types.Entry;
-import org.opends.server.types.LockManager;
-import org.opends.server.types.Operation;
+import org.opends.server.types.*;
 import org.opends.server.TestCaseUtils;
+import org.opends.server.tools.LDAPWriter;
 import org.opends.server.util.ServerConstants;
 import org.opends.server.controls.LDAPAssertionRequestControl;
 import org.opends.server.controls.ProxiedAuthV1Control;
@@ -128,6 +120,7 @@
   }
 
 
+  @Override
   protected Operation[] createTestOperations() throws Exception
   {
     InternalClientConnection conn =
@@ -139,8 +132,8 @@
                            conn, InternalClientConnection.nextOperationID(),
                            InternalClientConnection.nextMessageID(),
                            new ArrayList<Control>(),
-                           new ASN1OctetString(entry.getDN().toString()),
-                           "uid", new ASN1OctetString("rogasawara"))
+                           ByteString.valueOf(entry.getDN().toString()),
+                           "uid", ByteString.valueOf("rogasawara"))
     };
   }
 
@@ -219,8 +212,8 @@
                               conn, InternalClientConnection.nextOperationID(),
                               InternalClientConnection.nextMessageID(),
                               new ArrayList<Control>(),
-                              new ASN1OctetString(entry.getDN().toString()),
-                              "uid", new ASN1OctetString("rogasawara"));
+                              ByteString.valueOf(entry.getDN().toString()),
+                              "uid", ByteString.valueOf("rogasawara"));
 
     compareOperation.run();
     assertEquals(compareOperation.getResultCode(),
@@ -244,8 +237,8 @@
                               conn, InternalClientConnection.nextOperationID(),
                               InternalClientConnection.nextMessageID(),
                               new ArrayList<Control>(),
-                              new ASN1OctetString(entry.getDN().toString()),
-                              "uid", new ASN1OctetString("rogasawala"));
+                              ByteString.valueOf(entry.getDN().toString()),
+                              "uid", ByteString.valueOf("rogasawala"));
 
     compareOperation.run();
     assertEquals(compareOperation.getResultCode(),
@@ -268,8 +261,8 @@
                               conn, InternalClientConnection.nextOperationID(),
                               InternalClientConnection.nextMessageID(),
                               new ArrayList<Control>(),
-                              new ASN1OctetString("o=nonexistent,o=test"),
-                              "o", new ASN1OctetString("nonexistent"));
+                              ByteString.valueOf("o=nonexistent,o=test"),
+                              "o", ByteString.valueOf("nonexistent"));
 
     compareOperation.run();
     assertEquals(compareOperation.getResultCode(),
@@ -291,8 +284,8 @@
                               conn, InternalClientConnection.nextOperationID(),
                               InternalClientConnection.nextMessageID(),
                               new ArrayList<Control>(),
-                              new ASN1OctetString("rogasawara,o=test"),
-                              "uid", new ASN1OctetString("rogasawara"));
+                              ByteString.valueOf("rogasawara,o=test"),
+                              "uid", ByteString.valueOf("rogasawara"));
 
     compareOperation.run();
     assertEquals(compareOperation.getResultCode(),
@@ -314,8 +307,8 @@
                               conn, InternalClientConnection.nextOperationID(),
                               InternalClientConnection.nextMessageID(),
                               new ArrayList<Control>(),
-                              new ASN1OctetString(entry.getDN().toString()),
-                              "description", new ASN1OctetString("rogasawara"));
+                              ByteString.valueOf(entry.getDN().toString()),
+                              "description", ByteString.valueOf("rogasawara"));
 
     compareOperation.run();
     assertEquals(compareOperation.getResultCode(),
@@ -338,9 +331,9 @@
                               conn, InternalClientConnection.nextOperationID(),
                               InternalClientConnection.nextMessageID(),
                               new ArrayList<Control>(),
-                              new ASN1OctetString(entry.getDN().toString()),
+                              ByteString.valueOf(entry.getDN().toString()),
                               "NotAnAttribute",
-                              new ASN1OctetString("rogasawara"));
+                              ByteString.valueOf("rogasawara"));
 
     compareOperation.run();
     assertEquals(compareOperation.getResultCode(),
@@ -361,9 +354,9 @@
                               conn, InternalClientConnection.nextOperationID(),
                               InternalClientConnection.nextMessageID(),
                               new ArrayList<Control>(),
-                              new ASN1OctetString(entry.getDN().toString()),
+                              ByteString.valueOf(entry.getDN().toString()),
                               "name",
-                              new ASN1OctetString("Ogasawara"));
+                              ByteString.valueOf("Ogasawara"));
 
     compareOperation.run();
     assertEquals(compareOperation.getResultCode(),
@@ -381,9 +374,9 @@
                               conn, InternalClientConnection.nextOperationID(),
                               InternalClientConnection.nextMessageID(),
                               new ArrayList<Control>(),
-                              new ASN1OctetString(entry.getDN().toString()),
+                              ByteString.valueOf(entry.getDN().toString()),
                               "sn",
-                              new ASN1OctetString("Ogasawara"));
+                              ByteString.valueOf("Ogasawara"));
 
     compareOperation.run();
     assertEquals(compareOperation.getResultCode(),
@@ -401,9 +394,9 @@
                               conn, InternalClientConnection.nextOperationID(),
                               InternalClientConnection.nextMessageID(),
                               new ArrayList<Control>(),
-                              new ASN1OctetString(entry.getDN().toString()),
+                              ByteString.valueOf(entry.getDN().toString()),
                               "sn;lang-ja",
-                              new ASN1OctetString("Ogasawara"));
+                              ByteString.valueOf("Ogasawara"));
 
     compareOperation.run();
     assertEquals(compareOperation.getResultCode(),
@@ -421,9 +414,9 @@
                               conn, InternalClientConnection.nextOperationID(),
                               InternalClientConnection.nextMessageID(),
                               new ArrayList<Control>(),
-                              new ASN1OctetString(entry.getDN().toString()),
+                              ByteString.valueOf(entry.getDN().toString()),
                               "givenName;lAnG-En",
-                              new ASN1OctetString("Rodney"));
+                              ByteString.valueOf("Rodney"));
 
     compareOperation.run();
     assertEquals(compareOperation.getResultCode(),
@@ -449,8 +442,8 @@
                               conn, InternalClientConnection.nextOperationID(),
                               InternalClientConnection.nextMessageID(),
                               controls,
-                              new ASN1OctetString(entry.getDN().toString()),
-                              "uid", new ASN1OctetString("rogasawara"));
+                              ByteString.valueOf(entry.getDN().toString()),
+                              "uid", ByteString.valueOf("rogasawara"));
 
     compareOperation.run();
     assertEquals(compareOperation.getResultCode(),
@@ -479,8 +472,8 @@
                               conn, InternalClientConnection.nextOperationID(),
                               InternalClientConnection.nextMessageID(),
                               controls,
-                              new ASN1OctetString(entry.getDN().toString()),
-                              "uid", new ASN1OctetString("rogasawara"));
+                              ByteString.valueOf(entry.getDN().toString()),
+                              "uid", ByteString.valueOf("rogasawara"));
 
     compareOperation.run();
     assertEquals(compareOperation.getResultCode(),
@@ -495,7 +488,7 @@
     InvocationCounterPlugin.resetAllCounters();
 
     ProxiedAuthV1Control authV1Control =
-         new ProxiedAuthV1Control(new ASN1OctetString(
+         new ProxiedAuthV1Control(ByteString.valueOf(
               "cn=Directory Manager,cn=Root DNs,cn=config"));
     List<Control> controls = new ArrayList<Control>();
     controls.add(authV1Control);
@@ -506,8 +499,8 @@
                               InternalClientConnection.nextOperationID(),
                               InternalClientConnection.nextMessageID(),
                               controls,
-                              new ASN1OctetString(entry.getDN().toString()),
-                              "uid", new ASN1OctetString("rogasawara"));
+                              ByteString.valueOf(entry.getDN().toString()),
+                              "uid", ByteString.valueOf("rogasawara"));
 
     compareOperation.run();
     assertEquals(compareOperation.getResultCode(),
@@ -525,7 +518,7 @@
     InvocationCounterPlugin.resetAllCounters();
 
     ProxiedAuthV1Control authV1Control =
-         new ProxiedAuthV1Control(new ASN1OctetString("cn=nonexistent,o=test"));
+         new ProxiedAuthV1Control(ByteString.valueOf("cn=nonexistent,o=test"));
     List<Control> controls = new ArrayList<Control>();
     controls.add(authV1Control);
 
@@ -535,8 +528,8 @@
                               InternalClientConnection.nextOperationID(),
                               InternalClientConnection.nextMessageID(),
                               controls,
-                              new ASN1OctetString(entry.getDN().toString()),
-                              "uid", new ASN1OctetString("rogasawara"));
+                              ByteString.valueOf(entry.getDN().toString()),
+                              "uid", ByteString.valueOf("rogasawara"));
 
     compareOperation.run();
     assertEquals(compareOperation.getResultCode(),
@@ -551,7 +544,7 @@
     InvocationCounterPlugin.resetAllCounters();
 
     ProxiedAuthV2Control authV2Control =
-         new ProxiedAuthV2Control(new ASN1OctetString(
+         new ProxiedAuthV2Control(ByteString.valueOf(
                   "dn:cn=Directory Manager,cn=Root DNs,cn=config"));
     List<Control> controls = new ArrayList<Control>();
     controls.add(authV2Control);
@@ -562,8 +555,8 @@
                               InternalClientConnection.nextOperationID(),
                               InternalClientConnection.nextMessageID(),
                               controls,
-                              new ASN1OctetString(entry.getDN().toString()),
-                              "uid", new ASN1OctetString("rogasawara"));
+                              ByteString.valueOf(entry.getDN().toString()),
+                              "uid", ByteString.valueOf("rogasawara"));
 
     compareOperation.run();
     assertEquals(compareOperation.getResultCode(),
@@ -579,7 +572,7 @@
     InvocationCounterPlugin.resetAllCounters();
 
     ProxiedAuthV2Control authV2Control = new ProxiedAuthV2Control(
-         new ASN1OctetString("dn:cn=nonexistent,o=test"));
+         ByteString.valueOf("dn:cn=nonexistent,o=test"));
     List<Control> controls = new ArrayList<Control>();
     controls.add(authV2Control);
 
@@ -589,8 +582,8 @@
                               InternalClientConnection.nextOperationID(),
                               InternalClientConnection.nextMessageID(),
                               controls,
-                              new ASN1OctetString(entry.getDN().toString()),
-                              "uid", new ASN1OctetString("rogasawara"));
+                              ByteString.valueOf(entry.getDN().toString()),
+                              "uid", ByteString.valueOf("rogasawara"));
 
     compareOperation.run();
     assertEquals(compareOperation.getResultCode(),
@@ -605,8 +598,8 @@
     InvocationCounterPlugin.resetAllCounters();
 
     Control authV2Control =
-         new Control(ServerConstants.OID_PROXIED_AUTH_V2, false,
-                     new ASN1OctetString());
+         new LDAPControl(ServerConstants.OID_PROXIED_AUTH_V2, false,
+                     ByteString.empty());
 
     List<Control> controls = new ArrayList<Control>();
     controls.add(authV2Control);
@@ -617,8 +610,8 @@
                               InternalClientConnection.nextOperationID(),
                               InternalClientConnection.nextMessageID(),
                               controls,
-                              new ASN1OctetString(entry.getDN().toString()),
-                              "uid", new ASN1OctetString("rogasawara"));
+                              ByteString.valueOf(entry.getDN().toString()),
+                              "uid", ByteString.valueOf("rogasawara"));
 
     compareOperation.run();
     assertEquals(compareOperation.getResultCode(),
@@ -635,9 +628,9 @@
     InternalClientConnection conn =
          InternalClientConnection.getRootConnection();
 
-    LDAPFilter ldapFilter = LDAPFilter.decode("(preferredlanguage=ja)");
-    LDAPAssertionRequestControl assertControl =
-         new LDAPAssertionRequestControl("1.1.1.1.1.1", true, ldapFilter);
+    LDAPFilter.decode("(preferredlanguage=ja)");
+    LDAPControl assertControl =
+         new LDAPControl("1.1.1.1.1.1", true);
     List<Control> controls = new ArrayList<Control>();
     controls.add(assertControl);
     CompareOperationBasis compareOperation =
@@ -645,8 +638,8 @@
                               conn, InternalClientConnection.nextOperationID(),
                               InternalClientConnection.nextMessageID(),
                               controls,
-                              new ASN1OctetString(entry.getDN().toString()),
-                              "uid", new ASN1OctetString("rogasawara"));
+                              ByteString.valueOf(entry.getDN().toString()),
+                              "uid", ByteString.valueOf("rogasawara"));
 
     compareOperation.run();
     assertEquals(compareOperation.getResultCode(),
@@ -666,18 +659,19 @@
     Socket s = new Socket("127.0.0.1", TestCaseUtils.getServerLdapPort());
     try
     {
-      ASN1Reader r = new ASN1Reader(s);
-      ASN1Writer w = new ASN1Writer(s);
-      r.setIOTimeout(15000);
+      org.opends.server.tools.LDAPReader r =
+          new org.opends.server.tools.LDAPReader(s);
+      LDAPWriter w = new LDAPWriter(s);
+      s.setSoTimeout(15000);
 
       BindRequestProtocolOp bindRequest =
            new BindRequestProtocolOp(
-                new ASN1OctetString("cn=Directory Manager"),
-                3, new ASN1OctetString("password"));
+                ByteString.valueOf("cn=Directory Manager"),
+                3, ByteString.valueOf("password"));
       LDAPMessage message = new LDAPMessage(1, bindRequest);
-      w.writeElement(message.encode());
+      w.writeMessage(message);
 
-      message = LDAPMessage.decode(r.readElement().decodeAsSequence());
+      message = r.readMessage();
       BindResponseProtocolOp bindResponse = message.getBindResponseProtocolOp();
       assertEquals(bindResponse.getResultCode(), LDAPResultCode.SUCCESS);
 
@@ -699,12 +693,12 @@
 
         CompareRequestProtocolOp compareRequest =
           new CompareRequestProtocolOp(
-               new ASN1OctetString(entry.getDN().toString()),
-               "uid", new ASN1OctetString("rogasawara"));
+               ByteString.valueOf(entry.getDN().toString()),
+               "uid", ByteString.valueOf("rogasawara"));
         message = new LDAPMessage(2, compareRequest);
-        w.writeElement(message.encode());
+        w.writeMessage(message);
 
-        message = LDAPMessage.decode(r.readElement().decodeAsSequence());
+        message = r.readMessage();
         CompareResponseProtocolOp compareResponse =
              message.getCompareResponseProtocolOp();
 
@@ -714,8 +708,9 @@
 //        assertEquals(InvocationCounterPlugin.getPreParseCount(), 1);
 //        assertEquals(InvocationCounterPlugin.getPreOperationCount(), 0);
 //        assertEquals(InvocationCounterPlugin.getPostOperationCount(), 0);
-//        // The post response might not have been called yet.
-//        assertEquals(InvocationCounterPlugin.waitForPostResponse(), 1);
+
+        // The post response might not have been called yet.
+        assertEquals(InvocationCounterPlugin.waitForPostResponse(), 1);
 
         assertEquals(ldapStatistics.getCompareRequests(), compareRequests+1);
         assertEquals(ldapStatistics.getCompareResponses(), compareResponses+1);
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/core/DeleteOperationTestCase.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/core/DeleteOperationTestCase.java
index 2f5c32c..19c4bd5 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/core/DeleteOperationTestCase.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/core/DeleteOperationTestCase.java
@@ -41,8 +41,6 @@
 import org.opends.server.api.Backend;
 import org.opends.server.plugins.DisconnectClientPlugin;
 import org.opends.server.plugins.ShortCircuitPlugin;
-import org.opends.server.protocols.asn1.ASN1Element;
-import org.opends.server.protocols.asn1.ASN1OctetString;
 import org.opends.server.protocols.asn1.ASN1Reader;
 import org.opends.server.protocols.asn1.ASN1Writer;
 import org.opends.server.protocols.internal.InternalClientConnection;
@@ -51,6 +49,7 @@
 import org.opends.server.protocols.ldap.DeleteRequestProtocolOp;
 import org.opends.server.protocols.ldap.LDAPMessage;
 import org.opends.server.tools.LDAPDelete;
+import org.opends.server.tools.LDAPWriter;
 import org.opends.server.types.*;
 import org.opends.server.workflowelement.localbackend.LocalBackendDeleteOperation;
 
@@ -87,14 +86,14 @@
     return new Operation[]
     {
       new DeleteOperationBasis(conn, conn.nextOperationID(), conn.nextMessageID(),
-                          new ArrayList<Control>(), new ASN1OctetString()),
+                          new ArrayList<Control>(), ByteString.empty()),
       new DeleteOperationBasis(conn, conn.nextOperationID(), conn.nextMessageID(),
-                          null, new ASN1OctetString()),
+                          null, ByteString.empty()),
       new DeleteOperationBasis(conn, conn.nextOperationID(), conn.nextMessageID(),
                           new ArrayList<Control>(),
-                          new ASN1OctetString("o=test")),
+                          ByteString.valueOf("o=test")),
       new DeleteOperationBasis(conn, conn.nextOperationID(), conn.nextMessageID(),
-                          null, new ASN1OctetString("o=test")),
+                          null, ByteString.valueOf("o=test")),
       new DeleteOperationBasis(conn, conn.nextOperationID(), conn.nextMessageID(),
                           new ArrayList<Control>(), DN.nullDN()),
       new DeleteOperationBasis(conn, conn.nextOperationID(), conn.nextMessageID(),
@@ -120,9 +119,9 @@
     ByteString originalRawDN = deleteOperation.getRawEntryDN();
     assertNotNull(originalRawDN);
 
-    deleteOperation.setRawEntryDN(new ASN1OctetString("dc=example,dc=com"));
+    deleteOperation.setRawEntryDN(ByteString.valueOf("dc=example,dc=com"));
     assertEquals(deleteOperation.getRawEntryDN(),
-                 new ASN1OctetString("dc=example,dc=com"));
+                 ByteString.valueOf("dc=example,dc=com"));
 
     deleteOperation.setRawEntryDN(originalRawDN);
     assertEquals(deleteOperation.getRawEntryDN(), originalRawDN);
@@ -142,7 +141,7 @@
 
     DeleteOperation deleteOperation =
          new DeleteOperationBasis(conn, conn.nextOperationID(), conn.nextMessageID(),
-                             null, new ASN1OctetString("o=test"));
+                             null, ByteString.valueOf("o=test"));
     assertNotNull(deleteOperation.getEntryDN());
   }
 
@@ -189,7 +188,7 @@
                              null, DN.decode("o=test"));
     assertNotNull(deleteOperation.getEntryDN());
 
-    deleteOperation.setRawEntryDN(new ASN1OctetString("dc=example,dc=com"));
+    deleteOperation.setRawEntryDN(ByteString.valueOf("dc=example,dc=com"));
     assertNotNull(deleteOperation.getEntryDN());
   }
 
@@ -232,7 +231,7 @@
          InternalClientConnection.getRootConnection();
 
     DeleteOperation deleteOperation =
-         conn.processDelete(new ASN1OctetString("o=test"));
+         conn.processDelete(ByteString.valueOf("o=test"));
     assertEquals(deleteOperation.getResultCode(), ResultCode.SUCCESS);
     retrieveCompletedOperationElements(deleteOperation);
     List localOps =
@@ -262,7 +261,7 @@
          InternalClientConnection.getRootConnection();
 
     DeleteOperation deleteOperation =
-         conn.processDelete(new ASN1OctetString("ou=People,o=test"));
+         conn.processDelete(ByteString.valueOf("ou=People,o=test"));
     assertFalse(deleteOperation.getResultCode() == ResultCode.SUCCESS);
     List localOps =
       (List) (deleteOperation.getAttachment(Operation.LOCALBACKENDOPERATIONS));
@@ -314,7 +313,7 @@
          InternalClientConnection.getRootConnection();
 
     DeleteOperation deleteOperation =
-         conn.processDelete(new ASN1OctetString("o=test"));
+         conn.processDelete(ByteString.valueOf("o=test"));
     assertEquals(deleteOperation.getResultCode(), ResultCode.SUCCESS);
     retrieveCompletedOperationElements(deleteOperation);
   }
@@ -368,7 +367,7 @@
 
 
     DeleteOperation deleteOperation =
-         conn.processDelete(new ASN1OctetString("cn=test,o=test"));
+         conn.processDelete(ByteString.valueOf("cn=test,o=test"));
     assertEquals(deleteOperation.getResultCode(), ResultCode.SUCCESS);
     retrieveCompletedOperationElements(deleteOperation);
   }
@@ -422,7 +421,7 @@
          InternalClientConnection.getRootConnection();
 
     DeleteOperation deleteOperation =
-         conn.processDelete(new ASN1OctetString("malformed"));
+         conn.processDelete(ByteString.valueOf("malformed"));
     assertFalse(deleteOperation.getResultCode() == ResultCode.SUCCESS);
   }
 
@@ -444,7 +443,7 @@
          InternalClientConnection.getRootConnection();
 
     DeleteOperation deleteOperation =
-         conn.processDelete(new ASN1OctetString("o=does not exist"));
+         conn.processDelete(ByteString.valueOf("o=does not exist"));
     assertFalse(deleteOperation.getResultCode() == ResultCode.SUCCESS);
   }
 
@@ -487,7 +486,7 @@
          InternalClientConnection.getRootConnection();
 
     DeleteOperation deleteOperation =
-         conn.processDelete(new ASN1OctetString("cn=entry,o=does not exist"));
+         conn.processDelete(ByteString.valueOf("cn=entry,o=does not exist"));
     assertFalse(deleteOperation.getResultCode() == ResultCode.SUCCESS);
   }
 
@@ -531,7 +530,7 @@
          InternalClientConnection.getRootConnection();
 
     DeleteOperation deleteOperation =
-         conn.processDelete(new ASN1OctetString("cn=entry,o=test"));
+         conn.processDelete(ByteString.valueOf("cn=entry,o=test"));
     assertFalse(deleteOperation.getResultCode() == ResultCode.SUCCESS);
   }
 
@@ -584,7 +583,7 @@
 
 
     DeleteOperation deleteOperation =
-         conn.processDelete(new ASN1OctetString("o=test"));
+         conn.processDelete(ByteString.valueOf("o=test"));
     assertFalse(deleteOperation.getResultCode() == ResultCode.SUCCESS);
   }
 
@@ -615,7 +614,7 @@
 
 
     DeleteOperation deleteOperation =
-         conn.processDelete(new ASN1OctetString("o=test"));
+         conn.processDelete(ByteString.valueOf("o=test"));
     assertFalse(deleteOperation.getResultCode() == ResultCode.SUCCESS);
   }
 
@@ -639,7 +638,7 @@
     DirectoryServer.setWritabilityMode(WritabilityMode.DISABLED);
 
     DeleteOperation deleteOperation =
-         conn.processDelete(new ASN1OctetString("o=test"));
+         conn.processDelete(ByteString.valueOf("o=test"));
     assertFalse(deleteOperation.getResultCode() == ResultCode.SUCCESS);
 
     DirectoryServer.setWritabilityMode(WritabilityMode.ENABLED);
@@ -665,7 +664,7 @@
     DirectoryServer.setWritabilityMode(WritabilityMode.INTERNAL_ONLY);
 
     DeleteOperation deleteOperation =
-         conn.processDelete(new ASN1OctetString("o=test"));
+         conn.processDelete(ByteString.valueOf("o=test"));
     assertEquals(deleteOperation.getResultCode(), ResultCode.SUCCESS);
 
     DirectoryServer.setWritabilityMode(WritabilityMode.ENABLED);
@@ -721,7 +720,7 @@
     backend.setWritabilityMode(WritabilityMode.DISABLED);
 
     DeleteOperation deleteOperation =
-         conn.processDelete(new ASN1OctetString("o=test"));
+         conn.processDelete(ByteString.valueOf("o=test"));
     assertFalse(deleteOperation.getResultCode() == ResultCode.SUCCESS);
 
     backend.setWritabilityMode(WritabilityMode.ENABLED);
@@ -748,7 +747,7 @@
     backend.setWritabilityMode(WritabilityMode.INTERNAL_ONLY);
 
     DeleteOperation deleteOperation =
-         conn.processDelete(new ASN1OctetString("o=test"));
+         conn.processDelete(ByteString.valueOf("o=test"));
     assertEquals(deleteOperation.getResultCode(), ResultCode.SUCCESS);
 
     backend.setWritabilityMode(WritabilityMode.ENABLED);
@@ -802,7 +801,7 @@
 
     DeleteOperationBasis deleteOperation =
          new DeleteOperationBasis(conn, conn.nextOperationID(), conn.nextMessageID(),
-                             null, new ASN1OctetString("o=test"));
+                             null, ByteString.valueOf("o=test"));
 
     CancelRequest cancelRequest = new CancelRequest(false,
                                                     Message.raw("testCancelBeforeStartup"));
@@ -827,7 +826,7 @@
 
     DeleteOperationBasis deleteOperation =
          new DeleteOperationBasis(conn, conn.nextOperationID(), conn.nextMessageID(),
-                             null, new ASN1OctetString("o=test"));
+                             null, ByteString.valueOf("o=test"));
 
     deleteOperation.run();
 
@@ -861,7 +860,7 @@
            InternalClientConnection.getRootConnection();
 
       DeleteOperation deleteOperation =
-           conn.processDelete(new ASN1OctetString("o=test"));
+           conn.processDelete(ByteString.valueOf("o=test"));
       assertFalse(deleteOperation.getResultCode() == ResultCode.SUCCESS);
     }
     finally
@@ -884,34 +883,33 @@
     TestCaseUtils.initializeTestBackend(true);
 
     Socket s = new Socket("127.0.0.1", TestCaseUtils.getServerLdapPort());
-    ASN1Reader r = new ASN1Reader(s);
-    ASN1Writer w = new ASN1Writer(s);
-    r.setIOTimeout(5000);
+    org.opends.server.tools.LDAPReader r = new org.opends.server.tools.LDAPReader(s);
+    LDAPWriter w = new LDAPWriter(s);
+    s.setSoTimeout(5000);
 
     BindRequestProtocolOp bindRequest =
-         new BindRequestProtocolOp(new ASN1OctetString("cn=Directory Manager"),
-                                   3, new ASN1OctetString("password"));
+         new BindRequestProtocolOp(ByteString.valueOf("cn=Directory Manager"),
+                                   3, ByteString.valueOf("password"));
     LDAPMessage message = new LDAPMessage(1, bindRequest);
-    w.writeElement(message.encode());
+    w.writeMessage(message);
 
-    message = LDAPMessage.decode(r.readElement().decodeAsSequence());
+    message = r.readMessage();
     BindResponseProtocolOp bindResponse =
          message.getBindResponseProtocolOp();
     assertEquals(bindResponse.getResultCode(), 0);
 
 
     DeleteRequestProtocolOp deleteRequest =
-         new DeleteRequestProtocolOp(new ASN1OctetString("o=test"));
+         new DeleteRequestProtocolOp(ByteString.valueOf("o=test"));
     message = new LDAPMessage(2, deleteRequest,
-         DisconnectClientPlugin.createDisconnectLDAPControlList("PreParse"));
-    w.writeElement(message.encode());
+         DisconnectClientPlugin.createDisconnectControlList("PreParse"));
+    w.writeMessage(message);
 
-    ASN1Element element = r.readElement();
-    if (element != null)
+    message = r.readMessage();
+    if (message != null)
     {
       // If we got an element back, then it must be a notice of disconnect
       // unsolicited notification.
-      message = LDAPMessage.decode(element.decodeAsSequence());
       assertEquals(message.getProtocolOpType(), OP_TYPE_EXTENDED_RESPONSE);
     }
 
@@ -936,35 +934,34 @@
     TestCaseUtils.initializeTestBackend(true);
 
     Socket s = new Socket("127.0.0.1", TestCaseUtils.getServerLdapPort());
-    ASN1Reader r = new ASN1Reader(s);
-    ASN1Writer w = new ASN1Writer(s);
-    r.setIOTimeout(5000);
+    org.opends.server.tools.LDAPReader r = new org.opends.server.tools.LDAPReader(s);
+    LDAPWriter w = new LDAPWriter(s);
+    s.setSoTimeout(5000);
 
     BindRequestProtocolOp bindRequest =
-         new BindRequestProtocolOp(new ASN1OctetString("cn=Directory Manager"),
-                                   3, new ASN1OctetString("password"));
+         new BindRequestProtocolOp(ByteString.valueOf("cn=Directory Manager"),
+                                   3, ByteString.valueOf("password"));
     LDAPMessage message = new LDAPMessage(1, bindRequest);
-    w.writeElement(message.encode());
+    w.writeMessage(message);
 
-    message = LDAPMessage.decode(r.readElement().decodeAsSequence());
+    message = r.readMessage();
     BindResponseProtocolOp bindResponse =
          message.getBindResponseProtocolOp();
     assertEquals(bindResponse.getResultCode(), 0);
 
 
     DeleteRequestProtocolOp deleteRequest =
-         new DeleteRequestProtocolOp(new ASN1OctetString("o=test"));
+         new DeleteRequestProtocolOp(ByteString.valueOf("o=test"));
     message = new LDAPMessage(2, deleteRequest,
-         DisconnectClientPlugin.createDisconnectLDAPControlList(
+         DisconnectClientPlugin.createDisconnectControlList(
               "PreOperation"));
-    w.writeElement(message.encode());
+    w.writeMessage(message);
 
-    ASN1Element element = r.readElement();
-    if (element != null)
+    message = r.readMessage();
+    if (message != null)
     {
       // If we got an element back, then it must be a notice of disconnect
       // unsolicited notification.
-      message = LDAPMessage.decode(element.decodeAsSequence());
       assertEquals(message.getProtocolOpType(), OP_TYPE_EXTENDED_RESPONSE);
     }
 
@@ -989,35 +986,34 @@
     TestCaseUtils.initializeTestBackend(true);
 
     Socket s = new Socket("127.0.0.1", TestCaseUtils.getServerLdapPort());
-    ASN1Reader r = new ASN1Reader(s);
-    ASN1Writer w = new ASN1Writer(s);
-    r.setIOTimeout(5000);
+    org.opends.server.tools.LDAPReader r = new org.opends.server.tools.LDAPReader(s);
+    LDAPWriter w = new LDAPWriter(s);
+    s.setSoTimeout(5000);
 
     BindRequestProtocolOp bindRequest =
-         new BindRequestProtocolOp(new ASN1OctetString("cn=Directory Manager"),
-                                   3, new ASN1OctetString("password"));
+         new BindRequestProtocolOp(ByteString.valueOf("cn=Directory Manager"),
+                                   3, ByteString.valueOf("password"));
     LDAPMessage message = new LDAPMessage(1, bindRequest);
-    w.writeElement(message.encode());
+    w.writeMessage(message);
 
-    message = LDAPMessage.decode(r.readElement().decodeAsSequence());
+    message = r.readMessage();
     BindResponseProtocolOp bindResponse =
          message.getBindResponseProtocolOp();
     assertEquals(bindResponse.getResultCode(), 0);
 
 
     DeleteRequestProtocolOp deleteRequest =
-         new DeleteRequestProtocolOp(new ASN1OctetString("o=test"));
+         new DeleteRequestProtocolOp(ByteString.valueOf("o=test"));
     message = new LDAPMessage(2, deleteRequest,
-         DisconnectClientPlugin.createDisconnectLDAPControlList(
+         DisconnectClientPlugin.createDisconnectControlList(
               "PostOperation"));
-    w.writeElement(message.encode());
+    w.writeMessage(message);
 
-    ASN1Element element = r.readElement();
-    if (element != null)
+    message = r.readMessage();
+    if (message != null)
     {
       // If we got an element back, then it must be a notice of disconnect
       // unsolicited notification.
-      message = LDAPMessage.decode(element.decodeAsSequence());
       assertEquals(message.getProtocolOpType(), OP_TYPE_EXTENDED_RESPONSE);
     }
 
@@ -1042,40 +1038,39 @@
     TestCaseUtils.initializeTestBackend(true);
 
     Socket s = new Socket("127.0.0.1", TestCaseUtils.getServerLdapPort());
-    ASN1Reader r = new ASN1Reader(s);
-    ASN1Writer w = new ASN1Writer(s);
-    r.setIOTimeout(5000);
+    org.opends.server.tools.LDAPReader r = new org.opends.server.tools.LDAPReader(s);
+    LDAPWriter w = new LDAPWriter(s);
+    s.setSoTimeout(5000);
 
     BindRequestProtocolOp bindRequest =
-         new BindRequestProtocolOp(new ASN1OctetString("cn=Directory Manager"),
-                                   3, new ASN1OctetString("password"));
+         new BindRequestProtocolOp(ByteString.valueOf("cn=Directory Manager"),
+                                   3, ByteString.valueOf("password"));
     LDAPMessage message = new LDAPMessage(1, bindRequest);
-    w.writeElement(message.encode());
+    w.writeMessage(message);
 
-    message = LDAPMessage.decode(r.readElement().decodeAsSequence());
+    message = r.readMessage();
     BindResponseProtocolOp bindResponse =
          message.getBindResponseProtocolOp();
     assertEquals(bindResponse.getResultCode(), 0);
 
 
     DeleteRequestProtocolOp deleteRequest =
-         new DeleteRequestProtocolOp(new ASN1OctetString("o=test"));
+         new DeleteRequestProtocolOp(ByteString.valueOf("o=test"));
     message = new LDAPMessage(2, deleteRequest,
-         DisconnectClientPlugin.createDisconnectLDAPControlList(
+         DisconnectClientPlugin.createDisconnectControlList(
               "PostResponse"));
-    w.writeElement(message.encode());
+    w.writeMessage(message);
 
 responseLoop:
     while (true)
     {
-      ASN1Element element = r.readElement();
-      if (element == null)
+      message = r.readMessage();
+      if (message == null)
       {
         // The connection has been closed.
         break responseLoop;
       }
 
-      message = LDAPMessage.decode(element.decodeAsSequence());
       switch (message.getProtocolOpType())
       {
         case OP_TYPE_DELETE_RESPONSE:
@@ -1127,7 +1122,7 @@
          InternalClientConnection.getRootConnection();
 
     DeleteOperation deleteOperation =
-         conn.processDelete(new ASN1OctetString("o=test"));
+         conn.processDelete(ByteString.valueOf("o=test"));
     assertEquals(deleteOperation.getResultCode(), ResultCode.SUCCESS);
     retrieveCompletedOperationElements(deleteOperation);
 
@@ -1158,7 +1153,7 @@
          InternalClientConnection.getRootConnection();
 
     DeleteOperation deleteOperation =
-         conn.processDelete(new ASN1OctetString("cn=nonexistent,o=test"));
+         conn.processDelete(ByteString.valueOf("cn=nonexistent,o=test"));
     assertFalse(deleteOperation.getResultCode() == ResultCode.SUCCESS);
 
     assertEquals(changeListener.getDeleteCount(), 0);
@@ -1187,7 +1182,7 @@
 
     DeleteOperationBasis deleteOperation =
          new DeleteOperationBasis(conn, conn.nextOperationID(), conn.nextMessageID(),
-                             controls, new ASN1OctetString("o=test"));
+                             controls, ByteString.valueOf("o=test"));
     deleteOperation.run();
     assertEquals(deleteOperation.getResultCode(), ResultCode.SUCCESS);
     assertTrue(DirectoryServer.entryExists(DN.decode("o=test")));
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/core/IdleTimeLimitTestCase.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/core/IdleTimeLimitTestCase.java
index af5fa5d..fd02655 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/core/IdleTimeLimitTestCase.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/core/IdleTimeLimitTestCase.java
@@ -34,9 +34,11 @@
 import org.testng.annotations.Test;
 
 import org.opends.server.TestCaseUtils;
+import org.opends.server.types.ByteString;
 import org.opends.server.protocols.asn1.*;
 import org.opends.server.protocols.ldap.*;
 import org.opends.server.tools.dsconfig.DSConfig;
+import org.opends.server.tools.LDAPWriter;
 
 import static org.testng.Assert.*;
 
@@ -81,17 +83,17 @@
     try
     {
       s = new Socket("127.0.0.1", TestCaseUtils.getServerLdapPort());
-      ASN1Writer w = new ASN1Writer(s);
-      ASN1Reader r = new ASN1Reader(s);
-      r.setIOTimeout(60000);
+      LDAPWriter w = new LDAPWriter(s);
+      org.opends.server.tools.LDAPReader r = new org.opends.server.tools.LDAPReader(s);
+      s.setSoTimeout(60000);
 
-      LDAPMessage m = LDAPMessage.decode(r.readElement().decodeAsSequence());
+      LDAPMessage m = r.readMessage();
       ExtendedResponseProtocolOp extendedResponse =
            m.getExtendedResponseProtocolOp();
       assertEquals(extendedResponse.getOID(),
                    LDAPConstants.OID_NOTICE_OF_DISCONNECTION);
 
-      assertNull(r.readElement());
+      assertNull(r.readMessage());
     }
     finally
     {
@@ -141,30 +143,30 @@
     try
     {
       s = new Socket("127.0.0.1", TestCaseUtils.getServerLdapPort());
-      ASN1Writer w = new ASN1Writer(s);
-      ASN1Reader r = new ASN1Reader(s);
-      r.setIOTimeout(60000);
+      LDAPWriter w = new LDAPWriter(s);
+      org.opends.server.tools.LDAPReader r = new org.opends.server.tools.LDAPReader(s);
+      s.setSoTimeout(60000);
 
 
       BindRequestProtocolOp bindRequest = new BindRequestProtocolOp(
-           new ASN1OctetString("uid=test.user,o=test"), 3,
-           new ASN1OctetString("password"));
+           ByteString.valueOf("uid=test.user,o=test"), 3,
+           ByteString.valueOf("password"));
       LDAPMessage m = new LDAPMessage(1, bindRequest);
-      w.writeElement(m.encode());
+      w.writeMessage(m);
 
 
-      m = LDAPMessage.decode(r.readElement().decodeAsSequence());
+      m = r.readMessage();
       BindResponseProtocolOp bindResponse = m.getBindResponseProtocolOp();
       assertEquals(bindResponse.getResultCode(), 0);
 
 
-      m = LDAPMessage.decode(r.readElement().decodeAsSequence());
+      m = r.readMessage();
       ExtendedResponseProtocolOp extendedResponse =
            m.getExtendedResponseProtocolOp();
       assertEquals(extendedResponse.getOID(),
                    LDAPConstants.OID_NOTICE_OF_DISCONNECTION);
 
-      assertNull(r.readElement());
+      assertNull(r.readMessage());
     }
     finally
     {
@@ -210,30 +212,30 @@
     try
     {
       s = new Socket("127.0.0.1", TestCaseUtils.getServerLdapPort());
-      ASN1Writer w = new ASN1Writer(s);
-      ASN1Reader r = new ASN1Reader(s);
-      r.setIOTimeout(60000);
+      LDAPWriter w = new LDAPWriter(s);
+      org.opends.server.tools.LDAPReader r = new org.opends.server.tools.LDAPReader(s);
+      s.setSoTimeout(60000);
 
 
       BindRequestProtocolOp bindRequest = new BindRequestProtocolOp(
-           new ASN1OctetString("uid=test.user,o=test"), 3,
-           new ASN1OctetString("password"));
+           ByteString.valueOf("uid=test.user,o=test"), 3,
+           ByteString.valueOf("password"));
       LDAPMessage m = new LDAPMessage(1, bindRequest);
-      w.writeElement(m.encode());
+      w.writeMessage(m);
 
 
-      m = LDAPMessage.decode(r.readElement().decodeAsSequence());
+      m = r.readMessage();
       BindResponseProtocolOp bindResponse = m.getBindResponseProtocolOp();
       assertEquals(bindResponse.getResultCode(), 0);
 
 
-      m = LDAPMessage.decode(r.readElement().decodeAsSequence());
+      m = r.readMessage();
       ExtendedResponseProtocolOp extendedResponse =
            m.getExtendedResponseProtocolOp();
       assertEquals(extendedResponse.getOID(),
                    LDAPConstants.OID_NOTICE_OF_DISCONNECTION);
 
-      assertNull(r.readElement());
+      assertNull(r.readMessage());
     }
     finally
     {
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/core/ModifyOperationTestCase.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/core/ModifyOperationTestCase.java
index b6719b5..ae7100a 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/core/ModifyOperationTestCase.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/core/ModifyOperationTestCase.java
@@ -44,8 +44,6 @@
 import org.opends.server.plugins.DisconnectClientPlugin;
 import org.opends.server.plugins.ShortCircuitPlugin;
 import org.opends.server.plugins.UpdatePreOpPlugin;
-import org.opends.server.protocols.asn1.ASN1Element;
-import org.opends.server.protocols.asn1.ASN1OctetString;
 import org.opends.server.protocols.asn1.ASN1Reader;
 import org.opends.server.protocols.asn1.ASN1Writer;
 import org.opends.server.protocols.internal.InternalClientConnection;
@@ -59,6 +57,7 @@
 import org.opends.server.protocols.ldap.LDAPModification;
 import org.opends.server.protocols.ldap.LDAPFilter;
 import org.opends.server.tools.LDAPModify;
+import org.opends.server.tools.LDAPWriter;
 import org.opends.server.types.*;
 import org.opends.server.workflowelement.localbackend.LocalBackendModifyOperation;
 
@@ -111,75 +110,75 @@
 
 
     ArrayList<RawModification> ldapMods = new ArrayList<RawModification>();
-    ArrayList<ASN1OctetString> ldapValues = new ArrayList<ASN1OctetString>();
-    ldapValues.add(new ASN1OctetString("foo"));
+    ArrayList<ByteString> ldapValues = new ArrayList<ByteString>();
+    ldapValues.add(ByteString.valueOf("foo"));
     LDAPAttribute ldapAttr = new LDAPAttribute("description", ldapValues);
     ldapMods.add(new LDAPModification(ModificationType.ADD, ldapAttr));
 
     opList.add(new ModifyOperationBasis(conn, conn.nextOperationID(),
                                    conn.nextMessageID(), null,
-                                   new ASN1OctetString(), ldapMods));
+                                   ByteString.empty(), ldapMods));
     opList.add(new ModifyOperationBasis(conn, conn.nextOperationID(),
                                    conn.nextMessageID(), noControls,
-                                   new ASN1OctetString(), ldapMods));
+                                   ByteString.empty(), ldapMods));
     opList.add(new ModifyOperationBasis(conn, conn.nextOperationID(),
                                    conn.nextMessageID(), null,
-                                   new ASN1OctetString("o=test"), ldapMods));
+                                   ByteString.valueOf("o=test"), ldapMods));
     opList.add(new ModifyOperationBasis(conn, conn.nextOperationID(),
                                    conn.nextMessageID(), noControls,
-                                   new ASN1OctetString("o=test"), ldapMods));
+                                   ByteString.valueOf("o=test"), ldapMods));
 
     ldapMods = new ArrayList<RawModification>();
     ldapMods.add(new LDAPModification(ModificationType.DELETE, ldapAttr));
 
     opList.add(new ModifyOperationBasis(conn, conn.nextOperationID(),
                                    conn.nextMessageID(), null,
-                                   new ASN1OctetString(), ldapMods));
+                                   ByteString.empty(), ldapMods));
     opList.add(new ModifyOperationBasis(conn, conn.nextOperationID(),
                                    conn.nextMessageID(), noControls,
-                                   new ASN1OctetString(), ldapMods));
+                                   ByteString.empty(), ldapMods));
     opList.add(new ModifyOperationBasis(conn, conn.nextOperationID(),
                                    conn.nextMessageID(), null,
-                                   new ASN1OctetString("o=test"), ldapMods));
+                                   ByteString.valueOf("o=test"), ldapMods));
     opList.add(new ModifyOperationBasis(conn, conn.nextOperationID(),
                                    conn.nextMessageID(), noControls,
-                                   new ASN1OctetString("o=test"), ldapMods));
+                                   ByteString.valueOf("o=test"), ldapMods));
 
     ldapMods = new ArrayList<RawModification>();
     ldapMods.add(new LDAPModification(ModificationType.REPLACE, ldapAttr));
 
     opList.add(new ModifyOperationBasis(conn, conn.nextOperationID(),
                                    conn.nextMessageID(), null,
-                                   new ASN1OctetString(), ldapMods));
+                                   ByteString.empty(), ldapMods));
     opList.add(new ModifyOperationBasis(conn, conn.nextOperationID(),
                                    conn.nextMessageID(), noControls,
-                                   new ASN1OctetString(), ldapMods));
+                                   ByteString.empty(), ldapMods));
     opList.add(new ModifyOperationBasis(conn, conn.nextOperationID(),
                                    conn.nextMessageID(), null,
-                                   new ASN1OctetString("o=test"), ldapMods));
+                                   ByteString.valueOf("o=test"), ldapMods));
     opList.add(new ModifyOperationBasis(conn, conn.nextOperationID(),
                                    conn.nextMessageID(), noControls,
-                                   new ASN1OctetString("o=test"), ldapMods));
+                                   ByteString.valueOf("o=test"), ldapMods));
 
     ldapMods = new ArrayList<RawModification>();
-    ArrayList<ASN1OctetString> values2 = new ArrayList<ASN1OctetString>();
-    values2.add(new ASN1OctetString("bar"));
+    ArrayList<ByteString> values2 = new ArrayList<ByteString>();
+    values2.add(ByteString.valueOf("bar"));
     LDAPAttribute ldapAttr2 = new LDAPAttribute("description", values2);
     ldapMods.add(new LDAPModification(ModificationType.DELETE, ldapAttr));
     ldapMods.add(new LDAPModification(ModificationType.ADD, ldapAttr2));
 
     opList.add(new ModifyOperationBasis(conn, conn.nextOperationID(),
                                    conn.nextMessageID(), null,
-                                   new ASN1OctetString(), ldapMods));
+                                   ByteString.empty(), ldapMods));
     opList.add(new ModifyOperationBasis(conn, conn.nextOperationID(),
                                    conn.nextMessageID(), noControls,
-                                   new ASN1OctetString(), ldapMods));
+                                   ByteString.empty(), ldapMods));
     opList.add(new ModifyOperationBasis(conn, conn.nextOperationID(),
                                    conn.nextMessageID(), null,
-                                   new ASN1OctetString("o=test"), ldapMods));
+                                   ByteString.valueOf("o=test"), ldapMods));
     opList.add(new ModifyOperationBasis(conn, conn.nextOperationID(),
                                    conn.nextMessageID(), noControls,
-                                   new ASN1OctetString("o=test"), ldapMods));
+                                   ByteString.valueOf("o=test"), ldapMods));
 
     ldapMods = new ArrayList<RawModification>();
     ldapAttr2 = new LDAPAttribute("cn", values2);
@@ -188,16 +187,16 @@
 
     opList.add(new ModifyOperationBasis(conn, conn.nextOperationID(),
                                    conn.nextMessageID(), null,
-                                   new ASN1OctetString(), ldapMods));
+                                   ByteString.empty(), ldapMods));
     opList.add(new ModifyOperationBasis(conn, conn.nextOperationID(),
                                    conn.nextMessageID(), noControls,
-                                   new ASN1OctetString(), ldapMods));
+                                   ByteString.empty(), ldapMods));
     opList.add(new ModifyOperationBasis(conn, conn.nextOperationID(),
                                    conn.nextMessageID(), null,
-                                   new ASN1OctetString("o=test"), ldapMods));
+                                   ByteString.valueOf("o=test"), ldapMods));
     opList.add(new ModifyOperationBasis(conn, conn.nextOperationID(),
                                    conn.nextMessageID(), noControls,
-                                   new ASN1OctetString("o=test"), ldapMods));
+                                   ByteString.valueOf("o=test"), ldapMods));
 
 
 
@@ -343,10 +342,10 @@
     ByteString originalDN = modifyOperation.getRawEntryDN();
     assertNotNull(originalDN);
 
-    modifyOperation.setRawEntryDN(new ASN1OctetString("uid=test,o=test"));
+    modifyOperation.setRawEntryDN(ByteString.valueOf("uid=test,o=test"));
     assertNotNull(modifyOperation.getRawEntryDN());
     assertEquals(modifyOperation.getRawEntryDN(),
-                 new ASN1OctetString("uid=test,o=test"));
+                 ByteString.valueOf("uid=test,o=test"));
 
     modifyOperation.setRawEntryDN(originalDN);
     assertNotNull(modifyOperation.getRawEntryDN());
@@ -365,8 +364,8 @@
     InternalClientConnection conn =
          InternalClientConnection.getRootConnection();
 
-    ArrayList<ASN1OctetString> values = new ArrayList<ASN1OctetString>();
-    values.add(new ASN1OctetString("foo"));
+    ArrayList<ByteString> values = new ArrayList<ByteString>();
+    values.add(ByteString.valueOf("foo"));
     LDAPAttribute attr = new LDAPAttribute("description", values);
 
     ArrayList<RawModification> mods = new ArrayList<RawModification>();
@@ -374,7 +373,7 @@
 
     ModifyOperation modifyOperation =
          new ModifyOperationBasis(conn, conn.nextOperationID(), conn.nextMessageID(),
-                             null, new ASN1OctetString(), mods);
+                             null, ByteString.empty(), mods);
     assertNotNull(modifyOperation.getEntryDN());
   }
 
@@ -426,7 +425,7 @@
                              null, DN.nullDN(), mods);
     assertNotNull(modifyOperation.getEntryDN());
 
-    modifyOperation.setRawEntryDN(new ASN1OctetString("ou=Users,o=test"));
+    modifyOperation.setRawEntryDN(ByteString.valueOf("ou=Users,o=test"));
     assertNotNull(modifyOperation.getEntryDN());
   }
 
@@ -449,8 +448,8 @@
          new ArrayList<RawModification>(rawMods);
     modifyOperation.setRawModifications(clonedMods);
 
-    ArrayList<ASN1OctetString> values = new ArrayList<ASN1OctetString>();
-    values.add(new ASN1OctetString("test"));
+    ArrayList<ByteString> values = new ArrayList<ByteString>();
+    values.add(ByteString.valueOf("test"));
     LDAPAttribute attr = new LDAPAttribute("test", values);
 
     LDAPModification mod = new LDAPModification(ModificationType.REPLACE, attr);
@@ -572,15 +571,15 @@
     InternalClientConnection conn =
          InternalClientConnection.getRootConnection();
 
-    ArrayList<ASN1OctetString> values = new ArrayList<ASN1OctetString>();
-    values.add(new ASN1OctetString("foo"));
+    ArrayList<ByteString> values = new ArrayList<ByteString>();
+    values.add(ByteString.valueOf("foo"));
     LDAPAttribute attr = new LDAPAttribute("description", values);
 
     ArrayList<RawModification> mods = new ArrayList<RawModification>();
     mods.add(new LDAPModification(ModificationType.REPLACE, attr));
 
     ModifyOperation modifyOperation =
-         conn.processModify(new ASN1OctetString("invaliddn"), mods);
+         conn.processModify(ByteString.valueOf("invaliddn"), mods);
     assertFalse(modifyOperation.getResultCode() == ResultCode.SUCCESS);
     retrieveFailedOperationElements(modifyOperation);
   }
@@ -597,15 +596,15 @@
     InternalClientConnection conn =
          InternalClientConnection.getRootConnection();
 
-    ArrayList<ASN1OctetString> values = new ArrayList<ASN1OctetString>();
-    values.add(new ASN1OctetString("foo"));
+    ArrayList<ByteString> values = new ArrayList<ByteString>();
+    values.add(ByteString.valueOf("foo"));
     LDAPAttribute attr = new LDAPAttribute("description", values);
 
     ArrayList<RawModification> mods = new ArrayList<RawModification>();
     mods.add(new LDAPModification(ModificationType.REPLACE, attr));
 
     ModifyOperation modifyOperation =
-         conn.processModify(new ASN1OctetString("o=nonexistent"), mods);
+         conn.processModify(ByteString.valueOf("o=nonexistent"), mods);
     assertFalse(modifyOperation.getResultCode() == ResultCode.SUCCESS);
     retrieveFailedOperationElements(modifyOperation);
   }
@@ -627,8 +626,8 @@
     InternalClientConnection conn =
          InternalClientConnection.getRootConnection();
 
-    ArrayList<ASN1OctetString> values = new ArrayList<ASN1OctetString>();
-    values.add(new ASN1OctetString("foo"));
+    ArrayList<ByteString> values = new ArrayList<ByteString>();
+    values.add(ByteString.valueOf("foo"));
     LDAPAttribute attr = new LDAPAttribute("description", values);
 
     ArrayList<RawModification> mods = new ArrayList<RawModification>();
@@ -636,7 +635,7 @@
 
     ModifyOperation modifyOperation =
          conn.processModify(
-              new ASN1OctetString("cn=test,ou=nosuchparent," + baseDN), mods);
+              ByteString.valueOf("cn=test,ou=nosuchparent," + baseDN), mods);
     assertFalse(modifyOperation.getResultCode() == ResultCode.SUCCESS);
     retrieveFailedOperationElements(modifyOperation);
   }
@@ -658,15 +657,15 @@
     InternalClientConnection conn =
          InternalClientConnection.getRootConnection();
 
-    ArrayList<ASN1OctetString> values = new ArrayList<ASN1OctetString>();
-    values.add(new ASN1OctetString("foo"));
+    ArrayList<ByteString> values = new ArrayList<ByteString>();
+    values.add(ByteString.valueOf("foo"));
     LDAPAttribute attr = new LDAPAttribute("description", values);
 
     ArrayList<RawModification> mods = new ArrayList<RawModification>();
     mods.add(new LDAPModification(ModificationType.REPLACE, attr));
 
     ModifyOperation modifyOperation =
-         conn.processModify(new ASN1OctetString("cn=nosuchentry," + baseDN),
+         conn.processModify(ByteString.valueOf("cn=nosuchentry," + baseDN),
                             mods);
     assertFalse(modifyOperation.getResultCode() == ResultCode.SUCCESS);
     retrieveFailedOperationElements(modifyOperation);
@@ -692,7 +691,7 @@
     ArrayList<RawModification> mods = new ArrayList<RawModification>();
 
     ModifyOperation modifyOperation =
-         conn.processModify(new ASN1OctetString(baseDN), mods);
+         conn.processModify(ByteString.valueOf(baseDN), mods);
     assertFalse(modifyOperation.getResultCode() == ResultCode.SUCCESS);
     retrieveFailedOperationElements(modifyOperation);
   }
@@ -718,15 +717,15 @@
     InternalClientConnection conn =
          InternalClientConnection.getRootConnection();
 
-    ArrayList<ASN1OctetString> values = new ArrayList<ASN1OctetString>();
-    values.add(new ASN1OctetString("foo"));
+    ArrayList<ByteString> values = new ArrayList<ByteString>();
+    values.add(ByteString.valueOf("foo"));
     LDAPAttribute attr = new LDAPAttribute("description", values);
 
     ArrayList<RawModification> mods = new ArrayList<RawModification>();
     mods.add(new LDAPModification(ModificationType.REPLACE, attr));
 
     ModifyOperation modifyOperation =
-         conn.processModify(new ASN1OctetString("o=test"), mods);
+         conn.processModify(ByteString.valueOf("o=test"), mods);
     assertEquals(modifyOperation.getResultCode(), ResultCode.SUCCESS);
     retrieveSuccessfulOperationElements(modifyOperation);
 
@@ -763,15 +762,15 @@
     InternalClientConnection conn =
          InternalClientConnection.getRootConnection();
 
-    ArrayList<ASN1OctetString> values = new ArrayList<ASN1OctetString>();
-    values.add(new ASN1OctetString("test2"));
+    ArrayList<ByteString> values = new ArrayList<ByteString>();
+    values.add(ByteString.valueOf("test2"));
     LDAPAttribute attr = new LDAPAttribute("o", values);
 
     ArrayList<RawModification> mods = new ArrayList<RawModification>();
     mods.add(new LDAPModification(ModificationType.ADD, attr));
 
     ModifyOperation modifyOperation =
-         conn.processModify(new ASN1OctetString("o=test"), mods);
+         conn.processModify(ByteString.valueOf("o=test"), mods);
     assertEquals(modifyOperation.getResultCode(), ResultCode.SUCCESS);
     retrieveSuccessfulOperationElements(modifyOperation);
 
@@ -813,15 +812,15 @@
     InternalClientConnection conn =
          InternalClientConnection.getRootConnection();
 
-    ArrayList<ASN1OctetString> values = new ArrayList<ASN1OctetString>();
-    values.add(new ASN1OctetString("test"));
+    ArrayList<ByteString> values = new ArrayList<ByteString>();
+    values.add(ByteString.valueOf("test"));
     LDAPAttribute attr = new LDAPAttribute("dc;lang-en-us", values);
 
     ArrayList<RawModification> mods = new ArrayList<RawModification>();
     mods.add(new LDAPModification(ModificationType.ADD, attr));
 
     ModifyOperation modifyOperation =
-         conn.processModify(new ASN1OctetString(baseDN), mods);
+         conn.processModify(ByteString.valueOf(baseDN), mods);
     assertEquals(modifyOperation.getResultCode(), ResultCode.SUCCESS);
     retrieveSuccessfulOperationElements(modifyOperation);
 
@@ -872,15 +871,15 @@
     assertEquals(addOperation.getResultCode(), ResultCode.SUCCESS);
 
 
-    ArrayList<ASN1OctetString> values = new ArrayList<ASN1OctetString>();
-    values.add(new ASN1OctetString("foo"));
+    ArrayList<ByteString> values = new ArrayList<ByteString>();
+    values.add(ByteString.valueOf("foo"));
     LDAPAttribute attr = new LDAPAttribute("displayName", values);
 
     ArrayList<RawModification> mods = new ArrayList<RawModification>();
     mods.add(new LDAPModification(ModificationType.ADD, attr));
 
     ModifyOperation modifyOperation =
-         conn.processModify(new ASN1OctetString("uid=test.user," + baseDN),
+         conn.processModify(ByteString.valueOf("uid=test.user," + baseDN),
                             mods);
     assertFalse(modifyOperation.getResultCode() == ResultCode.SUCCESS);
     retrieveFailedOperationElements(modifyOperation);
@@ -924,15 +923,15 @@
     assertEquals(addOperation.getResultCode(), ResultCode.SUCCESS);
 
 
-    ArrayList<ASN1OctetString> values = new ArrayList<ASN1OctetString>();
-    values.add(new ASN1OctetString("false"));
+    ArrayList<ByteString> values = new ArrayList<ByteString>();
+    values.add(ByteString.valueOf("false"));
     LDAPAttribute attr = new LDAPAttribute("ds-pwp-account-disabled", values);
 
     ArrayList<RawModification> mods = new ArrayList<RawModification>();
     mods.add(new LDAPModification(ModificationType.ADD, attr));
 
     ModifyOperation modifyOperation =
-         conn.processModify(new ASN1OctetString("uid=test.user," + baseDN),
+         conn.processModify(ByteString.valueOf("uid=test.user," + baseDN),
                             mods);
     assertFalse(modifyOperation.getResultCode() == ResultCode.SUCCESS);
     retrieveFailedOperationElements(modifyOperation);
@@ -975,16 +974,16 @@
     assertEquals(addOperation.getResultCode(), ResultCode.SUCCESS);
 
 
-    ArrayList<ASN1OctetString> values = new ArrayList<ASN1OctetString>();
-    values.add(new ASN1OctetString("foo"));
-    values.add(new ASN1OctetString("bar"));
+    ArrayList<ByteString> values = new ArrayList<ByteString>();
+    values.add(ByteString.valueOf("foo"));
+    values.add(ByteString.valueOf("bar"));
     LDAPAttribute attr = new LDAPAttribute("displayName", values);
 
     ArrayList<RawModification> mods = new ArrayList<RawModification>();
     mods.add(new LDAPModification(ModificationType.REPLACE, attr));
 
     ModifyOperation modifyOperation =
-         conn.processModify(new ASN1OctetString("uid=test.user," + baseDN),
+         conn.processModify(ByteString.valueOf("uid=test.user," + baseDN),
                             mods);
     assertFalse(modifyOperation.getResultCode() == ResultCode.SUCCESS);
     retrieveFailedOperationElements(modifyOperation);
@@ -1028,16 +1027,16 @@
     assertEquals(addOperation.getResultCode(), ResultCode.SUCCESS);
 
 
-    ArrayList<ASN1OctetString> values = new ArrayList<ASN1OctetString>();
-    values.add(new ASN1OctetString("true"));
-    values.add(new ASN1OctetString("false"));
+    ArrayList<ByteString> values = new ArrayList<ByteString>();
+    values.add(ByteString.valueOf("true"));
+    values.add(ByteString.valueOf("false"));
     LDAPAttribute attr = new LDAPAttribute("ds-pwp-account-disabled", values);
 
     ArrayList<RawModification> mods = new ArrayList<RawModification>();
     mods.add(new LDAPModification(ModificationType.REPLACE, attr));
 
     ModifyOperation modifyOperation =
-         conn.processModify(new ASN1OctetString("uid=test.user," + baseDN),
+         conn.processModify(ByteString.valueOf("uid=test.user," + baseDN),
                             mods);
     assertFalse(modifyOperation.getResultCode() == ResultCode.SUCCESS);
     retrieveFailedOperationElements(modifyOperation);
@@ -1080,15 +1079,15 @@
     assertEquals(addOperation.getResultCode(), ResultCode.SUCCESS);
 
 
-    ArrayList<ASN1OctetString> values = new ArrayList<ASN1OctetString>();
-    values.add(new ASN1OctetString("Test"));
+    ArrayList<ByteString> values = new ArrayList<ByteString>();
+    values.add(ByteString.valueOf("Test"));
     LDAPAttribute attr = new LDAPAttribute("givenName", values);
 
     ArrayList<RawModification> mods = new ArrayList<RawModification>();
     mods.add(new LDAPModification(ModificationType.ADD, attr));
 
     ModifyOperation modifyOperation =
-         conn.processModify(new ASN1OctetString("uid=test.user," + baseDN),
+         conn.processModify(ByteString.valueOf("uid=test.user," + baseDN),
                             mods);
     assertFalse(modifyOperation.getResultCode() == ResultCode.SUCCESS);
     retrieveFailedOperationElements(modifyOperation);
@@ -1131,16 +1130,16 @@
     assertEquals(addOperation.getResultCode(), ResultCode.SUCCESS);
 
 
-    ArrayList<ASN1OctetString> values = new ArrayList<ASN1OctetString>();
-    values.add(new ASN1OctetString("Foo"));
-    values.add(new ASN1OctetString("Foo"));
+    ArrayList<ByteString> values = new ArrayList<ByteString>();
+    values.add(ByteString.valueOf("Foo"));
+    values.add(ByteString.valueOf("Foo"));
     LDAPAttribute attr = new LDAPAttribute("description", values);
 
     ArrayList<RawModification> mods = new ArrayList<RawModification>();
     mods.add(new LDAPModification(ModificationType.REPLACE, attr));
 
     ModifyOperation modifyOperation =
-         conn.processModify(new ASN1OctetString("uid=test.user," + baseDN),
+         conn.processModify(ByteString.valueOf("uid=test.user," + baseDN),
                             mods);
     assertFalse(modifyOperation.getResultCode() == ResultCode.SUCCESS);
     retrieveFailedOperationElements(modifyOperation);
@@ -1184,15 +1183,15 @@
     assertEquals(addOperation.getResultCode(), ResultCode.SUCCESS);
 
 
-    ArrayList<ASN1OctetString> values = new ArrayList<ASN1OctetString>();
-    values.add(new ASN1OctetString("invaliddn"));
+    ArrayList<ByteString> values = new ArrayList<ByteString>();
+    values.add(ByteString.valueOf("invaliddn"));
     LDAPAttribute attr = new LDAPAttribute("manager", values);
 
     ArrayList<RawModification> mods = new ArrayList<RawModification>();
     mods.add(new LDAPModification(ModificationType.REPLACE, attr));
 
     ModifyOperation modifyOperation =
-         conn.processModify(new ASN1OctetString("uid=test.user," + baseDN),
+         conn.processModify(ByteString.valueOf("uid=test.user," + baseDN),
                             mods);
     assertFalse(modifyOperation.getResultCode() == ResultCode.SUCCESS);
     retrieveFailedOperationElements(modifyOperation);
@@ -1235,15 +1234,15 @@
     assertEquals(addOperation.getResultCode(), ResultCode.SUCCESS);
 
 
-    ArrayList<ASN1OctetString> values = new ArrayList<ASN1OctetString>();
-    values.add(new ASN1OctetString("invaliddn"));
+    ArrayList<ByteString> values = new ArrayList<ByteString>();
+    values.add(ByteString.valueOf("invaliddn"));
     LDAPAttribute attr = new LDAPAttribute("manager", values);
 
     ArrayList<RawModification> mods = new ArrayList<RawModification>();
     mods.add(new LDAPModification(ModificationType.ADD, attr));
 
     ModifyOperation modifyOperation =
-         conn.processModify(new ASN1OctetString("uid=test.user," + baseDN),
+         conn.processModify(ByteString.valueOf("uid=test.user," + baseDN),
                             mods);
     assertFalse(modifyOperation.getResultCode() == ResultCode.SUCCESS);
     retrieveFailedOperationElements(modifyOperation);
@@ -1286,15 +1285,15 @@
     assertEquals(addOperation.getResultCode(), ResultCode.SUCCESS);
 
 
-    ArrayList<ASN1OctetString> values = new ArrayList<ASN1OctetString>();
-    values.add(new ASN1OctetString("foo"));
+    ArrayList<ByteString> values = new ArrayList<ByteString>();
+    values.add(ByteString.valueOf("foo"));
     LDAPAttribute attr = new LDAPAttribute("dc", values);
 
     ArrayList<RawModification> mods = new ArrayList<RawModification>();
     mods.add(new LDAPModification(ModificationType.ADD, attr));
 
     ModifyOperation modifyOperation =
-         conn.processModify(new ASN1OctetString("uid=test.user," + baseDN),
+         conn.processModify(ByteString.valueOf("uid=test.user," + baseDN),
                             mods);
     assertFalse(modifyOperation.getResultCode() == ResultCode.SUCCESS);
     retrieveFailedOperationElements(modifyOperation);
@@ -1339,20 +1338,20 @@
     assertEquals(addOperation.getResultCode(), ResultCode.SUCCESS);
 
 
-    ArrayList<ASN1OctetString> values = new ArrayList<ASN1OctetString>();
-    values.add(new ASN1OctetString("foo"));
+    ArrayList<ByteString> values = new ArrayList<ByteString>();
+    values.add(ByteString.valueOf("foo"));
     LDAPAttribute attr = new LDAPAttribute("dc", values);
 
     ArrayList<RawModification> mods = new ArrayList<RawModification>();
     mods.add(new LDAPModification(ModificationType.ADD, attr));
 
-    values = new ArrayList<ASN1OctetString>();
-    values.add(new ASN1OctetString("extensibleObject"));
+    values = new ArrayList<ByteString>();
+    values.add(ByteString.valueOf("extensibleObject"));
     attr = new LDAPAttribute("objectClass", values);
     mods.add(new LDAPModification(ModificationType.ADD, attr));
 
     ModifyOperation modifyOperation =
-         conn.processModify(new ASN1OctetString("uid=test.user," + baseDN),
+         conn.processModify(ByteString.valueOf("uid=test.user," + baseDN),
                             mods);
     assertEquals(modifyOperation.getResultCode(), ResultCode.SUCCESS);
     retrieveSuccessfulOperationElements(modifyOperation);
@@ -1395,15 +1394,15 @@
     assertEquals(addOperation.getResultCode(), ResultCode.SUCCESS);
 
 
-    ArrayList<ASN1OctetString> values = new ArrayList<ASN1OctetString>();
-    values.add(new ASN1OctetString("foo"));
+    ArrayList<ByteString> values = new ArrayList<ByteString>();
+    values.add(ByteString.valueOf("foo"));
     LDAPAttribute attr = new LDAPAttribute("uid", values);
 
     ArrayList<RawModification> mods = new ArrayList<RawModification>();
     mods.add(new LDAPModification(ModificationType.REPLACE, attr));
 
     ModifyOperation modifyOperation =
-         conn.processModify(new ASN1OctetString("uid=test.user," + baseDN),
+         conn.processModify(ByteString.valueOf("uid=test.user," + baseDN),
                             mods);
     assertFalse(modifyOperation.getResultCode() == ResultCode.SUCCESS);
     retrieveFailedOperationElements(modifyOperation);
@@ -1451,7 +1450,7 @@
     mods.add(new LDAPModification(ModificationType.DELETE, attr));
 
     ModifyOperation modifyOperation =
-         conn.processModify(new ASN1OctetString("uid=test.user," + baseDN),
+         conn.processModify(ByteString.valueOf("uid=test.user," + baseDN),
                             mods);
     assertFalse(modifyOperation.getResultCode() == ResultCode.SUCCESS);
     retrieveFailedOperationElements(modifyOperation);
@@ -1494,15 +1493,15 @@
     assertEquals(addOperation.getResultCode(), ResultCode.SUCCESS);
 
 
-    ArrayList<ASN1OctetString> values = new ArrayList<ASN1OctetString>();
-    values.add(new ASN1OctetString("test.user"));
+    ArrayList<ByteString> values = new ArrayList<ByteString>();
+    values.add(ByteString.valueOf("test.user"));
     LDAPAttribute attr = new LDAPAttribute("uid", values);
 
     ArrayList<RawModification> mods = new ArrayList<RawModification>();
     mods.add(new LDAPModification(ModificationType.DELETE, attr));
 
     ModifyOperation modifyOperation =
-         conn.processModify(new ASN1OctetString("uid=test.user," + baseDN),
+         conn.processModify(ByteString.valueOf("uid=test.user," + baseDN),
                             mods);
     assertFalse(modifyOperation.getResultCode() == ResultCode.SUCCESS);
     retrieveFailedOperationElements(modifyOperation);
@@ -1545,8 +1544,8 @@
     assertEquals(addOperation.getResultCode(), ResultCode.SUCCESS);
 
 
-    ArrayList<ASN1OctetString> values = new ArrayList<ASN1OctetString>();
-    values.add(new ASN1OctetString("Foo"));
+    ArrayList<ByteString> values = new ArrayList<ByteString>();
+    values.add(ByteString.valueOf("Foo"));
     LDAPAttribute attr = new LDAPAttribute("givenName", values);
 
     ArrayList<RawModification> mods = new ArrayList<RawModification>();
@@ -1554,7 +1553,7 @@
 
     ModifyOperation modifyOperation =
          conn.processModify(
-              new ASN1OctetString("givenName=Test,sn=User," + baseDN), mods);
+              ByteString.valueOf("givenName=Test,sn=User," + baseDN), mods);
     assertFalse(modifyOperation.getResultCode() == ResultCode.SUCCESS);
     retrieveFailedOperationElements(modifyOperation);
   }
@@ -1602,7 +1601,7 @@
 
     ModifyOperation modifyOperation =
          conn.processModify(
-              new ASN1OctetString("givenName=Test,sn=User," + baseDN), mods);
+              ByteString.valueOf("givenName=Test,sn=User," + baseDN), mods);
     assertFalse(modifyOperation.getResultCode() == ResultCode.SUCCESS);
     retrieveFailedOperationElements(modifyOperation);
   }
@@ -1649,7 +1648,7 @@
     mods.add(new LDAPModification(ModificationType.DELETE, attr));
 
     ModifyOperation modifyOperation =
-         conn.processModify(new ASN1OctetString("uid=test.user," + baseDN),
+         conn.processModify(ByteString.valueOf("uid=test.user," + baseDN),
                             mods);
     assertEquals(modifyOperation.getResultCode(), ResultCode.SUCCESS);
     retrieveSuccessfulOperationElements(modifyOperation);
@@ -1694,15 +1693,15 @@
     assertEquals(addOperation.getResultCode(), ResultCode.SUCCESS);
 
 
-    ArrayList<ASN1OctetString> values = new ArrayList<ASN1OctetString>();
-    values.add(new ASN1OctetString("foo"));
+    ArrayList<ByteString> values = new ArrayList<ByteString>();
+    values.add(ByteString.valueOf("foo"));
     LDAPAttribute attr = new LDAPAttribute("mail", values);
 
     ArrayList<RawModification> mods = new ArrayList<RawModification>();
     mods.add(new LDAPModification(ModificationType.DELETE, attr));
 
     ModifyOperation modifyOperation =
-         conn.processModify(new ASN1OctetString("uid=test.user," + baseDN),
+         conn.processModify(ByteString.valueOf("uid=test.user," + baseDN),
                             mods);
     assertEquals(modifyOperation.getResultCode(), ResultCode.SUCCESS);
     retrieveSuccessfulOperationElements(modifyOperation);
@@ -1746,15 +1745,15 @@
     assertEquals(addOperation.getResultCode(), ResultCode.SUCCESS);
 
 
-    ArrayList<ASN1OctetString> values = new ArrayList<ASN1OctetString>();
-    values.add(new ASN1OctetString("foo"));
+    ArrayList<ByteString> values = new ArrayList<ByteString>();
+    values.add(ByteString.valueOf("foo"));
     LDAPAttribute attr = new LDAPAttribute("mail", values);
 
     ArrayList<RawModification> mods = new ArrayList<RawModification>();
     mods.add(new LDAPModification(ModificationType.DELETE, attr));
 
     ModifyOperation modifyOperation =
-         conn.processModify(new ASN1OctetString("uid=test.user," + baseDN),
+         conn.processModify(ByteString.valueOf("uid=test.user," + baseDN),
                             mods);
     assertEquals(modifyOperation.getResultCode(), ResultCode.SUCCESS);
     retrieveSuccessfulOperationElements(modifyOperation);
@@ -1799,16 +1798,16 @@
     assertEquals(addOperation.getResultCode(), ResultCode.SUCCESS);
 
 
-    ArrayList<ASN1OctetString> values = new ArrayList<ASN1OctetString>();
-    values.add(new ASN1OctetString("foo"));
-    values.add(new ASN1OctetString("bar"));
+    ArrayList<ByteString> values = new ArrayList<ByteString>();
+    values.add(ByteString.valueOf("foo"));
+    values.add(ByteString.valueOf("bar"));
     LDAPAttribute attr = new LDAPAttribute("mail", values);
 
     ArrayList<RawModification> mods = new ArrayList<RawModification>();
     mods.add(new LDAPModification(ModificationType.DELETE, attr));
 
     ModifyOperation modifyOperation =
-         conn.processModify(new ASN1OctetString("uid=test.user," + baseDN),
+         conn.processModify(ByteString.valueOf("uid=test.user," + baseDN),
                             mods);
     assertEquals(modifyOperation.getResultCode(), ResultCode.SUCCESS);
     retrieveSuccessfulOperationElements(modifyOperation);
@@ -1856,7 +1855,7 @@
     mods.add(new LDAPModification(ModificationType.DELETE, attr));
 
     ModifyOperation modifyOperation =
-         conn.processModify(new ASN1OctetString("uid=test.user," + baseDN),
+         conn.processModify(ByteString.valueOf("uid=test.user," + baseDN),
                             mods);
     assertFalse(modifyOperation.getResultCode() == ResultCode.SUCCESS);
     retrieveFailedOperationElements(modifyOperation);
@@ -1899,15 +1898,15 @@
     assertEquals(addOperation.getResultCode(), ResultCode.SUCCESS);
 
 
-    ArrayList<ASN1OctetString> values = new ArrayList<ASN1OctetString>();
-    values.add(new ASN1OctetString("User"));
+    ArrayList<ByteString> values = new ArrayList<ByteString>();
+    values.add(ByteString.valueOf("User"));
     LDAPAttribute attr = new LDAPAttribute("sn", values);
 
     ArrayList<RawModification> mods = new ArrayList<RawModification>();
     mods.add(new LDAPModification(ModificationType.DELETE, attr));
 
     ModifyOperation modifyOperation =
-         conn.processModify(new ASN1OctetString("uid=test.user," + baseDN),
+         conn.processModify(ByteString.valueOf("uid=test.user," + baseDN),
                             mods);
     assertFalse(modifyOperation.getResultCode() == ResultCode.SUCCESS);
     retrieveFailedOperationElements(modifyOperation);
@@ -1951,15 +1950,15 @@
     assertEquals(addOperation.getResultCode(), ResultCode.SUCCESS);
 
 
-    ArrayList<ASN1OctetString> values = new ArrayList<ASN1OctetString>();
-    values.add(new ASN1OctetString("bar"));
+    ArrayList<ByteString> values = new ArrayList<ByteString>();
+    values.add(ByteString.valueOf("bar"));
     LDAPAttribute attr = new LDAPAttribute("description", values);
 
     ArrayList<RawModification> mods = new ArrayList<RawModification>();
     mods.add(new LDAPModification(ModificationType.REPLACE, attr));
 
     ModifyOperation modifyOperation =
-         conn.processModify(new ASN1OctetString("uid=test.user," + baseDN),
+         conn.processModify(ByteString.valueOf("uid=test.user," + baseDN),
                             mods);
     assertEquals(modifyOperation.getResultCode(), ResultCode.SUCCESS);
     retrieveSuccessfulOperationElements(modifyOperation);
@@ -2003,15 +2002,15 @@
     assertEquals(addOperation.getResultCode(), ResultCode.SUCCESS);
 
 
-    ArrayList<ASN1OctetString> values = new ArrayList<ASN1OctetString>();
-    values.add(new ASN1OctetString("test.user"));
+    ArrayList<ByteString> values = new ArrayList<ByteString>();
+    values.add(ByteString.valueOf("test.user"));
     LDAPAttribute attr = new LDAPAttribute("uid", values);
 
     ArrayList<RawModification> mods = new ArrayList<RawModification>();
     mods.add(new LDAPModification(ModificationType.REPLACE, attr));
 
     ModifyOperation modifyOperation =
-         conn.processModify(new ASN1OctetString("uid=test.user," + baseDN),
+         conn.processModify(ByteString.valueOf("uid=test.user," + baseDN),
                             mods);
     assertEquals(modifyOperation.getResultCode(), ResultCode.SUCCESS);
     retrieveSuccessfulOperationElements(modifyOperation);
@@ -2022,7 +2021,7 @@
               InternalClientConnection.nextOperationID(),
               InternalClientConnection.nextMessageID(),
               new ArrayList<Control>(),
-              new ASN1OctetString("uid=test.user," + baseDN),
+              ByteString.valueOf("uid=test.user," + baseDN),
               SearchScope.WHOLE_SUBTREE,
               DereferencePolicy.NEVER_DEREF_ALIASES,
               Integer.MAX_VALUE,
@@ -2075,8 +2074,8 @@
     assertEquals(addOperation.getResultCode(), ResultCode.SUCCESS);
 
 
-    ArrayList<ASN1OctetString> values = new ArrayList<ASN1OctetString>();
-    values.add(new ASN1OctetString("Test User"));
+    ArrayList<ByteString> values = new ArrayList<ByteString>();
+    values.add(ByteString.valueOf("Test User"));
     LDAPAttribute attr = new LDAPAttribute("cn", values);
 
     ArrayList<RawModification> mods = new ArrayList<RawModification>();
@@ -2084,7 +2083,7 @@
     mods.add(new LDAPModification(ModificationType.ADD, attr));
 
     ModifyOperation modifyOperation =
-         conn.processModify(new ASN1OctetString("uid=test.user," + baseDN),
+         conn.processModify(ByteString.valueOf("uid=test.user," + baseDN),
                             mods);
     assertEquals(modifyOperation.getResultCode(), ResultCode.SUCCESS);
     retrieveSuccessfulOperationElements(modifyOperation);
@@ -2095,7 +2094,7 @@
               InternalClientConnection.nextOperationID(),
               InternalClientConnection.nextMessageID(),
               new ArrayList<Control>(),
-              new ASN1OctetString(baseDN),
+              ByteString.valueOf(baseDN),
               SearchScope.WHOLE_SUBTREE,
               DereferencePolicy.NEVER_DEREF_ALIASES,
               Integer.MAX_VALUE,
@@ -2151,15 +2150,15 @@
     assertEquals(addOperation.getResultCode(), ResultCode.SUCCESS);
 
 
-    ArrayList<ASN1OctetString> values = new ArrayList<ASN1OctetString>();
-    values.add(new ASN1OctetString("X"));
+    ArrayList<ByteString> values = new ArrayList<ByteString>();
+    values.add(ByteString.valueOf("X"));
     LDAPAttribute attr = new LDAPAttribute("givenName;lang-fr", values);
 
     ArrayList<RawModification> mods = new ArrayList<RawModification>();
     mods.add(new LDAPModification(ModificationType.DELETE, attr));
 
     ModifyOperation modifyOperation =
-         conn.processModify(new ASN1OctetString("uid=test.user," + baseDN),
+         conn.processModify(ByteString.valueOf("uid=test.user," + baseDN),
                             mods);
     assertEquals(modifyOperation.getResultCode(), ResultCode.SUCCESS);
     retrieveSuccessfulOperationElements(modifyOperation);
@@ -2170,7 +2169,7 @@
               InternalClientConnection.nextOperationID(),
               InternalClientConnection.nextMessageID(),
               new ArrayList<Control>(),
-              new ASN1OctetString(baseDN),
+              ByteString.valueOf(baseDN),
               SearchScope.WHOLE_SUBTREE,
               DereferencePolicy.NEVER_DEREF_ALIASES,
               Integer.MAX_VALUE,
@@ -2228,7 +2227,7 @@
     mods.add(new LDAPModification(ModificationType.REPLACE, attr));
 
     ModifyOperation modifyOperation =
-         conn.processModify(new ASN1OctetString("uid=test.user," + baseDN),
+         conn.processModify(ByteString.valueOf("uid=test.user," + baseDN),
                             mods);
     assertEquals(modifyOperation.getResultCode(), ResultCode.SUCCESS);
     retrieveSuccessfulOperationElements(modifyOperation);
@@ -2276,7 +2275,7 @@
     mods.add(new LDAPModification(ModificationType.REPLACE, attr));
 
     ModifyOperation modifyOperation =
-         conn.processModify(new ASN1OctetString("uid=test.user," + baseDN),
+         conn.processModify(ByteString.valueOf("uid=test.user," + baseDN),
                             mods);
     assertEquals(modifyOperation.getResultCode(), ResultCode.SUCCESS);
     retrieveSuccessfulOperationElements(modifyOperation);
@@ -2319,15 +2318,15 @@
     assertEquals(addOperation.getResultCode(), ResultCode.SUCCESS);
 
 
-    ArrayList<ASN1OctetString> values = new ArrayList<ASN1OctetString>();
-    values.add(new ASN1OctetString("foo"));
+    ArrayList<ByteString> values = new ArrayList<ByteString>();
+    values.add(ByteString.valueOf("foo"));
     LDAPAttribute attr = new LDAPAttribute("description", values);
 
     ArrayList<RawModification> mods = new ArrayList<RawModification>();
     mods.add(new LDAPModification(ModificationType.REPLACE, attr));
 
     ModifyOperation modifyOperation =
-         conn.processModify(new ASN1OctetString("uid=test.user," + baseDN),
+         conn.processModify(ByteString.valueOf("uid=test.user," + baseDN),
                             mods);
     assertEquals(modifyOperation.getResultCode(), ResultCode.SUCCESS);
     retrieveSuccessfulOperationElements(modifyOperation);
@@ -2371,19 +2370,19 @@
     assertEquals(addOperation.getResultCode(), ResultCode.SUCCESS);
 
 
-    ArrayList<ASN1OctetString> values = new ArrayList<ASN1OctetString>();
-    values.add(new ASN1OctetString("foo"));
+    ArrayList<ByteString> values = new ArrayList<ByteString>();
+    values.add(ByteString.valueOf("foo"));
     LDAPAttribute attr = new LDAPAttribute("mail", values);
     ArrayList<RawModification> mods = new ArrayList<RawModification>();
     mods.add(new LDAPModification(ModificationType.DELETE, attr));
 
-    values = new ArrayList<ASN1OctetString>();
-    values.add(new ASN1OctetString("bar"));
+    values = new ArrayList<ByteString>();
+    values.add(ByteString.valueOf("bar"));
     attr = new LDAPAttribute("mail", values);
     mods.add(new LDAPModification(ModificationType.ADD, attr));
 
     ModifyOperation modifyOperation =
-         conn.processModify(new ASN1OctetString("uid=test.user," + baseDN),
+         conn.processModify(ByteString.valueOf("uid=test.user," + baseDN),
                             mods);
     assertEquals(modifyOperation.getResultCode(), ResultCode.SUCCESS);
     retrieveSuccessfulOperationElements(modifyOperation);
@@ -2428,19 +2427,19 @@
     assertEquals(addOperation.getResultCode(), ResultCode.SUCCESS);
 
 
-    ArrayList<ASN1OctetString> values = new ArrayList<ASN1OctetString>();
-    values.add(new ASN1OctetString("foo"));
+    ArrayList<ByteString> values = new ArrayList<ByteString>();
+    values.add(ByteString.valueOf("foo"));
     LDAPAttribute attr = new LDAPAttribute("mail", values);
     ArrayList<RawModification> mods = new ArrayList<RawModification>();
     mods.add(new LDAPModification(ModificationType.DELETE, attr));
 
-    values = new ArrayList<ASN1OctetString>();
-    values.add(new ASN1OctetString("baz"));
+    values = new ArrayList<ByteString>();
+    values.add(ByteString.valueOf("baz"));
     attr = new LDAPAttribute("mail", values);
     mods.add(new LDAPModification(ModificationType.ADD, attr));
 
     ModifyOperation modifyOperation =
-         conn.processModify(new ASN1OctetString("uid=test.user," + baseDN),
+         conn.processModify(ByteString.valueOf("uid=test.user," + baseDN),
                             mods);
     assertEquals(modifyOperation.getResultCode(), ResultCode.SUCCESS);
     retrieveSuccessfulOperationElements(modifyOperation);
@@ -2484,20 +2483,20 @@
     assertEquals(addOperation.getResultCode(), ResultCode.SUCCESS);
 
 
-    ArrayList<ASN1OctetString> values = new ArrayList<ASN1OctetString>();
-    values.add(new ASN1OctetString("foo"));
+    ArrayList<ByteString> values = new ArrayList<ByteString>();
+    values.add(ByteString.valueOf("foo"));
     LDAPAttribute attr = new LDAPAttribute("mail", values);
     ArrayList<RawModification> mods = new ArrayList<RawModification>();
     mods.add(new LDAPModification(ModificationType.DELETE, attr));
 
-    values = new ArrayList<ASN1OctetString>();
-    values.add(new ASN1OctetString("bar"));
-    values.add(new ASN1OctetString("baz"));
+    values = new ArrayList<ByteString>();
+    values.add(ByteString.valueOf("bar"));
+    values.add(ByteString.valueOf("baz"));
     attr = new LDAPAttribute("mail", values);
     mods.add(new LDAPModification(ModificationType.ADD, attr));
 
     ModifyOperation modifyOperation =
-         conn.processModify(new ASN1OctetString("uid=test.user," + baseDN),
+         conn.processModify(ByteString.valueOf("uid=test.user," + baseDN),
                             mods);
     assertEquals(modifyOperation.getResultCode(), ResultCode.SUCCESS);
     retrieveSuccessfulOperationElements(modifyOperation);
@@ -2544,7 +2543,7 @@
     mods.add(new LDAPModification(ModificationType.DELETE, attr));
 
     ModifyOperation modifyOperation =
-         conn.processModify(new ASN1OctetString("uid=test.user," + baseDN),
+         conn.processModify(ByteString.valueOf("uid=test.user," + baseDN),
                             mods);
     assertFalse(modifyOperation.getResultCode() == ResultCode.SUCCESS);
     retrieveFailedOperationElements(modifyOperation);
@@ -2587,15 +2586,15 @@
     assertEquals(addOperation.getResultCode(), ResultCode.SUCCESS);
 
 
-    ArrayList<ASN1OctetString> values = new ArrayList<ASN1OctetString>();
-    values.add(new ASN1OctetString("Foo"));
+    ArrayList<ByteString> values = new ArrayList<ByteString>();
+    values.add(ByteString.valueOf("Foo"));
     LDAPAttribute attr = new LDAPAttribute("displayName", values);
 
     ArrayList<RawModification> mods = new ArrayList<RawModification>();
     mods.add(new LDAPModification(ModificationType.DELETE, attr));
 
     ModifyOperation modifyOperation =
-         conn.processModify(new ASN1OctetString("uid=test.user," + baseDN),
+         conn.processModify(ByteString.valueOf("uid=test.user," + baseDN),
                             mods);
     assertFalse(modifyOperation.getResultCode() == ResultCode.SUCCESS);
     retrieveFailedOperationElements(modifyOperation);
@@ -2643,7 +2642,7 @@
     mods.add(new LDAPModification(ModificationType.DELETE, attr));
 
     ModifyOperation modifyOperation =
-         conn.processModify(new ASN1OctetString("uid=test.user," + baseDN),
+         conn.processModify(ByteString.valueOf("uid=test.user," + baseDN),
                             mods);
     assertFalse(modifyOperation.getResultCode() == ResultCode.SUCCESS);
     retrieveFailedOperationElements(modifyOperation);
@@ -2691,7 +2690,7 @@
     mods.add(new LDAPModification(ModificationType.REPLACE, attr));
 
     ModifyOperation modifyOperation =
-         conn.processModify(new ASN1OctetString("uid=test.user," + baseDN),
+         conn.processModify(ByteString.valueOf("uid=test.user," + baseDN),
                             mods);
     assertFalse(modifyOperation.getResultCode() == ResultCode.SUCCESS);
     retrieveFailedOperationElements(modifyOperation);
@@ -2728,15 +2727,15 @@
     assertEquals(addOperation.getResultCode(), ResultCode.SUCCESS);
 
 
-    ArrayList<ASN1OctetString> values = new ArrayList<ASN1OctetString>();
-    values.add(new ASN1OctetString("organizationalUnit"));
+    ArrayList<ByteString> values = new ArrayList<ByteString>();
+    values.add(ByteString.valueOf("organizationalUnit"));
     LDAPAttribute attr = new LDAPAttribute("objectClass", values);
 
     ArrayList<RawModification> mods = new ArrayList<RawModification>();
     mods.add(new LDAPModification(ModificationType.DELETE, attr));
 
     ModifyOperation modifyOperation =
-         conn.processModify(new ASN1OctetString("ou=People," + baseDN), mods);
+         conn.processModify(ByteString.valueOf("ou=People," + baseDN), mods);
     assertFalse(modifyOperation.getResultCode() == ResultCode.SUCCESS);
     retrieveFailedOperationElements(modifyOperation);
   }
@@ -2772,15 +2771,15 @@
     assertEquals(addOperation.getResultCode(), ResultCode.SUCCESS);
 
 
-    ArrayList<ASN1OctetString> values = new ArrayList<ASN1OctetString>();
-    values.add(new ASN1OctetString("organization"));
+    ArrayList<ByteString> values = new ArrayList<ByteString>();
+    values.add(ByteString.valueOf("organization"));
     LDAPAttribute attr = new LDAPAttribute("objectClass", values);
 
     ArrayList<RawModification> mods = new ArrayList<RawModification>();
     mods.add(new LDAPModification(ModificationType.ADD, attr));
 
     ModifyOperation modifyOperation =
-         conn.processModify(new ASN1OctetString("ou=People," + baseDN), mods);
+         conn.processModify(ByteString.valueOf("ou=People," + baseDN), mods);
     assertFalse(modifyOperation.getResultCode() == ResultCode.SUCCESS);
     retrieveFailedOperationElements(modifyOperation);
   }
@@ -2824,14 +2823,14 @@
     assertEquals(addOperation.getResultCode(), ResultCode.SUCCESS);
 
 
-    ArrayList<ASN1OctetString> values = new ArrayList<ASN1OctetString>();
-    values.add(new ASN1OctetString("1"));
+    ArrayList<ByteString> values = new ArrayList<ByteString>();
+    values.add(ByteString.valueOf("1"));
     LDAPAttribute attr = new LDAPAttribute("employeeNumber", values);
     ArrayList<RawModification> mods = new ArrayList<RawModification>();
     mods.add(new LDAPModification(ModificationType.INCREMENT, attr));
 
     ModifyOperation modifyOperation =
-         conn.processModify(new ASN1OctetString("uid=test.user," + baseDN),
+         conn.processModify(ByteString.valueOf("uid=test.user," + baseDN),
                             mods);
     assertEquals(modifyOperation.getResultCode(), ResultCode.SUCCESS);
     retrieveSuccessfulOperationElements(modifyOperation);
@@ -2847,7 +2846,7 @@
     {
       for (AttributeValue v : a)
       {
-        assertEquals(Integer.parseInt(v.getStringValue()), 2);
+        assertEquals(Integer.parseInt(v.getValue().toString()), 2);
         found = true;
       }
     }
@@ -2893,14 +2892,14 @@
     assertEquals(addOperation.getResultCode(), ResultCode.SUCCESS);
 
 
-    ArrayList<ASN1OctetString> values = new ArrayList<ASN1OctetString>();
-    values.add(new ASN1OctetString("10"));
+    ArrayList<ByteString> values = new ArrayList<ByteString>();
+    values.add(ByteString.valueOf("10"));
     LDAPAttribute attr = new LDAPAttribute("employeeNumber", values);
     ArrayList<RawModification> mods = new ArrayList<RawModification>();
     mods.add(new LDAPModification(ModificationType.INCREMENT, attr));
 
     ModifyOperation modifyOperation =
-         conn.processModify(new ASN1OctetString("uid=test.user," + baseDN),
+         conn.processModify(ByteString.valueOf("uid=test.user," + baseDN),
                             mods);
     assertEquals(modifyOperation.getResultCode(), ResultCode.SUCCESS);
     retrieveSuccessfulOperationElements(modifyOperation);
@@ -2916,7 +2915,7 @@
     {
       for (AttributeValue v : a)
       {
-        assertEquals(Integer.parseInt(v.getStringValue()), 11);
+        assertEquals(Integer.parseInt(v.getValue().toString()), 11);
         found = true;
       }
     }
@@ -2962,14 +2961,14 @@
     assertEquals(addOperation.getResultCode(), ResultCode.SUCCESS);
 
 
-    ArrayList<ASN1OctetString> values = new ArrayList<ASN1OctetString>();
-    values.add(new ASN1OctetString("-1"));
+    ArrayList<ByteString> values = new ArrayList<ByteString>();
+    values.add(ByteString.valueOf("-1"));
     LDAPAttribute attr = new LDAPAttribute("employeeNumber", values);
     ArrayList<RawModification> mods = new ArrayList<RawModification>();
     mods.add(new LDAPModification(ModificationType.INCREMENT, attr));
 
     ModifyOperation modifyOperation =
-         conn.processModify(new ASN1OctetString("uid=test.user," + baseDN),
+         conn.processModify(ByteString.valueOf("uid=test.user," + baseDN),
                             mods);
     assertEquals(modifyOperation.getResultCode(), ResultCode.SUCCESS);
     retrieveSuccessfulOperationElements(modifyOperation);
@@ -2985,7 +2984,7 @@
     {
       for (AttributeValue v : a)
       {
-        assertEquals(Integer.parseInt(v.getStringValue()), 0);
+        assertEquals(Integer.parseInt(v.getValue().toString()), 0);
         found = true;
       }
     }
@@ -3029,14 +3028,14 @@
     assertEquals(addOperation.getResultCode(), ResultCode.SUCCESS);
 
 
-    ArrayList<ASN1OctetString> values = new ArrayList<ASN1OctetString>();
-    values.add(new ASN1OctetString("1"));
+    ArrayList<ByteString> values = new ArrayList<ByteString>();
+    values.add(ByteString.valueOf("1"));
     LDAPAttribute attr = new LDAPAttribute("displayName", values);
     ArrayList<RawModification> mods = new ArrayList<RawModification>();
     mods.add(new LDAPModification(ModificationType.INCREMENT, attr));
 
     ModifyOperation modifyOperation =
-         conn.processModify(new ASN1OctetString("uid=test.user," + baseDN),
+         conn.processModify(ByteString.valueOf("uid=test.user," + baseDN),
                             mods);
     assertFalse(modifyOperation.getResultCode() == ResultCode.SUCCESS);
     retrieveFailedOperationElements(modifyOperation);
@@ -3080,14 +3079,14 @@
     assertEquals(addOperation.getResultCode(), ResultCode.SUCCESS);
 
 
-    ArrayList<ASN1OctetString> values = new ArrayList<ASN1OctetString>();
-    values.add(new ASN1OctetString("notnumeric"));
+    ArrayList<ByteString> values = new ArrayList<ByteString>();
+    values.add(ByteString.valueOf("notnumeric"));
     LDAPAttribute attr = new LDAPAttribute("description", values);
     ArrayList<RawModification> mods = new ArrayList<RawModification>();
     mods.add(new LDAPModification(ModificationType.INCREMENT, attr));
 
     ModifyOperation modifyOperation =
-         conn.processModify(new ASN1OctetString("uid=test.user," + baseDN),
+         conn.processModify(ByteString.valueOf("uid=test.user," + baseDN),
                             mods);
     assertFalse(modifyOperation.getResultCode() == ResultCode.SUCCESS);
     retrieveFailedOperationElements(modifyOperation);
@@ -3132,14 +3131,14 @@
     assertEquals(addOperation.getResultCode(), ResultCode.SUCCESS);
 
 
-    ArrayList<ASN1OctetString> values = new ArrayList<ASN1OctetString>();
-    values.add(new ASN1OctetString("1"));
+    ArrayList<ByteString> values = new ArrayList<ByteString>();
+    values.add(ByteString.valueOf("1"));
     LDAPAttribute attr = new LDAPAttribute("roomNumber", values);
     ArrayList<RawModification> mods = new ArrayList<RawModification>();
     mods.add(new LDAPModification(ModificationType.INCREMENT, attr));
 
     ModifyOperation modifyOperation =
-         conn.processModify(new ASN1OctetString("uid=test.user," + baseDN),
+         conn.processModify(ByteString.valueOf("uid=test.user," + baseDN),
                             mods);
     assertEquals(modifyOperation.getResultCode(), ResultCode.SUCCESS);
     retrieveSuccessfulOperationElements(modifyOperation);
@@ -3188,7 +3187,7 @@
     mods.add(new LDAPModification(ModificationType.INCREMENT, attr));
 
     ModifyOperation modifyOperation =
-         conn.processModify(new ASN1OctetString("uid=test.user," + baseDN),
+         conn.processModify(ByteString.valueOf("uid=test.user," + baseDN),
                             mods);
     assertFalse(modifyOperation.getResultCode() == ResultCode.SUCCESS);
     retrieveFailedOperationElements(modifyOperation);
@@ -3232,15 +3231,15 @@
     assertEquals(addOperation.getResultCode(), ResultCode.SUCCESS);
 
 
-    ArrayList<ASN1OctetString> values = new ArrayList<ASN1OctetString>();
-    values.add(new ASN1OctetString("1"));
-    values.add(new ASN1OctetString("2"));
+    ArrayList<ByteString> values = new ArrayList<ByteString>();
+    values.add(ByteString.valueOf("1"));
+    values.add(ByteString.valueOf("2"));
     LDAPAttribute attr = new LDAPAttribute("roomNumber", values);
     ArrayList<RawModification> mods = new ArrayList<RawModification>();
     mods.add(new LDAPModification(ModificationType.INCREMENT, attr));
 
     ModifyOperation modifyOperation =
-         conn.processModify(new ASN1OctetString("uid=test.user," + baseDN),
+         conn.processModify(ByteString.valueOf("uid=test.user," + baseDN),
                             mods);
     assertFalse(modifyOperation.getResultCode() == ResultCode.SUCCESS);
     retrieveFailedOperationElements(modifyOperation);
@@ -3283,14 +3282,14 @@
     assertEquals(addOperation.getResultCode(), ResultCode.SUCCESS);
 
 
-    ArrayList<ASN1OctetString> values = new ArrayList<ASN1OctetString>();
-    values.add(new ASN1OctetString("1"));
+    ArrayList<ByteString> values = new ArrayList<ByteString>();
+    values.add(ByteString.valueOf("1"));
     LDAPAttribute attr = new LDAPAttribute("employeeNumber", values);
     ArrayList<RawModification> mods = new ArrayList<RawModification>();
     mods.add(new LDAPModification(ModificationType.INCREMENT, attr));
 
     ModifyOperation modifyOperation =
-         conn.processModify(new ASN1OctetString("uid=test.user," + baseDN),
+         conn.processModify(ByteString.valueOf("uid=test.user," + baseDN),
                             mods);
     assertFalse(modifyOperation.getResultCode() == ResultCode.SUCCESS);
     retrieveFailedOperationElements(modifyOperation);
@@ -3336,14 +3335,14 @@
     assertEquals(addOperation.getResultCode(), ResultCode.SUCCESS);
 
 
-    ArrayList<ASN1OctetString> values = new ArrayList<ASN1OctetString>();
-    values.add(new ASN1OctetString("extensibleObject"));
+    ArrayList<ByteString> values = new ArrayList<ByteString>();
+    values.add(ByteString.valueOf("extensibleObject"));
     LDAPAttribute attr = new LDAPAttribute("objectClass", values);
     ArrayList<RawModification> mods = new ArrayList<RawModification>();
     mods.add(new LDAPModification(ModificationType.DELETE, attr));
 
     ModifyOperation modifyOperation =
-         conn.processModify(new ASN1OctetString("uid=test.user," + baseDN),
+         conn.processModify(ByteString.valueOf("uid=test.user," + baseDN),
                             mods);
     assertEquals(modifyOperation.getResultCode(), ResultCode.SUCCESS);
     retrieveSuccessfulOperationElements(modifyOperation);
@@ -3392,14 +3391,14 @@
     assertEquals(addOperation.getResultCode(), ResultCode.SUCCESS);
 
 
-    ArrayList<ASN1OctetString> values = new ArrayList<ASN1OctetString>();
-    values.add(new ASN1OctetString("extensibleObject"));
+    ArrayList<ByteString> values = new ArrayList<ByteString>();
+    values.add(ByteString.valueOf("extensibleObject"));
     LDAPAttribute attr = new LDAPAttribute("objectClass", values);
     ArrayList<RawModification> mods = new ArrayList<RawModification>();
     mods.add(new LDAPModification(ModificationType.ADD, attr));
 
     ModifyOperation modifyOperation =
-         conn.processModify(new ASN1OctetString("uid=test.user," + baseDN),
+         conn.processModify(ByteString.valueOf("uid=test.user," + baseDN),
                             mods);
     assertEquals(modifyOperation.getResultCode(), ResultCode.SUCCESS);
     retrieveSuccessfulOperationElements(modifyOperation);
@@ -3447,14 +3446,14 @@
     assertEquals(addOperation.getResultCode(), ResultCode.SUCCESS);
 
 
-    ArrayList<ASN1OctetString> values = new ArrayList<ASN1OctetString>();
-    values.add(new ASN1OctetString("inetOrgPerson"));
+    ArrayList<ByteString> values = new ArrayList<ByteString>();
+    values.add(ByteString.valueOf("inetOrgPerson"));
     LDAPAttribute attr = new LDAPAttribute("objectClass", values);
     ArrayList<RawModification> mods = new ArrayList<RawModification>();
     mods.add(new LDAPModification(ModificationType.ADD, attr));
 
     ModifyOperation modifyOperation =
-         conn.processModify(new ASN1OctetString("uid=test.user," + baseDN),
+         conn.processModify(ByteString.valueOf("uid=test.user," + baseDN),
                             mods);
     assertFalse(modifyOperation.getResultCode() == ResultCode.SUCCESS);
     retrieveFailedOperationElements(modifyOperation);
@@ -3499,14 +3498,14 @@
     assertEquals(addOperation.getResultCode(), ResultCode.SUCCESS);
 
 
-    ArrayList<ASN1OctetString> values = new ArrayList<ASN1OctetString>();
-    values.add(new ASN1OctetString("organizationalUnit"));
+    ArrayList<ByteString> values = new ArrayList<ByteString>();
+    values.add(ByteString.valueOf("organizationalUnit"));
     LDAPAttribute attr = new LDAPAttribute("objectClass", values);
     ArrayList<RawModification> mods = new ArrayList<RawModification>();
     mods.add(new LDAPModification(ModificationType.DELETE, attr));
 
     ModifyOperation modifyOperation =
-         conn.processModify(new ASN1OctetString("uid=test.user," + baseDN),
+         conn.processModify(ByteString.valueOf("uid=test.user," + baseDN),
                             mods);
     assertFalse(modifyOperation.getResultCode() == ResultCode.SUCCESS);
     retrieveFailedOperationElements(modifyOperation);
@@ -3550,23 +3549,23 @@
 
 
     Socket s = new Socket("127.0.0.1", TestCaseUtils.getServerLdapPort());
-    ASN1Reader r = new ASN1Reader(s);
-    ASN1Writer w = new ASN1Writer(s);
-    r.setIOTimeout(3000);
+    org.opends.server.tools.LDAPReader r = new org.opends.server.tools.LDAPReader(s);
+    LDAPWriter w = new LDAPWriter(s);
+    s.setSoTimeout(3000);
 
     BindRequestProtocolOp bindRequest =
-         new BindRequestProtocolOp(new ASN1OctetString("cn=Directory Manager"),
-                                   3, new ASN1OctetString("password"));
+         new BindRequestProtocolOp(ByteString.valueOf("cn=Directory Manager"),
+                                   3, ByteString.valueOf("password"));
     LDAPMessage message = new LDAPMessage(1, bindRequest);
-    w.writeElement(message.encode());
+    w.writeMessage(message);
 
-    message = LDAPMessage.decode(r.readElement().decodeAsSequence());
+    message = r.readMessage();
     BindResponseProtocolOp bindResponse =
          message.getBindResponseProtocolOp();
     assertEquals(bindResponse.getResultCode(), 0);
 
-    ArrayList<ASN1OctetString> values = new ArrayList<ASN1OctetString>();
-    values.add(new ASN1OctetString("12345678-1234-1234-1234-1234567890ab"));
+    ArrayList<ByteString> values = new ArrayList<ByteString>();
+    values.add(ByteString.valueOf("12345678-1234-1234-1234-1234567890ab"));
     LDAPAttribute attr = new LDAPAttribute("entryUUID", values);
     ArrayList<RawModification> mods = new ArrayList<RawModification>();
     mods.add(new LDAPModification(ModificationType.REPLACE, attr));
@@ -3576,11 +3575,11 @@
 
     ModifyRequestProtocolOp modifyRequest =
          new ModifyRequestProtocolOp(
-                  new ASN1OctetString("uid=test.user," + baseDN), mods);
+                  ByteString.valueOf("uid=test.user," + baseDN), mods);
     message = new LDAPMessage(2, modifyRequest);
-    w.writeElement(message.encode());
+    w.writeMessage(message);
 
-    message = LDAPMessage.decode(r.readElement().decodeAsSequence());
+    message = r.readMessage();
     ModifyResponseProtocolOp modifyResponse =
          message.getModifyResponseProtocolOp();
     assertFalse(modifyResponse.getResultCode() == 0);
@@ -3630,14 +3629,14 @@
 
     DirectoryServer.setWritabilityMode(WritabilityMode.DISABLED);
 
-    ArrayList<ASN1OctetString> values = new ArrayList<ASN1OctetString>();
-    values.add(new ASN1OctetString("extensibleObject"));
+    ArrayList<ByteString> values = new ArrayList<ByteString>();
+    values.add(ByteString.valueOf("extensibleObject"));
     LDAPAttribute attr = new LDAPAttribute("objectClass", values);
     ArrayList<RawModification> mods = new ArrayList<RawModification>();
     mods.add(new LDAPModification(ModificationType.ADD, attr));
 
     ModifyOperation modifyOperation =
-         conn.processModify(new ASN1OctetString("uid=test.user," + baseDN),
+         conn.processModify(ByteString.valueOf("uid=test.user," + baseDN),
                             mods);
     assertFalse(modifyOperation.getResultCode() == ResultCode.SUCCESS);
     retrieveFailedOperationElements(modifyOperation);
@@ -3686,14 +3685,14 @@
 
     DirectoryServer.setWritabilityMode(WritabilityMode.INTERNAL_ONLY);
 
-    ArrayList<ASN1OctetString> values = new ArrayList<ASN1OctetString>();
-    values.add(new ASN1OctetString("extensibleObject"));
+    ArrayList<ByteString> values = new ArrayList<ByteString>();
+    values.add(ByteString.valueOf("extensibleObject"));
     LDAPAttribute attr = new LDAPAttribute("objectClass", values);
     ArrayList<RawModification> mods = new ArrayList<RawModification>();
     mods.add(new LDAPModification(ModificationType.ADD, attr));
 
     ModifyOperation modifyOperation =
-         conn.processModify(new ASN1OctetString("uid=test.user," + baseDN),
+         conn.processModify(ByteString.valueOf("uid=test.user," + baseDN),
                             mods);
     assertEquals(modifyOperation.getResultCode(), ResultCode.SUCCESS);
     retrieveSuccessfulOperationElements(modifyOperation);
@@ -3744,23 +3743,23 @@
 
 
     Socket s = new Socket("127.0.0.1", TestCaseUtils.getServerLdapPort());
-    ASN1Reader r = new ASN1Reader(s);
-    ASN1Writer w = new ASN1Writer(s);
-    r.setIOTimeout(3000);
+    org.opends.server.tools.LDAPReader r = new org.opends.server.tools.LDAPReader(s);
+    LDAPWriter w = new LDAPWriter(s);
+    s.setSoTimeout(3000);
 
     BindRequestProtocolOp bindRequest =
-         new BindRequestProtocolOp(new ASN1OctetString("cn=Directory Manager"),
-                                   3, new ASN1OctetString("password"));
+         new BindRequestProtocolOp(ByteString.valueOf("cn=Directory Manager"),
+                                   3, ByteString.valueOf("password"));
     LDAPMessage message = new LDAPMessage(1, bindRequest);
-    w.writeElement(message.encode());
+    w.writeMessage(message);
 
-    message = LDAPMessage.decode(r.readElement().decodeAsSequence());
+    message = r.readMessage();
     BindResponseProtocolOp bindResponse =
          message.getBindResponseProtocolOp();
     assertEquals(bindResponse.getResultCode(), 0);
 
-    ArrayList<ASN1OctetString> values = new ArrayList<ASN1OctetString>();
-    values.add(new ASN1OctetString("extensibleObject"));
+    ArrayList<ByteString> values = new ArrayList<ByteString>();
+    values.add(ByteString.valueOf("extensibleObject"));
     LDAPAttribute attr = new LDAPAttribute("objectClass", values);
     ArrayList<RawModification> mods = new ArrayList<RawModification>();
     mods.add(new LDAPModification(ModificationType.ADD, attr));
@@ -3770,11 +3769,11 @@
 
     ModifyRequestProtocolOp modifyRequest =
          new ModifyRequestProtocolOp(
-                  new ASN1OctetString("uid=test.user," + baseDN), mods);
+                  ByteString.valueOf("uid=test.user," + baseDN), mods);
     message = new LDAPMessage(2, modifyRequest);
-    w.writeElement(message.encode());
+    w.writeMessage(message);
 
-    message = LDAPMessage.decode(r.readElement().decodeAsSequence());
+    message = r.readMessage();
     ModifyResponseProtocolOp modifyResponse =
          message.getModifyResponseProtocolOp();
     assertFalse(modifyResponse.getResultCode() == 0);
@@ -3827,14 +3826,14 @@
     Backend b = DirectoryServer.getBackend(DN.decode(baseDN));
     b.setWritabilityMode(WritabilityMode.DISABLED);
 
-    ArrayList<ASN1OctetString> values = new ArrayList<ASN1OctetString>();
-    values.add(new ASN1OctetString("extensibleObject"));
+    ArrayList<ByteString> values = new ArrayList<ByteString>();
+    values.add(ByteString.valueOf("extensibleObject"));
     LDAPAttribute attr = new LDAPAttribute("objectClass", values);
     ArrayList<RawModification> mods = new ArrayList<RawModification>();
     mods.add(new LDAPModification(ModificationType.ADD, attr));
 
     ModifyOperation modifyOperation =
-         conn.processModify(new ASN1OctetString("uid=test.user," + baseDN),
+         conn.processModify(ByteString.valueOf("uid=test.user," + baseDN),
                             mods);
     assertFalse(modifyOperation.getResultCode() == ResultCode.SUCCESS);
     retrieveFailedOperationElements(modifyOperation);
@@ -3884,14 +3883,14 @@
     Backend b = DirectoryServer.getBackend(DN.decode(baseDN));
     b.setWritabilityMode(WritabilityMode.INTERNAL_ONLY);
 
-    ArrayList<ASN1OctetString> values = new ArrayList<ASN1OctetString>();
-    values.add(new ASN1OctetString("extensibleObject"));
+    ArrayList<ByteString> values = new ArrayList<ByteString>();
+    values.add(ByteString.valueOf("extensibleObject"));
     LDAPAttribute attr = new LDAPAttribute("objectClass", values);
     ArrayList<RawModification> mods = new ArrayList<RawModification>();
     mods.add(new LDAPModification(ModificationType.ADD, attr));
 
     ModifyOperation modifyOperation =
-         conn.processModify(new ASN1OctetString("uid=test.user," + baseDN),
+         conn.processModify(ByteString.valueOf("uid=test.user," + baseDN),
                             mods);
     assertEquals(modifyOperation.getResultCode(), ResultCode.SUCCESS);
     retrieveSuccessfulOperationElements(modifyOperation);
@@ -3943,23 +3942,23 @@
 
 
     Socket s = new Socket("127.0.0.1", TestCaseUtils.getServerLdapPort());
-    ASN1Reader r = new ASN1Reader(s);
-    ASN1Writer w = new ASN1Writer(s);
-    r.setIOTimeout(3000);
+    org.opends.server.tools.LDAPReader r = new org.opends.server.tools.LDAPReader(s);
+    LDAPWriter w = new LDAPWriter(s);
+    s.setSoTimeout(3000);
 
     BindRequestProtocolOp bindRequest =
-         new BindRequestProtocolOp(new ASN1OctetString("cn=Directory Manager"),
-                                   3, new ASN1OctetString("password"));
+         new BindRequestProtocolOp(ByteString.valueOf("cn=Directory Manager"),
+                                   3, ByteString.valueOf("password"));
     LDAPMessage message = new LDAPMessage(1, bindRequest);
-    w.writeElement(message.encode());
+    w.writeMessage(message);
 
-    message = LDAPMessage.decode(r.readElement().decodeAsSequence());
+    message = r.readMessage();
     BindResponseProtocolOp bindResponse =
          message.getBindResponseProtocolOp();
     assertEquals(bindResponse.getResultCode(), 0);
 
-    ArrayList<ASN1OctetString> values = new ArrayList<ASN1OctetString>();
-    values.add(new ASN1OctetString("extensibleObject"));
+    ArrayList<ByteString> values = new ArrayList<ByteString>();
+    values.add(ByteString.valueOf("extensibleObject"));
     LDAPAttribute attr = new LDAPAttribute("objectClass", values);
     ArrayList<RawModification> mods = new ArrayList<RawModification>();
     mods.add(new LDAPModification(ModificationType.ADD, attr));
@@ -3969,11 +3968,11 @@
 
     ModifyRequestProtocolOp modifyRequest =
          new ModifyRequestProtocolOp(
-                  new ASN1OctetString("uid=test.user," + baseDN), mods);
+                  ByteString.valueOf("uid=test.user," + baseDN), mods);
     message = new LDAPMessage(2, modifyRequest);
-    w.writeElement(message.encode());
+    w.writeMessage(message);
 
-    message = LDAPMessage.decode(r.readElement().decodeAsSequence());
+    message = r.readMessage();
     ModifyResponseProtocolOp modifyResponse =
          message.getModifyResponseProtocolOp();
     assertFalse(modifyResponse.getResultCode() == 0);
@@ -4006,15 +4005,15 @@
     InternalClientConnection conn =
          InternalClientConnection.getRootConnection();
 
-    ArrayList<ASN1OctetString> values = new ArrayList<ASN1OctetString>();
-    values.add(new ASN1OctetString("foo"));
+    ArrayList<ByteString> values = new ArrayList<ByteString>();
+    values.add(ByteString.valueOf("foo"));
     LDAPAttribute attr = new LDAPAttribute("description", values);
 
     ArrayList<RawModification> mods = new ArrayList<RawModification>();
     mods.add(new LDAPModification(ModificationType.REPLACE, attr));
 
     ModifyOperation modifyOperation =
-         conn.processModify(new ASN1OctetString("o=test"), mods);
+         conn.processModify(ByteString.valueOf("o=test"), mods);
     assertEquals(modifyOperation.getResultCode(), ResultCode.SUCCESS);
     retrieveSuccessfulOperationElements(modifyOperation);
 
@@ -4044,15 +4043,15 @@
     InternalClientConnection conn =
          InternalClientConnection.getRootConnection();
 
-    ArrayList<ASN1OctetString> values = new ArrayList<ASN1OctetString>();
-    values.add(new ASN1OctetString("foo"));
+    ArrayList<ByteString> values = new ArrayList<ByteString>();
+    values.add(ByteString.valueOf("foo"));
     LDAPAttribute attr = new LDAPAttribute("dc", values);
 
     ArrayList<RawModification> mods = new ArrayList<RawModification>();
     mods.add(new LDAPModification(ModificationType.REPLACE, attr));
 
     ModifyOperation modifyOperation =
-         conn.processModify(new ASN1OctetString(baseDN), mods);
+         conn.processModify(ByteString.valueOf(baseDN), mods);
     assertFalse(modifyOperation.getResultCode() == ResultCode.SUCCESS);
     retrieveFailedOperationElements(modifyOperation);
 
@@ -4076,8 +4075,8 @@
     InternalClientConnection conn =
          InternalClientConnection.getRootConnection();
 
-    ArrayList<ASN1OctetString> values = new ArrayList<ASN1OctetString>();
-    values.add(new ASN1OctetString("foo"));
+    ArrayList<ByteString> values = new ArrayList<ByteString>();
+    values.add(ByteString.valueOf("foo"));
     LDAPAttribute attr = new LDAPAttribute("description", values);
 
     ArrayList<RawModification> mods = new ArrayList<RawModification>();
@@ -4085,7 +4084,7 @@
 
     ModifyOperationBasis modifyOperation =
          new ModifyOperationBasis(conn, conn.nextOperationID(), conn.nextMessageID(),
-                             null, new ASN1OctetString(baseDN), mods);
+                             null, ByteString.valueOf(baseDN), mods);
 
     CancelRequest cancelRequest = new CancelRequest(false,
                                                     Message.raw("testCancelBeforeStartup"));
@@ -4110,8 +4109,8 @@
     InternalClientConnection conn =
          InternalClientConnection.getRootConnection();
 
-    ArrayList<ASN1OctetString> values = new ArrayList<ASN1OctetString>();
-    values.add(new ASN1OctetString("foo"));
+    ArrayList<ByteString> values = new ArrayList<ByteString>();
+    values.add(ByteString.valueOf("foo"));
     LDAPAttribute attr = new LDAPAttribute("description", values);
 
     ArrayList<RawModification> mods = new ArrayList<RawModification>();
@@ -4119,7 +4118,7 @@
 
     ModifyOperationBasis modifyOperation =
          new ModifyOperationBasis(conn, conn.nextOperationID(), conn.nextMessageID(),
-                             null, new ASN1OctetString(baseDN), mods);
+                             null, ByteString.valueOf(baseDN), mods);
 
     modifyOperation.run();
 
@@ -4151,15 +4150,15 @@
       InternalClientConnection conn =
            InternalClientConnection.getRootConnection();
 
-      ArrayList<ASN1OctetString> values = new ArrayList<ASN1OctetString>();
-      values.add(new ASN1OctetString("foo"));
+      ArrayList<ByteString> values = new ArrayList<ByteString>();
+      values.add(ByteString.valueOf("foo"));
       LDAPAttribute attr = new LDAPAttribute("description", values);
 
       ArrayList<RawModification> mods = new ArrayList<RawModification>();
       mods.add(new LDAPModification(ModificationType.REPLACE, attr));
 
       ModifyOperation modifyOperation =
-           conn.processModify(new ASN1OctetString(baseDN), mods);
+           conn.processModify(ByteString.valueOf(baseDN), mods);
       assertFalse(modifyOperation.getResultCode() == ResultCode.SUCCESS);
     }
     finally
@@ -4182,41 +4181,40 @@
     TestCaseUtils.clearJEBackend(true,"userRoot",baseDN);
 
     Socket s = new Socket("127.0.0.1", TestCaseUtils.getServerLdapPort());
-    ASN1Reader r = new ASN1Reader(s);
-    ASN1Writer w = new ASN1Writer(s);
-    r.setIOTimeout(5000);
+    org.opends.server.tools.LDAPReader r = new org.opends.server.tools.LDAPReader(s);
+    LDAPWriter w = new LDAPWriter(s);
+    s.setSoTimeout(5000);
 
     BindRequestProtocolOp bindRequest =
-         new BindRequestProtocolOp(new ASN1OctetString("cn=Directory Manager"),
-                                   3, new ASN1OctetString("password"));
+         new BindRequestProtocolOp(ByteString.valueOf("cn=Directory Manager"),
+                                   3, ByteString.valueOf("password"));
     LDAPMessage message = new LDAPMessage(1, bindRequest);
-    w.writeElement(message.encode());
+    w.writeMessage(message);
 
-    message = LDAPMessage.decode(r.readElement().decodeAsSequence());
+    message = r.readMessage();
     BindResponseProtocolOp bindResponse =
          message.getBindResponseProtocolOp();
     assertEquals(bindResponse.getResultCode(), 0);
 
 
-    ArrayList<ASN1OctetString> values = new ArrayList<ASN1OctetString>();
-    values.add(new ASN1OctetString("foo"));
+    ArrayList<ByteString> values = new ArrayList<ByteString>();
+    values.add(ByteString.valueOf("foo"));
     LDAPAttribute attr = new LDAPAttribute("description", values);
 
     ArrayList<RawModification> mods = new ArrayList<RawModification>();
     mods.add(new LDAPModification(ModificationType.REPLACE, attr));
 
     ModifyRequestProtocolOp modifyRequest =
-         new ModifyRequestProtocolOp(new ASN1OctetString(baseDN), mods);
+         new ModifyRequestProtocolOp(ByteString.valueOf(baseDN), mods);
     message = new LDAPMessage(2, modifyRequest,
-         DisconnectClientPlugin.createDisconnectLDAPControlList("PreParse"));
-    w.writeElement(message.encode());
+         DisconnectClientPlugin.createDisconnectControlList("PreParse"));
+    w.writeMessage(message);
 
-    ASN1Element element = r.readElement();
-    if (element != null)
+    message = r.readMessage();
+    if (message != null)
     {
       // If we got an element back, then it must be a notice of disconnect
       // unsolicited notification.
-      message = LDAPMessage.decode(element.decodeAsSequence());
       assertEquals(message.getProtocolOpType(), OP_TYPE_EXTENDED_RESPONSE);
     }
 
@@ -4241,42 +4239,41 @@
     TestCaseUtils.initializeTestBackend(true);
 
     Socket s = new Socket("127.0.0.1", TestCaseUtils.getServerLdapPort());
-    ASN1Reader r = new ASN1Reader(s);
-    ASN1Writer w = new ASN1Writer(s);
-    r.setIOTimeout(5000);
+    org.opends.server.tools.LDAPReader r = new org.opends.server.tools.LDAPReader(s);
+    LDAPWriter w = new LDAPWriter(s);
+    s.setSoTimeout(5000);
 
     BindRequestProtocolOp bindRequest =
-         new BindRequestProtocolOp(new ASN1OctetString("cn=Directory Manager"),
-                                   3, new ASN1OctetString("password"));
+         new BindRequestProtocolOp(ByteString.valueOf("cn=Directory Manager"),
+                                   3, ByteString.valueOf("password"));
     LDAPMessage message = new LDAPMessage(1, bindRequest);
-    w.writeElement(message.encode());
+    w.writeMessage(message);
 
-    message = LDAPMessage.decode(r.readElement().decodeAsSequence());
+    message = r.readMessage();
     BindResponseProtocolOp bindResponse =
          message.getBindResponseProtocolOp();
     assertEquals(bindResponse.getResultCode(), 0);
 
 
-    ArrayList<ASN1OctetString> values = new ArrayList<ASN1OctetString>();
-    values.add(new ASN1OctetString("foo"));
+    ArrayList<ByteString> values = new ArrayList<ByteString>();
+    values.add(ByteString.valueOf("foo"));
     LDAPAttribute attr = new LDAPAttribute("description", values);
 
     ArrayList<RawModification> mods = new ArrayList<RawModification>();
     mods.add(new LDAPModification(ModificationType.REPLACE, attr));
 
     ModifyRequestProtocolOp modifyRequest =
-         new ModifyRequestProtocolOp(new ASN1OctetString("o=test"), mods);
+         new ModifyRequestProtocolOp(ByteString.valueOf("o=test"), mods);
     message = new LDAPMessage(2, modifyRequest,
-         DisconnectClientPlugin.createDisconnectLDAPControlList(
+         DisconnectClientPlugin.createDisconnectControlList(
               "PreOperation"));
-    w.writeElement(message.encode());
+    w.writeMessage(message);
 
-    ASN1Element element = r.readElement();
-    if (element != null)
+    message = r.readMessage();
+    if (message != null)
     {
       // If we got an element back, then it must be a notice of disconnect
       // unsolicited notification.
-      message = LDAPMessage.decode(element.decodeAsSequence());
       assertEquals(message.getProtocolOpType(), OP_TYPE_EXTENDED_RESPONSE);
     }
 
@@ -4301,35 +4298,35 @@
     TestCaseUtils.clearJEBackend(true,"userRoot",baseDN);
 
     Socket s = new Socket("127.0.0.1", TestCaseUtils.getServerLdapPort());
-    ASN1Reader r = new ASN1Reader(s);
-    ASN1Writer w = new ASN1Writer(s);
-    r.setIOTimeout(5000);
+    org.opends.server.tools.LDAPReader r = new org.opends.server.tools.LDAPReader(s);
+    LDAPWriter w = new LDAPWriter(s);
+    s.setSoTimeout(5000);
 
     BindRequestProtocolOp bindRequest =
-         new BindRequestProtocolOp(new ASN1OctetString("cn=Directory Manager"),
-                                   3, new ASN1OctetString("password"));
+         new BindRequestProtocolOp(ByteString.valueOf("cn=Directory Manager"),
+                                   3, ByteString.valueOf("password"));
     LDAPMessage message = new LDAPMessage(1, bindRequest);
-    w.writeElement(message.encode());
+    w.writeMessage(message);
 
-    message = LDAPMessage.decode(r.readElement().decodeAsSequence());
+    message = r.readMessage();
     BindResponseProtocolOp bindResponse =
          message.getBindResponseProtocolOp();
     assertEquals(bindResponse.getResultCode(), 0);
 
 
-    ArrayList<ASN1OctetString> values = new ArrayList<ASN1OctetString>();
-    values.add(new ASN1OctetString("foo"));
+    ArrayList<ByteString> values = new ArrayList<ByteString>();
+    values.add(ByteString.valueOf("foo"));
     LDAPAttribute attr = new LDAPAttribute("description", values);
 
     ArrayList<RawModification> mods = new ArrayList<RawModification>();
     mods.add(new LDAPModification(ModificationType.REPLACE, attr));
 
     ModifyRequestProtocolOp modifyRequest =
-         new ModifyRequestProtocolOp(new ASN1OctetString(baseDN), mods);
+         new ModifyRequestProtocolOp(ByteString.valueOf(baseDN), mods);
     message = new LDAPMessage(2, modifyRequest,
-         DisconnectClientPlugin.createDisconnectLDAPControlList(
+         DisconnectClientPlugin.createDisconnectControlList(
               "PostOperation"));
-    w.writeElement(message.encode());
+    w.writeMessage(message);
 
     // The operation should NOT be aborted at the post operation stage. While
     // the plugin can disconnect the client, the modify should have already
@@ -4338,14 +4335,13 @@
 responseLoop:
     while (true)
     {
-      ASN1Element element = r.readElement();
-      if (element == null)
+      message = r.readMessage();
+      if (message == null)
       {
         // The connection has been closed.
         break responseLoop;
       }
 
-      message = LDAPMessage.decode(element.decodeAsSequence());
       switch (message.getProtocolOpType())
       {
         case OP_TYPE_MODIFY_RESPONSE:
@@ -4389,47 +4385,46 @@
     TestCaseUtils.clearJEBackend(true,"userRoot",baseDN);
 
     Socket s = new Socket("127.0.0.1", TestCaseUtils.getServerLdapPort());
-    ASN1Reader r = new ASN1Reader(s);
-    ASN1Writer w = new ASN1Writer(s);
-    r.setIOTimeout(5000);
+    org.opends.server.tools.LDAPReader r = new org.opends.server.tools.LDAPReader(s);
+    LDAPWriter w = new LDAPWriter(s);
+    s.setSoTimeout(5000);
 
     BindRequestProtocolOp bindRequest =
-         new BindRequestProtocolOp(new ASN1OctetString("cn=Directory Manager"),
-                                   3, new ASN1OctetString("password"));
+         new BindRequestProtocolOp(ByteString.valueOf("cn=Directory Manager"),
+                                   3, ByteString.valueOf("password"));
     LDAPMessage message = new LDAPMessage(1, bindRequest);
-    w.writeElement(message.encode());
+    w.writeMessage(message);
 
-    message = LDAPMessage.decode(r.readElement().decodeAsSequence());
+    message = r.readMessage();
     BindResponseProtocolOp bindResponse =
          message.getBindResponseProtocolOp();
     assertEquals(bindResponse.getResultCode(), 0);
 
 
-    ArrayList<ASN1OctetString> values = new ArrayList<ASN1OctetString>();
-    values.add(new ASN1OctetString("foo"));
+    ArrayList<ByteString> values = new ArrayList<ByteString>();
+    values.add(ByteString.valueOf("foo"));
     LDAPAttribute attr = new LDAPAttribute("description", values);
 
     ArrayList<RawModification> mods = new ArrayList<RawModification>();
     mods.add(new LDAPModification(ModificationType.REPLACE, attr));
 
     ModifyRequestProtocolOp modifyRequest =
-         new ModifyRequestProtocolOp(new ASN1OctetString(baseDN), mods);
+         new ModifyRequestProtocolOp(ByteString.valueOf(baseDN), mods);
     message = new LDAPMessage(2, modifyRequest,
-         DisconnectClientPlugin.createDisconnectLDAPControlList(
+         DisconnectClientPlugin.createDisconnectControlList(
               "PostResponse"));
-    w.writeElement(message.encode());
+    w.writeMessage(message);
 
 responseLoop:
     while (true)
     {
-      ASN1Element element = r.readElement();
-      if (element == null)
+      message = r.readMessage();
+      if (message == null)
       {
         // The connection has been closed.
         break responseLoop;
       }
 
-      message = LDAPMessage.decode(element.decodeAsSequence());
       switch (message.getProtocolOpType())
       {
         case OP_TYPE_MODIFY_RESPONSE:
@@ -4602,7 +4597,7 @@
 
     ModifyOperationBasis modifyOperation =
          new ModifyOperationBasis(conn, conn.nextOperationID(), conn.nextMessageID(),
-                             controls, new ASN1OctetString("o=test"), mods);
+                             controls, ByteString.valueOf("o=test"), mods);
     modifyOperation.run();
     assertEquals(modifyOperation.getResultCode(), ResultCode.SUCCESS);
     assertTrue(DirectoryServer.entryExists(DN.decode("o=test")));
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/core/OperationTestCase.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/core/OperationTestCase.java
index f647bbc..a711a14 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/core/OperationTestCase.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/core/OperationTestCase.java
@@ -37,6 +37,7 @@
 import org.opends.server.api.ConnectionHandler;
 import org.opends.server.protocols.ldap.LDAPConnectionHandler;
 import org.opends.server.protocols.ldap.LDAPStatistics;
+import org.opends.server.protocols.ldap.LDAPControl;
 import org.opends.server.types.Control;
 import org.opends.server.types.Operation;
 
@@ -448,7 +449,7 @@
   @Test(dataProvider = "testOperations")
   public void testAddAndRemoveResponseControl(Operation operation)
   {
-    Control c = new Control("1.2.3.4", false);
+    Control c = new LDAPControl("1.2.3.4", false);
     operation.addResponseControl(c);
     operation.removeResponseControl(c);
 
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/core/PluginConfigManagerTestCase.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/core/PluginConfigManagerTestCase.java
index df4a88c..0d0026a 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/core/PluginConfigManagerTestCase.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/core/PluginConfigManagerTestCase.java
@@ -643,7 +643,7 @@
 
       DN dn = pluginArray[i].getPluginEntryDN();
       String name =
-           dn.getRDN().getAttributeValue(0).getStringValue().toLowerCase();
+           dn.getRDN().getAttributeValue(0).getValue().toString().toLowerCase();
       actualOrder.append(name);
 
       if (! name.equals(expectedNameOrder[i]))
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/core/RejectUnauthReqTests.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/core/RejectUnauthReqTests.java
index 508926f..94f621f 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/core/RejectUnauthReqTests.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/core/RejectUnauthReqTests.java
@@ -37,12 +37,8 @@
 import org.testng.annotations.Test;
 import org.testng.annotations.BeforeClass;
 import org.opends.server.TestCaseUtils;
-import org.opends.server.protocols.asn1.ASN1OctetString;
 import org.opends.server.protocols.internal.InternalClientConnection;
-import org.opends.server.types.DN;
-import org.opends.server.types.AuthenticationInfo;
-import org.opends.server.types.LDAPException;
-import org.opends.server.types.ResultCode;
+import org.opends.server.types.*;
 import org.opends.server.protocols.ldap.LDAPControl;
 import org.opends.server.protocols.ldap.LDAPMessage;
 import org.opends.server.protocols.ldap.UnbindRequestProtocolOp;
@@ -383,8 +379,8 @@
 
     InternalClientConnection conn = new InternalClientConnection(
         new AuthenticationInfo());
-    ASN1OctetString user = new ASN1OctetString("cn=Directory Manager");
-    ASN1OctetString password = new ASN1OctetString("password");
+    ByteString user = ByteString.valueOf("cn=Directory Manager");
+    ByteString password = ByteString.valueOf("password");
     BindOperation bindOperation = conn.processSimpleBind(user, password);
     assertEquals(bindOperation.getResultCode(), ResultCode.SUCCESS);
   }
@@ -429,10 +425,10 @@
     AtomicInteger nextMessageID = new AtomicInteger(1);
     LDAPAuthenticationHandler authHandler = new LDAPAuthenticationHandler(
         reader, writer, "localhost", nextMessageID);
-    authHandler.doSimpleBind(3, new ASN1OctetString("cn=Directory Manager"),
-        new ASN1OctetString("password"), new ArrayList<LDAPControl>(),
-        new ArrayList<LDAPControl>());
-    ASN1OctetString authzID = authHandler.requestAuthorizationIdentity();
+    authHandler.doSimpleBind(3, ByteString.valueOf("cn=Directory Manager"),
+        ByteString.valueOf("password"), new ArrayList<Control>(),
+        new ArrayList<Control>());
+    ByteString authzID = authHandler.requestAuthorizationIdentity();
     assertNotNull(authzID);
 
     LDAPMessage unbindMessage = new LDAPMessage(
@@ -463,7 +459,7 @@
     AtomicInteger nextMessageID = new AtomicInteger(1);
     LDAPAuthenticationHandler authHandler = new LDAPAuthenticationHandler(
         reader, writer, "localhost", nextMessageID);
-    ASN1OctetString authzID = authHandler.requestAuthorizationIdentity();
+    ByteString authzID = authHandler.requestAuthorizationIdentity();
     assertNull(authzID);
 
     LDAPMessage unbindMessage = new LDAPMessage(
@@ -631,8 +627,8 @@
 
       InternalClientConnection conn = new InternalClientConnection(
           new AuthenticationInfo());
-      ASN1OctetString user = new ASN1OctetString("cn=Directory Manager");
-      ASN1OctetString password = new ASN1OctetString("password");
+      ByteString user = ByteString.valueOf("cn=Directory Manager");
+      ByteString password = ByteString.valueOf("password");
       // Unauthenticated BIND request.
       BindOperation bindOperation = conn.processSimpleBind(DN.nullDN(), null);
       assertEquals(bindOperation.getResultCode(), ResultCode.SUCCESS);
@@ -748,7 +744,7 @@
       AtomicInteger nextMessageID = new AtomicInteger(1);
       LDAPAuthenticationHandler authHandler = new LDAPAuthenticationHandler(
           reader, writer, "localhost", nextMessageID);
-      ASN1OctetString authzID = null;
+      ByteString authzID = null;
       try
       {
         authzID = authHandler.requestAuthorizationIdentity();
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/core/SearchOperationTestCase.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/core/SearchOperationTestCase.java
index 4cb0cd9..ee479c0 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/core/SearchOperationTestCase.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/core/SearchOperationTestCase.java
@@ -27,27 +27,10 @@
 
 package org.opends.server.core;
 
-import org.opends.server.protocols.internal.InternalClientConnection;
-import org.opends.server.protocols.internal.InternalSearchOperation;
-import org.opends.server.protocols.asn1.ASN1OctetString;
-import org.opends.server.protocols.asn1.ASN1Reader;
-import org.opends.server.protocols.asn1.ASN1Writer;
-import org.opends.server.protocols.asn1.ASN1Exception;
-import org.opends.server.protocols.asn1.ASN1Element;
-import org.opends.server.protocols.ldap.*;
-import org.opends.server.types.*;
-import org.opends.server.TestCaseUtils;
-import org.opends.server.util.ServerConstants;
-import org.opends.server.util.StaticUtils;
-import org.opends.server.controls.MatchedValuesFilter;
-import org.opends.server.controls.MatchedValuesControl;
-import org.opends.server.plugins.InvocationCounterPlugin;
-import org.testng.annotations.BeforeClass;
-import org.testng.annotations.DataProvider;
-import org.testng.annotations.Test;
-
 import static org.testng.Assert.*;
 
+import java.io.IOException;
+import java.net.Socket;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.HashSet;
@@ -55,8 +38,43 @@
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Set;
-import java.net.Socket;
-import java.io.IOException;
+
+import org.opends.server.TestCaseUtils;
+import org.opends.server.controls.MatchedValuesControl;
+import org.opends.server.controls.MatchedValuesFilter;
+import org.opends.server.plugins.InvocationCounterPlugin;
+import org.opends.server.protocols.asn1.ASN1Exception;
+import org.opends.server.protocols.internal.InternalClientConnection;
+import org.opends.server.protocols.internal.InternalSearchOperation;
+import org.opends.server.protocols.ldap.BindRequestProtocolOp;
+import org.opends.server.protocols.ldap.BindResponseProtocolOp;
+import org.opends.server.protocols.ldap.LDAPAttribute;
+import org.opends.server.protocols.ldap.LDAPConstants;
+import org.opends.server.protocols.ldap.LDAPControl;
+import org.opends.server.protocols.ldap.LDAPFilter;
+import org.opends.server.protocols.ldap.LDAPMessage;
+import org.opends.server.protocols.ldap.LDAPResultCode;
+import org.opends.server.protocols.ldap.SearchRequestProtocolOp;
+import org.opends.server.protocols.ldap.SearchResultDoneProtocolOp;
+import org.opends.server.protocols.ldap.SearchResultEntryProtocolOp;
+import org.opends.server.tools.LDAPWriter;
+import org.opends.server.types.Attribute;
+import org.opends.server.types.ByteString;
+import org.opends.server.types.Control;
+import org.opends.server.types.DN;
+import org.opends.server.types.DereferencePolicy;
+import org.opends.server.types.Entry;
+import org.opends.server.types.LDAPException;
+import org.opends.server.types.Operation;
+import org.opends.server.types.ResultCode;
+import org.opends.server.types.SearchResultEntry;
+import org.opends.server.types.SearchResultReference;
+import org.opends.server.types.SearchScope;
+import org.opends.server.util.ServerConstants;
+import org.opends.server.util.StaticUtils;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
 
 public class SearchOperationTestCase extends OperationTestCase
 {
@@ -192,7 +210,7 @@
                              InternalClientConnection.nextOperationID(),
                              InternalClientConnection.nextMessageID(),
                              new ArrayList<Control>(),
-                             new ASN1OctetString(BASE),
+                             ByteString.valueOf(BASE),
                              SearchScope.WHOLE_SUBTREE,
                              DereferencePolicy.NEVER_DEREF_ALIASES,
                              -1,
@@ -240,16 +258,16 @@
 
   private SearchResultEntryProtocolOp searchExternalForSingleEntry(
        SearchRequestProtocolOp searchRequest,
-       ArrayList<LDAPControl> controls)
+       ArrayList<Control> controls)
        throws IOException, LDAPException, ASN1Exception, InterruptedException
   {
     // Establish a connection to the server.
     Socket s = new Socket("127.0.0.1", TestCaseUtils.getServerLdapPort());
     try
     {
-      ASN1Reader r = new ASN1Reader(s);
-      ASN1Writer w = new ASN1Writer(s);
-      r.setIOTimeout(1500000);
+      org.opends.server.tools.LDAPReader r = new org.opends.server.tools.LDAPReader(s);
+      LDAPWriter w = new LDAPWriter(s);
+      s.setSoTimeout(1500000);
 
       bindAsManager(w, r);
 
@@ -269,14 +287,12 @@
 
       LDAPMessage message;
       message = new LDAPMessage(2, searchRequest, controls);
-      w.writeElement(message.encode());
+      w.writeMessage(message);
 
       SearchResultEntryProtocolOp searchResultEntry = null;
       SearchResultDoneProtocolOp searchResultDone = null;
-      ASN1Element element;
-      while (searchResultDone == null && (element = r.readElement()) != null)
+      while (searchResultDone == null && (message = r.readMessage()) != null)
       {
-        message = LDAPMessage.decode(element.decodeAsSequence());
         switch (message.getProtocolOpType())
         {
           case LDAPConstants.OP_TYPE_SEARCH_RESULT_ENTRY:
@@ -313,7 +329,7 @@
     }
   }
 
-  private void bindAsManager(ASN1Writer w, ASN1Reader r)
+  private void bindAsManager(LDAPWriter w, org.opends.server.tools.LDAPReader r)
        throws IOException, LDAPException, ASN1Exception, InterruptedException
   {
     // Since we are going to be watching the post-response count, we need to
@@ -326,12 +342,12 @@
     InvocationCounterPlugin.resetAllCounters();
     BindRequestProtocolOp bindRequest =
          new BindRequestProtocolOp(
-              new ASN1OctetString("cn=Directory Manager"),
-              3, new ASN1OctetString("password"));
+              ByteString.valueOf("cn=Directory Manager"),
+              3, ByteString.valueOf("password"));
     LDAPMessage message = new LDAPMessage(1, bindRequest);
-    w.writeElement(message.encode());
+    w.writeMessage(message);
 
-    message = LDAPMessage.decode(r.readElement().decodeAsSequence());
+    message = r.readMessage();
     BindResponseProtocolOp bindResponse = message.getBindResponseProtocolOp();
 //    assertEquals(InvocationCounterPlugin.waitForPostResponse(), 1);
     assertEquals(bindResponse.getResultCode(), LDAPResultCode.SUCCESS);
@@ -351,7 +367,7 @@
               InternalClientConnection.nextOperationID(),
               InternalClientConnection.nextMessageID(),
               new ArrayList<Control>(),
-              new ASN1OctetString(BASE),
+              ByteString.valueOf(BASE),
               SearchScope.WHOLE_SUBTREE,
               DereferencePolicy.NEVER_DEREF_ALIASES,
               Integer.MAX_VALUE,
@@ -381,7 +397,7 @@
               InternalClientConnection.nextOperationID(),
               InternalClientConnection.nextMessageID(),
               new ArrayList<Control>(),
-              new ASN1OctetString(BASE),
+              ByteString.valueOf(BASE),
               SearchScope.WHOLE_SUBTREE,
               DereferencePolicy.NEVER_DEREF_ALIASES,
               Integer.MAX_VALUE,
@@ -414,7 +430,7 @@
               InternalClientConnection.nextOperationID(),
               InternalClientConnection.nextMessageID(),
               new ArrayList<Control>(),
-              new ASN1OctetString(BASE),
+              ByteString.valueOf(BASE),
               SearchScope.WHOLE_SUBTREE,
               DereferencePolicy.NEVER_DEREF_ALIASES,
               Integer.MAX_VALUE,
@@ -446,7 +462,7 @@
               InternalClientConnection.nextOperationID(),
               InternalClientConnection.nextMessageID(),
               new ArrayList<Control>(),
-              new ASN1OctetString(BASE),
+              ByteString.valueOf(BASE),
               SearchScope.WHOLE_SUBTREE,
               DereferencePolicy.NEVER_DEREF_ALIASES,
               Integer.MAX_VALUE,
@@ -478,7 +494,7 @@
               InternalClientConnection.nextOperationID(),
               InternalClientConnection.nextMessageID(),
               new ArrayList<Control>(),
-              new ASN1OctetString(BASE),
+              ByteString.valueOf(BASE),
               SearchScope.WHOLE_SUBTREE,
               DereferencePolicy.NEVER_DEREF_ALIASES,
               Integer.MAX_VALUE,
@@ -513,7 +529,7 @@
               InternalClientConnection.nextOperationID(),
               InternalClientConnection.nextMessageID(),
               new ArrayList<Control>(),
-              new ASN1OctetString(BASE),
+              ByteString.valueOf(BASE),
               SearchScope.WHOLE_SUBTREE,
               DereferencePolicy.NEVER_DEREF_ALIASES,
               Integer.MAX_VALUE,
@@ -549,7 +565,7 @@
               InternalClientConnection.nextOperationID(),
               InternalClientConnection.nextMessageID(),
               new ArrayList<Control>(),
-              new ASN1OctetString(BASE),
+              ByteString.valueOf(BASE),
               SearchScope.WHOLE_SUBTREE,
               DereferencePolicy.NEVER_DEREF_ALIASES,
               Integer.MAX_VALUE,
@@ -570,7 +586,7 @@
   {
     SearchRequestProtocolOp searchRequest =
          new SearchRequestProtocolOp(
-              new ASN1OctetString(BASE),
+              ByteString.valueOf(BASE),
               SearchScope.WHOLE_SUBTREE,
               DereferencePolicy.NEVER_DEREF_ALIASES,
               Integer.MAX_VALUE,
@@ -590,7 +606,7 @@
     attributes.add("*");
     SearchRequestProtocolOp searchRequest =
          new SearchRequestProtocolOp(
-              new ASN1OctetString(BASE),
+              ByteString.valueOf(BASE),
               SearchScope.WHOLE_SUBTREE,
               DereferencePolicy.NEVER_DEREF_ALIASES,
               Integer.MAX_VALUE,
@@ -609,7 +625,7 @@
   {
     SearchRequestProtocolOp searchRequest =
          new SearchRequestProtocolOp(
-              new ASN1OctetString(BASE),
+              ByteString.valueOf(BASE),
               SearchScope.WHOLE_SUBTREE,
               DereferencePolicy.NEVER_DEREF_ALIASES,
               Integer.MAX_VALUE,
@@ -634,7 +650,7 @@
     attributes.add("*");
     SearchRequestProtocolOp searchRequest =
          new SearchRequestProtocolOp(
-              new ASN1OctetString(BASE),
+              ByteString.valueOf(BASE),
               SearchScope.WHOLE_SUBTREE,
               DereferencePolicy.NEVER_DEREF_ALIASES,
               Integer.MAX_VALUE,
@@ -659,7 +675,7 @@
     attributes.add("objectclass");
     SearchRequestProtocolOp searchRequest =
          new SearchRequestProtocolOp(
-              new ASN1OctetString(BASE),
+              ByteString.valueOf(BASE),
               SearchScope.WHOLE_SUBTREE,
               DereferencePolicy.NEVER_DEREF_ALIASES,
               Integer.MAX_VALUE,
@@ -684,7 +700,7 @@
     attributes.add("objectclass");
     SearchRequestProtocolOp searchRequest =
          new SearchRequestProtocolOp(
-              new ASN1OctetString(BASE),
+              ByteString.valueOf(BASE),
               SearchScope.WHOLE_SUBTREE,
               DereferencePolicy.NEVER_DEREF_ALIASES,
               Integer.MAX_VALUE,
@@ -709,7 +725,7 @@
     attributes.add("createtimestamp");
     SearchRequestProtocolOp searchRequest =
          new SearchRequestProtocolOp(
-              new ASN1OctetString(BASE),
+              ByteString.valueOf(BASE),
               SearchScope.WHOLE_SUBTREE,
               DereferencePolicy.NEVER_DEREF_ALIASES,
               Integer.MAX_VALUE,
@@ -731,7 +747,7 @@
     attributes.add("title");
     SearchRequestProtocolOp searchRequest =
          new SearchRequestProtocolOp(
-              new ASN1OctetString(BASE),
+              ByteString.valueOf(BASE),
               SearchScope.WHOLE_SUBTREE,
               DereferencePolicy.NEVER_DEREF_ALIASES,
               Integer.MAX_VALUE,
@@ -754,7 +770,7 @@
     attributes.add("title");
     SearchRequestProtocolOp searchRequest =
          new SearchRequestProtocolOp(
-              new ASN1OctetString(BASE),
+              ByteString.valueOf(BASE),
               SearchScope.WHOLE_SUBTREE,
               DereferencePolicy.NEVER_DEREF_ALIASES,
               Integer.MAX_VALUE,
@@ -780,7 +796,7 @@
     attributes.add("title;lang-ja;phonetic");
     SearchRequestProtocolOp searchRequest =
          new SearchRequestProtocolOp(
-              new ASN1OctetString(BASE),
+              ByteString.valueOf(BASE),
               SearchScope.WHOLE_SUBTREE,
               DereferencePolicy.NEVER_DEREF_ALIASES,
               Integer.MAX_VALUE,
@@ -806,12 +822,12 @@
          new ArrayList<MatchedValuesFilter>();
     filters.add(matchedValuesFilter);
     MatchedValuesControl mvc = new MatchedValuesControl(true, filters);
-    ArrayList<LDAPControl> controls = new ArrayList<LDAPControl>();
-    controls.add(new LDAPControl(mvc));
+    ArrayList<Control> controls = new ArrayList<Control>();
+    controls.add(mvc);
 
     SearchRequestProtocolOp searchRequest =
          new SearchRequestProtocolOp(
-              new ASN1OctetString(BASE),
+              ByteString.valueOf(BASE),
               SearchScope.WHOLE_SUBTREE,
               DereferencePolicy.NEVER_DEREF_ALIASES,
               Integer.MAX_VALUE,
@@ -848,7 +864,7 @@
               InternalClientConnection.nextOperationID(),
               InternalClientConnection.nextMessageID(),
               new ArrayList<Control>(),
-              new ASN1OctetString(BASE),
+              ByteString.valueOf(BASE),
               SearchScope.WHOLE_SUBTREE,
               DereferencePolicy.NEVER_DEREF_ALIASES,
               Integer.MAX_VALUE,
@@ -887,7 +903,7 @@
               InternalClientConnection.nextOperationID(),
               InternalClientConnection.nextMessageID(),
               new ArrayList<Control>(),
-              new ASN1OctetString("ou=nonexistent,o=test"),
+              ByteString.valueOf("ou=nonexistent,o=test"),
               SearchScope.WHOLE_SUBTREE,
               DereferencePolicy.NEVER_DEREF_ALIASES,
               Integer.MAX_VALUE,
@@ -1025,13 +1041,13 @@
 
     if (stripRealAttributes)
     {
-      controls.add(new Control(ServerConstants.OID_VIRTUAL_ATTRS_ONLY,
+      controls.add(new LDAPControl(ServerConstants.OID_VIRTUAL_ATTRS_ONLY,
           false));
     }
 
     if (stripVirtualAttributes)
     {
-      controls.add(new Control(ServerConstants.OID_REAL_ATTRS_ONLY,
+      controls.add(new LDAPControl(ServerConstants.OID_REAL_ATTRS_ONLY,
           false));
     }
 
@@ -1311,7 +1327,7 @@
 
     SearchRequestProtocolOp searchRequest =
       new SearchRequestProtocolOp(
-          new ASN1OctetString(userDNString),
+          ByteString.valueOf(userDNString),
           SearchScope.BASE_OBJECT,
           DereferencePolicy.NEVER_DEREF_ALIASES,
           Integer.MAX_VALUE,
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/core/TestModifyDNOperation.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/core/TestModifyDNOperation.java
index fc646e3..e79e7ee 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/core/TestModifyDNOperation.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/core/TestModifyDNOperation.java
@@ -34,7 +34,6 @@
 import static org.testng.Assert.assertTrue;
 import static org.testng.Assert.assertFalse;
 import org.opends.server.protocols.internal.InternalClientConnection;
-import org.opends.server.protocols.asn1.ASN1OctetString;
 import org.opends.server.protocols.asn1.ASN1Reader;
 import org.opends.server.protocols.asn1.ASN1Writer;
 import org.opends.server.protocols.ldap.*;
@@ -47,6 +46,7 @@
 import org.opends.server.plugins.InvocationCounterPlugin;
 import org.opends.server.plugins.ShortCircuitPlugin;
 import org.opends.server.tools.LDAPModify;
+import org.opends.server.tools.LDAPWriter;
 import org.opends.messages.Message;
 
 import java.util.ArrayList;
@@ -261,9 +261,9 @@
     ModifyDNOperationBasis[] modifies = new ModifyDNOperationBasis[]
     {
       new ModifyDNOperationBasis(conn, conn.nextOperationID(), conn.nextMessageID(),
-                            noControls, new ASN1OctetString("cn=test,ou=test"),
-                            new ASN1OctetString("cn=test2"), true,
-                            new ASN1OctetString("dc=example,dc=com")),
+                            noControls, ByteString.valueOf("cn=test,ou=test"),
+                            ByteString.valueOf("cn=test2"), true,
+                            ByteString.valueOf("dc=example,dc=com")),
       new ModifyDNOperationBasis(conn, conn.nextOperationID(), conn.nextMessageID(),
                             noControls, DN.decode("cn=test,ou=test"),
                             RDN.decode("cn=test2"), true,
@@ -285,8 +285,8 @@
     ModifyDNOperationBasis modifyDNOperation =
          new ModifyDNOperationBasis(conn, conn.nextOperationID(), conn.nextMessageID(),
                                noControls,
-                               new ASN1OctetString("uid=user.0,ou=People,dc=example,dc=com"),
-                               new ASN1OctetString("uid=user.test0"), false,
+                               ByteString.valueOf("uid=user.0,ou=People,dc=example,dc=com"),
+                               ByteString.valueOf("uid=user.test0"), false,
                                null);
 
     modifyDNOperation.run();
@@ -300,8 +300,8 @@
     for (int i = 0; i < rdn.getNumValues(); i++)
     {
       AttributeType attribute = rdn.getAttributeType(i);
-      assertTrue(newEntry.hasValue(attribute, null, new AttributeValue(attribute, "user.0")));
-      assertTrue(newEntry.hasValue(attribute, null, new AttributeValue(attribute, "user.test0")));
+      assertTrue(newEntry.hasValue(attribute, null, AttributeValues.create(attribute, "user.0")));
+      assertTrue(newEntry.hasValue(attribute, null, AttributeValues.create(attribute, "user.test0")));
     }
 
     examineCompletedOperation(modifyDNOperation);
@@ -310,8 +310,8 @@
     modifyDNOperation =
          new ModifyDNOperationBasis(conn, conn.nextOperationID(), conn.nextMessageID(),
                                noControls,
-                               new ASN1OctetString("uid=user.test0,ou=People,dc=example,dc=com"),
-                               new ASN1OctetString("uid=user.0"), true,
+                               ByteString.valueOf("uid=user.test0,ou=People,dc=example,dc=com"),
+                               ByteString.valueOf("uid=user.0"), true,
                                null);
 
     modifyDNOperation.run();
@@ -325,8 +325,8 @@
     for (int i = 0; i < rdn.getNumValues(); i++)
     {
       AttributeType attribute = rdn.getAttributeType(i);
-      assertTrue(newEntry.hasValue(attribute, null, new AttributeValue(attribute, "user.0")));
-      assertFalse(newEntry.hasValue(attribute, null, new AttributeValue(attribute, "user.test0")));
+      assertTrue(newEntry.hasValue(attribute, null, AttributeValues.create(attribute, "user.0")));
+      assertFalse(newEntry.hasValue(attribute, null, AttributeValues.create(attribute, "user.test0")));
     }
 
     examineCompletedOperation(modifyDNOperation);
@@ -359,8 +359,8 @@
     for (int i = 0; i < rdn.getNumValues(); i++)
     {
       AttributeType attribute = rdn.getAttributeType(i);
-      assertTrue(newEntry.hasValue(attribute, null, new AttributeValue(attribute, "user.0")));
-      assertTrue(newEntry.hasValue(attribute, null, new AttributeValue(attribute, "user.test0")));
+      assertTrue(newEntry.hasValue(attribute, null, AttributeValues.create(attribute, "user.0")));
+      assertTrue(newEntry.hasValue(attribute, null, AttributeValues.create(attribute, "user.test0")));
     }
 
     examineCompletedOperation(modifyDNOperation);
@@ -384,8 +384,8 @@
     for (int i = 0; i < rdn.getNumValues(); i++)
     {
       AttributeType attribute = rdn.getAttributeType(i);
-      assertTrue(newEntry.hasValue(attribute, null, new AttributeValue(attribute, "user.0")));
-      assertFalse(newEntry.hasValue(attribute, null, new AttributeValue(attribute, "user.test0")));
+      assertTrue(newEntry.hasValue(attribute, null, AttributeValues.create(attribute, "user.0")));
+      assertFalse(newEntry.hasValue(attribute, null, AttributeValues.create(attribute, "user.test0")));
     }
 
     examineCompletedOperation(modifyDNOperation);
@@ -403,8 +403,8 @@
     ModifyDNOperationBasis modifyDNOperation =
          new ModifyDNOperationBasis(conn, conn.nextOperationID(), conn.nextMessageID(),
                                noControls,
-                               new ASN1OctetString("uid=user.0,ou=People,dc=example,dc=com"),
-                               new ASN1OctetString("uid=user.test0"), true,
+                               ByteString.valueOf("uid=user.0,ou=People,dc=example,dc=com"),
+                               ByteString.valueOf("uid=user.test0"), true,
                                null);
 
     modifyDNOperation.run();
@@ -418,8 +418,8 @@
     for (int i = 0; i < rdn.getNumValues(); i++)
     {
       AttributeType attribute = rdn.getAttributeType(i);
-      assertFalse(newEntry.hasValue(attribute, null, new AttributeValue(attribute, "user.0")));
-      assertTrue(newEntry.hasValue(attribute, null, new AttributeValue(attribute, "user.test0")));
+      assertFalse(newEntry.hasValue(attribute, null, AttributeValues.create(attribute, "user.0")));
+      assertTrue(newEntry.hasValue(attribute, null, AttributeValues.create(attribute, "user.test0")));
     }
 
     examineCompletedOperation(modifyDNOperation);
@@ -428,8 +428,8 @@
     modifyDNOperation =
          new ModifyDNOperationBasis(conn, conn.nextOperationID(), conn.nextMessageID(),
                                noControls,
-                               new ASN1OctetString("uid=user.test0,ou=People,dc=example,dc=com"),
-                               new ASN1OctetString("uid=user.0"), true,
+                               ByteString.valueOf("uid=user.test0,ou=People,dc=example,dc=com"),
+                               ByteString.valueOf("uid=user.0"), true,
                                null);
 
     modifyDNOperation.run();
@@ -443,8 +443,8 @@
     for (int i = 0; i < rdn.getNumValues(); i++)
     {
       AttributeType attribute = rdn.getAttributeType(i);
-      assertTrue(newEntry.hasValue(attribute, null, new AttributeValue(attribute, "user.0")));
-      assertFalse(newEntry.hasValue(attribute, null, new AttributeValue(attribute, "user.test0")));
+      assertTrue(newEntry.hasValue(attribute, null, AttributeValues.create(attribute, "user.0")));
+      assertFalse(newEntry.hasValue(attribute, null, AttributeValues.create(attribute, "user.test0")));
     }
 
     examineCompletedOperation(modifyDNOperation);
@@ -483,8 +483,8 @@
     for (int i = 0; i < rdn.getNumValues(); i++)
     {
       AttributeType attribute = rdn.getAttributeType(i);
-      assertFalse(newEntry.hasValue(attribute, null, new AttributeValue(attribute, "user.0")));
-      assertTrue(newEntry.hasValue(attribute, null, new AttributeValue(attribute, "user.test0")));
+      assertFalse(newEntry.hasValue(attribute, null, AttributeValues.create(attribute, "user.0")));
+      assertTrue(newEntry.hasValue(attribute, null, AttributeValues.create(attribute, "user.test0")));
     }
 
     examineCompletedOperation(modifyDNOperation);
@@ -508,8 +508,8 @@
     for (int i = 0; i < rdn.getNumValues(); i++)
     {
       AttributeType attribute = rdn.getAttributeType(i);
-      assertTrue(newEntry.hasValue(attribute, null, new AttributeValue(attribute, "user.0")));
-      assertFalse(newEntry.hasValue(attribute, null, new AttributeValue(attribute, "user.test0")));
+      assertTrue(newEntry.hasValue(attribute, null, AttributeValues.create(attribute, "user.0")));
+      assertFalse(newEntry.hasValue(attribute, null, AttributeValues.create(attribute, "user.test0")));
     }
 
     examineCompletedOperation(modifyDNOperation);
@@ -527,9 +527,9 @@
     ModifyDNOperationBasis modifyDNOperation =
          new ModifyDNOperationBasis(conn, conn.nextOperationID(), conn.nextMessageID(),
                                noControls,
-                               new ASN1OctetString("uid=user.0,ou=People,dc=example,dc=com"),
-                               new ASN1OctetString("uid=user.test0"), true,
-                               new ASN1OctetString("dc=example,dc=com"));
+                               ByteString.valueOf("uid=user.0,ou=People,dc=example,dc=com"),
+                               ByteString.valueOf("uid=user.test0"), true,
+                               ByteString.valueOf("dc=example,dc=com"));
 
     modifyDNOperation.run();
     assertEquals(modifyDNOperation.getResultCode(),
@@ -542,8 +542,8 @@
     for (int i = 0; i < rdn.getNumValues(); i++)
     {
       AttributeType attribute = rdn.getAttributeType(i);
-      assertFalse(newEntry.hasValue(attribute, null, new AttributeValue(attribute, "user.0")));
-      assertTrue(newEntry.hasValue(attribute, null, new AttributeValue(attribute, "user.test0")));
+      assertFalse(newEntry.hasValue(attribute, null, AttributeValues.create(attribute, "user.0")));
+      assertTrue(newEntry.hasValue(attribute, null, AttributeValues.create(attribute, "user.test0")));
     }
 
     examineCompletedOPNoExtraPluginCounts(modifyDNOperation);
@@ -552,9 +552,9 @@
     modifyDNOperation =
          new ModifyDNOperationBasis(conn, conn.nextOperationID(), conn.nextMessageID(),
                                noControls,
-                               new ASN1OctetString("uid=user.test0,dc=example,dc=com"),
-                               new ASN1OctetString("uid=user.0"), true,
-                               new ASN1OctetString("ou=People,dc=example,dc=com"));
+                               ByteString.valueOf("uid=user.test0,dc=example,dc=com"),
+                               ByteString.valueOf("uid=user.0"), true,
+                               ByteString.valueOf("ou=People,dc=example,dc=com"));
 
     modifyDNOperation.run();
     assertEquals(modifyDNOperation.getResultCode(),
@@ -567,8 +567,8 @@
     for (int i = 0; i < rdn.getNumValues(); i++)
     {
       AttributeType attribute = rdn.getAttributeType(i);
-      assertTrue(newEntry.hasValue(attribute, null, new AttributeValue(attribute, "user.0")));
-      assertFalse(newEntry.hasValue(attribute, null, new AttributeValue(attribute, "user.test0")));
+      assertTrue(newEntry.hasValue(attribute, null, AttributeValues.create(attribute, "user.0")));
+      assertFalse(newEntry.hasValue(attribute, null, AttributeValues.create(attribute, "user.test0")));
     }
 
     examineCompletedOPNoExtraPluginCounts(modifyDNOperation);
@@ -601,8 +601,8 @@
     for (int i = 0; i < rdn.getNumValues(); i++)
     {
       AttributeType attribute = rdn.getAttributeType(i);
-      assertFalse(newEntry.hasValue(attribute, null, new AttributeValue(attribute, "user.0")));
-      assertTrue(newEntry.hasValue(attribute, null, new AttributeValue(attribute, "user.test0")));
+      assertFalse(newEntry.hasValue(attribute, null, AttributeValues.create(attribute, "user.0")));
+      assertTrue(newEntry.hasValue(attribute, null, AttributeValues.create(attribute, "user.test0")));
     }
 
     examineCompletedOPNoExtraPluginCounts(modifyDNOperation);
@@ -626,8 +626,8 @@
     for (int i = 0; i < rdn.getNumValues(); i++)
     {
       AttributeType attribute = rdn.getAttributeType(i);
-      assertTrue(newEntry.hasValue(attribute, null, new AttributeValue(attribute, "user.0")));
-      assertFalse(newEntry.hasValue(attribute, null, new AttributeValue(attribute, "user.test0")));
+      assertTrue(newEntry.hasValue(attribute, null, AttributeValues.create(attribute, "user.0")));
+      assertFalse(newEntry.hasValue(attribute, null, AttributeValues.create(attribute, "user.test0")));
     }
 
     examineCompletedOPNoExtraPluginCounts(modifyDNOperation);
@@ -661,8 +661,8 @@
 
     for(Attribute attribute : newEntry.getAttribute("cn"))
     {
-      assertTrue(attribute.contains(new AttributeValue(attribute.getAttributeType(), "Aaccf Amar Test")));
-      assertTrue(attribute.contains(new AttributeValue(attribute.getAttributeType(), "Aaccf Amar")));
+      assertTrue(attribute.contains(AttributeValues.create(attribute.getAttributeType(), "Aaccf Amar Test")));
+      assertTrue(attribute.contains(AttributeValues.create(attribute.getAttributeType(), "Aaccf Amar")));
     }
 
     examineCompletedOPNoExtraPluginCounts(modifyDNOperation);
@@ -685,12 +685,12 @@
     assertNull(DirectoryServer.getEntry(DN.decode("cn=Aaccf Amar Test,dc=example,dc=com")));
     for(Attribute attribute : newOldEntry.getAttribute("cn"))
     {
-      assertTrue(attribute.contains(new AttributeValue(attribute.getAttributeType(), "Aaccf Amar Test")));
-      assertTrue(attribute.contains(new AttributeValue(attribute.getAttributeType(), "Aaccf Amar")));
+      assertTrue(attribute.contains(AttributeValues.create(attribute.getAttributeType(), "Aaccf Amar Test")));
+      assertTrue(attribute.contains(AttributeValues.create(attribute.getAttributeType(), "Aaccf Amar")));
     }
     for(Attribute attribute : newOldEntry.getAttribute("uid"))
     {
-      assertTrue(attribute.contains(new AttributeValue(attribute.getAttributeType(), "user.0")));
+      assertTrue(attribute.contains(AttributeValues.create(attribute.getAttributeType(), "user.0")));
     }
     examineCompletedOPNoExtraPluginCounts(modifyDNOperation);
   }
@@ -776,9 +776,9 @@
     ModifyDNOperationBasis modifyDNOperation =
          new ModifyDNOperationBasis(conn, conn.nextOperationID(), conn.nextMessageID(),
                                noControls,
-                               new ASN1OctetString("invalid DN"),
-                               new ASN1OctetString("uid=user.test0"), true,
-                               new ASN1OctetString("dc=example,dc=com"));
+                               ByteString.valueOf("invalid DN"),
+                               ByteString.valueOf("uid=user.test0"), true,
+                               ByteString.valueOf("dc=example,dc=com"));
 
     modifyDNOperation.run();
     assertEquals(modifyDNOperation.getResultCode(),
@@ -799,9 +799,9 @@
     ModifyDNOperationBasis modifyDNOperation =
          new ModifyDNOperationBasis(conn, conn.nextOperationID(), conn.nextMessageID(),
                                noControls,
-                               new ASN1OctetString("uid=user.0,ou=People,dc=example,dc=com"),
-                               new ASN1OctetString("invalid RDN"), true,
-                               new ASN1OctetString("dc=example,dc=com"));
+                               ByteString.valueOf("uid=user.0,ou=People,dc=example,dc=com"),
+                               ByteString.valueOf("invalid RDN"), true,
+                               ByteString.valueOf("dc=example,dc=com"));
 
     modifyDNOperation.run();
     assertEquals(modifyDNOperation.getResultCode(),
@@ -822,9 +822,9 @@
     ModifyDNOperationBasis modifyDNOperation =
          new ModifyDNOperationBasis(conn, conn.nextOperationID(), conn.nextMessageID(),
                                noControls,
-                               new ASN1OctetString("uid=user.0,ou=People,dc=example,dc=com"),
-                               new ASN1OctetString("uid=user.test0"), true,
-                               new ASN1OctetString("invalid superior"));
+                               ByteString.valueOf("uid=user.0,ou=People,dc=example,dc=com"),
+                               ByteString.valueOf("uid=user.test0"), true,
+                               ByteString.valueOf("invalid superior"));
 
     modifyDNOperation.run();
     assertEquals(modifyDNOperation.getResultCode(),
@@ -860,7 +860,7 @@
   public void testRawProxyAuthV1Modify() throws Exception
   {
     ProxiedAuthV1Control authV1Control = new ProxiedAuthV1Control(
-         new ASN1OctetString("cn=Directory Manager,cn=Root DNs,cn=config"));
+         ByteString.valueOf("cn=Directory Manager,cn=Root DNs,cn=config"));
     List<Control> controls = new ArrayList<Control>();
     controls.add(authV1Control);
     InvocationCounterPlugin.resetAllCounters();
@@ -868,8 +868,8 @@
     ModifyDNOperationBasis modifyDNOperation =
          new ModifyDNOperationBasis(proxyUserConn, proxyUserConn.nextOperationID(),
                                proxyUserConn.nextMessageID(), controls,
-                               new ASN1OctetString("uid=user.0,ou=People,dc=example,dc=com"),
-                               new ASN1OctetString("uid=user.test0"), false,
+                               ByteString.valueOf("uid=user.0,ou=People,dc=example,dc=com"),
+                               ByteString.valueOf("uid=user.test0"), false,
                                null);
 
     modifyDNOperation.run();
@@ -883,8 +883,8 @@
     for (int i = 0; i < rdn.getNumValues(); i++)
     {
       AttributeType attribute = rdn.getAttributeType(i);
-      assertTrue(newEntry.hasValue(attribute, null, new AttributeValue(attribute, "user.0")));
-      assertTrue(newEntry.hasValue(attribute, null, new AttributeValue(attribute, "user.test0")));
+      assertTrue(newEntry.hasValue(attribute, null, AttributeValues.create(attribute, "user.0")));
+      assertTrue(newEntry.hasValue(attribute, null, AttributeValues.create(attribute, "user.test0")));
     }
 
     examineCompletedOperation(modifyDNOperation);
@@ -893,8 +893,8 @@
     modifyDNOperation =
          new ModifyDNOperationBasis(proxyUserConn, proxyUserConn.nextOperationID(),
                                proxyUserConn.nextMessageID(), controls,
-                               new ASN1OctetString("uid=user.test0,ou=People,dc=example,dc=com"),
-                               new ASN1OctetString("uid=user.0"), true,
+                               ByteString.valueOf("uid=user.test0,ou=People,dc=example,dc=com"),
+                               ByteString.valueOf("uid=user.0"), true,
                                null);
 
     modifyDNOperation.run();
@@ -908,8 +908,8 @@
     for (int i = 0; i < rdn.getNumValues(); i++)
     {
       AttributeType attribute = rdn.getAttributeType(i);
-      assertTrue(newEntry.hasValue(attribute, null, new AttributeValue(attribute, "user.0")));
-      assertFalse(newEntry.hasValue(attribute, null, new AttributeValue(attribute, "user.test0")));
+      assertTrue(newEntry.hasValue(attribute, null, AttributeValues.create(attribute, "user.0")));
+      assertFalse(newEntry.hasValue(attribute, null, AttributeValues.create(attribute, "user.test0")));
     }
 
     examineCompletedOperation(modifyDNOperation);
@@ -918,7 +918,7 @@
   @Test
   public void testProcessedProxyAuthV1Modify() throws Exception
   {
-    ProxiedAuthV1Control authV1Control = new ProxiedAuthV1Control(new ASN1OctetString(
+    ProxiedAuthV1Control authV1Control = new ProxiedAuthV1Control(ByteString.valueOf(
       "cn=Directory Manager,cn=Root DNs,cn=config"));
     List<Control> controls = new ArrayList<Control>();
     controls.add(authV1Control);
@@ -942,8 +942,8 @@
     for (int i = 0; i < rdn.getNumValues(); i++)
     {
       AttributeType attribute = rdn.getAttributeType(i);
-      assertTrue(newEntry.hasValue(attribute, null, new AttributeValue(attribute, "user.0")));
-      assertTrue(newEntry.hasValue(attribute, null, new AttributeValue(attribute, "user.test0")));
+      assertTrue(newEntry.hasValue(attribute, null, AttributeValues.create(attribute, "user.0")));
+      assertTrue(newEntry.hasValue(attribute, null, AttributeValues.create(attribute, "user.test0")));
     }
 
     examineCompletedOperation(modifyDNOperation);
@@ -968,8 +968,8 @@
     for (int i = 0; i < rdn.getNumValues(); i++)
     {
       AttributeType attribute = rdn.getAttributeType(i);
-      assertTrue(newEntry.hasValue(attribute, null, new AttributeValue(attribute, "user.0")));
-      assertFalse(newEntry.hasValue(attribute, null, new AttributeValue(attribute, "user.test0")));
+      assertTrue(newEntry.hasValue(attribute, null, AttributeValues.create(attribute, "user.0")));
+      assertFalse(newEntry.hasValue(attribute, null, AttributeValues.create(attribute, "user.test0")));
     }
 
     examineCompletedOperation(modifyDNOperation);
@@ -979,7 +979,7 @@
   public void testProcessedProxyAuthV1DeniedModify() throws Exception
   {
     ProxiedAuthV1Control authV1Control =
-         new ProxiedAuthV1Control(new ASN1OctetString("cn=nonexistent,o=test"));
+         new ProxiedAuthV1Control(ByteString.valueOf("cn=nonexistent,o=test"));
     List<Control> controls = new ArrayList<Control>();
     controls.add(authV1Control);
     InvocationCounterPlugin.resetAllCounters();
@@ -1003,7 +1003,7 @@
   public void testProcessedProxyAuthV2Modify() throws Exception
   {
     ProxiedAuthV2Control authV2Control =
-         new ProxiedAuthV2Control(new ASN1OctetString(
+         new ProxiedAuthV2Control(ByteString.valueOf(
               "dn:cn=Directory Manager,cn=Root DNs,cn=config"));
     List<Control> controls = new ArrayList<Control>();
     controls.add(authV2Control);
@@ -1027,8 +1027,8 @@
     for (int i = 0; i < rdn.getNumValues(); i++)
     {
       AttributeType attribute = rdn.getAttributeType(i);
-      assertTrue(newEntry.hasValue(attribute, null, new AttributeValue(attribute, "user.0")));
-      assertTrue(newEntry.hasValue(attribute, null, new AttributeValue(attribute, "user.test0")));
+      assertTrue(newEntry.hasValue(attribute, null, AttributeValues.create(attribute, "user.0")));
+      assertTrue(newEntry.hasValue(attribute, null, AttributeValues.create(attribute, "user.test0")));
     }
 
     examineCompletedOperation(modifyDNOperation);
@@ -1052,8 +1052,8 @@
     for (int i = 0; i < rdn.getNumValues(); i++)
     {
       AttributeType attribute = rdn.getAttributeType(i);
-      assertTrue(newEntry.hasValue(attribute, null, new AttributeValue(attribute, "user.0")));
-      assertFalse(newEntry.hasValue(attribute, null, new AttributeValue(attribute, "user.test0")));
+      assertTrue(newEntry.hasValue(attribute, null, AttributeValues.create(attribute, "user.0")));
+      assertFalse(newEntry.hasValue(attribute, null, AttributeValues.create(attribute, "user.test0")));
     }
 
     examineCompletedOperation(modifyDNOperation);
@@ -1063,7 +1063,7 @@
   public void testProcessedProxyAuthV2DeniedModify() throws Exception
   {
     ProxiedAuthV2Control authV2Control = new ProxiedAuthV2Control(
-         new ASN1OctetString("dn:cn=nonexistent,o=test"));
+         ByteString.valueOf("dn:cn=nonexistent,o=test"));
     List<Control> controls = new ArrayList<Control>();
     controls.add(authV2Control);
     InvocationCounterPlugin.resetAllCounters();
@@ -1087,8 +1087,8 @@
   public void testProcessedProxyAuthV2CriticalityModify() throws Exception
   {
     Control authV2Control =
-         new Control(ServerConstants.OID_PROXIED_AUTH_V2, false,
-                     new ASN1OctetString("dn:cn=nonexistent,o=test"));
+         new LDAPControl(ServerConstants.OID_PROXIED_AUTH_V2, false,
+                     ByteString.valueOf("dn:cn=nonexistent,o=test"));
 
     List<Control> controls = new ArrayList<Control>();
     controls.add(authV2Control);
@@ -1113,8 +1113,8 @@
   public void testProcessedUnsupportedControlModify() throws Exception
   {
     LDAPFilter ldapFilter = LDAPFilter.decode("(preferredlanguage=ja)");
-    LDAPAssertionRequestControl assertControl =
-         new LDAPAssertionRequestControl("1.1.1.1.1.1", true, ldapFilter);
+    LDAPControl assertControl =
+         new LDAPControl("1.1.1.1.1.1", true);
     List<Control> controls = new ArrayList<Control>();
     controls.add(assertControl);
     InvocationCounterPlugin.resetAllCounters();
@@ -1152,17 +1152,17 @@
 
     InvocationCounterPlugin.resetAllCounters();
 
-    ASN1Reader r = new ASN1Reader(s);
-    ASN1Writer w = new ASN1Writer(s);
-    r.setIOTimeout(6000);
+    org.opends.server.tools.LDAPReader r = new org.opends.server.tools.LDAPReader(s);
+    LDAPWriter w = new LDAPWriter(s);
+    s.setSoTimeout(6000);
     BindRequestProtocolOp bindRequest =
               new BindRequestProtocolOp(
-                      new ASN1OctetString("cn=Directory Manager"),
-                      3, new ASN1OctetString("password"));
+                      ByteString.valueOf("cn=Directory Manager"),
+                      3, ByteString.valueOf("password"));
     LDAPMessage bindMessage = new LDAPMessage(1, bindRequest);
-    w.writeElement(bindMessage.encode());
+    w.writeMessage(bindMessage);
 
-    bindMessage = LDAPMessage.decode(r.readElement().decodeAsSequence());
+    bindMessage = r.readMessage();
     BindResponseProtocolOp bindResponse = bindMessage.getBindResponseProtocolOp();
     assertEquals(bindResponse.getResultCode(), LDAPResultCode.SUCCESS);
 
@@ -1170,13 +1170,13 @@
     InvocationCounterPlugin.resetAllCounters();
     ModifyDNRequestProtocolOp modifyRequest =
         new ModifyDNRequestProtocolOp(
-            new ASN1OctetString(entry.getDN().toString()),
-            new ASN1OctetString("uid=user.test0"), false);
+            ByteString.valueOf(entry.getDN().toString()),
+            ByteString.valueOf("uid=user.test0"), false);
     LDAPMessage message = new LDAPMessage(2, modifyRequest,
-                                          ShortCircuitPlugin.createShortCircuitLDAPControlList(80, "PreOperation"));
-    w.writeElement(message.encode());
+                                          ShortCircuitPlugin.createShortCircuitControlList(80, "PreOperation"));
+    w.writeMessage(message);
 
-    message = LDAPMessage.decode(r.readElement().decodeAsSequence());
+    message = r.readMessage();
     ModifyDNResponseProtocolOp modifyResponse =
         message.getModifyDNResponseProtocolOp();
 
@@ -1200,18 +1200,18 @@
     Socket s = new Socket("127.0.0.1", TestCaseUtils.getServerLdapPort());
     try
     {
-      ASN1Reader r = new ASN1Reader(s);
-      ASN1Writer w = new ASN1Writer(s);
-      r.setIOTimeout(15000);
+      org.opends.server.tools.LDAPReader r = new org.opends.server.tools.LDAPReader(s);
+      LDAPWriter w = new LDAPWriter(s);
+      s.setSoTimeout(15000);
 
       BindRequestProtocolOp bindRequest =
            new BindRequestProtocolOp(
-                new ASN1OctetString("cn=Directory Manager"),
-                3, new ASN1OctetString("password"));
+                ByteString.valueOf("cn=Directory Manager"),
+                3, ByteString.valueOf("password"));
       LDAPMessage message = new LDAPMessage(1, bindRequest);
-      w.writeElement(message.encode());
+      w.writeMessage(message);
 
-      message = LDAPMessage.decode(r.readElement().decodeAsSequence());
+      message = r.readMessage();
       BindResponseProtocolOp bindResponse = message.getBindResponseProtocolOp();
       assertEquals(bindResponse.getResultCode(), LDAPResultCode.SUCCESS);
 
@@ -1234,12 +1234,12 @@
 
         ModifyDNRequestProtocolOp modifyRequest =
           new ModifyDNRequestProtocolOp(
-               new ASN1OctetString(entry.getDN().toString()),
-               new ASN1OctetString("uid=user.test0"), false);
+               ByteString.valueOf(entry.getDN().toString()),
+               ByteString.valueOf("uid=user.test0"), false);
         message = new LDAPMessage(2, modifyRequest);
-        w.writeElement(message.encode());
+        w.writeMessage(message);
 
-        message = LDAPMessage.decode(r.readElement().decodeAsSequence());
+        message = r.readMessage();
         ModifyDNResponseProtocolOp modifyResponse =
              message.getModifyDNResponseProtocolOp();
 
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/core/WorkflowConfigurationTest.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/core/WorkflowConfigurationTest.java
index 243c76f..79dea36 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/core/WorkflowConfigurationTest.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/core/WorkflowConfigurationTest.java
@@ -38,20 +38,12 @@
 import org.opends.server.api.ClientConnection;
 import org.opends.server.config.ConfigConstants;
 import org.opends.server.core.networkgroups.NetworkGroup;
-import org.opends.server.protocols.asn1.ASN1OctetString;
 import org.opends.server.protocols.internal.InternalClientConnection;
 import org.opends.server.protocols.internal.InternalSearchOperation;
 import org.opends.server.protocols.ldap.LDAPAttribute;
 import org.opends.server.protocols.ldap.LDAPFilter;
 import org.opends.server.protocols.ldap.LDAPModification;
-import org.opends.server.types.Control;
-import org.opends.server.types.DN;
-import org.opends.server.types.DereferencePolicy;
-import org.opends.server.types.Entry;
-import org.opends.server.types.ModificationType;
-import org.opends.server.types.RawModification;
-import org.opends.server.types.ResultCode;
-import org.opends.server.types.SearchScope;
+import org.opends.server.types.*;
 import org.opends.server.util.StaticUtils;
 import org.opends.server.util.UtilTestCase;
 import org.opends.server.workflowelement.WorkflowElement;
@@ -234,7 +226,7 @@
        InternalClientConnection.nextOperationID(),
        InternalClientConnection.nextMessageID(),
        new ArrayList<Control>(),
-       new ASN1OctetString(baseDN),
+       ByteString.valueOf(baseDN),
        scope,
        DereferencePolicy.NEVER_DEREF_ALIASES,
        Integer.MAX_VALUE,
@@ -264,8 +256,8 @@
       String           attributeType,
       String           attributeValue)
   {
-    ArrayList<ASN1OctetString> ldapValues = new ArrayList<ASN1OctetString>();
-    ldapValues.add(new ASN1OctetString(attributeValue));
+    ArrayList<ByteString> ldapValues = new ArrayList<ByteString>();
+    ldapValues.add(ByteString.valueOf(attributeValue));
 
     LDAPAttribute ldapAttr = new LDAPAttribute(attributeType, ldapValues);
 
@@ -277,7 +269,7 @@
         InternalClientConnection.nextOperationID(),
         InternalClientConnection.nextMessageID(),
         new ArrayList<Control>(),
-        new ASN1OctetString(entryDN),
+        ByteString.valueOf(entryDN),
         ldapMods);
 
     return modifyOperation;
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/core/networkgroups/MockClientConnection.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/core/networkgroups/MockClientConnection.java
index 63a9776..80f20ad 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/core/networkgroups/MockClientConnection.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/core/networkgroups/MockClientConnection.java
@@ -37,10 +37,8 @@
 import org.opends.server.admin.std.meta.NetworkGroupCfgDefn.AllowedAuthMethod;
 import org.opends.server.api.ClientConnection;
 import org.opends.server.api.ConnectionHandler;
-import org.opends.server.api.ConnectionSecurityProvider;
 import org.opends.server.core.DirectoryServer;
 import org.opends.server.core.SearchOperation;
-import org.opends.server.protocols.asn1.ASN1OctetString;
 import org.opends.server.types.AuthenticationInfo;
 import org.opends.server.types.ByteString;
 import org.opends.server.types.CancelRequest;
@@ -96,8 +94,7 @@
       break;
     case SIMPLE:
       Entry simpleUser = DirectoryServer.getEntry(bindDN);
-      ByteString password = new ASN1OctetString();
-      password.setValue("password");
+      ByteString password = ByteString.valueOf("password");
       this.authInfo =
           new AuthenticationInfo(simpleUser, password, true);
       break;
@@ -190,15 +187,6 @@
 
 
   @Override
-  public ConnectionSecurityProvider getConnectionSecurityProvider()
-  {
-    // Stub.
-    return null;
-  }
-
-
-
-  @Override
   public InetAddress getLocalAddress()
   {
     // Stub.
@@ -268,15 +256,6 @@
 
 
   @Override
-  public String getSecurityMechanism()
-  {
-    // Stub.
-    return null;
-  }
-
-
-
-  @Override
   public String getServerAddress()
   {
     // Stub.
@@ -358,17 +337,20 @@
 
 
   @Override
-  public void setConnectionSecurityProvider(
-      ConnectionSecurityProvider securityProvider)
+  public void toString(StringBuilder buffer)
   {
     // Stub.
   }
 
 
 
+  /**
+   * {@inheritDoc}
+   */
   @Override
-  public void toString(StringBuilder buffer)
+  public int getSSF()
   {
     // Stub.
+    return 0;
   }
 }
\ No newline at end of file
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/core/networkgroups/NetworkGroupTest.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/core/networkgroups/NetworkGroupTest.java
index ae3775b..6fb0afd 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/core/networkgroups/NetworkGroupTest.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/core/networkgroups/NetworkGroupTest.java
@@ -42,8 +42,6 @@
 import org.opends.server.admin.std.meta.NetworkGroupCfgDefn.AllowedAuthMethod;
 import org.opends.server.api.ClientConnection;
 import org.opends.server.core.*;
-import org.opends.server.extensions.NullConnectionSecurityProvider;
-import org.opends.server.protocols.asn1.ASN1OctetString;
 import org.opends.server.protocols.internal.InternalClientConnection;
 import org.opends.server.protocols.ldap.LDAPFilter;
 import org.opends.server.types.Attribute;
@@ -946,8 +944,7 @@
     // Use simple bind on this connection
     Entry userEntry = DirectoryServer.getEntry(
             DN.decode("cn=Directory Manager, cn=Root DNs, cn=config"));
-    ByteString password = new ASN1OctetString();
-    password.setValue("password");
+    ByteString password = ByteString.valueOf("password");
     ClientConnection connection2 = new InternalClientConnection(
           new AuthenticationInfo(userEntry, password, true));
     ng = NetworkGroup.findMatchingNetworkGroup(connection2);
@@ -998,8 +995,7 @@
     // Use simple bind on this connection
     Entry userEntry = DirectoryServer.getEntry(
             DN.decode("cn=Directory Manager, cn=Root DNs, cn=config"));
-    ByteString password = new ASN1OctetString();
-    password.setValue("password");
+    ByteString password = ByteString.valueOf("password");
     ClientConnection connection2 = new InternalClientConnection(
           new AuthenticationInfo(userEntry, password, true));
     ng = NetworkGroup.findMatchingNetworkGroup(connection2);
@@ -1050,13 +1046,6 @@
     NetworkGroup ng = NetworkGroup.findMatchingNetworkGroup(connection1);
     assertEquals(ng, networkGroup);
 
-    // Now set the security provider to NullConnectionSecurityProvider
-    // the connection is not secured any more
-    connection1.setConnectionSecurityProvider(
-            new NullConnectionSecurityProvider());
-    ng = NetworkGroup.findMatchingNetworkGroup(connection1);
-    assertEquals(ng, defaultNg);
-
     // now change the criteria (security not mandatory)
     secCriteria = SecurityConnectionCriteria.SECURITY_NOT_REQUIRED;
     networkGroup.setConnectionCriteria(secCriteria);
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/crypto/GetSymmetricKeyExtendedOperationTestCase.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/crypto/GetSymmetricKeyExtendedOperationTestCase.java
index e8ab6dc..5047319 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/crypto/GetSymmetricKeyExtendedOperationTestCase.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/crypto/GetSymmetricKeyExtendedOperationTestCase.java
@@ -36,7 +36,6 @@
 import org.opends.server.core.ExtendedOperation;
 import org.opends.server.core.DirectoryServer;
 import org.opends.server.util.ServerConstants;
-import org.opends.server.protocols.asn1.ASN1OctetString;
 import org.opends.server.protocols.internal.InternalClientConnection;
 import org.opends.server.protocols.internal.InternalSearchOperation;
 import org.opends.admin.ads.ADSContext;
@@ -127,7 +126,7 @@
     for (Entry e : searchOp.getSearchEntries()) {
       final String symmetricKeyAttributeValue
               = e.getAttributeValue(attrSymmetricKey, DirectoryStringSyntax.DECODER);
-      final ASN1OctetString requestValue =
+      final ByteString requestValue =
            GetSymmetricKeyExtendedOperation.encodeRequestValue(
                 symmetricKeyAttributeValue, instanceKeyID);
       final ExtendedOperation extendedOperation =
@@ -138,7 +137,7 @@
       // The key should be re-wrapped, and hence have a different binary
       // representation....
       final String responseValue
-              = extendedOperation.getResponseValue().stringValue();
+              = extendedOperation.getResponseValue().toString();
       assertFalse(symmetricKeyAttributeValue.equals(responseValue));
       // ... but the keyIDs should be equal (ideally, the validity of
       // the returned value would be checked by decoding the
@@ -158,7 +157,7 @@
     String symmetricKey = "1";
     String instanceKeyID = cm.getInstanceKeyID();
 
-    ASN1OctetString requestValue =
+    ByteString requestValue =
          GetSymmetricKeyExtendedOperation.encodeRequestValue(
               symmetricKey, instanceKeyID);
 
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/AnonymousSASLMechanismHandlerTestCase.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/AnonymousSASLMechanismHandlerTestCase.java
index 2221b00..4b15211 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/AnonymousSASLMechanismHandlerTestCase.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/AnonymousSASLMechanismHandlerTestCase.java
@@ -35,12 +35,12 @@
 
 import org.opends.server.TestCaseUtils;
 import org.opends.server.core.BindOperationBasis;
-import org.opends.server.protocols.asn1.ASN1OctetString;
 import org.opends.server.protocols.internal.InternalClientConnection;
 import org.opends.server.tools.LDAPSearch;
 import org.opends.server.types.Control;
 import org.opends.server.types.DN;
 import org.opends.server.types.ResultCode;
+import org.opends.server.types.ByteString;
 
 import static org.testng.Assert.*;
 
@@ -167,7 +167,7 @@
     BindOperationBasis bindOperation =
          new BindOperationBasis(conn, conn.nextOperationID(), conn.nextMessageID(),
                            new ArrayList<Control>(), "3", DN.nullDN(),
-                           SASL_MECHANISM_ANONYMOUS, new ASN1OctetString());
+                           SASL_MECHANISM_ANONYMOUS, ByteString.empty());
     handler.processSASLBind(bindOperation);
     assertEquals(bindOperation.getResultCode(), ResultCode.SUCCESS);
 
@@ -194,7 +194,7 @@
          new BindOperationBasis(conn, conn.nextOperationID(), conn.nextMessageID(),
                            new ArrayList<Control>(), "3", DN.nullDN(),
                            SASL_MECHANISM_ANONYMOUS,
-                           new ASN1OctetString("Internal Trace String"));
+                           ByteString.valueOf("Internal Trace String"));
     handler.processSASLBind(bindOperation);
     assertEquals(bindOperation.getResultCode(), ResultCode.SUCCESS);
 
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/AttributeValuePasswordValidatorTestCase.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/AttributeValuePasswordValidatorTestCase.java
index 6cf0323..0d98bce 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/AttributeValuePasswordValidatorTestCase.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/AttributeValuePasswordValidatorTestCase.java
@@ -43,7 +43,6 @@
 import org.opends.server.admin.server.AdminTestCaseUtils;
 import org.opends.server.config.ConfigException;
 import org.opends.server.core.ModifyOperationBasis;
-import org.opends.server.protocols.asn1.ASN1OctetString;
 import org.opends.server.protocols.internal.InternalClientConnection;
 import org.opends.server.types.Attributes;
 import org.opends.server.types.ByteString;
@@ -408,7 +407,7 @@
          new AttributeValuePasswordValidator();
     validator.initializePasswordValidator(configuration);
 
-    ASN1OctetString pwOS = new ASN1OctetString(password);
+    ByteString pwOS = ByteString.valueOf(password);
     ArrayList<Modification> mods = new ArrayList<Modification>();
     mods.add(new Modification(ModificationType.REPLACE,
         Attributes.create("userpassword", password)));
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/CRAMMD5SASLMechanismHandlerTestCase.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/CRAMMD5SASLMechanismHandlerTestCase.java
index b3be84d..4f81980 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/CRAMMD5SASLMechanismHandlerTestCase.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/CRAMMD5SASLMechanismHandlerTestCase.java
@@ -46,15 +46,9 @@
 import org.opends.server.core.AddOperation;
 import org.opends.server.core.BindOperation;
 import org.opends.server.core.DirectoryServer;
-import org.opends.server.protocols.asn1.ASN1OctetString;
 import org.opends.server.protocols.internal.InternalClientConnection;
 import org.opends.server.tools.LDAPSearch;
-import org.opends.server.types.AuthenticationInfo;
-import org.opends.server.types.Control;
-import org.opends.server.types.DN;
-import org.opends.server.types.Entry;
-import org.opends.server.types.InitializationException;
-import org.opends.server.types.ResultCode;
+import org.opends.server.types.*;
 
 import static org.testng.Assert.*;
 
@@ -706,7 +700,7 @@
          new InternalClientConnection(new AuthenticationInfo());
     BindOperation bindOperation =
          conn.processSASLBind(DN.nullDN(), SASL_MECHANISM_CRAM_MD5,
-                              new ASN1OctetString("invalid"));
+                              ByteString.valueOf("invalid"));
     assertFalse(bindOperation.getResultCode() == ResultCode.SUCCESS);
   }
 
@@ -731,7 +725,7 @@
 
     bindOperation =
          conn.processSASLBind(DN.nullDN(), SASL_MECHANISM_CRAM_MD5,
-                              new ASN1OctetString("malformed"));
+                              ByteString.valueOf("malformed"));
     assertFalse(bindOperation.getResultCode() == ResultCode.SUCCESS);
   }
 
@@ -754,8 +748,8 @@
     assertEquals(bindOperation.getResultCode(),
                  ResultCode.SASL_BIND_IN_PROGRESS);
 
-    ASN1OctetString creds =
-         new ASN1OctetString("dn:cn=Directory Manager malformeddigest");
+    ByteString creds =
+         ByteString.valueOf("dn:cn=Directory Manager malformeddigest");
     bindOperation =
          conn.processSASLBind(DN.nullDN(), SASL_MECHANISM_CRAM_MD5, creds);
     assertFalse(bindOperation.getResultCode() == ResultCode.SUCCESS);
@@ -781,8 +775,8 @@
     assertEquals(bindOperation.getResultCode(),
                  ResultCode.SASL_BIND_IN_PROGRESS);
 
-    ASN1OctetString creds =
-         new ASN1OctetString("dn:cn=Directory Manager " +
+    ByteString creds =
+         ByteString.valueOf("dn:cn=Directory Manager " +
                           "malformedcredswiththerightlength");
     bindOperation =
          conn.processSASLBind(DN.nullDN(), SASL_MECHANISM_CRAM_MD5, creds);
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/CancelExtendedOperationTestCase.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/CancelExtendedOperationTestCase.java
index c614ca8..4a95bfe 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/CancelExtendedOperationTestCase.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/CancelExtendedOperationTestCase.java
@@ -40,12 +40,9 @@
 import org.opends.server.core.AddOperation;
 import org.opends.server.core.AbandonOperationBasis;
 import org.opends.server.plugins.DelayPreOpPlugin;
-import org.opends.server.protocols.asn1.ASN1Element;
-import org.opends.server.protocols.asn1.ASN1Integer;
-import org.opends.server.protocols.asn1.ASN1OctetString;
 import org.opends.server.protocols.asn1.ASN1Reader;
-import org.opends.server.protocols.asn1.ASN1Sequence;
 import org.opends.server.protocols.asn1.ASN1Writer;
+import org.opends.server.protocols.asn1.ASN1;
 import org.opends.server.protocols.internal.InternalClientConnection;
 import org.opends.server.protocols.ldap.AddRequestProtocolOp;
 import org.opends.server.protocols.ldap.AddResponseProtocolOp;
@@ -114,16 +111,18 @@
     // Create a new connection to the Directory Server and authenticate as
     // the Directory Manager.
     Socket socket = new Socket("127.0.0.1", TestCaseUtils.getServerLdapPort());
-    ASN1Reader reader = new ASN1Reader(socket);
-    ASN1Writer writer = new ASN1Writer(socket);
+    org.opends.server.tools.LDAPReader r =
+        new org.opends.server.tools.LDAPReader(socket);
+    org.opends.server.tools.LDAPWriter w =
+        new org.opends.server.tools.LDAPWriter(socket);
 
     BindRequestProtocolOp bindRequest =
-         new BindRequestProtocolOp(new ASN1OctetString("cn=Directory Manager"),
-                                   3, new ASN1OctetString("password"));
+         new BindRequestProtocolOp(ByteString.valueOf("cn=Directory Manager"),
+                                   3, ByteString.valueOf("password"));
     LDAPMessage message = new LDAPMessage(1, bindRequest);
-    writer.writeElement(message.encode());
+    w.writeMessage(message);
 
-    message = LDAPMessage.decode(reader.readElement().decodeAsSequence());
+    message = r.readMessage();
     BindResponseProtocolOp bindResponse = message.getBindResponseProtocolOp();
     assertEquals(bindResponse.getResultCode(), LDAPResultCode.SUCCESS);
 
@@ -133,32 +132,34 @@
     // cancel request.
     ArrayList<RawAttribute> attributes = new ArrayList<RawAttribute>();
 
-    ArrayList<ASN1OctetString> values = new ArrayList<ASN1OctetString>(2);
-    values.add(new ASN1OctetString("top"));
-    values.add(new ASN1OctetString("organizationalUnit"));
+    ArrayList<ByteString> values = new ArrayList<ByteString>(2);
+    values.add(ByteString.valueOf("top"));
+    values.add(ByteString.valueOf("organizationalUnit"));
     attributes.add(new LDAPAttribute("objectClass", values));
 
-    values = new ArrayList<ASN1OctetString>(1);
-    values.add(new ASN1OctetString("People"));
+    values = new ArrayList<ByteString>(1);
+    values.add(ByteString.valueOf("People"));
     attributes.add(new LDAPAttribute("ou", values));
 
     AddRequestProtocolOp addRequest =
-         new AddRequestProtocolOp(new ASN1OctetString("ou=People,o=test"),
+         new AddRequestProtocolOp(ByteString.valueOf("ou=People,o=test"),
                                   attributes);
     message = new LDAPMessage(2, addRequest,
-                       DelayPreOpPlugin.createDelayLDAPControlList(5000));
-    writer.writeElement(message.encode());
+        DelayPreOpPlugin.createDelayControlList(5000));
+    w.writeMessage(message);
 
 
     // Create a cancel request and send it to the server.
-    ArrayList<ASN1Element> sequenceElements = new ArrayList<ASN1Element>(1);
-    sequenceElements.add(new ASN1Integer(2));
-    ASN1Sequence valueSequence = new ASN1Sequence(sequenceElements);
-    ASN1OctetString extendedValue = new ASN1OctetString(valueSequence.encode());
+    ByteStringBuilder builder = new ByteStringBuilder();
+    ASN1Writer writer = ASN1.getWriter(builder);
+    writer.writeStartSequence();
+    writer.writeInteger(2);
+    writer.writeEndSequence();
     ExtendedRequestProtocolOp extendedRequest =
-         new ExtendedRequestProtocolOp(OID_CANCEL_REQUEST, extendedValue);
+         new ExtendedRequestProtocolOp(OID_CANCEL_REQUEST,
+             builder.toByteString());
     message = new LDAPMessage(3, extendedRequest);
-    writer.writeElement(message.encode());
+    w.writeMessage(message);
 
 
     // Read two response messages from the server.  One should be an add
@@ -166,7 +167,7 @@
     // have a result code of "cancelled".
     for (int i=0; i < 2; i++)
     {
-      message = LDAPMessage.decode(reader.readElement().decodeAsSequence());
+      message = r.readMessage();
       switch (message.getProtocolOpType())
       {
         case OP_TYPE_ADD_RESPONSE:
@@ -204,16 +205,18 @@
     // Create a new connection to the Directory Server and authenticate as
     // the Directory Manager.
     Socket socket = new Socket("127.0.0.1", TestCaseUtils.getServerLdapPort());
-    ASN1Reader reader = new ASN1Reader(socket);
-    ASN1Writer writer = new ASN1Writer(socket);
+    org.opends.server.tools.LDAPReader r =
+        new org.opends.server.tools.LDAPReader(socket);
+    org.opends.server.tools.LDAPWriter w =
+        new org.opends.server.tools.LDAPWriter(socket);
 
     BindRequestProtocolOp bindRequest =
-         new BindRequestProtocolOp(new ASN1OctetString("cn=Directory Manager"),
-                                   3, new ASN1OctetString("password"));
+         new BindRequestProtocolOp(ByteString.valueOf("cn=Directory Manager"),
+                                   3, ByteString.valueOf("password"));
     LDAPMessage message = new LDAPMessage(1, bindRequest);
-    writer.writeElement(message.encode());
+    w.writeMessage(message);
 
-    message = LDAPMessage.decode(reader.readElement().decodeAsSequence());
+    message = r.readMessage();
     BindResponseProtocolOp bindResponse = message.getBindResponseProtocolOp();
     assertEquals(bindResponse.getResultCode(), LDAPResultCode.SUCCESS);
 
@@ -222,22 +225,24 @@
     // the delay request control so it won't complete before we can send the
     // cancel request.
     CompareRequestProtocolOp compareRequest =
-         new CompareRequestProtocolOp(new ASN1OctetString("o=test"), "o",
-                                      new ASN1OctetString("test"));
+         new CompareRequestProtocolOp(ByteString.valueOf("o=test"), "o",
+                                      ByteString.valueOf("test"));
     message = new LDAPMessage(2, compareRequest,
-                       DelayPreOpPlugin.createDelayLDAPControlList(5000));
-    writer.writeElement(message.encode());
+        DelayPreOpPlugin.createDelayControlList(5000));
+    w.writeMessage(message);
 
 
     // Create a cancel request and send it to the server.
-    ArrayList<ASN1Element> sequenceElements = new ArrayList<ASN1Element>(1);
-    sequenceElements.add(new ASN1Integer(2));
-    ASN1Sequence valueSequence = new ASN1Sequence(sequenceElements);
-    ASN1OctetString extendedValue = new ASN1OctetString(valueSequence.encode());
+    ByteStringBuilder builder = new ByteStringBuilder();
+    ASN1Writer writer = ASN1.getWriter(builder);
+    writer.writeStartSequence();
+    writer.writeInteger(2);
+    writer.writeEndSequence();
     ExtendedRequestProtocolOp extendedRequest =
-         new ExtendedRequestProtocolOp(OID_CANCEL_REQUEST, extendedValue);
+         new ExtendedRequestProtocolOp(OID_CANCEL_REQUEST,
+             builder.toByteString());
     message = new LDAPMessage(3, extendedRequest);
-    writer.writeElement(message.encode());
+    w.writeMessage(message);
 
 
     // Read two response messages from the server.  One should be a compare
@@ -245,7 +250,7 @@
     // have a result code of "cancelled".
     for (int i=0; i < 2; i++)
     {
-      message = LDAPMessage.decode(reader.readElement().decodeAsSequence());
+      message = r.readMessage();
       switch (message.getProtocolOpType())
       {
         case OP_TYPE_COMPARE_RESPONSE:
@@ -298,16 +303,18 @@
     // Create a new connection to the Directory Server and authenticate as
     // the Directory Manager.
     Socket socket = new Socket("127.0.0.1", TestCaseUtils.getServerLdapPort());
-    ASN1Reader reader = new ASN1Reader(socket);
-    ASN1Writer writer = new ASN1Writer(socket);
+    org.opends.server.tools.LDAPReader r =
+        new org.opends.server.tools.LDAPReader(socket);
+    org.opends.server.tools.LDAPWriter w =
+        new org.opends.server.tools.LDAPWriter(socket);
 
     BindRequestProtocolOp bindRequest =
-         new BindRequestProtocolOp(new ASN1OctetString("cn=Directory Manager"),
-                                   3, new ASN1OctetString("password"));
+         new BindRequestProtocolOp(ByteString.valueOf("cn=Directory Manager"),
+                                   3, ByteString.valueOf("password"));
     LDAPMessage message = new LDAPMessage(1, bindRequest);
-    writer.writeElement(message.encode());
+    w.writeMessage(message);
 
-    message = LDAPMessage.decode(reader.readElement().decodeAsSequence());
+    message = r.readMessage();
     BindResponseProtocolOp bindResponse = message.getBindResponseProtocolOp();
     assertEquals(bindResponse.getResultCode(), LDAPResultCode.SUCCESS);
 
@@ -316,21 +323,23 @@
     // the delay request control so it won't complete before we can send the
     // cancel request.
     DeleteRequestProtocolOp deleteRequest =
-         new DeleteRequestProtocolOp(new ASN1OctetString("cn=test,o=test"));
+         new DeleteRequestProtocolOp(ByteString.valueOf("cn=test,o=test"));
     message = new LDAPMessage(2, deleteRequest,
-                       DelayPreOpPlugin.createDelayLDAPControlList(5000));
-    writer.writeElement(message.encode());
+        DelayPreOpPlugin.createDelayControlList(5000));
+    w.writeMessage(message);
 
 
     // Create a cancel request and send it to the server.
-    ArrayList<ASN1Element> sequenceElements = new ArrayList<ASN1Element>(1);
-    sequenceElements.add(new ASN1Integer(2));
-    ASN1Sequence valueSequence = new ASN1Sequence(sequenceElements);
-    ASN1OctetString extendedValue = new ASN1OctetString(valueSequence.encode());
+    ByteStringBuilder builder = new ByteStringBuilder();
+    ASN1Writer writer = ASN1.getWriter(builder);
+    writer.writeStartSequence();
+    writer.writeInteger(2);
+    writer.writeEndSequence();
     ExtendedRequestProtocolOp extendedRequest =
-         new ExtendedRequestProtocolOp(OID_CANCEL_REQUEST, extendedValue);
+         new ExtendedRequestProtocolOp(OID_CANCEL_REQUEST,
+             builder.toByteString());
     message = new LDAPMessage(3, extendedRequest);
-    writer.writeElement(message.encode());
+    w.writeMessage(message);
 
 
     // Read two response messages from the server.  One should be a delete
@@ -338,7 +347,7 @@
     // have a result code of "cancelled".
     for (int i=0; i < 2; i++)
     {
-      message = LDAPMessage.decode(reader.readElement().decodeAsSequence());
+      message = r.readMessage();
       switch (message.getProtocolOpType())
       {
         case OP_TYPE_DELETE_RESPONSE:
@@ -377,16 +386,18 @@
     // Create a new connection to the Directory Server and authenticate as
     // the Directory Manager.
     Socket socket = new Socket("127.0.0.1", TestCaseUtils.getServerLdapPort());
-    ASN1Reader reader = new ASN1Reader(socket);
-    ASN1Writer writer = new ASN1Writer(socket);
+    org.opends.server.tools.LDAPReader r =
+        new org.opends.server.tools.LDAPReader(socket);
+    org.opends.server.tools.LDAPWriter w =
+        new org.opends.server.tools.LDAPWriter(socket);
 
     BindRequestProtocolOp bindRequest =
-         new BindRequestProtocolOp(new ASN1OctetString("cn=Directory Manager"),
-                                   3, new ASN1OctetString("password"));
+         new BindRequestProtocolOp(ByteString.valueOf("cn=Directory Manager"),
+                                   3, ByteString.valueOf("password"));
     LDAPMessage message = new LDAPMessage(1, bindRequest);
-    writer.writeElement(message.encode());
+    w.writeMessage(message);
 
-    message = LDAPMessage.decode(reader.readElement().decodeAsSequence());
+    message = r.readMessage();
     BindResponseProtocolOp bindResponse = message.getBindResponseProtocolOp();
     assertEquals(bindResponse.getResultCode(), LDAPResultCode.SUCCESS);
 
@@ -397,26 +408,28 @@
     ExtendedRequestProtocolOp whoAmIRequest =
          new ExtendedRequestProtocolOp(OID_WHO_AM_I_REQUEST, null);
     message = new LDAPMessage(2, whoAmIRequest,
-                       DelayPreOpPlugin.createDelayLDAPControlList(5000));
-    writer.writeElement(message.encode());
+        DelayPreOpPlugin.createDelayControlList(5000));
+    w.writeMessage(message);
 
 
     // Create a cancel request and send it to the server.
-    ArrayList<ASN1Element> sequenceElements = new ArrayList<ASN1Element>(1);
-    sequenceElements.add(new ASN1Integer(2));
-    ASN1Sequence valueSequence = new ASN1Sequence(sequenceElements);
-    ASN1OctetString extendedValue = new ASN1OctetString(valueSequence.encode());
+    ByteStringBuilder builder = new ByteStringBuilder();
+    ASN1Writer writer = ASN1.getWriter(builder);
+    writer.writeStartSequence();
+    writer.writeInteger(2);
+    writer.writeEndSequence();
     ExtendedRequestProtocolOp extendedRequest =
-         new ExtendedRequestProtocolOp(OID_CANCEL_REQUEST, extendedValue);
+         new ExtendedRequestProtocolOp(OID_CANCEL_REQUEST,
+             builder.toByteString());
     message = new LDAPMessage(3, extendedRequest);
-    writer.writeElement(message.encode());
+    w.writeMessage(message);
 
-
+                                                          
     // Read two response messages from the server.  They should both be extended
     // responses and they should both have result codes of "cancelled".
     for (int i=0; i < 2; i++)
     {
-      message = LDAPMessage.decode(reader.readElement().decodeAsSequence());
+      message = r.readMessage();
       ExtendedResponseProtocolOp extendedResponse =
            message.getExtendedResponseProtocolOp();
       assertEquals(extendedResponse.getResultCode(), LDAPResultCode.CANCELED);
@@ -442,16 +455,18 @@
     // Create a new connection to the Directory Server and authenticate as
     // the Directory Manager.
     Socket socket = new Socket("127.0.0.1", TestCaseUtils.getServerLdapPort());
-    ASN1Reader reader = new ASN1Reader(socket);
-    ASN1Writer writer = new ASN1Writer(socket);
+    org.opends.server.tools.LDAPReader r =
+        new org.opends.server.tools.LDAPReader(socket);
+    org.opends.server.tools.LDAPWriter w =
+        new org.opends.server.tools.LDAPWriter(socket);
 
     BindRequestProtocolOp bindRequest =
-         new BindRequestProtocolOp(new ASN1OctetString("cn=Directory Manager"),
-                                   3, new ASN1OctetString("password"));
+         new BindRequestProtocolOp(ByteString.valueOf("cn=Directory Manager"),
+                                   3, ByteString.valueOf("password"));
     LDAPMessage message = new LDAPMessage(1, bindRequest);
-    writer.writeElement(message.encode());
+    w.writeMessage(message);
 
-    message = LDAPMessage.decode(reader.readElement().decodeAsSequence());
+    message = r.readMessage();
     BindResponseProtocolOp bindResponse = message.getBindResponseProtocolOp();
     assertEquals(bindResponse.getResultCode(), LDAPResultCode.SUCCESS);
 
@@ -459,29 +474,31 @@
     // Create a modify request and send it to the server.  Make sure to include
     // the delay request control so it won't complete before we can send the
     // cancel request.
-    ArrayList<ASN1OctetString> values = new ArrayList<ASN1OctetString>(1);
-    values.add(new ASN1OctetString("foo"));
+    ArrayList<ByteString> values = new ArrayList<ByteString>(1);
+    values.add(ByteString.valueOf("foo"));
 
     ArrayList<RawModification> mods = new ArrayList<RawModification>(1);
     mods.add(new LDAPModification(ModificationType.REPLACE,
                                   new LDAPAttribute("description", values)));
 
     ModifyRequestProtocolOp modifyRequest =
-         new ModifyRequestProtocolOp(new ASN1OctetString("o=test"), mods);
+         new ModifyRequestProtocolOp(ByteString.valueOf("o=test"), mods);
     message = new LDAPMessage(2, modifyRequest,
-                       DelayPreOpPlugin.createDelayLDAPControlList(5000));
-    writer.writeElement(message.encode());
+        DelayPreOpPlugin.createDelayControlList(5000));
+    w.writeMessage(message);
 
 
     // Create a cancel request and send it to the server.
-    ArrayList<ASN1Element> sequenceElements = new ArrayList<ASN1Element>(1);
-    sequenceElements.add(new ASN1Integer(2));
-    ASN1Sequence valueSequence = new ASN1Sequence(sequenceElements);
-    ASN1OctetString extendedValue = new ASN1OctetString(valueSequence.encode());
+    ByteStringBuilder builder = new ByteStringBuilder();
+    ASN1Writer writer = ASN1.getWriter(builder);
+    writer.writeStartSequence();
+    writer.writeInteger(2);
+    writer.writeEndSequence();
     ExtendedRequestProtocolOp extendedRequest =
-         new ExtendedRequestProtocolOp(OID_CANCEL_REQUEST, extendedValue);
+         new ExtendedRequestProtocolOp(OID_CANCEL_REQUEST,
+             builder.toByteString());
     message = new LDAPMessage(3, extendedRequest);
-    writer.writeElement(message.encode());
+    w.writeMessage(message);
 
 
     // Read two response messages from the server.  One should be a modify
@@ -489,7 +506,7 @@
     // have a result code of "cancelled".
     for (int i=0; i < 2; i++)
     {
-      message = LDAPMessage.decode(reader.readElement().decodeAsSequence());
+      message = r.readMessage();
       switch (message.getProtocolOpType())
       {
         case OP_TYPE_MODIFY_RESPONSE:
@@ -542,16 +559,18 @@
     // Create a new connection to the Directory Server and authenticate as
     // the Directory Manager.
     Socket socket = new Socket("127.0.0.1", TestCaseUtils.getServerLdapPort());
-    ASN1Reader reader = new ASN1Reader(socket);
-    ASN1Writer writer = new ASN1Writer(socket);
+    org.opends.server.tools.LDAPReader r =
+        new org.opends.server.tools.LDAPReader(socket);
+    org.opends.server.tools.LDAPWriter w =
+        new org.opends.server.tools.LDAPWriter(socket);
 
     BindRequestProtocolOp bindRequest =
-         new BindRequestProtocolOp(new ASN1OctetString("cn=Directory Manager"),
-                                   3, new ASN1OctetString("password"));
+         new BindRequestProtocolOp(ByteString.valueOf("cn=Directory Manager"),
+                                   3, ByteString.valueOf("password"));
     LDAPMessage message = new LDAPMessage(1, bindRequest);
-    writer.writeElement(message.encode());
+    w.writeMessage(message);
 
-    message = LDAPMessage.decode(reader.readElement().decodeAsSequence());
+    message = r.readMessage();
     BindResponseProtocolOp bindResponse = message.getBindResponseProtocolOp();
     assertEquals(bindResponse.getResultCode(), LDAPResultCode.SUCCESS);
 
@@ -560,22 +579,24 @@
     // include the delay request control so it won't complete before we can send
     // the cancel request.
     ModifyDNRequestProtocolOp modifyDNRequest =
-         new ModifyDNRequestProtocolOp(new ASN1OctetString("cn=test,o=test"),
-                                       new ASN1OctetString("cn=test2"), true);
+         new ModifyDNRequestProtocolOp(ByteString.valueOf("cn=test,o=test"),
+                                       ByteString.valueOf("cn=test2"), true);
     message = new LDAPMessage(2, modifyDNRequest,
-                       DelayPreOpPlugin.createDelayLDAPControlList(5000));
-    writer.writeElement(message.encode());
+        DelayPreOpPlugin.createDelayControlList(5000));
+    w.writeMessage(message);
 
 
     // Create a cancel request and send it to the server.
-    ArrayList<ASN1Element> sequenceElements = new ArrayList<ASN1Element>(1);
-    sequenceElements.add(new ASN1Integer(2));
-    ASN1Sequence valueSequence = new ASN1Sequence(sequenceElements);
-    ASN1OctetString extendedValue = new ASN1OctetString(valueSequence.encode());
+    ByteStringBuilder builder = new ByteStringBuilder();
+    ASN1Writer writer = ASN1.getWriter(builder);
+    writer.writeStartSequence();
+    writer.writeInteger(2);
+    writer.writeEndSequence();
     ExtendedRequestProtocolOp extendedRequest =
-         new ExtendedRequestProtocolOp(OID_CANCEL_REQUEST, extendedValue);
+         new ExtendedRequestProtocolOp(OID_CANCEL_REQUEST,
+             builder.toByteString());
     message = new LDAPMessage(3, extendedRequest);
-    writer.writeElement(message.encode());
+    w.writeMessage(message);
 
 
     // Read two response messages from the server.  One should be a modify DN
@@ -583,7 +604,7 @@
     // have a result code of "cancelled".
     for (int i=0; i < 2; i++)
     {
-      message = LDAPMessage.decode(reader.readElement().decodeAsSequence());
+      message = r.readMessage();
       switch (message.getProtocolOpType())
       {
         case OP_TYPE_MODIFY_DN_RESPONSE:
@@ -622,16 +643,18 @@
     // Create a new connection to the Directory Server and authenticate as
     // the Directory Manager.
     Socket socket = new Socket("127.0.0.1", TestCaseUtils.getServerLdapPort());
-    ASN1Reader reader = new ASN1Reader(socket);
-    ASN1Writer writer = new ASN1Writer(socket);
+    org.opends.server.tools.LDAPReader r =
+        new org.opends.server.tools.LDAPReader(socket);
+    org.opends.server.tools.LDAPWriter w =
+        new org.opends.server.tools.LDAPWriter(socket);
 
     BindRequestProtocolOp bindRequest =
-         new BindRequestProtocolOp(new ASN1OctetString("cn=Directory Manager"),
-                                   3, new ASN1OctetString("password"));
+         new BindRequestProtocolOp(ByteString.valueOf("cn=Directory Manager"),
+                                   3, ByteString.valueOf("password"));
     LDAPMessage message = new LDAPMessage(1, bindRequest);
-    writer.writeElement(message.encode());
+    w.writeMessage(message);
 
-    message = LDAPMessage.decode(reader.readElement().decodeAsSequence());
+    message = r.readMessage();
     BindResponseProtocolOp bindResponse = message.getBindResponseProtocolOp();
     assertEquals(bindResponse.getResultCode(), LDAPResultCode.SUCCESS);
 
@@ -640,26 +663,28 @@
     // the delay request control so it won't complete before we can send the
     // cancel request.
     SearchRequestProtocolOp searchRequest =
-         new SearchRequestProtocolOp(new ASN1OctetString("o=test"),
+         new SearchRequestProtocolOp(ByteString.valueOf("o=test"),
                                      SearchScope.BASE_OBJECT,
                                      DereferencePolicy.NEVER_DEREF_ALIASES, 0,
                                      0, false,
                                      LDAPFilter.decode("(match=false)"),
                                      new LinkedHashSet<String>());
     message = new LDAPMessage(2, searchRequest,
-                       DelayPreOpPlugin.createDelayLDAPControlList(5000));
-    writer.writeElement(message.encode());
+        DelayPreOpPlugin.createDelayControlList(5000));
+    w.writeMessage(message);
 
 
     // Create a cancel request and send it to the server.
-    ArrayList<ASN1Element> sequenceElements = new ArrayList<ASN1Element>(1);
-    sequenceElements.add(new ASN1Integer(2));
-    ASN1Sequence valueSequence = new ASN1Sequence(sequenceElements);
-    ASN1OctetString extendedValue = new ASN1OctetString(valueSequence.encode());
+    ByteStringBuilder builder = new ByteStringBuilder();
+    ASN1Writer writer = ASN1.getWriter(builder);
+    writer.writeStartSequence();
+    writer.writeInteger(2);
+    writer.writeEndSequence();
     ExtendedRequestProtocolOp extendedRequest =
-         new ExtendedRequestProtocolOp(OID_CANCEL_REQUEST, extendedValue);
+         new ExtendedRequestProtocolOp(OID_CANCEL_REQUEST,
+             builder.toByteString());
     message = new LDAPMessage(3, extendedRequest);
-    writer.writeElement(message.encode());
+    w.writeMessage(message);
 
 
     // Read two response messages from the server.  One should be a search
@@ -667,7 +692,7 @@
     // both have a result code of "cancelled".
     for (int i=0; i < 2; i++)
     {
-      message = LDAPMessage.decode(reader.readElement().decodeAsSequence());
+      message = r.readMessage();
       switch (message.getProtocolOpType())
       {
         case OP_TYPE_SEARCH_RESULT_DONE:
@@ -706,34 +731,38 @@
     // Create a new connection to the Directory Server and authenticate as
     // the Directory Manager.
     Socket socket = new Socket("127.0.0.1", TestCaseUtils.getServerLdapPort());
-    ASN1Reader reader = new ASN1Reader(socket);
-    ASN1Writer writer = new ASN1Writer(socket);
+    org.opends.server.tools.LDAPReader r =
+        new org.opends.server.tools.LDAPReader(socket);
+    org.opends.server.tools.LDAPWriter w =
+        new org.opends.server.tools.LDAPWriter(socket);
 
     BindRequestProtocolOp bindRequest =
-         new BindRequestProtocolOp(new ASN1OctetString("cn=Directory Manager"),
-                                   3, new ASN1OctetString("password"));
+         new BindRequestProtocolOp(ByteString.valueOf("cn=Directory Manager"),
+                                   3, ByteString.valueOf("password"));
     LDAPMessage message = new LDAPMessage(1, bindRequest);
-    writer.writeElement(message.encode());
+    w.writeMessage(message);
 
-    message = LDAPMessage.decode(reader.readElement().decodeAsSequence());
+    message = r.readMessage();
     BindResponseProtocolOp bindResponse = message.getBindResponseProtocolOp();
     assertEquals(bindResponse.getResultCode(), LDAPResultCode.SUCCESS);
 
 
     // Create a cancel request and send it to the server.
-    ArrayList<ASN1Element> sequenceElements = new ArrayList<ASN1Element>(1);
-    sequenceElements.add(new ASN1Integer(2));
-    ASN1Sequence valueSequence = new ASN1Sequence(sequenceElements);
-    ASN1OctetString extendedValue = new ASN1OctetString(valueSequence.encode());
+    ByteStringBuilder builder = new ByteStringBuilder();
+    ASN1Writer writer = ASN1.getWriter(builder);
+    writer.writeStartSequence();
+    writer.writeInteger(2);
+    writer.writeEndSequence();
     ExtendedRequestProtocolOp extendedRequest =
-         new ExtendedRequestProtocolOp(OID_CANCEL_REQUEST, extendedValue);
+         new ExtendedRequestProtocolOp(OID_CANCEL_REQUEST,
+             builder.toByteString());
     message = new LDAPMessage(3, extendedRequest);
-    writer.writeElement(message.encode());
+    w.writeMessage(message);
 
 
     // Read the response message from the server.  It should be an extended
     // response with a result code of "no such operation".
-    message = LDAPMessage.decode(reader.readElement().decodeAsSequence());
+    message = r.readMessage();
     ExtendedResponseProtocolOp extendedResponse =
          message.getExtendedResponseProtocolOp();
     assertEquals(extendedResponse.getResultCode(),
@@ -759,16 +788,18 @@
     // Create a new connection to the Directory Server and authenticate as
     // the Directory Manager.
     Socket socket = new Socket("127.0.0.1", TestCaseUtils.getServerLdapPort());
-    ASN1Reader reader = new ASN1Reader(socket);
-    ASN1Writer writer = new ASN1Writer(socket);
+    org.opends.server.tools.LDAPReader r =
+        new org.opends.server.tools.LDAPReader(socket);
+    org.opends.server.tools.LDAPWriter w =
+        new org.opends.server.tools.LDAPWriter(socket);
 
     BindRequestProtocolOp bindRequest =
-         new BindRequestProtocolOp(new ASN1OctetString("cn=Directory Manager"),
-                                   3, new ASN1OctetString("password"));
+         new BindRequestProtocolOp(ByteString.valueOf("cn=Directory Manager"),
+                                   3, ByteString.valueOf("password"));
     LDAPMessage message = new LDAPMessage(1, bindRequest);
-    writer.writeElement(message.encode());
+    w.writeMessage(message);
 
-    message = LDAPMessage.decode(reader.readElement().decodeAsSequence());
+    message = r.readMessage();
     BindResponseProtocolOp bindResponse = message.getBindResponseProtocolOp();
     assertEquals(bindResponse.getResultCode(), LDAPResultCode.SUCCESS);
 
@@ -777,12 +808,12 @@
     ExtendedRequestProtocolOp extendedRequest =
          new ExtendedRequestProtocolOp(OID_CANCEL_REQUEST, null);
     message = new LDAPMessage(3, extendedRequest);
-    writer.writeElement(message.encode());
+    w.writeMessage(message);
 
 
     // Read the response message from the server.  It should be an extended
     // response with a result code of "no such operation".
-    message = LDAPMessage.decode(reader.readElement().decodeAsSequence());
+    message = r.readMessage();
     ExtendedResponseProtocolOp extendedResponse =
          message.getExtendedResponseProtocolOp();
     assertEquals(extendedResponse.getResultCode(),
@@ -808,16 +839,18 @@
     // Create a new connection to the Directory Server and authenticate as
     // the Directory Manager.
     Socket socket = new Socket("127.0.0.1", TestCaseUtils.getServerLdapPort());
-    ASN1Reader reader = new ASN1Reader(socket);
-    ASN1Writer writer = new ASN1Writer(socket);
+    org.opends.server.tools.LDAPReader r =
+        new org.opends.server.tools.LDAPReader(socket);
+    org.opends.server.tools.LDAPWriter w =
+        new org.opends.server.tools.LDAPWriter(socket);
 
     BindRequestProtocolOp bindRequest =
-         new BindRequestProtocolOp(new ASN1OctetString("cn=Directory Manager"),
-                                   3, new ASN1OctetString("password"));
+         new BindRequestProtocolOp(ByteString.valueOf("cn=Directory Manager"),
+                                   3, ByteString.valueOf("password"));
     LDAPMessage message = new LDAPMessage(1, bindRequest);
-    writer.writeElement(message.encode());
+    w.writeMessage(message);
 
-    message = LDAPMessage.decode(reader.readElement().decodeAsSequence());
+    message = r.readMessage();
     BindResponseProtocolOp bindResponse = message.getBindResponseProtocolOp();
     assertEquals(bindResponse.getResultCode(), LDAPResultCode.SUCCESS);
 
@@ -825,14 +858,14 @@
     // Create a cancel request and send it to the server.
     ExtendedRequestProtocolOp extendedRequest =
          new ExtendedRequestProtocolOp(OID_CANCEL_REQUEST,
-                                       new ASN1OctetString("malformed"));
+                                       ByteString.valueOf("malformed"));
     message = new LDAPMessage(3, extendedRequest);
-    writer.writeElement(message.encode());
+    w.writeMessage(message);
 
 
     // Read the response message from the server.  It should be an extended
     // response with a result code of "no such operation".
-    message = LDAPMessage.decode(reader.readElement().decodeAsSequence());
+    message = r.readMessage();
     ExtendedResponseProtocolOp extendedResponse =
          message.getExtendedResponseProtocolOp();
     assertEquals(extendedResponse.getResultCode(),
@@ -856,16 +889,18 @@
     // Create a new connection to the Directory Server and authenticate as
     // the Directory Manager.
     Socket socket = new Socket("127.0.0.1", TestCaseUtils.getServerLdapPort());
-    ASN1Reader reader = new ASN1Reader(socket);
-    ASN1Writer writer = new ASN1Writer(socket);
+    org.opends.server.tools.LDAPReader r =
+        new org.opends.server.tools.LDAPReader(socket);
+    org.opends.server.tools.LDAPWriter w =
+        new org.opends.server.tools.LDAPWriter(socket);
 
     BindRequestProtocolOp bindRequest =
-         new BindRequestProtocolOp(new ASN1OctetString("cn=Directory Manager"),
-                                   3, new ASN1OctetString("password"));
+         new BindRequestProtocolOp(ByteString.valueOf("cn=Directory Manager"),
+                                   3, ByteString.valueOf("password"));
     LDAPMessage message = new LDAPMessage(1, bindRequest);
-    writer.writeElement(message.encode());
+    w.writeMessage(message);
 
-    message = LDAPMessage.decode(reader.readElement().decodeAsSequence());
+    message = r.readMessage();
     BindResponseProtocolOp bindResponse = message.getBindResponseProtocolOp();
     assertEquals(bindResponse.getResultCode(), LDAPResultCode.SUCCESS);
 
@@ -873,16 +908,18 @@
     // Create a self cancelling request and send it to the server. Make sure
     // to include the delay request control so it won't complete before we
     // can send the cancel request.
-    ArrayList<ASN1Element> sequenceElements = new ArrayList<ASN1Element>(1);
-    sequenceElements.add(new ASN1Integer(2));
-    ASN1Sequence valueSequence = new ASN1Sequence(sequenceElements);
-    ASN1OctetString extendedValue = new ASN1OctetString(valueSequence.encode());
+    ByteStringBuilder builder = new ByteStringBuilder();
+    ASN1Writer writer = ASN1.getWriter(builder);
+    writer.writeStartSequence();
+    writer.writeInteger(2);
+    writer.writeEndSequence();
     ExtendedRequestProtocolOp extendedRequest =
-        new ExtendedRequestProtocolOp(OID_CANCEL_REQUEST, extendedValue);
+        new ExtendedRequestProtocolOp(OID_CANCEL_REQUEST,
+             builder.toByteString());
     message = new LDAPMessage(2, extendedRequest);
-    writer.writeElement(message.encode());
+    w.writeMessage(message);
 
-    message = LDAPMessage.decode(reader.readElement().decodeAsSequence());
+    message = r.readMessage();
     ExtendedResponseProtocolOp extendedResponse =
         message.getExtendedResponseProtocolOp();
     assertEquals(extendedResponse.getResultCode(),
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/CharacterSetPasswordValidatorTestCase.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/CharacterSetPasswordValidatorTestCase.java
index 48b9c13..7e59728 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/CharacterSetPasswordValidatorTestCase.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/CharacterSetPasswordValidatorTestCase.java
@@ -43,7 +43,6 @@
 import org.opends.server.admin.server.AdminTestCaseUtils;
 import org.opends.server.config.ConfigException;
 import org.opends.server.core.ModifyOperationBasis;
-import org.opends.server.protocols.asn1.ASN1OctetString;
 import org.opends.server.protocols.internal.InternalClientConnection;
 import org.opends.server.types.Attributes;
 import org.opends.server.types.ByteString;
@@ -524,7 +523,7 @@
          new CharacterSetPasswordValidator();
     validator.initializePasswordValidator(configuration);
 
-    ASN1OctetString pwOS = new ASN1OctetString(password);
+    ByteString pwOS = ByteString.valueOf(password);
     ArrayList<Modification> mods = new ArrayList<Modification>();
     mods.add(new Modification(ModificationType.REPLACE,
         Attributes.create("userpassword", password)));
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/DictionaryPasswordValidatorTestCase.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/DictionaryPasswordValidatorTestCase.java
index e6dad21..1197145 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/DictionaryPasswordValidatorTestCase.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/DictionaryPasswordValidatorTestCase.java
@@ -44,7 +44,6 @@
 import org.opends.server.admin.server.AdminTestCaseUtils;
 import org.opends.server.config.ConfigException;
 import org.opends.server.core.ModifyOperationBasis;
-import org.opends.server.protocols.asn1.ASN1OctetString;
 import org.opends.server.protocols.internal.InternalClientConnection;
 import org.opends.server.types.Attributes;
 import org.opends.server.types.ByteString;
@@ -499,7 +498,7 @@
          new DictionaryPasswordValidator();
     validator.initializePasswordValidator(configuration);
 
-    ASN1OctetString pwOS = new ASN1OctetString(password);
+    ByteString pwOS = ByteString.valueOf(password);
     ArrayList<Modification> mods = new ArrayList<Modification>();
     mods.add(new Modification(ModificationType.REPLACE,
         Attributes.create("userpassword", password)));
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/DigestMD5SASLMechanismHandlerTestCase.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/DigestMD5SASLMechanismHandlerTestCase.java
index 4488593..3d94d09 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/DigestMD5SASLMechanismHandlerTestCase.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/DigestMD5SASLMechanismHandlerTestCase.java
@@ -48,15 +48,9 @@
 import org.opends.server.core.BindOperation;
 import org.opends.server.core.DeleteOperation;
 import org.opends.server.core.DirectoryServer;
-import org.opends.server.protocols.asn1.ASN1OctetString;
 import org.opends.server.protocols.internal.InternalClientConnection;
 import org.opends.server.tools.LDAPSearch;
-import org.opends.server.types.AuthenticationInfo;
-import org.opends.server.types.Control;
-import org.opends.server.types.DN;
-import org.opends.server.types.Entry;
-import org.opends.server.types.InitializationException;
-import org.opends.server.types.ResultCode;
+import org.opends.server.types.*;
 
 import static org.testng.Assert.*;
 
@@ -1023,7 +1017,7 @@
          new InternalClientConnection(new AuthenticationInfo());
     BindOperation bindOperation =
          conn.processSASLBind(DN.nullDN(), SASL_MECHANISM_DIGEST_MD5,
-                              new ASN1OctetString("invalid"));
+                              ByteString.valueOf("invalid"));
     assertFalse(bindOperation.getResultCode() == ResultCode.SUCCESS);
   }
 
@@ -1048,7 +1042,7 @@
 
     bindOperation =
          conn.processSASLBind(DN.nullDN(), SASL_MECHANISM_DIGEST_MD5,
-                              new ASN1OctetString("malformed"));
+                              ByteString.valueOf("malformed"));
     assertFalse(bindOperation.getResultCode() == ResultCode.SUCCESS);
   }
 }
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/EntryDNVirtualAttributeProviderTestCase.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/EntryDNVirtualAttributeProviderTestCase.java
index cfdf382..28f6384 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/EntryDNVirtualAttributeProviderTestCase.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/EntryDNVirtualAttributeProviderTestCase.java
@@ -43,19 +43,8 @@
 import org.opends.server.core.DirectoryServer;
 import org.opends.server.protocols.internal.InternalClientConnection;
 import org.opends.server.protocols.internal.InternalSearchOperation;
-import org.opends.server.types.Attribute;
-import org.opends.server.types.AttributeType;
-import org.opends.server.types.AttributeValue;
-import org.opends.server.types.ByteString;
-import org.opends.server.types.ByteStringFactory;
-import org.opends.server.types.ConditionResult;
-import org.opends.server.types.Control;
-import org.opends.server.types.DereferencePolicy;
-import org.opends.server.types.DN;
-import org.opends.server.types.Entry;
-import org.opends.server.types.SearchFilter;
-import org.opends.server.types.SearchScope;
-import org.opends.server.types.VirtualAttributeRule;
+import org.opends.server.protocols.ldap.LDAPControl;
+import org.opends.server.types.*;
 import org.opends.server.workflowelement.localbackend.LocalBackendSearchOperation;
 
 import static org.testng.Assert.*;
@@ -147,7 +136,7 @@
     {
       assertTrue(!a.isEmpty());
       assertEquals(a.size(), 1);
-      assertTrue(a.contains(new AttributeValue(entryDNType,
+      assertTrue(a.contains(AttributeValues.create(entryDNType,
                                                entryDN.toNormalizedString())));
     }
   }
@@ -459,7 +448,7 @@
     attrList.add("entrydn");
 
     LinkedList<Control> requestControls = new LinkedList<Control>();
-    requestControls.add(new Control(OID_REAL_ATTRS_ONLY, true));
+    requestControls.add(new LDAPControl(OID_REAL_ATTRS_ONLY, true));
 
     InternalClientConnection conn =
          InternalClientConnection.getRootConnection();
@@ -502,7 +491,7 @@
     attrList.add("entrydn");
 
     LinkedList<Control> requestControls = new LinkedList<Control>();
-    requestControls.add(new Control(OID_VIRTUAL_ATTRS_ONLY, true));
+    requestControls.add(new LDAPControl(OID_VIRTUAL_ATTRS_ONLY, true));
 
     InternalClientConnection conn =
          InternalClientConnection.getRootConnection();
@@ -564,7 +553,7 @@
     Set<AttributeValue> values = provider.getValues(entry, rule);
     assertNotNull(values);
     assertEquals(values.size(), 1);
-    assertTrue(values.contains(new AttributeValue(entryDNType, "o=test")));
+    assertTrue(values.contains(AttributeValues.create(entryDNType, "o=test")));
   }
 
 
@@ -629,7 +618,7 @@
                        VIRTUAL_OVERRIDES_REAL);
 
     assertTrue(provider.hasValue(entry, rule,
-                                 new AttributeValue(entryDNType, "o=test")));
+        AttributeValues.create(entryDNType, "o=test")));
   }
 
 
@@ -662,7 +651,7 @@
                        VIRTUAL_OVERRIDES_REAL);
 
     assertFalse(provider.hasValue(entry, rule,
-                     new AttributeValue(entryDNType, "o=not test")));
+        AttributeValues.create(entryDNType, "o=not test")));
   }
 
 
@@ -727,7 +716,7 @@
                        VIRTUAL_OVERRIDES_REAL);
 
     LinkedHashSet<AttributeValue> values = new LinkedHashSet<AttributeValue>(1);
-    values.add(new AttributeValue(entryDNType, "o=test"));
+    values.add(AttributeValues.create(entryDNType, "o=test"));
 
     assertTrue(provider.hasAnyValue(entry, rule, values));
   }
@@ -762,7 +751,7 @@
                        VIRTUAL_OVERRIDES_REAL);
 
     LinkedHashSet<AttributeValue> values = new LinkedHashSet<AttributeValue>(1);
-    values.add(new AttributeValue(entryDNType, "o=not test"));
+    values.add(AttributeValues.create(entryDNType, "o=not test"));
 
     assertFalse(provider.hasAnyValue(entry, rule, values));
   }
@@ -797,9 +786,9 @@
                        VIRTUAL_OVERRIDES_REAL);
 
     LinkedHashSet<AttributeValue> values = new LinkedHashSet<AttributeValue>(3);
-    values.add(new AttributeValue(entryDNType, "o=test"));
-    values.add(new AttributeValue(entryDNType, "o=not test"));
-    values.add(new AttributeValue(entryDNType, "o=not test either"));
+    values.add(AttributeValues.create(entryDNType, "o=test"));
+    values.add(AttributeValues.create(entryDNType, "o=not test"));
+    values.add(AttributeValues.create(entryDNType, "o=not test either"));
 
     assertTrue(provider.hasAnyValue(entry, rule, values));
   }
@@ -834,9 +823,9 @@
                        VIRTUAL_OVERRIDES_REAL);
 
     LinkedHashSet<AttributeValue> values = new LinkedHashSet<AttributeValue>(3);
-    values.add(new AttributeValue(entryDNType, "o=not test"));
-    values.add(new AttributeValue(entryDNType, "o=not test either"));
-    values.add(new AttributeValue(entryDNType, "o=still not test"));
+    values.add(AttributeValues.create(entryDNType, "o=not test"));
+    values.add(AttributeValues.create(entryDNType, "o=not test either"));
+    values.add(AttributeValues.create(entryDNType, "o=still not test"));
 
     assertFalse(provider.hasAnyValue(entry, rule, values));
   }
@@ -871,7 +860,7 @@
                        VIRTUAL_OVERRIDES_REAL);
 
     LinkedList<ByteString> subAny = new LinkedList<ByteString>();
-    subAny.add(ByteStringFactory.create("="));
+    subAny.add(ByteString.valueOf("="));
 
     assertEquals(provider.matchesSubstring(entry, rule, null, subAny, null),
                  ConditionResult.UNDEFINED);
@@ -906,7 +895,7 @@
                   VirtualAttributeCfgDefn.ConflictBehavior.
                        VIRTUAL_OVERRIDES_REAL);
 
-    AttributeValue value = new AttributeValue(entryDNType, "o=test2");
+    AttributeValue value = AttributeValues.create(entryDNType, "o=test2");
     assertEquals(provider.greaterThanOrEqualTo(entry, rule, value),
                  ConditionResult.UNDEFINED);
   }
@@ -940,7 +929,7 @@
                   VirtualAttributeCfgDefn.ConflictBehavior.
                        VIRTUAL_OVERRIDES_REAL);
 
-    AttributeValue value = new AttributeValue(entryDNType, "o=test2");
+    AttributeValue value = AttributeValues.create(entryDNType, "o=test2");
     assertEquals(provider.lessThanOrEqualTo(entry, rule, value),
                  ConditionResult.UNDEFINED);
   }
@@ -974,7 +963,7 @@
                   VirtualAttributeCfgDefn.ConflictBehavior.
                        VIRTUAL_OVERRIDES_REAL);
 
-    AttributeValue value = new AttributeValue(entryDNType, "o=test2");
+    AttributeValue value = AttributeValues.create(entryDNType, "o=test2");
     assertEquals(provider.approximatelyEqualTo(entry, rule, value),
                  ConditionResult.UNDEFINED);
   }
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/EntryUUIDVirtualAttributeProviderTestCase.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/EntryUUIDVirtualAttributeProviderTestCase.java
index 3fba399..f187d93 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/EntryUUIDVirtualAttributeProviderTestCase.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/EntryUUIDVirtualAttributeProviderTestCase.java
@@ -45,17 +45,8 @@
 import org.opends.server.core.DirectoryServer;
 import org.opends.server.protocols.internal.InternalClientConnection;
 import org.opends.server.protocols.internal.InternalSearchOperation;
-import org.opends.server.types.Attribute;
-import org.opends.server.types.AttributeType;
-import org.opends.server.types.AttributeValue;
-import org.opends.server.types.Control;
-import org.opends.server.types.DereferencePolicy;
-import org.opends.server.types.DN;
-import org.opends.server.types.Entry;
-import org.opends.server.types.ResultCode;
-import org.opends.server.types.SearchFilter;
-import org.opends.server.types.SearchScope;
-import org.opends.server.types.VirtualAttributeRule;
+import org.opends.server.protocols.ldap.LDAPControl;
+import org.opends.server.types.*;
 
 import static org.testng.Assert.*;
 
@@ -145,7 +136,7 @@
     {
       assertTrue(!a.isEmpty());
       assertEquals(a.size(), 1);
-      assertTrue(a.contains(new AttributeValue(entryUUIDType, uuidString)));
+      assertTrue(a.contains(AttributeValues.create(entryUUIDType, uuidString)));
     }
   }
 
@@ -189,7 +180,7 @@
     {
       assertTrue(!a.isEmpty());
       assertEquals(a.size(), 1);
-      assertFalse(a.contains(new AttributeValue(entryUUIDType, uuidString)));
+      assertFalse(a.contains(AttributeValues.create(entryUUIDType, uuidString)));
     }
   }
 
@@ -474,7 +465,7 @@
     attrList.add("entryuuid");
 
     LinkedList<Control> requestControls = new LinkedList<Control>();
-    requestControls.add(new Control(OID_REAL_ATTRS_ONLY, true));
+    requestControls.add(new LDAPControl(OID_REAL_ATTRS_ONLY, true));
 
     InternalClientConnection conn =
          InternalClientConnection.getRootConnection();
@@ -514,7 +505,7 @@
     attrList.add("entryuuid");
 
     LinkedList<Control> requestControls = new LinkedList<Control>();
-    requestControls.add(new Control(OID_VIRTUAL_ATTRS_ONLY, true));
+    requestControls.add(new LDAPControl(OID_VIRTUAL_ATTRS_ONLY, true));
 
     InternalClientConnection conn =
          InternalClientConnection.getRootConnection();
@@ -578,7 +569,7 @@
     Set<AttributeValue> values = provider.getValues(entry, rule);
     assertNotNull(values);
     assertEquals(values.size(), 1);
-    assertTrue(values.contains(new AttributeValue(entryUUIDType, uuidString)));
+    assertTrue(values.contains(AttributeValues.create(entryUUIDType, uuidString)));
   }
 
 
@@ -645,7 +636,7 @@
                        VIRTUAL_OVERRIDES_REAL);
 
     assertTrue(provider.hasValue(entry, rule,
-                                 new AttributeValue(entryUUIDType,
+        AttributeValues.create(entryUUIDType,
                                                     uuidString)));
   }
 
@@ -679,7 +670,7 @@
                        VIRTUAL_OVERRIDES_REAL);
 
     assertFalse(provider.hasValue(entry, rule,
-                     new AttributeValue(entryUUIDType, "wrong")));
+        AttributeValues.create(entryUUIDType, "wrong")));
   }
 
 
@@ -746,7 +737,7 @@
                        VIRTUAL_OVERRIDES_REAL);
 
     LinkedHashSet<AttributeValue> values = new LinkedHashSet<AttributeValue>(1);
-    values.add(new AttributeValue(entryUUIDType, uuidString));
+    values.add(AttributeValues.create(entryUUIDType, uuidString));
 
     assertTrue(provider.hasAnyValue(entry, rule, values));
   }
@@ -781,7 +772,7 @@
                        VIRTUAL_OVERRIDES_REAL);
 
     LinkedHashSet<AttributeValue> values = new LinkedHashSet<AttributeValue>(1);
-    values.add(new AttributeValue(entryUUIDType, "wrong"));
+    values.add(AttributeValues.create(entryUUIDType, "wrong"));
 
     assertFalse(provider.hasAnyValue(entry, rule, values));
   }
@@ -818,9 +809,9 @@
                        VIRTUAL_OVERRIDES_REAL);
 
     LinkedHashSet<AttributeValue> values = new LinkedHashSet<AttributeValue>(3);
-    values.add(new AttributeValue(entryUUIDType, uuidString));
-    values.add(new AttributeValue(entryUUIDType, "wrong"));
-    values.add(new AttributeValue(entryUUIDType, "also wrong"));
+    values.add(AttributeValues.create(entryUUIDType, uuidString));
+    values.add(AttributeValues.create(entryUUIDType, "wrong"));
+    values.add(AttributeValues.create(entryUUIDType, "also wrong"));
 
     assertTrue(provider.hasAnyValue(entry, rule, values));
   }
@@ -855,9 +846,9 @@
                        VIRTUAL_OVERRIDES_REAL);
 
     LinkedHashSet<AttributeValue> values = new LinkedHashSet<AttributeValue>(3);
-    values.add(new AttributeValue(entryUUIDType, "wrong"));
-    values.add(new AttributeValue(entryUUIDType, "also wrong"));
-    values.add(new AttributeValue(entryUUIDType, "still wrong"));
+    values.add(AttributeValues.create(entryUUIDType, "wrong"));
+    values.add(AttributeValues.create(entryUUIDType, "also wrong"));
+    values.add(AttributeValues.create(entryUUIDType, "still wrong"));
 
     assertFalse(provider.hasAnyValue(entry, rule, values));
   }
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/ExactMatchIdentityMapperTestCase.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/ExactMatchIdentityMapperTestCase.java
index 22e52ba..a37d730 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/ExactMatchIdentityMapperTestCase.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/ExactMatchIdentityMapperTestCase.java
@@ -44,20 +44,10 @@
 import org.opends.server.core.AddOperation;
 import org.opends.server.core.DirectoryServer;
 import org.opends.server.core.ModifyOperation;
-import org.opends.server.protocols.asn1.ASN1OctetString;
 import org.opends.server.protocols.ldap.LDAPAttribute;
 import org.opends.server.protocols.ldap.LDAPModification;
 import org.opends.server.protocols.internal.InternalClientConnection;
-import org.opends.server.types.AttributeType;
-import org.opends.server.types.AttributeValue;
-import org.opends.server.types.Attributes;
-import org.opends.server.types.DirectoryException;
-import org.opends.server.types.DN;
-import org.opends.server.types.Entry;
-import org.opends.server.types.InitializationException;
-import org.opends.server.types.ModificationType;
-import org.opends.server.types.RawModification;
-import org.opends.server.types.ResultCode;
+import org.opends.server.types.*;
 
 import static org.testng.Assert.*;
 
@@ -884,15 +874,15 @@
 
 
     // Create a modification to change the map attribute from uid to cn.
-    ArrayList<ASN1OctetString> values = new ArrayList<ASN1OctetString>();
-    values.add(new ASN1OctetString("cn"));
+    ArrayList<ByteString> values = new ArrayList<ByteString>();
+    values.add(ByteString.valueOf("cn"));
 
     ArrayList<RawModification> mods = new ArrayList<RawModification>();
     mods.add(new LDAPModification(ModificationType.REPLACE,
                                   new LDAPAttribute("ds-cfg-match-attribute",
                                                     values)));
     ModifyOperation modifyOperation =
-         conn.processModify(new ASN1OctetString(mapperDNString), mods);
+         conn.processModify(ByteString.valueOf(mapperDNString), mods);
     assertEquals(modifyOperation.getResultCode(), ResultCode.SUCCESS);
 
 
@@ -906,9 +896,9 @@
 
 
     // Change the configuration back to the way it was.
-    values.set(0, new ASN1OctetString("uid"));
+    values.set(0, ByteString.valueOf("uid"));
     modifyOperation =
-         conn.processModify(new ASN1OctetString(mapperDNString), mods);
+         conn.processModify(ByteString.valueOf(mapperDNString), mods);
     assertEquals(modifyOperation.getResultCode(), ResultCode.SUCCESS);
 
 
@@ -969,15 +959,15 @@
 
 
     // Create a modification to set the map base DN to "dc=example,dc=com".
-    ArrayList<ASN1OctetString> values = new ArrayList<ASN1OctetString>();
-    values.add(new ASN1OctetString("dc=example,dc=com"));
+    ArrayList<ByteString> values = new ArrayList<ByteString>();
+    values.add(ByteString.valueOf("dc=example,dc=com"));
 
     ArrayList<RawModification> mods = new ArrayList<RawModification>();
     mods.add(new LDAPModification(ModificationType.REPLACE,
                                   new LDAPAttribute("ds-cfg-match-base-dn",
                                                     values)));
     ModifyOperation modifyOperation =
-         conn.processModify(new ASN1OctetString(mapperDNString), mods);
+         conn.processModify(ByteString.valueOf(mapperDNString), mods);
     assertEquals(modifyOperation.getResultCode(), ResultCode.SUCCESS);
 
 
@@ -987,9 +977,9 @@
 
 
     // Change the base DN to "o=test".
-    values.set(0, new ASN1OctetString("o=test"));
+    values.set(0, ByteString.valueOf("o=test"));
     modifyOperation =
-         conn.processModify(new ASN1OctetString(mapperDNString), mods);
+         conn.processModify(ByteString.valueOf(mapperDNString), mods);
     assertEquals(modifyOperation.getResultCode(), ResultCode.SUCCESS);
 
 
@@ -1002,7 +992,7 @@
     // Change the configuration back to its original setting.
     values.clear();
     modifyOperation =
-         conn.processModify(new ASN1OctetString(mapperDNString), mods);
+         conn.processModify(ByteString.valueOf(mapperDNString), mods);
     assertEquals(modifyOperation.getResultCode(), ResultCode.SUCCESS);
 
 
@@ -1032,7 +1022,7 @@
          InternalClientConnection.getRootConnection();
     String mapperDNString = "cn=Exact Match,cn=Identity Mappers,cn=config";
     ModifyOperation modifyOperation =
-         conn.processModify(new ASN1OctetString(mapperDNString), mods);
+         conn.processModify(ByteString.valueOf(mapperDNString), mods);
     assertFalse(modifyOperation.getResultCode() == ResultCode.SUCCESS);
   }
 
@@ -1049,8 +1039,8 @@
          throws Exception
   {
     // Create a modification to remove the match attribute.
-    ArrayList<ASN1OctetString> values = new ArrayList<ASN1OctetString>();
-    values.add(new ASN1OctetString("undefinedAttribute"));
+    ArrayList<ByteString> values = new ArrayList<ByteString>();
+    values.add(ByteString.valueOf("undefinedAttribute"));
 
     ArrayList<RawModification> mods = new ArrayList<RawModification>();
     mods.add(new LDAPModification(ModificationType.REPLACE,
@@ -1060,7 +1050,7 @@
          InternalClientConnection.getRootConnection();
     String mapperDNString = "cn=Exact Match,cn=Identity Mappers,cn=config";
     ModifyOperation modifyOperation =
-         conn.processModify(new ASN1OctetString(mapperDNString), mods);
+         conn.processModify(ByteString.valueOf(mapperDNString), mods);
     assertFalse(modifyOperation.getResultCode() == ResultCode.SUCCESS);
   }
 
@@ -1077,8 +1067,8 @@
          throws Exception
   {
     // Create a modification to remove the match attribute.
-    ArrayList<ASN1OctetString> values = new ArrayList<ASN1OctetString>();
-    values.add(new ASN1OctetString("invalidDN"));
+    ArrayList<ByteString> values = new ArrayList<ByteString>();
+    values.add(ByteString.valueOf("invalidDN"));
 
     ArrayList<RawModification> mods = new ArrayList<RawModification>();
     mods.add(new LDAPModification(ModificationType.REPLACE,
@@ -1088,7 +1078,7 @@
          InternalClientConnection.getRootConnection();
     String mapperDNString = "cn=Exact Match,cn=Identity Mappers,cn=config";
     ModifyOperation modifyOperation =
-         conn.processModify(new ASN1OctetString(mapperDNString), mods);
+         conn.processModify(ByteString.valueOf(mapperDNString), mods);
     assertFalse(modifyOperation.getResultCode() == ResultCode.SUCCESS);
   }
 }
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/ExternalSASLMechanismHandlerTestCase.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/ExternalSASLMechanismHandlerTestCase.java
index 2b9eebd..fb36c47 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/ExternalSASLMechanismHandlerTestCase.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/ExternalSASLMechanismHandlerTestCase.java
@@ -45,7 +45,6 @@
 import org.opends.server.core.AddOperation;
 import org.opends.server.core.DirectoryServer;
 import org.opends.server.core.ModifyOperation;
-import org.opends.server.protocols.asn1.ASN1OctetString;
 import org.opends.server.protocols.asn1.ASN1Reader;
 import org.opends.server.protocols.asn1.ASN1Writer;
 import org.opends.server.protocols.internal.InternalClientConnection;
@@ -53,13 +52,9 @@
 import org.opends.server.protocols.ldap.BindResponseProtocolOp;
 import org.opends.server.protocols.ldap.LDAPMessage;
 import org.opends.server.tools.LDAPSearch;
-import org.opends.server.types.Attributes;
-import org.opends.server.types.DN;
-import org.opends.server.types.Entry;
-import org.opends.server.types.InitializationException;
-import org.opends.server.types.Modification;
-import org.opends.server.types.ModificationType;
-import org.opends.server.types.ResultCode;
+import org.opends.server.tools.LDAPReader;
+import org.opends.server.tools.LDAPWriter;
+import org.opends.server.types.*;
 import org.opends.server.util.Base64;
 import org.testng.annotations.BeforeClass;
 import org.testng.annotations.DataProvider;
@@ -310,15 +305,15 @@
     TestCaseUtils.initializeTestBackend(true);
 
     Socket s = new Socket("127.0.0.1", TestCaseUtils.getServerLdapPort());
-    ASN1Reader reader = new ASN1Reader(s);
-    ASN1Writer writer = new ASN1Writer(s);
+    LDAPReader reader = new LDAPReader(s);
+    LDAPWriter writer = new LDAPWriter(s);
 
     BindRequestProtocolOp bindRequest =
-         new BindRequestProtocolOp(new ASN1OctetString(), "EXTERNAL", null);
+         new BindRequestProtocolOp(ByteString.empty(), "EXTERNAL", null);
     LDAPMessage message = new LDAPMessage(1, bindRequest);
-    writer.writeElement(message.encode());
+    writer.writeMessage(message);
 
-    message = LDAPMessage.decode(reader.readElement().decodeAsSequence());
+    message = reader.readMessage();
     BindResponseProtocolOp bindResponse = message.getBindResponseProtocolOp();
     assertFalse(bindResponse.getResultCode() == 0);
 
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/HasSubordinatesVirtualAttributeProviderTestCase.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/HasSubordinatesVirtualAttributeProviderTestCase.java
index 6635588..79a04e4 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/HasSubordinatesVirtualAttributeProviderTestCase.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/HasSubordinatesVirtualAttributeProviderTestCase.java
@@ -34,6 +34,7 @@
 import static org.opends.server.util.ServerConstants.OID_VIRTUAL_ATTRS_ONLY;
 import org.opends.server.protocols.internal.InternalClientConnection;
 import org.opends.server.protocols.internal.InternalSearchOperation;
+import org.opends.server.protocols.ldap.LDAPControl;
 import org.opends.server.core.DirectoryServer;
 import org.testng.annotations.BeforeClass;
 import org.testng.annotations.DataProvider;
@@ -223,10 +224,10 @@
     {
       assertTrue(!a.isEmpty());
       assertEquals(a.size(), 1);
-      assertTrue(a.contains(new AttributeValue(ByteStringFactory
-          .create(toUpperCase(String.valueOf(hasSubs))), ByteStringFactory
-          .create(toUpperCase(String.valueOf(hasSubs))))));
-      assertTrue(a.contains(new AttributeValue(hasSubordinatesType,
+      assertTrue(a.contains(AttributeValues.create(
+          ByteString.valueOf(toUpperCase(String.valueOf(hasSubs))),
+          ByteString.valueOf(toUpperCase(String.valueOf(hasSubs))))));
+      assertTrue(a.contains(AttributeValues.create(hasSubordinatesType,
           toUpperCase(String.valueOf(hasSubs)))));
     }
   }
@@ -506,7 +507,7 @@
     attrList.add("hasSubordinates");
 
     LinkedList<Control> requestControls = new LinkedList<Control>();
-    requestControls.add(new Control(OID_REAL_ATTRS_ONLY, true));
+    requestControls.add(new LDAPControl(OID_REAL_ATTRS_ONLY, true));
 
     InternalClientConnection conn =
          InternalClientConnection.getRootConnection();
@@ -546,7 +547,7 @@
     attrList.add("hasSubordinates");
 
     LinkedList<Control> requestControls = new LinkedList<Control>();
-    requestControls.add(new Control(OID_VIRTUAL_ATTRS_ONLY, true));
+    requestControls.add(new LDAPControl(OID_VIRTUAL_ATTRS_ONLY, true));
 
     InternalClientConnection conn =
          InternalClientConnection.getRootConnection();
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/InternalConnectionSecurityProviderTestCase.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/InternalConnectionSecurityProviderTestCase.java
deleted file mode 100644
index 5c67698..0000000
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/InternalConnectionSecurityProviderTestCase.java
+++ /dev/null
@@ -1,123 +0,0 @@
-/*
- * CDDL HEADER START
- *
- * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
- *
- * You can obtain a copy of the license at
- * trunk/opends/resource/legal-notices/OpenDS.LICENSE
- * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
- * See the License for the specific language governing permissions
- * and limitations under the License.
- *
- * When distributing Covered Code, include this CDDL HEADER in each
- * file and include the License file at
- * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
- * add the following below this CDDL 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.server.extensions;
-
-
-
-import java.util.ArrayList;
-import java.util.concurrent.locks.Lock;
-
-import org.testng.annotations.BeforeClass;
-import org.testng.annotations.Test;
-
-import org.opends.server.TestCaseUtils;
-import org.opends.server.api.Backend;
-import org.opends.server.core.DirectoryServer;
-import org.opends.server.types.DN;
-import org.opends.server.types.Entry;
-import org.opends.server.types.LockType;
-
-import static org.testng.Assert.*;
-
-
-
-/**
- * A set of test cases for the internal connection security provider.
- */
-public class InternalConnectionSecurityProviderTestCase
-       extends ExtensionsTestCase
-{
-  /**
-   * Ensures that the Directory Server is running.
-   *
-   * @throws  Exception  If an unexpected problem occurs.
-   */
-  @BeforeClass()
-  public void startServer()
-         throws Exception
-  {
-    TestCaseUtils.startServer();
-  }
-
-
-
-  /**
-   * Tests the default constructor for this class.
-   *
-   * @throws  Exception  If an unexpected problem occurs.
-   */
-  @Test()
-  public void testConstructor()
-         throws Exception
-  {
-    InternalConnectionSecurityProvider provider =
-         new InternalConnectionSecurityProvider();
-    provider.initializeConnectionSecurityProvider(null);
-    provider.finalizeConnectionSecurityProvider();
-  }
-
-
-
-  /**
-   * Tests the <CODE>getSecurityMechanismName</CODE> method.
-   *
-   * @throws  Exception  If an unexpected problem occurs.
-   */
-  @Test()
-  public void testGetSecurityMechanismName()
-         throws Exception
-  {
-    InternalConnectionSecurityProvider provider =
-         new InternalConnectionSecurityProvider();
-    provider.initializeConnectionSecurityProvider(null);
-
-    assertNotNull(provider.getSecurityMechanismName());
-
-    provider.finalizeConnectionSecurityProvider();
-  }
-
-
-
-  /**
-   * Tests the <CODE>isSecure</CODE> method.
-   *
-   * @throws  Exception  If an unexpected problem occurs.
-   */
-  @Test()
-  public void testIsSecure()
-         throws Exception
-  {
-    InternalConnectionSecurityProvider provider =
-         new InternalConnectionSecurityProvider();
-    provider.initializeConnectionSecurityProvider(null);
-
-    assertTrue(provider.isSecure());
-
-    provider.finalizeConnectionSecurityProvider();
-  }
-}
-
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/IsMemberOfVirtualAttributeProviderTestCase.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/IsMemberOfVirtualAttributeProviderTestCase.java
index 30f15a4..1d76cbf 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/IsMemberOfVirtualAttributeProviderTestCase.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/IsMemberOfVirtualAttributeProviderTestCase.java
@@ -28,14 +28,12 @@
 
 
 
+import static org.testng.Assert.*;
+
 import java.util.Collections;
 import java.util.LinkedHashSet;
 import java.util.LinkedList;
 
-import org.testng.annotations.BeforeClass;
-import org.testng.annotations.DataProvider;
-import org.testng.annotations.Test;
-
 import org.opends.server.TestCaseUtils;
 import org.opends.server.admin.std.meta.VirtualAttributeCfgDefn;
 import org.opends.server.core.DeleteOperation;
@@ -45,19 +43,20 @@
 import org.opends.server.types.Attribute;
 import org.opends.server.types.AttributeType;
 import org.opends.server.types.AttributeValue;
+import org.opends.server.types.AttributeValues;
 import org.opends.server.types.ByteString;
-import org.opends.server.types.ByteStringFactory;
 import org.opends.server.types.ConditionResult;
-import org.opends.server.types.DereferencePolicy;
 import org.opends.server.types.DN;
+import org.opends.server.types.DereferencePolicy;
 import org.opends.server.types.Entry;
 import org.opends.server.types.ResultCode;
 import org.opends.server.types.SearchFilter;
 import org.opends.server.types.SearchScope;
 import org.opends.server.types.VirtualAttributeRule;
 import org.opends.server.workflowelement.localbackend.LocalBackendSearchOperation;
-
-import static org.testng.Assert.*;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
 
 
 
@@ -138,11 +137,11 @@
       assertEquals(a.size(), 1);
 
       assertTrue(!a.isEmpty());
-      assertTrue(a.contains(new AttributeValue(isMemberOfType,
+      assertTrue(a.contains(AttributeValues.create(isMemberOfType,
                                      "cn=test static group,ou=groups,o=test")));
-      assertFalse(a.contains(new AttributeValue(isMemberOfType,
+      assertFalse(a.contains(AttributeValues.create(isMemberOfType,
                                       "cn=not a group,ou=groups,o=test")));
-      assertFalse(a.contains(new AttributeValue(isMemberOfType, "invalid")));
+      assertFalse(a.contains(AttributeValues.create(isMemberOfType, "invalid")));
     }
 
     InternalClientConnection conn =
@@ -204,11 +203,11 @@
       assertEquals(a.size(), 1);
 
       assertTrue(!a.isEmpty());
-      assertTrue(a.contains(new AttributeValue(isMemberOfType,
+      assertTrue(a.contains(AttributeValues.create(isMemberOfType,
                                      "cn=test static group,ou=groups,o=test")));
-      assertFalse(a.contains(new AttributeValue(isMemberOfType,
+      assertFalse(a.contains(AttributeValues.create(isMemberOfType,
                                       "cn=not a group,ou=groups,o=test")));
-      assertFalse(a.contains(new AttributeValue(isMemberOfType, "invalid")));
+      assertFalse(a.contains(AttributeValues.create(isMemberOfType, "invalid")));
     }
 
     InternalClientConnection conn =
@@ -269,11 +268,11 @@
       assertEquals(a.size(), 1);
 
       assertTrue(!a.isEmpty());
-      assertTrue(a.contains(new AttributeValue(isMemberOfType,
+      assertTrue(a.contains(AttributeValues.create(isMemberOfType,
                       "cn=test dynamic group,ou=groups,o=test")));
-      assertFalse(a.contains(new AttributeValue(isMemberOfType,
+      assertFalse(a.contains(AttributeValues.create(isMemberOfType,
                                       "cn=not a group,ou=groups,o=test")));
-      assertFalse(a.contains(new AttributeValue(isMemberOfType, "invalid")));
+      assertFalse(a.contains(AttributeValues.create(isMemberOfType, "invalid")));
     }
 
     InternalClientConnection conn =
@@ -359,15 +358,15 @@
       assertEquals(a.size(), 2);
 
       assertTrue(!a.isEmpty());
-      assertTrue(a.contains(new AttributeValue(isMemberOfType,
+      assertTrue(a.contains(AttributeValues.create(isMemberOfType,
                                      "cn=test group 1,ou=groups,o=test")));
-      assertFalse(a.contains(new AttributeValue(isMemberOfType,
+      assertFalse(a.contains(AttributeValues.create(isMemberOfType,
                                       "cn=test group 2,ou=groups,o=test")));
-      assertTrue(a.contains(new AttributeValue(isMemberOfType,
+      assertTrue(a.contains(AttributeValues.create(isMemberOfType,
                                      "cn=test group 3,ou=groups,o=test")));
-      assertFalse(a.contains(new AttributeValue(isMemberOfType,
+      assertFalse(a.contains(AttributeValues.create(isMemberOfType,
                                       "cn=not a group,ou=groups,o=test")));
-      assertFalse(a.contains(new AttributeValue(isMemberOfType, "invalid")));
+      assertFalse(a.contains(AttributeValues.create(isMemberOfType, "invalid")));
     }
 
     InternalClientConnection conn =
@@ -478,21 +477,21 @@
       assertEquals(a.size(), 4);
 
       assertTrue(!a.isEmpty());
-      assertTrue(a.contains(new AttributeValue(isMemberOfType,
+      assertTrue(a.contains(AttributeValues.create(isMemberOfType,
                                      "cn=test group 1,ou=groups,o=test")));
-      assertFalse(a.contains(new AttributeValue(isMemberOfType,
+      assertFalse(a.contains(AttributeValues.create(isMemberOfType,
                                       "cn=test group 2,ou=groups,o=test")));
-      assertTrue(a.contains(new AttributeValue(isMemberOfType,
+      assertTrue(a.contains(AttributeValues.create(isMemberOfType,
                                      "cn=test group 3,ou=groups,o=test")));
-      assertTrue(a.contains(new AttributeValue(isMemberOfType,
+      assertTrue(a.contains(AttributeValues.create(isMemberOfType,
                                      "cn=test group 4,ou=groups,o=test")));
-      assertFalse(a.contains(new AttributeValue(isMemberOfType,
+      assertFalse(a.contains(AttributeValues.create(isMemberOfType,
                                       "cn=test group 5,ou=groups,o=test")));
-      assertTrue(a.contains(new AttributeValue(isMemberOfType,
+      assertTrue(a.contains(AttributeValues.create(isMemberOfType,
                                      "cn=test group 6,ou=groups,o=test")));
-      assertFalse(a.contains(new AttributeValue(isMemberOfType,
+      assertFalse(a.contains(AttributeValues.create(isMemberOfType,
                                       "cn=not a group,ou=groups,o=test")));
-      assertFalse(a.contains(new AttributeValue(isMemberOfType, "invalid")));
+      assertFalse(a.contains(AttributeValues.create(isMemberOfType, "invalid")));
     }
 
     InternalClientConnection conn =
@@ -653,7 +652,7 @@
                        VIRTUAL_OVERRIDES_REAL);
 
     LinkedHashSet<AttributeValue> values = new LinkedHashSet<AttributeValue>();
-    values.add(new AttributeValue(isMemberOfType,
+    values.add(AttributeValues.create(isMemberOfType,
                                   "cn=test static group,ou=groups,o=test"));
 
     assertTrue(provider.hasAnyValue(e, rule, values));
@@ -720,7 +719,7 @@
                        VIRTUAL_OVERRIDES_REAL);
 
     LinkedHashSet<AttributeValue> values = new LinkedHashSet<AttributeValue>();
-    values.add(new AttributeValue(isMemberOfType,
+    values.add(AttributeValues.create(isMemberOfType,
                                   "cn=test dynamic group,ou=groups,o=test"));
 
     assertFalse(provider.hasAnyValue(e, rule, values));
@@ -787,9 +786,9 @@
                        VIRTUAL_OVERRIDES_REAL);
 
     LinkedHashSet<AttributeValue> values = new LinkedHashSet<AttributeValue>();
-    values.add(new AttributeValue(isMemberOfType,
+    values.add(AttributeValues.create(isMemberOfType,
                                   "cn=test static group,ou=groups,o=test"));
-    values.add(new AttributeValue(isMemberOfType,
+    values.add(AttributeValues.create(isMemberOfType,
                                   "cn=test dynamic group,ou=groups,o=test"));
 
     assertTrue(provider.hasAnyValue(e, rule, values));
@@ -856,9 +855,9 @@
                        VIRTUAL_OVERRIDES_REAL);
 
     LinkedHashSet<AttributeValue> values = new LinkedHashSet<AttributeValue>();
-    values.add(new AttributeValue(isMemberOfType,
+    values.add(AttributeValues.create(isMemberOfType,
                                   "cn=test nonstatic group,ou=groups,o=test"));
-    values.add(new AttributeValue(isMemberOfType,
+    values.add(AttributeValues.create(isMemberOfType,
                                   "cn=test dynamic group,ou=groups,o=test"));
 
     assertFalse(provider.hasAnyValue(e, rule, values));
@@ -900,7 +899,7 @@
                        VIRTUAL_OVERRIDES_REAL);
 
     LinkedList<ByteString> subAny = new LinkedList<ByteString>();
-    subAny.add(ByteStringFactory.create("="));
+    subAny.add(ByteString.valueOf("="));
 
     assertEquals(provider.matchesSubstring(entry, rule, null, subAny, null),
                  ConditionResult.UNDEFINED);
@@ -935,7 +934,7 @@
                   VirtualAttributeCfgDefn.ConflictBehavior.
                        VIRTUAL_OVERRIDES_REAL);
 
-    AttributeValue value = new AttributeValue(isMemberOfType, "o=test2");
+    AttributeValue value = AttributeValues.create(isMemberOfType, "o=test2");
     assertEquals(provider.greaterThanOrEqualTo(entry, rule, value),
                  ConditionResult.UNDEFINED);
   }
@@ -969,7 +968,7 @@
                   VirtualAttributeCfgDefn.ConflictBehavior.
                        VIRTUAL_OVERRIDES_REAL);
 
-    AttributeValue value = new AttributeValue(isMemberOfType, "o=test2");
+    AttributeValue value = AttributeValues.create(isMemberOfType, "o=test2");
     assertEquals(provider.lessThanOrEqualTo(entry, rule, value),
                  ConditionResult.UNDEFINED);
   }
@@ -1003,7 +1002,7 @@
                   VirtualAttributeCfgDefn.ConflictBehavior.
                        VIRTUAL_OVERRIDES_REAL);
 
-    AttributeValue value = new AttributeValue(isMemberOfType, "o=test2");
+    AttributeValue value = AttributeValues.create(isMemberOfType, "o=test2");
     assertEquals(provider.approximatelyEqualTo(entry, rule, value),
                  ConditionResult.UNDEFINED);
   }
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/LengthBasedPasswordValidatorTestCase.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/LengthBasedPasswordValidatorTestCase.java
index c40ad47..386f15c 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/LengthBasedPasswordValidatorTestCase.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/LengthBasedPasswordValidatorTestCase.java
@@ -41,7 +41,6 @@
 import org.opends.server.admin.std.server.LengthBasedPasswordValidatorCfg;
 import org.opends.server.config.ConfigException;
 import org.opends.server.core.ModifyOperationBasis;
-import org.opends.server.protocols.asn1.ASN1OctetString;
 import org.opends.server.protocols.internal.InternalClientConnection;
 import org.opends.server.types.Attributes;
 import org.opends.server.types.ByteString;
@@ -361,7 +360,7 @@
     for (int i=0; i < 20; i++)
     {
       buffer.append('x');
-      ASN1OctetString password = new ASN1OctetString(buffer.toString());
+      ByteString password = ByteString.valueOf(buffer.toString());
 
       ArrayList<Modification> mods = new ArrayList<Modification>();
       mods.add(new Modification(ModificationType.REPLACE,
@@ -434,7 +433,7 @@
     for (int i=0; i < 20; i++)
     {
       buffer.append('x');
-      ASN1OctetString password = new ASN1OctetString(buffer.toString());
+      ByteString password = ByteString.valueOf(buffer.toString());
 
       ArrayList<Modification> mods = new ArrayList<Modification>();
       mods.add(new Modification(ModificationType.REPLACE,
@@ -509,7 +508,7 @@
     for (int i=0; i < 20; i++)
     {
       buffer.append('x');
-      ASN1OctetString password = new ASN1OctetString(buffer.toString());
+      ByteString password = ByteString.valueOf(buffer.toString());
 
       ArrayList<Modification> mods = new ArrayList<Modification>();
       mods.add(new Modification(ModificationType.REPLACE,
@@ -584,7 +583,7 @@
     for (int i=0; i < 20; i++)
     {
       buffer.append('x');
-      ASN1OctetString password = new ASN1OctetString(buffer.toString());
+      ByteString password = ByteString.valueOf(buffer.toString());
 
       ArrayList<Modification> mods = new ArrayList<Modification>();
       mods.add(new Modification(ModificationType.REPLACE,
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/NullConnectionSecurityProviderTestCase.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/NullConnectionSecurityProviderTestCase.java
deleted file mode 100644
index 7863dd1..0000000
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/NullConnectionSecurityProviderTestCase.java
+++ /dev/null
@@ -1,183 +0,0 @@
-/*
- * CDDL HEADER START
- *
- * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
- *
- * You can obtain a copy of the license at
- * trunk/opends/resource/legal-notices/OpenDS.LICENSE
- * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
- * See the License for the specific language governing permissions
- * and limitations under the License.
- *
- * When distributing Covered Code, include this CDDL HEADER in each
- * file and include the License file at
- * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
- * add the following below this CDDL 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.server.extensions;
-
-
-
-import java.util.ArrayList;
-import java.util.concurrent.locks.Lock;
-
-import org.testng.annotations.BeforeClass;
-import org.testng.annotations.Test;
-
-import org.opends.server.TestCaseUtils;
-import org.opends.server.api.Backend;
-import org.opends.server.core.DirectoryServer;
-import org.opends.server.types.DN;
-import org.opends.server.types.Entry;
-import org.opends.server.types.LockType;
-
-import static org.testng.Assert.*;
-
-
-
-/**
- * A set of test cases for the null connection security provider.
- */
-public class NullConnectionSecurityProviderTestCase
-       extends ExtensionsTestCase
-{
-  /**
-   * Ensures that the Directory Server is running.
-   *
-   * @throws  Exception  If an unexpected problem occurs.
-   */
-  @BeforeClass()
-  public void startServer()
-         throws Exception
-  {
-    TestCaseUtils.startServer();
-  }
-
-
-
-  /**
-   * Tests the default constructor for this class.
-   *
-   * @throws  Exception  If an unexpected problem occurs.
-   */
-  @Test()
-  public void testConstructor()
-         throws Exception
-  {
-    NullConnectionSecurityProvider provider =
-         new NullConnectionSecurityProvider();
-    provider.initializeConnectionSecurityProvider(null);
-    provider.finalizeConnectionSecurityProvider();
-  }
-
-
-
-  /**
-   * Tests the <CODE>getSecurityMechanismName</CODE> method.
-   *
-   * @throws  Exception  If an unexpected problem occurs.
-   */
-  @Test()
-  public void testGetSecurityMechanismName()
-         throws Exception
-  {
-    NullConnectionSecurityProvider provider =
-         new NullConnectionSecurityProvider();
-    provider.initializeConnectionSecurityProvider(null);
-
-    assertNotNull(provider.getSecurityMechanismName());
-
-    provider.finalizeConnectionSecurityProvider();
-  }
-
-
-
-  /**
-   * Tests the <CODE>isSecure</CODE> method.
-   *
-   * @throws  Exception  If an unexpected problem occurs.
-   */
-  @Test()
-  public void testIsSecure()
-         throws Exception
-  {
-    NullConnectionSecurityProvider provider =
-         new NullConnectionSecurityProvider();
-    provider.initializeConnectionSecurityProvider(null);
-
-    assertFalse(provider.isSecure());
-
-    provider.finalizeConnectionSecurityProvider();
-  }
-
-
-
-  /**
-   * Tests the <CODE>disconnect</CODE> method.
-   *
-   * @throws  Exception  If an unexpected problem occurs.
-   */
-  @Test()
-  public void testDisconnect()
-         throws Exception
-  {
-    NullConnectionSecurityProvider provider =
-         new NullConnectionSecurityProvider();
-    provider.initializeConnectionSecurityProvider(null);
-
-    provider.disconnect(true);
-
-    provider.finalizeConnectionSecurityProvider();
-  }
-
-
-
-  /**
-   * Tests the <CODE>getClearBufferSize</CODE> method.
-   *
-   * @throws  Exception  If an unexpected problem occurs.
-   */
-  @Test()
-  public void testGetClearBufferSize()
-         throws Exception
-  {
-    NullConnectionSecurityProvider provider =
-         new NullConnectionSecurityProvider();
-    provider.initializeConnectionSecurityProvider(null);
-
-    assertTrue(provider.getClearBufferSize() > 0);
-
-    provider.finalizeConnectionSecurityProvider();
-  }
-
-
-
-  /**
-   * Tests the <CODE>getEncodedBufferSize</CODE> method.
-   *
-   * @throws  Exception  If an unexpected problem occurs.
-   */
-  @Test()
-  public void testGetEncodedBufferSize()
-         throws Exception
-  {
-    NullConnectionSecurityProvider provider =
-         new NullConnectionSecurityProvider();
-    provider.initializeConnectionSecurityProvider(null);
-
-    assertTrue(provider.getEncodedBufferSize() > 0);
-
-    provider.finalizeConnectionSecurityProvider();
-  }
-}
-
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/NumSubordinatesVirtualAttributeProviderTestCase.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/NumSubordinatesVirtualAttributeProviderTestCase.java
index 90b32e2..8de0bc9 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/NumSubordinatesVirtualAttributeProviderTestCase.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/NumSubordinatesVirtualAttributeProviderTestCase.java
@@ -31,6 +31,7 @@
 import org.opends.server.DirectoryServerTestCase;
 import org.opends.server.protocols.internal.InternalClientConnection;
 import org.opends.server.protocols.internal.InternalSearchOperation;
+import org.opends.server.protocols.ldap.LDAPControl;
 import static org.opends.server.util.ServerConstants.OID_REAL_ATTRS_ONLY;
 import static org.opends.server.util.ServerConstants.OID_VIRTUAL_ATTRS_ONLY;
 import org.opends.server.core.DirectoryServer;
@@ -223,10 +224,10 @@
     {
       assertTrue(!a.isEmpty());
       assertEquals(a.size(), 1);
-      assertTrue(a.contains(new AttributeValue(
-          ByteStringFactory.create(String.valueOf(count)),
-          ByteStringFactory.create(String.valueOf(count)))));
-      assertTrue(a.contains(new AttributeValue(numSubordinatesType,
+      assertTrue(a.contains(AttributeValues.create(
+          ByteString.valueOf(String.valueOf(count)),
+          ByteString.valueOf(String.valueOf(count)))));
+      assertTrue(a.contains(AttributeValues.create(numSubordinatesType,
                                                String.valueOf(count))));
     }
   }
@@ -507,7 +508,7 @@
     attrList.add("numSubordinates");
 
     LinkedList<Control> requestControls = new LinkedList<Control>();
-    requestControls.add(new Control(OID_REAL_ATTRS_ONLY, true));
+    requestControls.add(new LDAPControl(OID_REAL_ATTRS_ONLY, true));
 
     InternalClientConnection conn =
          InternalClientConnection.getRootConnection();
@@ -547,7 +548,7 @@
     attrList.add("numSubordinates");
 
     LinkedList<Control> requestControls = new LinkedList<Control>();
-    requestControls.add(new Control(OID_VIRTUAL_ATTRS_ONLY, true));
+    requestControls.add(new LDAPControl(OID_VIRTUAL_ATTRS_ONLY, true));
 
     InternalClientConnection conn =
          InternalClientConnection.getRootConnection();
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/PasswordModifyExtendedOperationTestCase.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/PasswordModifyExtendedOperationTestCase.java
index 94b2c1f..35e3a05 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/PasswordModifyExtendedOperationTestCase.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/PasswordModifyExtendedOperationTestCase.java
@@ -45,20 +45,11 @@
 import org.opends.server.core.DirectoryServer;
 import org.opends.server.core.ExtendedOperation;
 import org.opends.server.core.ModifyOperation;
-import org.opends.server.protocols.asn1.ASN1Element;
-import org.opends.server.protocols.asn1.ASN1OctetString;
-import org.opends.server.protocols.asn1.ASN1Sequence;
 import org.opends.server.protocols.internal.InternalClientConnection;
+import org.opends.server.protocols.asn1.ASN1;
+import org.opends.server.protocols.asn1.ASN1Writer;
 import org.opends.server.tools.LDAPPasswordModify;
-import org.opends.server.types.AttributeType;
-import org.opends.server.types.Attributes;
-import org.opends.server.types.AuthenticationInfo;
-import org.opends.server.types.DN;
-import org.opends.server.types.Entry;
-import org.opends.server.types.InitializationException;
-import org.opends.server.types.Modification;
-import org.opends.server.types.ModificationType;
-import org.opends.server.types.ResultCode;
+import org.opends.server.types.*;
 
 import static org.testng.Assert.*;
 
@@ -198,7 +189,7 @@
          new InternalClientConnection(new AuthenticationInfo());
     BindOperation bindOperation =
          conn.processSimpleBind(DN.decode("cn=Directory Manager"),
-                                new ASN1OctetString("newPassword"));
+                                ByteString.valueOf("newPassword"));
     assertEquals(bindOperation.getResultCode(), ResultCode.SUCCESS);
 
 
@@ -255,7 +246,7 @@
          new InternalClientConnection(new AuthenticationInfo());
     BindOperation bindOperation =
          conn.processSimpleBind(DN.decode("cn=Directory Manager"),
-                                new ASN1OctetString("newPassword"));
+                                ByteString.valueOf("newPassword"));
     assertEquals(bindOperation.getResultCode(), ResultCode.SUCCESS);
 
 
@@ -311,7 +302,7 @@
          new InternalClientConnection(new AuthenticationInfo());
     BindOperation bindOperation =
          conn.processSimpleBind(DN.decode("cn=Directory Manager"),
-                                new ASN1OctetString("newPassword"));
+                                ByteString.valueOf("newPassword"));
     assertEquals(bindOperation.getResultCode(), ResultCode.SUCCESS);
 
 
@@ -390,7 +381,7 @@
     conn = new InternalClientConnection(new AuthenticationInfo());
     BindOperation bindOperation =
          conn.processSimpleBind(userEntry.getDN(),
-                                new ASN1OctetString("newPassword"));
+                                ByteString.valueOf("newPassword"));
     assertEquals(bindOperation.getResultCode(), ResultCode.SUCCESS);
   }
 
@@ -454,7 +445,7 @@
     conn = new InternalClientConnection(new AuthenticationInfo());
     BindOperation bindOperation =
          conn.processSimpleBind(userEntry.getDN(),
-                                new ASN1OctetString("newPassword"));
+                                ByteString.valueOf("newPassword"));
     assertEquals(bindOperation.getResultCode(), ResultCode.SUCCESS);
   }
 
@@ -575,7 +566,7 @@
     conn = new InternalClientConnection(new AuthenticationInfo());
     BindOperation bindOperation =
          conn.processSimpleBind(userEntry.getDN(),
-                                new ASN1OctetString("newPassword"));
+                                ByteString.valueOf("newPassword"));
     assertEquals(bindOperation.getResultCode(), ResultCode.SUCCESS);
   }
 
@@ -640,7 +631,7 @@
     conn = new InternalClientConnection(new AuthenticationInfo());
     BindOperation bindOperation =
          conn.processSimpleBind(userEntry.getDN(),
-                                new ASN1OctetString("newPassword"));
+                                ByteString.valueOf("newPassword"));
     assertEquals(bindOperation.getResultCode(), ResultCode.SUCCESS);
   }
 
@@ -705,7 +696,7 @@
     conn = new InternalClientConnection(new AuthenticationInfo());
     BindOperation bindOperation =
          conn.processSimpleBind(userEntry.getDN(),
-                                new ASN1OctetString("newPassword"));
+                                ByteString.valueOf("newPassword"));
     assertEquals(bindOperation.getResultCode(), ResultCode.SUCCESS);
   }
 
@@ -770,7 +761,7 @@
     conn = new InternalClientConnection(new AuthenticationInfo());
     BindOperation bindOperation =
          conn.processSimpleBind(userEntry.getDN(),
-                                new ASN1OctetString("newPassword"));
+                                ByteString.valueOf("newPassword"));
     assertEquals(bindOperation.getResultCode(), ResultCode.SUCCESS);
   }
 
@@ -834,7 +825,7 @@
     conn = new InternalClientConnection(new AuthenticationInfo());
     BindOperation bindOperation =
          conn.processSimpleBind(userEntry.getDN(),
-                                new ASN1OctetString("newPassword"));
+                                ByteString.valueOf("newPassword"));
     assertEquals(bindOperation.getResultCode(), ResultCode.SUCCESS);
   }
 
@@ -898,7 +889,7 @@
     conn = new InternalClientConnection(new AuthenticationInfo());
     BindOperation bindOperation =
          conn.processSimpleBind(userEntry.getDN(),
-                                new ASN1OctetString("newPassword"));
+                                ByteString.valueOf("newPassword"));
     assertEquals(bindOperation.getResultCode(), ResultCode.SUCCESS);
   }
 
@@ -963,7 +954,7 @@
     conn = new InternalClientConnection(new AuthenticationInfo());
     BindOperation bindOperation =
          conn.processSimpleBind(userEntry.getDN(),
-                                new ASN1OctetString("newPassword"));
+                                ByteString.valueOf("newPassword"));
     assertEquals(bindOperation.getResultCode(), ResultCode.SUCCESS);
   }
 
@@ -1394,7 +1385,7 @@
   @Test()
   public void testFailureInvalidRequestValueFormat()
   {
-    ASN1OctetString requestValue = new ASN1OctetString("malformed");
+    ByteString requestValue = ByteString.valueOf("malformed");
 
     InternalClientConnection conn =
          InternalClientConnection.getRootConnection();
@@ -1411,14 +1402,14 @@
    * with a request that contain an invalid sequence element type.
    */
   @Test()
-  public void testFailureInvalidSequenceElementType()
+  public void testFailureInvalidSequenceElementType() throws Exception
   {
-    ArrayList<ASN1Element> elements = new ArrayList<ASN1Element>();
-    elements.add(new ASN1Element((byte) 0x50));
-
-    ASN1Sequence requestSequence = new ASN1Sequence(elements);
-    ASN1OctetString requestValue =
-         new ASN1OctetString(requestSequence.encode());
+    ByteStringBuilder builder = new ByteStringBuilder();
+    ASN1Writer writer = ASN1.getWriter(builder);
+    writer.writeStartSequence();
+    writer.writeNull((byte)0x50);
+    writer.writeEndSequence();
+    ByteString requestValue = builder.toByteString();
 
     InternalClientConnection conn =
          InternalClientConnection.getRootConnection();
@@ -1435,15 +1426,15 @@
    * internal connection and without providing an authorization ID.
    */
   @Test()
-  public void testFailureCompletelyAnonymous()
+  public void testFailureCompletelyAnonymous() throws Exception
   {
-    ArrayList<ASN1Element> elements = new ArrayList<ASN1Element>();
-    elements.add(new ASN1OctetString(TYPE_PASSWORD_MODIFY_NEW_PASSWORD,
-                                     "newPassword"));
-
-    ASN1Sequence requestSequence = new ASN1Sequence(elements);
-    ASN1OctetString requestValue =
-         new ASN1OctetString(requestSequence.encode());
+    ByteStringBuilder builder = new ByteStringBuilder();
+    ASN1Writer writer = ASN1.getWriter(builder);
+    writer.writeStartSequence();
+    writer.writeOctetString(TYPE_PASSWORD_MODIFY_NEW_PASSWORD,
+                                     "newPassword");
+    writer.writeEndSequence();
+    ByteString requestValue = builder.toByteString();
 
     InternalClientConnection conn =
          new InternalClientConnection(new AuthenticationInfo());
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/PasswordStorageSchemeTestCase.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/PasswordStorageSchemeTestCase.java
index dbc93ba..5b66699 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/PasswordStorageSchemeTestCase.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/PasswordStorageSchemeTestCase.java
@@ -38,7 +38,6 @@
 import org.opends.server.core.DirectoryServer;
 import org.opends.server.core.ModifyOperation;
 import org.opends.server.core.PasswordPolicy;
-import org.opends.server.protocols.asn1.ASN1OctetString;
 import org.opends.server.protocols.internal.InternalClientConnection;
 import org.opends.server.schema.AuthPasswordSyntax;
 import org.opends.server.schema.UserPasswordSyntax;
@@ -118,27 +117,27 @@
   {
     return new Object[][]
     {
-      new Object[] { new ASN1OctetString() },
-      new Object[] { new ASN1OctetString("") },
-      new Object[] { new ASN1OctetString("\u0000") },
-      new Object[] { new ASN1OctetString("\t") },
-      new Object[] { new ASN1OctetString("\n") },
-      new Object[] { new ASN1OctetString("\r\n") },
-      new Object[] { new ASN1OctetString(" ") },
-      new Object[] { new ASN1OctetString("Test1\tTest2\tTest3") },
-      new Object[] { new ASN1OctetString("Test1\nTest2\nTest3") },
-      new Object[] { new ASN1OctetString("Test1\r\nTest2\r\nTest3") },
-      new Object[] { new ASN1OctetString("a") },
-      new Object[] { new ASN1OctetString("ab") },
-      new Object[] { new ASN1OctetString("abc") },
-      new Object[] { new ASN1OctetString("abcd") },
-      new Object[] { new ASN1OctetString("abcde") },
-      new Object[] { new ASN1OctetString("abcdef") },
-      new Object[] { new ASN1OctetString("abcdefg") },
-      new Object[] { new ASN1OctetString("abcdefgh") },
-      new Object[] { new ASN1OctetString("The Quick Brown Fox Jumps Over " +
+      new Object[] { ByteString.empty() },
+      new Object[] { ByteString.valueOf("") },
+      new Object[] { ByteString.valueOf("\u0000") },
+      new Object[] { ByteString.valueOf("\t") },
+      new Object[] { ByteString.valueOf("\n") },
+      new Object[] { ByteString.valueOf("\r\n") },
+      new Object[] { ByteString.valueOf(" ") },
+      new Object[] { ByteString.valueOf("Test1\tTest2\tTest3") },
+      new Object[] { ByteString.valueOf("Test1\nTest2\nTest3") },
+      new Object[] { ByteString.valueOf("Test1\r\nTest2\r\nTest3") },
+      new Object[] { ByteString.valueOf("a") },
+      new Object[] { ByteString.valueOf("ab") },
+      new Object[] { ByteString.valueOf("abc") },
+      new Object[] { ByteString.valueOf("abcd") },
+      new Object[] { ByteString.valueOf("abcde") },
+      new Object[] { ByteString.valueOf("abcdef") },
+      new Object[] { ByteString.valueOf("abcdefg") },
+      new Object[] { ByteString.valueOf("abcdefgh") },
+      new Object[] { ByteString.valueOf("The Quick Brown Fox Jumps Over " +
                                          "The Lazy Dog") },
-      new Object[] { new ASN1OctetString("\u00BFD\u00F3nde est\u00E1 el " +
+      new Object[] { ByteString.valueOf("\u00BFD\u00F3nde est\u00E1 el " +
                                          "ba\u00F1o?") }
     };
   }
@@ -165,12 +164,12 @@
     assertNotNull(encodedPassword);
     assertTrue(scheme.passwordMatches(plaintext, encodedPassword));
     assertFalse(scheme.passwordMatches(plaintext,
-                                       new ASN1OctetString("garbage")));
+                                       ByteString.valueOf("garbage")));
 
     ByteString schemeEncodedPassword =
          scheme.encodePasswordWithScheme(plaintext);
     String[] pwComponents = UserPasswordSyntax.decodeUserPassword(
-                                 schemeEncodedPassword.stringValue());
+                                 schemeEncodedPassword.toString());
     assertNotNull(pwComponents);
 
 
@@ -180,7 +179,7 @@
       ByteString encodedAuthPassword = scheme.encodeAuthPassword(plaintext);
       StringBuilder[] authPWComponents =
            AuthPasswordSyntax.decodeAuthPassword(
-                encodedAuthPassword.stringValue());
+                encodedAuthPassword.toString());
       assertTrue(scheme.authPasswordMatches(plaintext,
                                             authPWComponents[1].toString(),
                                             authPWComponents[2].toString()));
@@ -238,9 +237,9 @@
       // or other characters that will cause LDIF parsing errors.
       // We really don't need many test cases here, since that functionality
       // is tested above.
-      new Object[] { new ASN1OctetString("a") },
-      new Object[] { new ASN1OctetString("abcdefgh") },
-      new Object[] { new ASN1OctetString("abcdefghi") },
+      new Object[] { ByteString.valueOf("a") },
+      new Object[] { ByteString.valueOf("abcdefgh") },
+      new Object[] { ByteString.valueOf("abcdefghi") },
     };
   }
 
@@ -249,7 +248,7 @@
    * in a user entry, and then bind as that user using the cleartext password.
    */
   @Test(dataProvider = "passwordsForBinding")
-  public void testSettingEncodedPassword(ASN1OctetString plainPassword) throws Exception
+  public void testSettingEncodedPassword(ByteString plainPassword) throws Exception
   {
     // Start/clear-out the memory backend
     TestCaseUtils.initializeTestBackend(true);
@@ -277,17 +276,17 @@
            "sn: User",
            "cn: Test User",
            "ds-privilege-name: bypass-acl",
-           "userPassword: " + schemeEncodedPassword.stringValue());
+           "userPassword: " + schemeEncodedPassword.toString());
 
       // Add the entry
       TestCaseUtils.addEntry(userEntry);
 
       assertTrue(TestCaseUtils.canBind("uid=test.user,o=test",
-                 plainPassword.stringValue()),
+                 plainPassword.toString()),
                  "Failed to bind when pre-encoded password = \"" +
-                         schemeEncodedPassword.stringValue() + "\" and " +
+                         schemeEncodedPassword.toString() + "\" and " +
                          "plaintext password = \"" +
-                         plainPassword.stringValue() + "\"");
+                         plainPassword.toString() + "\"");
     } finally {
       setAllowPreencodedPasswords(allowPreencodedDefault);
     }
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/PlainSASLMechanismHandlerTestCase.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/PlainSASLMechanismHandlerTestCase.java
index e746867..3ef4cfd 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/PlainSASLMechanismHandlerTestCase.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/PlainSASLMechanismHandlerTestCase.java
@@ -37,18 +37,11 @@
 import org.opends.server.core.AddOperation;
 import org.opends.server.core.BindOperation;
 import org.opends.server.core.DirectoryServer;
-import org.opends.server.protocols.asn1.ASN1OctetString;
 import org.opends.server.protocols.internal.InternalClientConnection;
 import org.opends.server.protocols.internal.InternalSearchOperation;
 import org.opends.server.protocols.ldap.LDAPFilter;
 import org.opends.server.tools.LDAPSearch;
-import org.opends.server.types.AuthenticationInfo;
-import org.opends.server.types.ByteString;
-import org.opends.server.types.DN;
-import org.opends.server.types.Entry;
-import org.opends.server.types.ResultCode;
-import org.opends.server.types.SearchScope;
-import org.opends.server.types.SearchFilter;
+import org.opends.server.types.*;
 
 import static org.testng.Assert.*;
 
@@ -105,7 +98,7 @@
     InternalClientConnection conn =
          InternalClientConnection.getRootConnection();
     InternalSearchOperation op =
-         conn.processSearch(new ASN1OctetString(""), SearchScope.BASE_OBJECT,
+         conn.processSearch(ByteString.empty(), SearchScope.BASE_OBJECT,
               LDAPFilter.decode("(supportedSASLMechanisms=PLAIN)"));
     assertFalse(op.getSearchEntries().isEmpty());
   }
@@ -125,15 +118,15 @@
   {
     return new Object[][]
     {
-      new Object[] { new ASN1OctetString("a") },
-      new Object[] { new ASN1OctetString("ab") },
-      new Object[] { new ASN1OctetString("abc") },
-      new Object[] { new ASN1OctetString("abcd") },
-      new Object[] { new ASN1OctetString("abcde") },
-      new Object[] { new ASN1OctetString("abcdef") },
-      new Object[] { new ASN1OctetString("abcdefg") },
-      new Object[] { new ASN1OctetString("abcdefgh") },
-      new Object[] { new ASN1OctetString("The Quick Brown Fox Jumps Over " +
+      new Object[] { ByteString.valueOf("a") },
+      new Object[] { ByteString.valueOf("ab") },
+      new Object[] { ByteString.valueOf("abc") },
+      new Object[] { ByteString.valueOf("abcd") },
+      new Object[] { ByteString.valueOf("abcde") },
+      new Object[] { ByteString.valueOf("abcdef") },
+      new Object[] { ByteString.valueOf("abcdefg") },
+      new Object[] { ByteString.valueOf("abcdefgh") },
+      new Object[] { ByteString.valueOf("The Quick Brown Fox Jumps Over " +
                                          "The Lazy Dog") },
     };
   }
@@ -165,7 +158,7 @@
                    "givenName: Test",
                    "sn: User",
                    "cn: Test User",
-                   "userPassword: " + password.stringValue());
+                   "userPassword: " + password.toString());
 
     InternalClientConnection conn =
          InternalClientConnection.getRootConnection();
@@ -175,15 +168,16 @@
     assertEquals(addOperation.getResultCode(), ResultCode.SUCCESS);
 
 
-    byte[] saslCredBytes = new byte[11 + password.value().length];
-    System.arraycopy("test.user".getBytes("UTF-8"), 0, saslCredBytes, 1, 9);
-    System.arraycopy(password.value(), 0, saslCredBytes, 11,
-                     password.value().length);
+    ByteStringBuilder saslCredBytes = new ByteStringBuilder();
+    saslCredBytes.append((byte)0);
+    saslCredBytes.append("test.user");
+    saslCredBytes.append((byte)0);
+    saslCredBytes.append(password);
     InternalClientConnection anonymousConn =
          new InternalClientConnection(new AuthenticationInfo());
     BindOperation bindOperation =
-         anonymousConn.processSASLBind(new ASN1OctetString(), "PLAIN",
-                                       new ASN1OctetString(saslCredBytes));
+         anonymousConn.processSASLBind(ByteString.empty(), "PLAIN",
+                                       saslCredBytes.toByteString());
     assertEquals(bindOperation.getResultCode(), ResultCode.SUCCESS);
   }
 
@@ -213,7 +207,7 @@
                    "givenName: Test",
                    "sn: User",
                    "cn: Test User",
-                   "userPassword: " + password.stringValue());
+                   "userPassword: " + password.toString());
 
     InternalClientConnection conn =
          InternalClientConnection.getRootConnection();
@@ -223,15 +217,16 @@
     assertEquals(addOperation.getResultCode(), ResultCode.SUCCESS);
 
 
-    byte[] saslCredBytes = new byte[13 + password.value().length];
-    System.arraycopy("u:test.user".getBytes("UTF-8"), 0, saslCredBytes, 1, 11);
-    System.arraycopy(password.value(), 0, saslCredBytes, 13,
-                     password.value().length);
+    ByteStringBuilder saslCredBytes = new ByteStringBuilder();
+    saslCredBytes.append((byte)0);
+    saslCredBytes.append("u:test.user");
+    saslCredBytes.append((byte)0);
+    saslCredBytes.append(password);
     InternalClientConnection anonymousConn =
          new InternalClientConnection(new AuthenticationInfo());
     BindOperation bindOperation =
-         anonymousConn.processSASLBind(new ASN1OctetString(), "PLAIN",
-                                       new ASN1OctetString(saslCredBytes));
+         anonymousConn.processSASLBind(ByteString.empty(), "PLAIN",
+                                       saslCredBytes.toByteString());
     assertEquals(bindOperation.getResultCode(), ResultCode.SUCCESS);
   }
 
@@ -262,7 +257,7 @@
                    "givenName: Test",
                    "sn: User",
                    "cn: Test User",
-                   "userPassword: " + password.stringValue());
+                   "userPassword: " + password.toString());
 
     InternalClientConnection conn =
          InternalClientConnection.getRootConnection();
@@ -272,16 +267,17 @@
     assertEquals(addOperation.getResultCode(), ResultCode.SUCCESS);
 
 
-    byte[] saslCredBytes = new byte[24 + password.value().length];
-    System.arraycopy("u:test.user".getBytes("UTF-8"), 0, saslCredBytes, 0, 11);
-    System.arraycopy("u:test.user".getBytes("UTF-8"), 0, saslCredBytes, 12, 11);
-    System.arraycopy(password.value(), 0, saslCredBytes, 24,
-                     password.value().length);
+    ByteStringBuilder saslCredBytes = new ByteStringBuilder();
+    saslCredBytes.append("u:test.user");
+    saslCredBytes.append((byte)0);
+    saslCredBytes.append("u:test.user");
+    saslCredBytes.append((byte)0);
+    saslCredBytes.append(password);
     InternalClientConnection anonymousConn =
          new InternalClientConnection(new AuthenticationInfo());
     BindOperation bindOperation =
-         anonymousConn.processSASLBind(new ASN1OctetString(), "PLAIN",
-                                       new ASN1OctetString(saslCredBytes));
+         anonymousConn.processSASLBind(ByteString.empty(), "PLAIN",
+                                       saslCredBytes.toByteString());
     assertEquals(bindOperation.getResultCode(), ResultCode.SUCCESS);
   }
 
@@ -311,7 +307,7 @@
                    "givenName: Test",
                    "sn: User",
                    "cn: Test User",
-                   "userPassword: " + password.stringValue());
+                   "userPassword: " + password.toString());
 
     InternalClientConnection conn =
          InternalClientConnection.getRootConnection();
@@ -321,18 +317,17 @@
     assertEquals(addOperation.getResultCode(), ResultCode.SUCCESS);
 
 
-    byte[] dnBytes = e.getDN().toString().getBytes("UTF-8");
-    byte[] saslCredBytes =
-         new byte[5 + dnBytes.length + password.value().length];
-    System.arraycopy("dn:".getBytes("UTF-8"), 0, saslCredBytes, 1, 3);
-    System.arraycopy(dnBytes, 0, saslCredBytes, 4, dnBytes.length);
-    System.arraycopy(password.value(), 0, saslCredBytes, 5 + dnBytes.length,
-                     password.value().length);
+    ByteStringBuilder saslCredBytes = new ByteStringBuilder();
+    saslCredBytes.append((byte)0);
+    saslCredBytes.append("dn:");
+    saslCredBytes.append(e.getDN().toString());
+    saslCredBytes.append((byte)0);
+    saslCredBytes.append(password);
     InternalClientConnection anonymousConn =
          new InternalClientConnection(new AuthenticationInfo());
     BindOperation bindOperation =
-         anonymousConn.processSASLBind(new ASN1OctetString(), "PLAIN",
-                                       new ASN1OctetString(saslCredBytes));
+         anonymousConn.processSASLBind(ByteString.empty(), "PLAIN",
+                                       saslCredBytes.toByteString());
     assertEquals(bindOperation.getResultCode(), ResultCode.SUCCESS);
   }
 
@@ -363,7 +358,7 @@
                    "givenName: Test",
                    "sn: User",
                    "cn: Test User",
-                   "userPassword: " + password.stringValue());
+                   "userPassword: " + password.toString());
 
     InternalClientConnection conn =
          InternalClientConnection.getRootConnection();
@@ -373,19 +368,19 @@
     assertEquals(addOperation.getResultCode(), ResultCode.SUCCESS);
 
 
-    byte[] dnBytes = ("dn:" + e.getDN().toString()).getBytes("UTF-8");
-    byte[] saslCredBytes =
-         new byte[2 + (2*dnBytes.length) + password.value().length];
-    System.arraycopy(dnBytes, 0, saslCredBytes, 0, dnBytes.length);
-    System.arraycopy(dnBytes, 0, saslCredBytes, dnBytes.length+1,
-                     dnBytes.length);
-    System.arraycopy(password.value(), 0, saslCredBytes,
-                     (2*dnBytes.length + 2), password.value().length);
+    ByteStringBuilder saslCredBytes = new ByteStringBuilder();
+    saslCredBytes.append("dn:");
+    saslCredBytes.append(e.getDN().toString());
+    saslCredBytes.append((byte)0);
+    saslCredBytes.append("dn:");
+    saslCredBytes.append(e.getDN().toString());
+    saslCredBytes.append((byte)0);
+    saslCredBytes.append(password);
     InternalClientConnection anonymousConn =
          new InternalClientConnection(new AuthenticationInfo());
     BindOperation bindOperation =
-         anonymousConn.processSASLBind(new ASN1OctetString(), "PLAIN",
-                                       new ASN1OctetString(saslCredBytes));
+         anonymousConn.processSASLBind(ByteString.empty(), "PLAIN",
+                                       saslCredBytes.toByteString());
     assertEquals(bindOperation.getResultCode(), ResultCode.SUCCESS);
   }
 
@@ -400,13 +395,13 @@
   public void testSASLPlainAsRoot()
          throws Exception
   {
-    ASN1OctetString rootCreds =
-         new ASN1OctetString("\u0000dn:cn=Directory Manager\u0000password");
+    ByteString rootCreds =
+         ByteString.valueOf("\u0000dn:cn=Directory Manager\u0000password");
 
     InternalClientConnection anonymousConn =
          new InternalClientConnection(new AuthenticationInfo());
     BindOperation bindOperation =
-         anonymousConn.processSASLBind(new ASN1OctetString(), "PLAIN",
+         anonymousConn.processSASLBind(ByteString.empty(), "PLAIN",
                                     rootCreds);
     assertEquals(bindOperation.getResultCode(), ResultCode.SUCCESS);
   }
@@ -455,21 +450,21 @@
     return new Object[][]
     {
       new Object[] { null },
-      new Object[] { new ASN1OctetString() },
-      new Object[] { new ASN1OctetString("u:test.user") },
-      new Object[] { new ASN1OctetString("password") },
-      new Object[] { new ASN1OctetString("\u0000") },
-      new Object[] { new ASN1OctetString("\u0000\u0000") },
-      new Object[] { new ASN1OctetString("\u0000password") },
-      new Object[] { new ASN1OctetString("\u0000\u0000password") },
-      new Object[] { new ASN1OctetString("\u0000u:test.user\u0000") },
-      new Object[] { new ASN1OctetString("\u0000dn:\u0000password") },
-      new Object[] { new ASN1OctetString("\u0000dn:bogus\u0000password") },
-      new Object[] { new ASN1OctetString("\u0000dn:cn=no such user" +
+      new Object[] { ByteString.empty() },
+      new Object[] { ByteString.valueOf("u:test.user") },
+      new Object[] { ByteString.valueOf("password") },
+      new Object[] { ByteString.valueOf("\u0000") },
+      new Object[] { ByteString.valueOf("\u0000\u0000") },
+      new Object[] { ByteString.valueOf("\u0000password") },
+      new Object[] { ByteString.valueOf("\u0000\u0000password") },
+      new Object[] { ByteString.valueOf("\u0000u:test.user\u0000") },
+      new Object[] { ByteString.valueOf("\u0000dn:\u0000password") },
+      new Object[] { ByteString.valueOf("\u0000dn:bogus\u0000password") },
+      new Object[] { ByteString.valueOf("\u0000dn:cn=no such user" +
                                          "\u0000password") },
-      new Object[] { new ASN1OctetString("\u0000u:\u0000password") },
-      new Object[] { new ASN1OctetString("\u0000u:nosuchuser\u0000password") },
-      new Object[] { new ASN1OctetString("\u0000u:test.user\u0000" +
+      new Object[] { ByteString.valueOf("\u0000u:\u0000password") },
+      new Object[] { ByteString.valueOf("\u0000u:nosuchuser\u0000password") },
+      new Object[] { ByteString.valueOf("\u0000u:test.user\u0000" +
                                          "wrongpassword") },
     };
   }
@@ -485,7 +480,7 @@
    * @throws  Exception  If an unexpected problem occurs.
    */
   @Test(dataProvider = "invalidCredentials")
-  public void testInvalidCredentials(ASN1OctetString saslCredentials)
+  public void testInvalidCredentials(ByteString saslCredentials)
          throws Exception
   {
     TestCaseUtils.initializeTestBackend(true);
@@ -513,7 +508,7 @@
     InternalClientConnection anonymousConn =
          new InternalClientConnection(new AuthenticationInfo());
     BindOperation bindOperation =
-         anonymousConn.processSASLBind(new ASN1OctetString(), "PLAIN",
+         anonymousConn.processSASLBind(ByteString.empty(), "PLAIN",
                                        saslCredentials);
     assertEquals(bindOperation.getResultCode(), ResultCode.INVALID_CREDENTIALS);
   }
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/RepeatedCharactersPasswordValidatorTestCase.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/RepeatedCharactersPasswordValidatorTestCase.java
index 10d9c15..1b0259b 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/RepeatedCharactersPasswordValidatorTestCase.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/RepeatedCharactersPasswordValidatorTestCase.java
@@ -46,7 +46,6 @@
 import org.opends.server.admin.server.AdminTestCaseUtils;
 import org.opends.server.config.ConfigException;
 import org.opends.server.core.ModifyOperationBasis;
-import org.opends.server.protocols.asn1.ASN1OctetString;
 import org.opends.server.protocols.internal.InternalClientConnection;
 import org.opends.server.types.Attributes;
 import org.opends.server.types.ByteString;
@@ -309,7 +308,7 @@
          new RepeatedCharactersPasswordValidator();
     validator.initializePasswordValidator(configuration);
 
-    ASN1OctetString password = new ASN1OctetString("password");
+    ByteString password = ByteString.valueOf("password");
     ArrayList<Modification> mods = new ArrayList<Modification>();
     mods.add(new Modification(ModificationType.REPLACE,
         Attributes.create("userpassword", "password")));
@@ -378,7 +377,7 @@
          new RepeatedCharactersPasswordValidator();
     validator.initializePasswordValidator(configuration);
 
-    ASN1OctetString password = new ASN1OctetString("passsword");
+    ByteString password = ByteString.valueOf("passsword");
     ArrayList<Modification> mods = new ArrayList<Modification>();
     mods.add(new Modification(ModificationType.REPLACE,
         Attributes.create("userpassword", "passsword")));
@@ -446,7 +445,7 @@
          new RepeatedCharactersPasswordValidator();
     validator.initializePasswordValidator(configuration);
 
-    ASN1OctetString password = new ASN1OctetString("passSword");
+    ByteString password = ByteString.valueOf("passSword");
     ArrayList<Modification> mods = new ArrayList<Modification>();
     mods.add(new Modification(ModificationType.REPLACE,
         Attributes.create("userpassword", "passSword")));
@@ -515,7 +514,7 @@
          new RepeatedCharactersPasswordValidator();
     validator.initializePasswordValidator(configuration);
 
-    ASN1OctetString password = new ASN1OctetString("passSword");
+    ByteString password = ByteString.valueOf("passSword");
     ArrayList<Modification> mods = new ArrayList<Modification>();
     mods.add(new Modification(ModificationType.REPLACE,
         Attributes.create("userpassword", "passSword")));
@@ -582,7 +581,7 @@
          new RepeatedCharactersPasswordValidator();
     validator.initializePasswordValidator(configuration);
 
-    ASN1OctetString password = new ASN1OctetString("aaaaaaaa");
+    ByteString password = ByteString.valueOf("aaaaaaaa");
     ArrayList<Modification> mods = new ArrayList<Modification>();
     mods.add(new Modification(ModificationType.REPLACE,
         Attributes.create("userpassword", "aaaaaaaa")));
@@ -650,7 +649,7 @@
          new RepeatedCharactersPasswordValidator();
     validator.initializePasswordValidator(configuration);
 
-    ASN1OctetString password = new ASN1OctetString("aaaaaaaa");
+    ByteString password = ByteString.valueOf("aaaaaaaa");
     ArrayList<Modification> mods = new ArrayList<Modification>();
     mods.add(new Modification(ModificationType.REPLACE,
         Attributes.create("userpassword", "aaaaaaaa")));
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/SaltedSHA1PasswordStorageSchemeTestCase.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/SaltedSHA1PasswordStorageSchemeTestCase.java
index b5a75a4..96b5ac6 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/SaltedSHA1PasswordStorageSchemeTestCase.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/SaltedSHA1PasswordStorageSchemeTestCase.java
@@ -34,7 +34,6 @@
 import org.opends.server.admin.std.meta.SaltedSHA1PasswordStorageSchemeCfgDefn;
 import org.opends.server.admin.std.server.SaltedSHA1PasswordStorageSchemeCfg;
 import org.opends.server.api.PasswordStorageScheme;
-import org.opends.server.protocols.asn1.ASN1OctetString;
 import org.opends.server.schema.UserPasswordSyntax;
 import org.opends.server.types.ByteString;
 
@@ -105,9 +104,9 @@
 
     scheme.initializePasswordStorageScheme(configuration);
 
-    String passwordString = scheme.encodeOffline(plaintext.value());
+    String passwordString = scheme.encodeOffline(plaintext.toByteArray());
     String[] pwComps = UserPasswordSyntax.decodeUserPassword(passwordString);
-    ASN1OctetString encodedPassword = new ASN1OctetString(pwComps[1]);
+    ByteString encodedPassword = ByteString.valueOf(pwComps[1]);
 
     assertTrue(scheme.passwordMatches(plaintext, encodedPassword));
   }
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/SimilarityBasedPasswordValidatorTestCase.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/SimilarityBasedPasswordValidatorTestCase.java
index 935d7ae..672ff57 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/SimilarityBasedPasswordValidatorTestCase.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/SimilarityBasedPasswordValidatorTestCase.java
@@ -38,11 +38,9 @@
 import org.opends.messages.MessageBuilder;
 import org.opends.server.config.ConfigException;
 import org.opends.server.core.ModifyOperationBasis;
-import org.opends.server.protocols.asn1.ASN1OctetString;
 import org.opends.server.protocols.internal.InternalClientConnection;
 import org.opends.server.types.Attributes;
 import org.opends.server.types.ByteString;
-import org.opends.server.types.ByteStringFactory;
 import org.opends.server.types.Control;
 import org.opends.server.types.DN;
 import org.opends.server.types.Entry;
@@ -283,7 +281,7 @@
     for (int i=0; i < 20; i++)
     {
       buffer.append('x');
-      ASN1OctetString password = new ASN1OctetString(buffer.toString());
+      ByteString password = ByteString.valueOf(buffer.toString());
 
       ArrayList<Modification> mods = new ArrayList<Modification>();
       mods.add(new Modification(ModificationType.REPLACE,
@@ -355,11 +353,11 @@
 
     StringBuilder buffer = new StringBuilder();
     HashSet<ByteString> currentPassword = new HashSet<ByteString>(3);
-    currentPassword.add(ByteStringFactory.create("xxx"));
+    currentPassword.add(ByteString.valueOf("xxx"));
     for (int i=0; i < 7; i++)
     {
       buffer.append('x');
-      ASN1OctetString password = new ASN1OctetString(buffer.toString());
+      ByteString password = ByteString.valueOf(buffer.toString());
 
       ArrayList<Modification> mods = new ArrayList<Modification>();
       mods.add(new Modification(ModificationType.REPLACE,
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/SubschemaSubentryVirtualAttributeProviderTestCase.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/SubschemaSubentryVirtualAttributeProviderTestCase.java
index 518524b..7e3383a 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/SubschemaSubentryVirtualAttributeProviderTestCase.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/SubschemaSubentryVirtualAttributeProviderTestCase.java
@@ -28,35 +28,35 @@
 
 
 
+import static org.opends.server.util.ServerConstants.*;
+import static org.testng.Assert.*;
+
 import java.util.Collections;
 import java.util.LinkedHashSet;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Set;
 
-import org.testng.annotations.BeforeClass;
-import org.testng.annotations.DataProvider;
-import org.testng.annotations.Test;
-
 import org.opends.server.TestCaseUtils;
 import org.opends.server.admin.std.meta.VirtualAttributeCfgDefn;
 import org.opends.server.core.DirectoryServer;
 import org.opends.server.protocols.internal.InternalClientConnection;
 import org.opends.server.protocols.internal.InternalSearchOperation;
+import org.opends.server.protocols.ldap.LDAPControl;
 import org.opends.server.types.Attribute;
 import org.opends.server.types.AttributeType;
 import org.opends.server.types.AttributeValue;
+import org.opends.server.types.AttributeValues;
 import org.opends.server.types.Control;
-import org.opends.server.types.DereferencePolicy;
 import org.opends.server.types.DN;
+import org.opends.server.types.DereferencePolicy;
 import org.opends.server.types.Entry;
 import org.opends.server.types.SearchFilter;
 import org.opends.server.types.SearchScope;
 import org.opends.server.types.VirtualAttributeRule;
-
-import static org.testng.Assert.*;
-
-import static org.opends.server.util.ServerConstants.*;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
 
 
 
@@ -144,7 +144,7 @@
     {
       assertTrue(!a.isEmpty());
       assertEquals(a.size(), 1);
-      assertTrue(a.contains(new AttributeValue(subschemaSubentryType,
+      assertTrue(a.contains(AttributeValues.create(subschemaSubentryType,
                                                "cn=schema")));
     }
   }
@@ -455,16 +455,17 @@
     attrList.add("subschemaSubentry");
 
     LinkedList<Control> requestControls = new LinkedList<Control>();
-    requestControls.add(new Control(OID_REAL_ATTRS_ONLY, true));
+    requestControls.add(new LDAPControl(OID_REAL_ATTRS_ONLY, true));
 
     InternalClientConnection conn =
          InternalClientConnection.getRootConnection();
     InternalSearchOperation searchOperation =
-         new InternalSearchOperation(conn, conn.nextOperationID(),
-                                     conn.nextMessageID(), requestControls,
-                                     entryDN, SearchScope.BASE_OBJECT,
-                                     DereferencePolicy.NEVER_DEREF_ALIASES, 0,
-                                     0, false, filter, attrList, null);
+        new InternalSearchOperation(conn, InternalClientConnection
+            .nextOperationID(), InternalClientConnection
+            .nextMessageID(), requestControls, entryDN,
+            SearchScope.BASE_OBJECT,
+            DereferencePolicy.NEVER_DEREF_ALIASES, 0, 0, false, filter,
+            attrList, null);
     searchOperation.run();
     assertEquals(searchOperation.getSearchEntries().size(), 1);
 
@@ -498,16 +499,17 @@
     attrList.add("subschemaSubentry");
 
     LinkedList<Control> requestControls = new LinkedList<Control>();
-    requestControls.add(new Control(OID_VIRTUAL_ATTRS_ONLY, true));
+    requestControls.add(new LDAPControl(OID_VIRTUAL_ATTRS_ONLY, true));
 
     InternalClientConnection conn =
-         InternalClientConnection.getRootConnection();
+        InternalClientConnection.getRootConnection();
     InternalSearchOperation searchOperation =
-         new InternalSearchOperation(conn, conn.nextOperationID(),
-                                     conn.nextMessageID(), requestControls,
-                                     entryDN, SearchScope.BASE_OBJECT,
-                                     DereferencePolicy.NEVER_DEREF_ALIASES, 0,
-                                     0, false, filter, attrList, null);
+        new InternalSearchOperation(conn, InternalClientConnection
+            .nextOperationID(), InternalClientConnection
+            .nextMessageID(), requestControls, entryDN,
+            SearchScope.BASE_OBJECT,
+            DereferencePolicy.NEVER_DEREF_ALIASES, 0, 0, false, filter,
+            attrList, null);
     searchOperation.run();
     assertEquals(searchOperation.getSearchEntries().size(), 1);
 
@@ -560,7 +562,7 @@
     Set<AttributeValue> values = provider.getValues(entry, rule);
     assertNotNull(values);
     assertEquals(values.size(), 1);
-    assertTrue(values.contains(new AttributeValue(subschemaSubentryType,
+    assertTrue(values.contains(AttributeValues.create(subschemaSubentryType,
                                                   "cn=schema")));
   }
 
@@ -626,7 +628,7 @@
                        VIRTUAL_OVERRIDES_REAL);
 
     assertTrue(provider.hasValue(entry, rule,
-                                 new AttributeValue(subschemaSubentryType,
+        AttributeValues.create(subschemaSubentryType,
                                                     "cn=schema")));
   }
 
@@ -660,7 +662,7 @@
                        VIRTUAL_OVERRIDES_REAL);
 
     assertFalse(provider.hasValue(entry, rule,
-                     new AttributeValue(subschemaSubentryType,
+        AttributeValues.create(subschemaSubentryType,
                                         "cn=not schema")));
   }
 
@@ -726,7 +728,7 @@
                        VIRTUAL_OVERRIDES_REAL);
 
     LinkedHashSet<AttributeValue> values = new LinkedHashSet<AttributeValue>(1);
-    values.add(new AttributeValue(subschemaSubentryType, "cn=schema"));
+    values.add(AttributeValues.create(subschemaSubentryType, "cn=schema"));
 
     assertTrue(provider.hasAnyValue(entry, rule, values));
   }
@@ -761,7 +763,7 @@
                        VIRTUAL_OVERRIDES_REAL);
 
     LinkedHashSet<AttributeValue> values = new LinkedHashSet<AttributeValue>(1);
-    values.add(new AttributeValue(subschemaSubentryType, "cn=not schema"));
+    values.add(AttributeValues.create(subschemaSubentryType, "cn=not schema"));
 
     assertFalse(provider.hasAnyValue(entry, rule, values));
   }
@@ -796,9 +798,9 @@
                        VIRTUAL_OVERRIDES_REAL);
 
     LinkedHashSet<AttributeValue> values = new LinkedHashSet<AttributeValue>(3);
-    values.add(new AttributeValue(subschemaSubentryType, "cn=schema"));
-    values.add(new AttributeValue(subschemaSubentryType, "cn=not schema"));
-    values.add(new AttributeValue(subschemaSubentryType,
+    values.add(AttributeValues.create(subschemaSubentryType, "cn=schema"));
+    values.add(AttributeValues.create(subschemaSubentryType, "cn=not schema"));
+    values.add(AttributeValues.create(subschemaSubentryType,
                                   "cn=not schema either"));
 
     assertTrue(provider.hasAnyValue(entry, rule, values));
@@ -834,10 +836,10 @@
                        VIRTUAL_OVERRIDES_REAL);
 
     LinkedHashSet<AttributeValue> values = new LinkedHashSet<AttributeValue>(3);
-    values.add(new AttributeValue(subschemaSubentryType, "cn=not schema"));
-    values.add(new AttributeValue(subschemaSubentryType,
+    values.add(AttributeValues.create(subschemaSubentryType, "cn=not schema"));
+    values.add(AttributeValues.create(subschemaSubentryType,
                                   "cn=not schema either"));
-    values.add(new AttributeValue(subschemaSubentryType,
+    values.add(AttributeValues.create(subschemaSubentryType,
                                   "cn=still not schema"));
 
     assertFalse(provider.hasAnyValue(entry, rule, values));
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/TestPasswordValidator.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/TestPasswordValidator.java
index 80d371f..a084d01 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/TestPasswordValidator.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/TestPasswordValidator.java
@@ -32,13 +32,8 @@
 
 import org.opends.server.admin.std.server.PasswordValidatorCfg;
 import org.opends.server.api.PasswordValidator;
-import org.opends.server.config.ConfigEntry;
-import org.opends.server.types.ByteString;
-import org.opends.server.types.Entry;
-import org.opends.server.types.InitializationException;
-import org.opends.server.types.Operation;
+import org.opends.server.types.*;
 import org.opends.messages.MessageBuilder;
-import org.opends.messages.Message;
 
 
 /**
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/UniqueCharactersPasswordValidatorTestCase.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/UniqueCharactersPasswordValidatorTestCase.java
index 231446e..fe95691 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/UniqueCharactersPasswordValidatorTestCase.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/UniqueCharactersPasswordValidatorTestCase.java
@@ -46,7 +46,6 @@
 import org.opends.server.admin.server.AdminTestCaseUtils;
 import org.opends.server.config.ConfigException;
 import org.opends.server.core.ModifyOperationBasis;
-import org.opends.server.protocols.asn1.ASN1OctetString;
 import org.opends.server.protocols.internal.InternalClientConnection;
 import org.opends.server.types.Attributes;
 import org.opends.server.types.ByteString;
@@ -309,7 +308,7 @@
          new UniqueCharactersPasswordValidator();
     validator.initializePasswordValidator(configuration);
 
-    ASN1OctetString password = new ASN1OctetString("password");
+    ByteString password = ByteString.valueOf("password");
     ArrayList<Modification> mods = new ArrayList<Modification>();
     mods.add(new Modification(ModificationType.REPLACE,
         Attributes.create("userpassword", "password")));
@@ -378,7 +377,7 @@
          new UniqueCharactersPasswordValidator();
     validator.initializePasswordValidator(configuration);
 
-    ASN1OctetString password = new ASN1OctetString("passw");
+    ByteString password = ByteString.valueOf("passw");
     ArrayList<Modification> mods = new ArrayList<Modification>();
     mods.add(new Modification(ModificationType.REPLACE,
         Attributes.create("userpassword", "passw")));
@@ -446,7 +445,7 @@
          new UniqueCharactersPasswordValidator();
     validator.initializePasswordValidator(configuration);
 
-    ASN1OctetString password = new ASN1OctetString("pasSw");
+    ByteString password = ByteString.valueOf("pasSw");
     ArrayList<Modification> mods = new ArrayList<Modification>();
     mods.add(new Modification(ModificationType.REPLACE,
         Attributes.create("userpassword", "pasSw")));
@@ -515,7 +514,7 @@
          new UniqueCharactersPasswordValidator();
     validator.initializePasswordValidator(configuration);
 
-    ASN1OctetString password = new ASN1OctetString("pasSw");
+    ByteString password = ByteString.valueOf("pasSw");
     ArrayList<Modification> mods = new ArrayList<Modification>();
     mods.add(new Modification(ModificationType.REPLACE,
         Attributes.create("userpassword", "pasSw")));
@@ -582,7 +581,7 @@
          new UniqueCharactersPasswordValidator();
     validator.initializePasswordValidator(configuration);
 
-    ASN1OctetString password = new ASN1OctetString("aaaaaaaa");
+    ByteString password = ByteString.valueOf("aaaaaaaa");
     ArrayList<Modification> mods = new ArrayList<Modification>();
     mods.add(new Modification(ModificationType.REPLACE,
         Attributes.create("userpassword", "aaaaaaaa")));
@@ -650,7 +649,7 @@
          new UniqueCharactersPasswordValidator();
     validator.initializePasswordValidator(configuration);
 
-    ASN1OctetString password = new ASN1OctetString("aaaaaaaa");
+    ByteString password = ByteString.valueOf("aaaaaaaa");
     ArrayList<Modification> mods = new ArrayList<Modification>();
     mods.add(new Modification(ModificationType.REPLACE,
         Attributes.create("userpassword", "aaaaaaaa")));
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/UserDefinedVirtualAttributeProviderTestCase.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/UserDefinedVirtualAttributeProviderTestCase.java
index c9c85bb..7ea4ccf 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/UserDefinedVirtualAttributeProviderTestCase.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/UserDefinedVirtualAttributeProviderTestCase.java
@@ -40,15 +40,7 @@
 import org.opends.server.protocols.internal.InternalClientConnection;
 import org.opends.server.protocols.internal.InternalSearchOperation;
 import org.opends.server.tools.LDAPModify;
-import org.opends.server.types.Attribute;
-import org.opends.server.types.AttributeType;
-import org.opends.server.types.AttributeValue;
-import org.opends.server.types.DereferencePolicy;
-import org.opends.server.types.DN;
-import org.opends.server.types.SearchFilter;
-import org.opends.server.types.SearchScope;
-import org.opends.server.types.ResultCode;
-import org.opends.server.types.VirtualAttributeRule;
+import org.opends.server.types.*;
 
 import static org.testng.Assert.*;
 
@@ -272,7 +264,7 @@
 
     Attribute attr = attrList.get(0);
     assertEquals(attr.size(), 1);
-    assertTrue(attr.contains(new AttributeValue(descriptionType, value)));
+    assertTrue(attr.contains(AttributeValues.create(descriptionType, value)));
 
     DeleteOperation deleteOperation = conn.processDelete(DN.decode(ruleDN));
     assertEquals(deleteOperation.getResultCode(), ResultCode.SUCCESS);
@@ -336,8 +328,8 @@
 
     Attribute attr = attrList.get(0);
     assertEquals(attr.size(), 2);
-    assertTrue(attr.contains(new AttributeValue(descriptionType, value1)));
-    assertTrue(attr.contains(new AttributeValue(descriptionType, value2)));
+    assertTrue(attr.contains(AttributeValues.create(descriptionType, value1)));
+    assertTrue(attr.contains(AttributeValues.create(descriptionType, value2)));
 
     DeleteOperation deleteOperation = conn.processDelete(DN.decode(ruleDN));
     assertEquals(deleteOperation.getResultCode(), ResultCode.SUCCESS);
@@ -401,7 +393,7 @@
 
     Attribute attr = attrList.get(0);
     assertEquals(attr.size(), 1);
-    assertTrue(attr.contains(new AttributeValue(descriptionType, realValue)));
+    assertTrue(attr.contains(AttributeValues.create(descriptionType, realValue)));
 
     DeleteOperation deleteOperation = conn.processDelete(DN.decode(ruleDN));
     assertEquals(deleteOperation.getResultCode(), ResultCode.SUCCESS);
@@ -465,7 +457,7 @@
 
     Attribute attr = attrList.get(0);
     assertEquals(attr.size(), 1);
-    assertTrue(attr.contains(new AttributeValue(descriptionType,
+    assertTrue(attr.contains(AttributeValues.create(descriptionType,
                                                 virtualValue)));
 
     DeleteOperation deleteOperation = conn.processDelete(DN.decode(ruleDN));
@@ -537,9 +529,9 @@
       }
     }
 
-    assertTrue(allValues.contains(new AttributeValue(descriptionType,
+    assertTrue(allValues.contains(AttributeValues.create(descriptionType,
                                                      realValue)));
-    assertTrue(allValues.contains(new AttributeValue(descriptionType,
+    assertTrue(allValues.contains(AttributeValues.create(descriptionType,
                                                      virtualValue)));
 
     DeleteOperation deleteOperation = conn.processDelete(DN.decode(ruleDN));
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/VirtualStaticGroupTestCase.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/VirtualStaticGroupTestCase.java
index 704d06d..b0824e0 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/VirtualStaticGroupTestCase.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/VirtualStaticGroupTestCase.java
@@ -44,22 +44,7 @@
 import org.opends.server.core.ModifyOperation;
 import org.opends.server.protocols.internal.InternalClientConnection;
 import org.opends.server.protocols.internal.InternalSearchOperation;
-import org.opends.server.types.Attribute;
-import org.opends.server.types.AttributeType;
-import org.opends.server.types.AttributeValue;
-import org.opends.server.types.Attributes;
-import org.opends.server.types.ConditionResult;
-import org.opends.server.types.DereferencePolicy;
-import org.opends.server.types.DirectoryException;
-import org.opends.server.types.DN;
-import org.opends.server.types.Entry;
-import org.opends.server.types.MemberList;
-import org.opends.server.types.Modification;
-import org.opends.server.types.ModificationType;
-import org.opends.server.types.ResultCode;
-import org.opends.server.types.SearchScope;
-import org.opends.server.types.SearchFilter;
-import org.opends.server.types.VirtualAttributeRule;
+import org.opends.server.types.*;
 
 import static org.testng.Assert.*;
 
@@ -664,9 +649,9 @@
     assertFalse(values.isEmpty());
     assertTrue(provider.hasValue(entry, rule));
     assertTrue(provider.hasValue(entry, rule,
-                    new AttributeValue(memberType, u1.toString())));
+        AttributeValues.create(memberType, u1.toString())));
     assertFalse(provider.hasValue(entry, rule,
-                    new AttributeValue(memberType, ne.toString())));
+        AttributeValues.create(memberType, ne.toString())));
     assertTrue(provider.hasAnyValue(entry, rule, values));
     assertFalse(provider.hasAnyValue(entry, rule,
                                      Collections.<AttributeValue>emptySet()));
@@ -743,9 +728,9 @@
     assertTrue(values.isEmpty());
     assertFalse(provider.hasValue(entry, rule));
     assertFalse(provider.hasValue(entry, rule,
-                    new AttributeValue(memberType, u1.toString())));
+        AttributeValues.create(memberType, u1.toString())));
     assertFalse(provider.hasValue(entry, rule,
-                    new AttributeValue(memberType, ne.toString())));
+        AttributeValues.create(memberType, ne.toString())));
     assertFalse(provider.hasAnyValue(entry, rule, values));
     assertFalse(provider.hasAnyValue(entry, rule,
                                      Collections.<AttributeValue>emptySet()));
@@ -797,7 +782,7 @@
     Attribute a = e.getAttribute(memberType).get(0);
     assertEquals(a.size(), 4);
 
-    AttributeValue v = new AttributeValue(memberType, u1.toString());
+    AttributeValue v = AttributeValues.create(memberType, u1.toString());
     assertTrue(a.contains(v));
 
     cleanUp();
@@ -827,7 +812,7 @@
     Attribute a = e.getAttribute(memberType).get(0);
     assertEquals(a.size(), 1);
 
-    AttributeValue v = new AttributeValue(memberType, u4.toString());
+    AttributeValue v = AttributeValues.create(memberType, u4.toString());
     assertTrue(a.contains(v));
 
     InternalClientConnection conn =
@@ -869,7 +854,7 @@
     Attribute a = e.getAttribute(memberType).get(0);
     assertEquals(a.size(), 1);
 
-    AttributeValue v = new AttributeValue(memberType, u4.toString());
+    AttributeValue v = AttributeValues.create(memberType, u4.toString());
     assertTrue(a.contains(v));
 
 
@@ -892,7 +877,7 @@
     a = e.getAttribute(memberType).get(0);
     assertEquals(a.size(), 0);
 
-    v = new AttributeValue(memberType, u4.toString());
+    v = AttributeValues.create(memberType, u4.toString());
     assertTrue(a.contains(v));
 
 
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/WhoAmIExtendedOperationTestCase.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/WhoAmIExtendedOperationTestCase.java
index 971ea30..8ecc556 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/WhoAmIExtendedOperationTestCase.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/WhoAmIExtendedOperationTestCase.java
@@ -42,7 +42,6 @@
 import org.opends.server.core.AddOperation;
 import org.opends.server.core.DirectoryServer;
 import org.opends.server.core.ExtendedOperation;
-import org.opends.server.protocols.asn1.ASN1OctetString;
 import org.opends.server.protocols.internal.InternalClientConnection;
 import org.opends.server.protocols.ldap.ExtendedRequestProtocolOp;
 import org.opends.server.protocols.ldap.ExtendedResponseProtocolOp;
@@ -53,10 +52,7 @@
 import org.opends.server.tools.LDAPAuthenticationHandler;
 import org.opends.server.tools.LDAPReader;
 import org.opends.server.tools.LDAPWriter;
-import org.opends.server.types.AuthenticationInfo;
-import org.opends.server.types.DN;
-import org.opends.server.types.Entry;
-import org.opends.server.types.ResultCode;
+import org.opends.server.types.*;
 
 import static org.testng.Assert.*;
 
@@ -179,11 +175,11 @@
     LDAPAuthenticationHandler authHandler =
          new LDAPAuthenticationHandler(reader, writer, "localhost",
                                        nextMessageID);
-    authHandler.doSimpleBind(3, new ASN1OctetString("cn=Directory Manager"),
-                             new ASN1OctetString("password"),
-                             new ArrayList<LDAPControl>(),
-                             new ArrayList<LDAPControl>());
-    ASN1OctetString authzID = authHandler.requestAuthorizationIdentity();
+    authHandler.doSimpleBind(3, ByteString.valueOf("cn=Directory Manager"),
+                             ByteString.valueOf("password"),
+                             new ArrayList<Control>(),
+                             new ArrayList<Control>());
+    ByteString authzID = authHandler.requestAuthorizationIdentity();
     assertNotNull(authzID);
 
     LDAPMessage unbindMessage = new LDAPMessage(nextMessageID.getAndIncrement(),
@@ -212,7 +208,7 @@
     LDAPAuthenticationHandler authHandler =
          new LDAPAuthenticationHandler(reader, writer, "localhost",
                                        nextMessageID);
-    ASN1OctetString authzID = authHandler.requestAuthorizationIdentity();
+    ByteString authzID = authHandler.requestAuthorizationIdentity();
     assertNull(authzID);
 
     LDAPMessage unbindMessage = new LDAPMessage(nextMessageID.getAndIncrement(),
@@ -263,11 +259,11 @@
     LDAPAuthenticationHandler authHandler =
          new LDAPAuthenticationHandler(reader, writer, "localhost",
                                        nextMessageID);
-    authHandler.doSimpleBind(3, new ASN1OctetString("uid=test.user,o=test"),
-                             new ASN1OctetString("password"),
-                             new ArrayList<LDAPControl>(),
-                             new ArrayList<LDAPControl>());
-    ASN1OctetString authzID = authHandler.requestAuthorizationIdentity();
+    authHandler.doSimpleBind(3, ByteString.valueOf("uid=test.user,o=test"),
+                             ByteString.valueOf("password"),
+                             new ArrayList<Control>(),
+                             new ArrayList<Control>());
+    ByteString authzID = authHandler.requestAuthorizationIdentity();
     assertNotNull(authzID);
 
     LDAPMessage unbindMessage = new LDAPMessage(nextMessageID.getAndIncrement(),
@@ -340,11 +336,11 @@
     authzIDList.add("dn:uid=test.user,o=test");
     saslProperties.put("authzID", authzIDList);
 
-    authHandler.doSASLPlain(new ASN1OctetString(),
-                            new ASN1OctetString("password"), saslProperties,
-                            new ArrayList<LDAPControl>(),
-                            new ArrayList<LDAPControl>());
-    ASN1OctetString authzID = authHandler.requestAuthorizationIdentity();
+    authHandler.doSASLPlain(ByteString.empty(),
+                            ByteString.valueOf("password"), saslProperties,
+                            new ArrayList<Control>(),
+                            new ArrayList<Control>());
+    ByteString authzID = authHandler.requestAuthorizationIdentity();
     assertNotNull(authzID);
     assertEquals(authzID.toString(), "dn:uid=test.user,o=test");
 
@@ -407,11 +403,11 @@
     LDAPAuthenticationHandler authHandler =
          new LDAPAuthenticationHandler(reader, writer, "localhost",
                                        nextMessageID);
-    authHandler.doSimpleBind(3, new ASN1OctetString("uid=proxy.user,o=test"),
-                             new ASN1OctetString("password"),
-                             new ArrayList<LDAPControl>(),
-                             new ArrayList<LDAPControl>());
-    ASN1OctetString authzID = authHandler.requestAuthorizationIdentity();
+    authHandler.doSimpleBind(3, ByteString.valueOf("uid=proxy.user,o=test"),
+                             ByteString.valueOf("password"),
+                             new ArrayList<Control>(),
+                             new ArrayList<Control>());
+    ByteString authzID = authHandler.requestAuthorizationIdentity();
     assertNotNull(authzID);
     assertEquals(authzID.toString(), "dn:uid=proxy.user,o=test");
 
@@ -419,9 +415,9 @@
     // Use the "Who Am I?" operation again, this time with the proxy control.
     ExtendedRequestProtocolOp extendedRequest =
          new ExtendedRequestProtocolOp(OID_WHO_AM_I_REQUEST);
-    ArrayList<LDAPControl> requestControls = new ArrayList<LDAPControl>(1);
-    requestControls.add(new LDAPControl(new ProxiedAuthV2Control(
-         new ASN1OctetString("dn:uid=test.user,o=test"))));
+    ArrayList<Control> requestControls = new ArrayList<Control>(1);
+    requestControls.add(new ProxiedAuthV2Control(
+         ByteString.valueOf("dn:uid=test.user,o=test")));
     LDAPMessage message = new LDAPMessage(nextMessageID.getAndIncrement(),
                                           extendedRequest, requestControls);
     writer.writeMessage(message);
@@ -494,11 +490,11 @@
          new LDAPAuthenticationHandler(reader, writer, "localhost",
                                        nextMessageID);
     authHandler.doSimpleBind(3,
-                             new ASN1OctetString("uid=cantproxy.user,o=test"),
-                             new ASN1OctetString("password"),
-                             new ArrayList<LDAPControl>(),
-                             new ArrayList<LDAPControl>());
-    ASN1OctetString authzID = authHandler.requestAuthorizationIdentity();
+                             ByteString.valueOf("uid=cantproxy.user,o=test"),
+                             ByteString.valueOf("password"),
+                             new ArrayList<Control>(),
+                             new ArrayList<Control>());
+    ByteString authzID = authHandler.requestAuthorizationIdentity();
     assertNotNull(authzID);
     assertEquals(authzID.toString(), "dn:uid=cantproxy.user,o=test");
 
@@ -506,9 +502,9 @@
     // Use the "Who Am I?" operation again, this time with the proxy control.
     ExtendedRequestProtocolOp extendedRequest =
          new ExtendedRequestProtocolOp(OID_WHO_AM_I_REQUEST);
-    ArrayList<LDAPControl> requestControls = new ArrayList<LDAPControl>(1);
-    requestControls.add(new LDAPControl(new ProxiedAuthV2Control(
-         new ASN1OctetString("dn:uid=test.user,o=test"))));
+    ArrayList<Control> requestControls = new ArrayList<Control>(1);
+    requestControls.add(new ProxiedAuthV2Control(
+         ByteString.valueOf("dn:uid=test.user,o=test")));
     LDAPMessage message = new LDAPMessage(nextMessageID.getAndIncrement(),
                                           extendedRequest, requestControls);
     writer.writeMessage(message);
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/monitors/InternalSearchMonitorTestCase.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/monitors/InternalSearchMonitorTestCase.java
index 6d52725..232187d 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/monitors/InternalSearchMonitorTestCase.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/monitors/InternalSearchMonitorTestCase.java
@@ -36,19 +36,10 @@
 import org.testng.annotations.AfterClass;
 
 import org.opends.server.TestCaseUtils;
-import org.opends.server.api.MonitorProvider;
-import static org.opends.server.util.ServerConstants.ATTR_COMMON_NAME;
 import org.opends.server.core.DirectoryServer;
 import org.opends.server.protocols.internal.InternalClientConnection;
 import org.opends.server.protocols.internal.InternalSearchOperation;
-import org.opends.server.types.DN;
-import org.opends.server.types.ResultCode;
-import org.opends.server.types.SearchScope;
-import org.opends.server.types.SearchFilter;
-import org.opends.server.types.AttributeType;
-import org.opends.server.types.RDN;
-import org.opends.server.types.AttributeValue;
-import org.opends.server.types.SearchResultEntry;
+import org.opends.server.types.*;
 
 import static org.testng.Assert.*;
 
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/plugins/DelayPreOpPlugin.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/plugins/DelayPreOpPlugin.java
index 20eea6f..57da85e 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/plugins/DelayPreOpPlugin.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/plugins/DelayPreOpPlugin.java
@@ -28,22 +28,23 @@
 
 
 
+import java.util.Set;
 import java.util.ArrayList;
 import java.util.List;
-import java.util.Set;
+import java.io.IOException;
 
 import org.opends.server.admin.std.server.PluginCfg;
 import org.opends.server.api.plugin.DirectoryServerPlugin;
 import org.opends.server.api.plugin.PluginType;
 import org.opends.server.api.plugin.PluginResult;
 import org.opends.server.config.ConfigException;
-import org.opends.server.protocols.asn1.ASN1Long;
-import org.opends.server.protocols.asn1.ASN1OctetString;
-import org.opends.server.protocols.ldap.LDAPControl;
-import org.opends.server.types.Control;
-import org.opends.server.types.ResultCode;
-import org.opends.server.types.CanceledOperationException;
+import org.opends.server.protocols.asn1.ASN1Writer;
+import org.opends.server.protocols.asn1.ASN1Reader;
+import org.opends.server.protocols.asn1.ASN1;
+import static org.opends.server.protocols.asn1.ASN1Constants.UNIVERSAL_OCTET_STRING_TYPE;
+import org.opends.server.types.*;
 import org.opends.server.types.operation.*;
+import org.opends.server.controls.ControlDecoder;
 import org.opends.messages.Message;
 
 
@@ -64,6 +65,93 @@
    */
   public static final String OID_DELAY_REQUEST = "1.3.6.1.4.1.26027.1.999.1";
 
+  /**
+   * The control used by this plugin.
+   */
+  public static class DelayRequestControl extends Control
+  {
+
+    /**
+     * ControlDecoder implentation to decode this control from a ByteString.
+     */
+    private final static class Decoder
+        implements ControlDecoder<DelayRequestControl>
+    {
+      /**
+       * {@inheritDoc}
+       */
+      public DelayRequestControl decode(boolean isCritical, ByteString value)
+          throws DirectoryException
+      {
+        ASN1Reader reader = ASN1.getReader(value);
+
+        try
+        {
+          long delay = reader.readInteger();
+
+          return new DelayRequestControl(isCritical, delay);
+        }
+        catch (Exception e)
+        {
+          // TODO: Need a better message
+          throw new DirectoryException(ResultCode.PROTOCOL_ERROR, null, e);
+        }
+      }
+
+      public String getOID()
+      {
+        return OID_DELAY_REQUEST;
+      }
+
+    }
+
+    /**
+     * The Control Decoder that can be used to decode this control.
+     */
+    public static final ControlDecoder<DelayRequestControl> DECODER =
+      new Decoder();
+
+
+    private long delayDuration;
+
+    /**
+     * Constructs a new change number control.
+     *
+     * @param  isCritical   Indicates whether support for this control should be
+     *                      considered a critical part of the server processing.
+     * @param delayDuration The requested delay duration.
+     */
+    public DelayRequestControl(boolean isCritical, long delayDuration)
+    {
+      super(OID_DELAY_REQUEST, isCritical);
+      this.delayDuration = delayDuration;
+    }
+
+    /**
+     * Writes this control's value to an ASN.1 writer. The value (if any)
+     * must be written as an ASN1OctetString.
+     *
+     * @param writer The ASN.1 writer to use.
+     * @throws IOException If a problem occurs while writing to the stream.
+     */
+    @Override
+    protected void writeValue(ASN1Writer writer) throws IOException {
+      writer.writeStartSequence(UNIVERSAL_OCTET_STRING_TYPE);
+      writer.writeInteger(delayDuration);
+      writer.writeEndSequence();
+    }
+
+    /**
+     * Retrieves the delay duration.
+     *
+     * @return The delay duration.
+     */
+    public long getDelayDuration()
+    {
+      return delayDuration;
+    }
+  }
+
 
 
   /**
@@ -228,45 +316,39 @@
    */
   private PluginResult.PreOperation
        doPreOperationInternal(PreOperationOperation operation)
-      throws CanceledOperationException {
-    long delayDuration = 0L;
-    List<Control> requestControls = operation.getRequestControls();
-    if (requestControls != null)
+      throws CanceledOperationException
+  {
+    DelayRequestControl control;
+    try
     {
-      for (Control c : requestControls)
+      control = operation.getRequestControl(DelayRequestControl.DECODER);
+    }
+    catch (Exception e)
+    {
+      return PluginResult.PreOperation.stopProcessing(
+          ResultCode.PROTOCOL_ERROR,
+          Message.raw("Unable to decode the delay request control:  " +
+              e));
+    }
+
+    if(control != null)
+    {
+      long delayDuration = control.getDelayDuration();
+      if (delayDuration <= 0)
       {
-        if (c.getOID().equals(OID_DELAY_REQUEST))
-        {
-          try
-          {
-            delayDuration =
-                 ASN1Long.decodeAsLong(c.getValue().value()).longValue();
-          }
-          catch (Exception e)
-          {
-            return PluginResult.PreOperation.stopProcessing(
-                ResultCode.PROTOCOL_ERROR,
-                Message.raw("Unable to decode the delay request control:  " +
-                    e));
-          }
-        }
+        return PluginResult.PreOperation.continueOperationProcessing();
       }
-    }
 
-    if (delayDuration <= 0)
-    {
-      return PluginResult.PreOperation.continueOperationProcessing();
-    }
-
-    long stopSleepTime = System.currentTimeMillis() + delayDuration;
-    while (System.currentTimeMillis() < stopSleepTime)
-    {
-      operation.checkIfCanceled(false);
-
-      try
+      long stopSleepTime = System.currentTimeMillis() + delayDuration;
+      while (System.currentTimeMillis() < stopSleepTime)
       {
-        Thread.sleep(10);
-      } catch (Exception e) {}
+        operation.checkIfCanceled(false);
+
+        try
+        {
+          Thread.sleep(10);
+        } catch (Exception e) {}
+      }
     }
 
     return PluginResult.PreOperation.continueOperationProcessing();
@@ -274,6 +356,7 @@
 
 
 
+
   /**
    * Creates a delay request control with the specified delay.
    *
@@ -283,44 +366,7 @@
    */
   public static Control createDelayControl(long delay)
   {
-    return new Control(OID_DELAY_REQUEST, false,
-                       new ASN1OctetString(new ASN1Long(delay).encode()));
-  }
-
-
-
-  /**
-   * Retrieves a list containing a delay request control with the specified
-   * delay.
-   *
-   * @param  delay  The length of time in milliseconds to sleep.
-   *
-   * @return  A list containing the appropriate delay request control.
-   */
-  public static List<Control> createDelayControlList(long delay)
-  {
-    ArrayList<Control> controlList = new ArrayList<Control>(1);
-
-    ASN1OctetString controlValue =
-         new ASN1OctetString(new ASN1Long(delay).encode());
-    controlList.add(new Control(OID_DELAY_REQUEST, false, controlValue));
-
-    return controlList;
-  }
-
-
-
-  /**
-   * Creates a delay request LDAP control with the specified delay.
-   *
-   * @param  delay  The length of time in milliseconds to sleep.
-   *
-   * @return  The appropriate delay request LDAP control.
-   */
-  public static LDAPControl createDelayLDAPControl(long delay)
-  {
-    return new LDAPControl(OID_DELAY_REQUEST, false,
-                           new ASN1OctetString(new ASN1Long(delay).encode()));
+    return new DelayRequestControl(false, delay);
   }
 
 
@@ -333,13 +379,11 @@
    *
    * @return  A list containing the appropriate delay request LDAP control.
    */
-  public static ArrayList<LDAPControl> createDelayLDAPControlList(long delay)
+  public static List<Control> createDelayControlList(long delay)
   {
-    ArrayList<LDAPControl> controlList = new ArrayList<LDAPControl>(1);
+    ArrayList<Control> controlList = new ArrayList<Control>(1);
 
-    ASN1OctetString controlValue =
-         new ASN1OctetString(new ASN1Long(delay).encode());
-    controlList.add(new LDAPControl(OID_DELAY_REQUEST, false, controlValue));
+    controlList.add(new DelayRequestControl(false, delay));
 
     return controlList;
   }
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/plugins/DisconnectClientPlugin.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/plugins/DisconnectClientPlugin.java
index d8e13e6..61581f5 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/plugins/DisconnectClientPlugin.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/plugins/DisconnectClientPlugin.java
@@ -31,16 +31,20 @@
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Set;
+import java.io.IOException;
 
 import org.opends.server.admin.std.server.PluginCfg;
 import org.opends.server.api.plugin.*;
 import org.opends.server.config.ConfigException;
-import org.opends.server.protocols.asn1.ASN1OctetString;
 import org.opends.server.protocols.ldap.LDAPControl;
-import org.opends.server.types.Control;
-import org.opends.server.types.DisconnectReason;
-import org.opends.server.types.CanceledOperationException;
+import org.opends.server.protocols.asn1.ASN1Reader;
+import org.opends.server.protocols.asn1.ASN1;
+import org.opends.server.protocols.asn1.ASN1Writer;
+import static org.opends.server.protocols.asn1.ASN1Constants.UNIVERSAL_OCTET_STRING_TYPE;
+import org.opends.server.types.*;
 import org.opends.server.types.operation.*;
+import org.opends.server.controls.ControlDecoder;
+import org.opends.server.loggers.ErrorLogger;
 import org.opends.messages.Message;
 
 
@@ -70,6 +74,78 @@
        "1.3.6.1.4.1.26027.1.999.2";
 
 
+  /**
+   * The control used by this plugin.
+   */
+  public static class DisconnectClientControl extends Control
+  {
+    /**
+     * ControlDecoder implentation to decode this control from a ByteString.
+     */
+    private final static class Decoder
+        implements ControlDecoder<DisconnectClientControl>
+    {
+      /**
+       * {@inheritDoc}
+       */
+      public DisconnectClientControl decode(boolean isCritical,
+                                            ByteString value)
+          throws DirectoryException
+      {
+        return new DisconnectClientControl(isCritical, value.toString());
+      }
+
+      public String getOID()
+      {
+        return OID_DISCONNECT_REQUEST;
+      }
+
+    }
+
+    /**
+     * The Control Decoder that can be used to decode this control.
+     */
+    public static final ControlDecoder<DisconnectClientControl> DECODER =
+      new Decoder();
+
+
+    private String section;
+
+    /**
+     * Constructs a new change number control.
+     *
+     * @param  isCritical   Indicates whether support for this control should be
+     *                      considered a critical part of the server processing.
+     * @param section  The section to use for the disconnect.
+     */
+    public DisconnectClientControl(boolean isCritical, String section)
+    {
+      super(OID_DISCONNECT_REQUEST, isCritical);
+      this.section = section;
+    }
+
+    /**
+     * Writes this control's value to an ASN.1 writer. The value (if any)
+     * must be written as an ASN1OctetString.
+     *
+     * @param writer The ASN.1 writer to use.
+     * @throws java.io.IOException If a problem occurs while writing to the stream.
+     */
+    @Override
+    protected void writeValue(ASN1Writer writer) throws IOException {
+      writer.writeOctetString(section);
+    }
+
+    /**
+     * Retrieves the delay duration.
+     *
+     * @return The delay duration.
+     */
+    public String getSection()
+    {
+      return section;
+    }
+  }
 
   /**
    * Creates a new instance of this Directory Server plugin.  Every
@@ -667,24 +743,25 @@
   private boolean disconnectInternal(PluginOperation operation,
                                      String section)
   {
-    List<Control> requestControls = operation.getRequestControls();
-    if (requestControls != null)
+    try
     {
-      for (Control c : requestControls)
-      {
-        if (c.getOID().equals(OID_DISCONNECT_REQUEST))
-        {
-          if (c.getValue().stringValue().equalsIgnoreCase(section))
-          {
-            operation.disconnectClient(DisconnectReason.CLOSED_BY_PLUGIN, true,
-                 Message.raw("Closed by disconnect client plugin (section " +
-                         section + ")"));
+      DisconnectClientControl control =
+          operation.getRequestControl(DisconnectClientControl.DECODER);
 
-            return true;
-          }
-        }
+      if (control != null && control.getSection().equalsIgnoreCase(section))
+      {
+        operation.disconnectClient(DisconnectReason.CLOSED_BY_PLUGIN, true,
+            Message.raw("Closed by disconnect client plugin (section " +
+                section + ")"));
+
+        return true;
       }
     }
+    catch (Exception e)
+    {
+      ErrorLogger.logError(Message.raw("Unable to decode the disconnect client control:  " +
+              e));
+    }
 
 
     // If we've gotten here, then we shouldn't disconnect the client.
@@ -702,8 +779,7 @@
    */
   public static Control createDisconnectControl(String section)
   {
-    return new Control(OID_DISCONNECT_REQUEST, false,
-                       new ASN1OctetString(section));
+    return new DisconnectClientControl(false, section);
   }
 
 
@@ -720,44 +796,7 @@
   {
     ArrayList<Control> controlList = new ArrayList<Control>(1);
 
-    controlList.add(new Control(OID_DISCONNECT_REQUEST, false,
-                                new ASN1OctetString(section)));
-
-    return controlList;
-  }
-
-
-
-  /**
-   * Creates a disconnect request LDAP control with the specified section.
-   *
-   * @param  section  The section to use for the disconnect.
-   *
-   * @return  The appropriate disconnect request LDAP control.
-   */
-  public static LDAPControl createDisconnectLDAPControl(String section)
-  {
-    return new LDAPControl(OID_DISCONNECT_REQUEST, false,
-                           new ASN1OctetString(section));
-  }
-
-
-
-  /**
-   * Retrieves a list containing a disconnect request LDAP control with the
-   * specified section.
-   *
-   * @param  section  The section to use for the disconnect.
-   *
-   * @return  A list containing the appropriate disconnect request LDAP control.
-   */
-  public static ArrayList<LDAPControl> createDisconnectLDAPControlList(
-                                            String section)
-  {
-    ArrayList<LDAPControl> controlList = new ArrayList<LDAPControl>(1);
-
-    controlList.add(new LDAPControl(OID_DISCONNECT_REQUEST, false,
-                                    new ASN1OctetString(section)));
+    controlList.add(new DisconnectClientControl(false, section));
 
     return controlList;
   }
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/plugins/EntryUUIDPluginTestCase.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/plugins/EntryUUIDPluginTestCase.java
index ce75e26..99c544a 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/plugins/EntryUUIDPluginTestCase.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/plugins/EntryUUIDPluginTestCase.java
@@ -147,7 +147,8 @@
     {
       for (AttributeValue v : a)
       {
-        pluginTypes.add(PluginType.forName(v.getStringValue().toLowerCase()));
+        pluginTypes.add(PluginType.forName(
+            v.getValue().toString().toLowerCase()));
       }
     }
 
@@ -186,7 +187,8 @@
     {
       for (AttributeValue v : a)
       {
-        pluginTypes.add(PluginType.forName(v.getStringValue().toLowerCase()));
+        pluginTypes.add(PluginType.forName(
+            v.getValue().toString().toLowerCase()));
       }
     }
 
@@ -265,7 +267,8 @@
     {
       for (AttributeValue v : a)
       {
-        pluginTypes.add(PluginType.forName(v.getStringValue().toLowerCase()));
+        pluginTypes.add(PluginType.forName(
+            v.getValue().toString().toLowerCase()));
       }
     }
 
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/plugins/LDAPADListPluginTestCase.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/plugins/LDAPADListPluginTestCase.java
index 9dc4efa..dde90d9 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/plugins/LDAPADListPluginTestCase.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/plugins/LDAPADListPluginTestCase.java
@@ -128,7 +128,7 @@
     {
       for (AttributeValue v : a)
       {
-        pluginTypes.add(PluginType.forName(v.getStringValue().toLowerCase()));
+        pluginTypes.add(PluginType.forName(v.getValue().toString().toLowerCase()));
       }
     }
 
@@ -214,7 +214,8 @@
       {
         for (AttributeValue v : a)
         {
-          pluginTypes.add(PluginType.forName(v.getStringValue().toLowerCase()));
+          pluginTypes.add(PluginType.forName(
+              v.getValue().toString().toLowerCase()));
         }
       }
     }
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/plugins/LastModPluginTestCase.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/plugins/LastModPluginTestCase.java
index 9b40de3..5083148 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/plugins/LastModPluginTestCase.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/plugins/LastModPluginTestCase.java
@@ -161,7 +161,8 @@
     {
       for (AttributeValue v : a)
       {
-        pluginTypes.add(PluginType.forName(v.getStringValue().toLowerCase()));
+        pluginTypes.add(PluginType.forName(
+            v.getValue().toString().toLowerCase()));
       }
     }
 
@@ -210,7 +211,8 @@
     {
       for (AttributeValue v : a)
       {
-        pluginTypes.add(PluginType.forName(v.getStringValue().toLowerCase()));
+        pluginTypes.add(PluginType.forName(
+            v.getValue().toString().toLowerCase()));
       }
     }
 
@@ -293,7 +295,8 @@
     {
       for (AttributeValue v : a)
       {
-        pluginTypes.add(PluginType.forName(v.getStringValue().toLowerCase()));
+        pluginTypes.add(PluginType.forName(
+            v.getValue().toString().toLowerCase()));
       }
     }
 
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/plugins/PasswordPolicyImportPluginTestCase.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/plugins/PasswordPolicyImportPluginTestCase.java
index 5c56d0e..33042df 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/plugins/PasswordPolicyImportPluginTestCase.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/plugins/PasswordPolicyImportPluginTestCase.java
@@ -174,7 +174,8 @@
     {
       for (AttributeValue v : a)
       {
-        pluginTypes.add(PluginType.forName(v.getStringValue().toLowerCase()));
+        pluginTypes.add(PluginType.forName(
+            v.getValue().toString().toLowerCase()));
       }
     }
 
@@ -250,7 +251,8 @@
       {
         for (AttributeValue v : a)
         {
-          pluginTypes.add(PluginType.forName(v.getStringValue().toLowerCase()));
+          pluginTypes.add(PluginType.forName(
+              v.getValue().toString().toLowerCase()));
         }
       }
     }
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/plugins/ReferentialIntegrityPluginTestCase.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/plugins/ReferentialIntegrityPluginTestCase.java
index 9e22f52..2cd6ae6 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/plugins/ReferentialIntegrityPluginTestCase.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/plugins/ReferentialIntegrityPluginTestCase.java
@@ -404,7 +404,8 @@
     List<Attribute> attrList = e.getAttribute("ds-cfg-plugin-type");
     for (Attribute a : attrList){
       for (AttributeValue v : a)
-        pluginTypes.add(PluginType.forName(v.getStringValue().toLowerCase()));
+        pluginTypes.add(PluginType.forName(
+            v.getValue().toString().toLowerCase()));
     }
     ReferentialIntegrityPluginCfg configuration =
             AdminTestCaseUtils.getConfiguration(
@@ -553,7 +554,8 @@
     List<Attribute> attrList = e.getAttribute("ds-cfg-plugin-type");
     for (Attribute a : attrList){
       for (AttributeValue v : a)
-        pluginTypes.add(PluginType.forName(v.getStringValue().toLowerCase()));
+        pluginTypes.add(PluginType.forName(
+            v.getValue().toString().toLowerCase()));
     }
     ReferentialIntegrityPluginCfg configuration =
             AdminTestCaseUtils.getConfiguration(
@@ -921,7 +923,7 @@
             null);
     for (SearchResultEntry entry : operation.getSearchEntries()) {
       for(String dn : dns) {
-        AttributeValue value = new AttributeValue(type, dn);
+        AttributeValue value = AttributeValues.create(type, dn);
         assertEquals(entry.hasValue(type, null, value), expected);
       }
     }
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/plugins/ShortCircuitPlugin.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/plugins/ShortCircuitPlugin.java
index 3e5da05..016d9db 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/plugins/ShortCircuitPlugin.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/plugins/ShortCircuitPlugin.java
@@ -28,26 +28,31 @@
 
 
 
-import java.util.ArrayList;
-import java.util.List;
 import java.util.Set;
 import java.util.Map;
+import java.util.List;
+import java.util.ArrayList;
 import java.util.concurrent.ConcurrentHashMap;
+import java.io.IOException;
 
 import org.opends.server.admin.std.server.PluginCfg;
 import org.opends.server.api.plugin.*;
 import org.opends.server.config.ConfigException;
-import org.opends.server.protocols.asn1.ASN1Element;
-import org.opends.server.protocols.asn1.ASN1Enumerated;
-import org.opends.server.protocols.asn1.ASN1OctetString;
-import org.opends.server.protocols.asn1.ASN1Sequence;
-import org.opends.server.protocols.ldap.LDAPControl;
+import org.opends.server.protocols.asn1.ASN1;
+import org.opends.server.protocols.asn1.ASN1Writer;
+import org.opends.server.protocols.asn1.ASN1Reader;
+import org.opends.server.types.ByteString;
 import org.opends.server.types.Control;
+import org.opends.server.types.DirectoryException;
 import org.opends.server.types.ResultCode;
 import org.opends.server.types.OperationType;
 import org.opends.server.types.operation.*;
+import org.opends.server.controls.ControlDecoder;
 import org.opends.messages.Message;
 
+import static org.opends.server.protocols.asn1.ASN1Constants.
+    UNIVERSAL_OCTET_STRING_TYPE;
+
 
 /**
  * This class defines a very simple plugin that causes request processing to end
@@ -66,6 +71,114 @@
   public static final String OID_SHORT_CIRCUIT_REQUEST =
        "1.3.6.1.4.1.26027.1.999.3";
 
+  /**
+   * The control used by this plugin.
+   */
+  public static class ShortCircuitRequestControl extends Control
+  {
+    /**
+     * ControlDecoder implentation to decode this control from a ByteString.
+     */
+    private final static class Decoder
+        implements ControlDecoder<ShortCircuitRequestControl>
+    {
+      /**
+       * {@inheritDoc}
+       */
+      public ShortCircuitRequestControl decode(boolean isCritical,
+                                               ByteString value)
+          throws DirectoryException
+      {
+        ASN1Reader reader = ASN1.getReader(value);
+
+        try
+        {
+          reader.readStartSequence();
+          int resultCode = (int)reader.readInteger();
+          String section = reader.readOctetStringAsString();
+          reader.readEndSequence();
+
+          return new ShortCircuitRequestControl(isCritical,
+              resultCode, section);
+        }
+        catch (Exception e)
+        {
+          // TODO: Need a better message
+          throw new DirectoryException(ResultCode.PROTOCOL_ERROR, null, e);
+        }
+      }
+
+      public String getOID()
+      {
+        return OID_SHORT_CIRCUIT_REQUEST;
+      }
+
+    }
+
+    /**
+     * The Control Decoder that can be used to decode this control.
+     */
+    public static final ControlDecoder<ShortCircuitRequestControl> DECODER =
+      new Decoder();
+
+
+    private int resultCode;
+    private String section;
+
+    /**
+     * Constructs a new change number control.
+     *
+     * @param  isCritical   Indicates whether support for this control should be
+     *                      considered a critical part of the server processing.
+   * @param  resultCode  The result code to return to the client.
+   * @param  section     The section to use to determine when to short circuit.
+     */
+    public ShortCircuitRequestControl(boolean isCritical, int resultCode,
+                                      String section)
+    {
+      super(OID_SHORT_CIRCUIT_REQUEST, isCritical);
+      this.resultCode = resultCode;
+      this.section = section;
+    }
+
+    /**
+     * Writes this control's value to an ASN.1 writer. The value (if any)
+     * must be written as an ASN1OctetString.
+     *
+     * @param writer The ASN.1 writer to use.
+     * @throws IOException If a problem occurs while writing to the stream.
+     */
+    @Override
+    protected void writeValue(ASN1Writer writer) throws IOException {
+      writer.writeStartSequence(UNIVERSAL_OCTET_STRING_TYPE);
+      writer.writeStartSequence();
+      writer.writeInteger(resultCode);
+      writer.writeOctetString(section);
+      writer.writeEndSequence();
+      writer.writeEndSequence();
+    }
+
+    /**
+     * Retrieves the resultCode.
+     *
+     * @return The resultCode.
+     */
+    public int getResultCode()
+    {
+      return resultCode;
+    }
+
+    /**
+     * Retrieves the section.
+     *
+     * @return The section.
+     */
+    public String getSection()
+    {
+      return section;
+    }
+  }
+
 
 
   /**
@@ -530,36 +643,23 @@
    */
   private int shortCircuitInternal(PluginOperation operation, String section)
   {
-    List<Control> requestControls = operation.getRequestControls();
-    if (requestControls != null)
+    try
     {
-      for (Control c : requestControls)
+      ShortCircuitRequestControl control =
+          operation.getRequestControl(ShortCircuitRequestControl.DECODER);
+      
+      if (control != null && section.equalsIgnoreCase(control.getSection()))
       {
-        if (c.getOID().equals(OID_SHORT_CIRCUIT_REQUEST))
-        {
-          try
-          {
-            ASN1Sequence sequence =
-                 ASN1Sequence.decodeAsSequence(c.getValue().value());
-            ArrayList<ASN1Element> elements = sequence.elements();
-            int resultCode = elements.get(0).decodeAsEnumerated().intValue();
-            String controlSection =
-                        elements.get(1).decodeAsOctetString().stringValue();
-            if (section.equalsIgnoreCase(controlSection))
-            {
-              return resultCode;
-            }
-          }
-          catch (Exception e)
-          {
-            System.err.println("***** ERROR:  Could not decode short circuit " +
-                               "control value:  " + e);
-            e.printStackTrace();
-            return -1;
-          }
-        }
+        return control.resultCode;
       }
     }
+    catch (Exception e)
+    {
+      System.err.println("***** ERROR:  Could not decode short circuit " +
+          "control value:  " + e);
+      e.printStackTrace();
+      return -1;
+    }
 
     // Check for registered short circuits.
     Integer resultCode = shortCircuits.get(
@@ -588,14 +688,7 @@
   public static Control createShortCircuitControl(int resultCode,
                                                   String section)
   {
-    ArrayList<ASN1Element> elements = new ArrayList<ASN1Element>(2);
-    elements.add(new ASN1Enumerated(resultCode));
-    elements.add(new ASN1OctetString(section));
-
-    ASN1OctetString controlValue =
-         new ASN1OctetString(new ASN1Sequence(elements).encode());
-
-    return new Control(OID_SHORT_CIRCUIT_REQUEST, false, controlValue);
+    return new ShortCircuitRequestControl(false, resultCode, section);
   }
 
 
@@ -617,43 +710,6 @@
     return controlList;
   }
 
-
-
-  /**
-   * Creates a short circuit LDAP request control with the specified result code
-   * and section.
-   *
-   * @param  resultCode  The result code to return to the client.
-   * @param  section     The section to use to determine when to short circuit.
-   *
-   * @return  The appropriate short circuit LDAP request control.
-   */
-  public static LDAPControl createShortCircuitLDAPControl(int resultCode,
-                                                          String section)
-  {
-    return new LDAPControl(createShortCircuitControl(resultCode, section));
-  }
-
-
-
-  /**
-   * Retrieves a list containing a short circuit LDAP control with the specified
-   * result code and section.
-   *
-   * @param  resultCode  The result code to return to the client.
-   * @param  section     The section to use to determine when to short circuit.
-   *
-   * @return  A list containing the appropriate short circuit LDAP request
-   *          control.
-   */
-  public static ArrayList<LDAPControl> createShortCircuitLDAPControlList(
-                                            int resultCode, String section)
-  {
-    ArrayList<LDAPControl> controlList = new ArrayList<LDAPControl>(1);
-    controlList.add(createShortCircuitLDAPControl(resultCode, section));
-    return controlList;
-  }
-
   /**
    * Registered short circuits for operations regardless of controls.
    */
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/plugins/UniqueAttributePluginTestCase.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/plugins/UniqueAttributePluginTestCase.java
index c7eb127..62c910e 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/plugins/UniqueAttributePluginTestCase.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/plugins/UniqueAttributePluginTestCase.java
@@ -70,7 +70,7 @@
   {
     TestCaseUtils.restartServer();
     TestCaseUtils.initializeTestBackend(true);
-    
+
     //Add entries to two backends to test public naming context.
     addTestEntries("o=test", 't');
     TestCaseUtils.clearJEBackend(true,"userRoot", "dc=example,dc=com");
@@ -216,7 +216,8 @@
     List<Attribute> attrList = e.getAttribute("ds-cfg-plugin-type");
     for (Attribute a : attrList){
       for (AttributeValue v : a)
-        pluginTypes.add(PluginType.forName(v.getStringValue().toLowerCase()));
+        pluginTypes.add(PluginType.forName(
+            v.getValue().toString().toLowerCase()));
     }
     UniqueAttributePluginCfg configuration =
             AdminTestCaseUtils.getConfiguration(
@@ -334,7 +335,8 @@
     for (Attribute a : attrList)
     {
       for (AttributeValue v : a)
-        pluginTypes.add(PluginType.forName(v.getStringValue().toLowerCase()));
+        pluginTypes.add(PluginType.forName(
+            v.getValue().toString().toLowerCase()));
     }
     UniqueAttributePluginCfg configuration =
          AdminTestCaseUtils.getConfiguration(
@@ -745,7 +747,7 @@
     conn.processModify(dn, mods);
   }
 
-  
+
 
   private void
   replaceAttrInEntry(DN dn, String attrTypeString, String... attrValStrings) {
@@ -753,7 +755,7 @@
     AttributeType attrType = getAttrType(attrTypeString);
     AttributeBuilder builder = new AttributeBuilder(attrType, attrTypeString);
     for(String valString : attrValStrings) {
-      builder.add(new AttributeValue(attrType, valString));
+      builder.add(AttributeValues.create(attrType, valString));
     }
     mods.add(new Modification(ModificationType.REPLACE, builder.toAttribute()));
     InternalClientConnection conn =
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/asn1/ASN1ByteChannelReaderTestCase.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/asn1/ASN1ByteChannelReaderTestCase.java
new file mode 100644
index 0000000..13fa758
--- /dev/null
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/asn1/ASN1ByteChannelReaderTestCase.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 2006-2009 Sun Microsystems, Inc.
+ */
+package org.opends.server.protocols.asn1;
+
+import org.testng.annotations.Test;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.nio.channels.Channels;
+import java.nio.channels.IllegalBlockingModeException;
+
+/**
+ * Test class for ASN1ByteChannelReader
+ */
+public class ASN1ByteChannelReaderTestCase extends ASN1ReaderTestCase
+{
+  ASN1Reader getReader(byte[] b, int maxElementSize) throws IOException
+  {
+    ByteArrayInputStream inStream = new ByteArrayInputStream(b);
+    ASN1ByteChannelReader reader =
+        new ASN1ByteChannelReader(Channels.newChannel(inStream),
+            b.length, maxElementSize);
+    reader.processChannelData();
+    return reader;
+  }
+
+  /**
+   * 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 = { IllegalBlockingModeException.class })
+  public void testDecodeShortArrayAsNull()
+      throws Exception
+  {
+    super.testDecodeShortArrayAsNull();
+  }
+
+  /**
+   * Tests the <CODE>decodeAsInteger</CODE> method that takes a byte array with
+   * a short array.
+   *
+   * @throws  Exception  If an unexpected problem occurs.
+   */
+  @Test(expectedExceptions = { IllegalBlockingModeException.class })
+  public void testDecodeShortArrayAsInteger()
+      throws Exception
+  {
+    super.testDecodeShortArrayAsInteger();
+  }
+
+  /**
+   * 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 = { IllegalBlockingModeException.class })
+  public void testDecodeShortArrayAsBoolean()
+      throws Exception
+  {
+    super.testDecodeShortArrayAsBoolean();
+  }
+
+  /**
+   * Tests the <CODE>decodeAsOctetString</CODE> method that takes a byte array
+   * using a short array.
+   *
+   * @throws  Exception  If an unexpected problem occurs.
+   */
+  @Test(expectedExceptions  = { IllegalBlockingModeException.class })
+  public void testDecodeShortArrayAsOctetString()
+      throws Exception
+  {
+    super.testDecodeShortArrayAsOctetString();
+  }
+
+  /**
+   * 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 = { IllegalBlockingModeException.class })
+  public void testDecodeShortArrayAsSequence()
+      throws Exception
+  {
+    super.testDecodeShortArrayAsSequence();
+  }
+
+  /**
+   * 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 = { IllegalBlockingModeException.class })
+  public void testDecodeLengthMismatchArrayAsBoolean()
+      throws Exception
+  {
+    super.testDecodeLengthMismatchArrayAsBoolean();
+  }
+
+  /**
+   * Tests the <CODE>decodeAsInteger</CODE> method that takes a byte array with
+   * a length mismatch.
+   *
+   * @throws  Exception  If an unexpected problem occurs.
+   */
+  @Test(expectedExceptions = { IllegalBlockingModeException.class })
+  public void testDecodeLengthMismatchArrayAsInteger()
+      throws Exception
+  {
+    super.testDecodeLengthMismatchArrayAsInteger();
+  }
+
+  /**
+   * 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  = { IllegalBlockingModeException.class })
+  public void testDecodeLengthMismatchArrayAsOctetString()
+      throws Exception
+  {
+    super.testDecodeLengthMismatchArrayAsOctetString();
+  }
+
+  /**
+   * 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 = { IllegalBlockingModeException.class })
+  public void testDecodeTruncatedLengthArrayAsBoolean()
+      throws Exception
+  {
+    super.testDecodeTruncatedLengthArrayAsBoolean();
+  }
+
+  /**
+   * 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 = { IllegalBlockingModeException.class })
+  public void testDecodeTruncatedLengthArrayAsInteger()
+      throws Exception
+  {
+    super.testDecodeTruncatedLengthArrayAsInteger();
+  }
+
+  /**
+   * 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 = { IllegalBlockingModeException.class })
+  public void testDecodeTruncatedLengthArrayAsNull()
+      throws Exception
+  {
+    super.testDecodeTruncatedLengthArrayAsNull();
+  }
+
+  /**
+   * 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  = { IllegalBlockingModeException.class })
+  public void testDecodeTruncatedLengthArrayAsOctetString()
+      throws Exception
+  {
+    super.testDecodeTruncatedLengthArrayAsOctetString();
+  }
+
+  /**
+   * 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 = { IllegalBlockingModeException.class })
+  public void testDecodeTruncatedLengthArrayAsSequence()
+      throws Exception
+  {
+    super.testDecodeTruncatedLengthArrayAsSequence();
+  }
+
+  /**
+   * Tests to make sure a premature EOF while reading a sub sequence can be
+   * detected.
+   *
+   * @throws  Exception  If an unexpected problem occurs.
+   */
+  @Test(expectedExceptions = { IllegalBlockingModeException.class })
+  public void testDecodeSequencePrematureEof()
+      throws Exception
+  {
+    super.testDecodeSequencePrematureEof();
+  }
+
+  /**
+   * Tests the <CODE>skipElement</CODE> method.
+   *
+   * @throws  Exception  If an unexpected problem occurs.
+   */
+  @Test(expectedExceptions = { IllegalBlockingModeException.class })
+  public void testSkipElementIncompleteRead()
+      throws Exception
+  {
+    super.testSkipElementIncompleteRead();
+  }
+}
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/asn1/ASN1ByteChannelWriterTestCase.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/asn1/ASN1ByteChannelWriterTestCase.java
new file mode 100644
index 0000000..7e5e291
--- /dev/null
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/asn1/ASN1ByteChannelWriterTestCase.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 2006-2009 Sun Microsystems, Inc.
+ */
+package org.opends.server.protocols.asn1;
+
+import org.opends.server.types.ByteString;
+
+import java.io.ByteArrayOutputStream;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.nio.channels.WritableByteChannel;
+import java.nio.channels.Channels;
+import java.nio.channels.ReadableByteChannel;
+
+/**
+ * Test class for ASN1ByteChannelWriter
+ */
+public class ASN1ByteChannelWriterTestCase extends ASN1WriterTestCase
+{
+  ByteArrayOutputStream outStream = new ByteArrayOutputStream();
+  WritableByteChannel outChannel = Channels.newChannel(outStream);
+  ASN1Writer writer = new ASN1ByteChannelWriter(outChannel, 500);
+
+  ASN1Writer getWriter() throws IOException
+  {
+    writer.flush();
+    outStream.reset();
+    return writer;
+  }
+
+  ASN1Reader getReader(byte[] encodedBytes) throws ASN1Exception, IOException
+  {
+    ByteArrayInputStream inStream =
+        new ByteArrayInputStream(encodedBytes);
+    ReadableByteChannel inChannel = Channels.newChannel(inStream);
+    ASN1ByteChannelReader reader =
+        new ASN1ByteChannelReader(inChannel, 500, 0);
+    while(!reader.elementAvailable())
+    {
+      reader.processChannelData();
+    }
+    return reader;
+  }
+
+  byte[] getEncodedBytes() throws IOException, ASN1Exception
+  {
+    writer.flush();
+    return outStream.toByteArray();
+  }
+}
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/asn1/ASN1TestCase.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/asn1/ASN1ByteSequenceReaderTestCase.java
similarity index 67%
copy from opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/asn1/ASN1TestCase.java
copy to opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/asn1/ASN1ByteSequenceReaderTestCase.java
index 7e13c41..85da533 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/asn1/ASN1TestCase.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/asn1/ASN1ByteSequenceReaderTestCase.java
@@ -22,17 +22,21 @@
  * CDDL HEADER END
  *
  *
- *      Copyright 2006-2008 Sun Microsystems, Inc.
+ *      Copyright 2006-2009 Sun Microsystems, Inc.
  */
 package org.opends.server.protocols.asn1;
 
-import org.opends.server.DirectoryServerTestCase;
-import org.testng.annotations.Test;
+import org.opends.server.types.ByteSequenceReader;
+import org.opends.server.types.ByteString;
 
 /**
- * An abstract base class for all ASN1 test cases.
+ * Test class for ASN1ByteSequenceReaderTestCase
  */
-@Test(groups = { "precommit", "asn1" }, sequential = true)
-public abstract class ASN1TestCase extends DirectoryServerTestCase {
-  // No implementation required.
+public class ASN1ByteSequenceReaderTestCase extends ASN1ReaderTestCase
+{
+  ASN1Reader getReader(byte[] b, int maxElementSize)
+  {
+    ByteSequenceReader reader = ByteString.wrap(b).asReader();
+    return new ASN1ByteSequenceReader(reader, maxElementSize);
+  }
 }
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/asn1/ASN1TestCase.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/asn1/ASN1InputStreamReaderTestCase.java
similarity index 71%
rename from opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/asn1/ASN1TestCase.java
rename to opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/asn1/ASN1InputStreamReaderTestCase.java
index 7e13c41..b0a44b9 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/asn1/ASN1TestCase.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/asn1/ASN1InputStreamReaderTestCase.java
@@ -22,17 +22,20 @@
  * CDDL HEADER END
  *
  *
- *      Copyright 2006-2008 Sun Microsystems, Inc.
+ *      Copyright 2006-2009 Sun Microsystems, Inc.
  */
 package org.opends.server.protocols.asn1;
 
-import org.opends.server.DirectoryServerTestCase;
-import org.testng.annotations.Test;
+import java.io.ByteArrayInputStream;
 
 /**
- * An abstract base class for all ASN1 test cases.
+ * Test class for ASN1InputStreamReader
  */
-@Test(groups = { "precommit", "asn1" }, sequential = true)
-public abstract class ASN1TestCase extends DirectoryServerTestCase {
-  // No implementation required.
+public class ASN1InputStreamReaderTestCase extends ASN1ReaderTestCase
+{
+  ASN1Reader getReader(byte[] b, int maxElementSize)
+  {
+    ByteArrayInputStream inStream = new ByteArrayInputStream(b);
+    return new ASN1InputStreamReader(inStream, maxElementSize);
+  }
 }
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/asn1/ASN1OutputStreamWriterTestCase.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/asn1/ASN1OutputStreamWriterTestCase.java
new file mode 100644
index 0000000..5638870
--- /dev/null
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/asn1/ASN1OutputStreamWriterTestCase.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 2006-2009 Sun Microsystems, Inc.
+ */
+package org.opends.server.protocols.asn1;
+
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+import static org.testng.Assert.*;
+import org.opends.server.types.ByteStringBuilder;
+import org.opends.server.types.ByteString;
+import static org.opends.server.protocols.asn1.ASN1Constants.*;
+import org.opends.server.util.StaticUtils;
+
+import java.io.ByteArrayOutputStream;
+import java.io.ByteArrayInputStream;
+import java.util.Arrays;
+
+/**
+ * Test class for ASN1OutputStreamWriter
+ */
+public class ASN1OutputStreamWriterTestCase extends ASN1WriterTestCase
+{
+  ByteArrayOutputStream outStream = new ByteArrayOutputStream();
+  ASN1Writer writer = new ASN1OutputStreamWriter(outStream);
+
+  ASN1Writer getWriter()
+  {
+    outStream.reset();
+    return writer;
+  }
+
+  ASN1Reader getReader(byte[] encodedBytes)
+  {
+    ByteArrayInputStream inStream =
+        new ByteArrayInputStream(encodedBytes);
+    return new ASN1InputStreamReader(inStream, 0);
+  }
+
+  byte[] getEncodedBytes()
+  {
+    return outStream.toByteArray();
+  }
+}
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/asn1/ASN1ReaderTestCase.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/asn1/ASN1ReaderTestCase.java
new file mode 100644
index 0000000..ee4299b
--- /dev/null
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/asn1/ASN1ReaderTestCase.java
@@ -0,0 +1,804 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License").  You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE
+ * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
+ * add the following below this CDDL 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.server.protocols.asn1;
+
+import org.testng.annotations.Test;
+import org.testng.annotations.DataProvider;
+import static org.testng.Assert.*;
+import org.opends.server.types.ByteStringBuilder;
+import org.opends.server.types.ByteString;
+import org.opends.server.DirectoryServerTestCase;
+
+import java.io.IOException;
+
+/**
+ * An abstract base class for all ASN1Reader test cases.
+ */
+@Test(groups = { "precommit", "asn1" }, sequential = true)
+public abstract class ASN1ReaderTestCase extends DirectoryServerTestCase
+{
+
+  /**
+   * 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()
+  {
+    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.
+   *
+   * @throws  Exception  If an unexpected problem occurs.
+   */
+  @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 } },
+        };
+  }
+
+  abstract ASN1Reader getReader(byte[] b, int maxElementSize)
+      throws IOException;
+
+  /**
+   * 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 = { ASN1Exception.class })
+  public void testDecodeShortArrayAsNull()
+      throws Exception
+  {
+    byte[] b = new byte[1];
+    getReader(b, 0).readNull();
+  }
+
+
+
+  /**
+   * 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 = { ASN1Exception.class })
+  public void testDecodeLongLengthArrayAsNull()
+      throws Exception
+  {
+    byte[] b = new byte[] { 0x05, (byte) 0x85, 0x00, 0x00, 0x00, 0x00, 0x00 };
+    getReader(b, 0).readNull();
+  }
+
+
+
+  /**
+   * 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 = { ASN1Exception.class })
+  public void testDecodeTruncatedLengthArrayAsNull()
+      throws Exception
+  {
+    byte[] b = new byte[] { 0x05, (byte) 0x82, 0x00 };
+    getReader(b, 0).readNull();
+  }
+
+
+
+  /**
+   * 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 = { ASN1Exception.class })
+  public void testDecodeNonZeroLengthArrayAsNull()
+      throws Exception
+  {
+    byte[] b = new byte[] { 0x05, 0x01, 0x00 };
+    getReader(b, 0).readNull();
+  }
+
+
+
+  /**
+   * 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
+  {
+    byte[] b = new byte[] { 0x05, 0x00 };
+    getReader(b, 0).readNull();
+  }
+
+
+
+  /**
+   * 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
+  {
+    byte[] b = new byte[] { 0x05, (byte) 0x81, 0x00 };
+    getReader(b, 0).readNull();
+  }
+
+  /**
+   * Tests the <CODE>decodeAsInteger</CODE> method that takes a byte array with
+   * a short array.
+   *
+   * @throws  Exception  If an unexpected problem occurs.
+   */
+  @Test(expectedExceptions = { ASN1Exception.class })
+  public void testDecodeShortArrayAsInteger()
+      throws Exception
+  {
+    byte[] b = new byte[0];
+    getReader(b, 0).readInteger();
+  }
+
+
+
+  /**
+   * 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 = { ASN1Exception.class })
+  public void testDecodeLongLengthArrayAsInteger()
+      throws Exception
+  {
+    byte[] b = { 0x02, (byte) 0x85, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00 };
+    getReader(b, 0).readInteger();
+  }
+
+
+
+  /**
+   * 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 = { ASN1Exception.class })
+  public void testDecodeTruncatedLengthArrayAsInteger()
+      throws Exception
+  {
+    byte[] b = { 0x02, (byte) 0x82, 0x00 };
+    getReader(b, 0).readInteger();
+  }
+
+
+
+  /**
+   * Tests the <CODE>decodeAsInteger</CODE> method that takes a byte array with
+   * a length mismatch.
+   *
+   * @throws  Exception  If an unexpected problem occurs.
+   */
+  @Test(expectedExceptions = { ASN1Exception.class })
+  public void testDecodeLengthMismatchArrayAsInteger()
+      throws Exception
+  {
+    byte[] b = { 0x02, (byte) 0x81, 0x01 };
+    getReader(b, 0).readInteger();
+  }
+
+  /**
+   * 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(byte[] b)
+      throws Exception
+  {
+    // First, test with the standard Boolean type.
+    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>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(byte[] b)
+      throws Exception
+  {
+    // First, test with the standard Boolean type.
+    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>decodeAsBoolean</CODE> method that takes a byte array
+   * argument with a short array.
+   *
+   * @throws  Exception  If an unexpected problem occurs.
+   */
+  @Test(expectedExceptions = { ASN1Exception.class })
+  public void testDecodeShortArrayAsBoolean()
+      throws Exception
+  {
+    byte[] b = new byte[1];
+    getReader(b, 0).readBoolean();
+  }
+
+
+
+  /**
+   * 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 = { ASN1Exception.class })
+  public void testDecodeLongLengthArrayAsBoolean()
+      throws Exception
+  {
+    byte[] b = { 0x01, (byte) 0x85, 0x00, 0x00, 0x00, 0x00, 0x01, 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 = { ASN1Exception.class })
+  public void testDecodeTruncatedLengthArrayAsBoolean()
+      throws Exception
+  {
+    byte[] b = { 0x01, (byte) 0x82, 0x00 };
+    getReader(b, 0).readBoolean();
+  }
+
+
+
+  /**
+   * 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 = { ASN1Exception.class })
+  public void testDecodeLengthMismatchArrayAsBoolean()
+      throws Exception
+  {
+    byte[] b = { 0x01, 0x01 };
+    getReader(b, 0).readBoolean();
+  }
+
+
+  /**
+   * 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 = { ASN1Exception.class })
+  public void testDecodeShortValueArrayAsBoolean()
+      throws Exception
+  {
+    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 has an invalid number of bytes in the value.
+   *
+   * @throws  Exception  If an unexpected problem occurs.
+   */
+  @Test(expectedExceptions = { ASN1Exception.class })
+  public void testDecodeLongValueArrayAsBoolean()
+      throws Exception
+  {
+    byte[] b = { 0x01, 0x02, 0x00, 0x00 };
+    getReader(b, 0).readBoolean();
+  }
+
+
+
+  /**
+   * 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(byte[] b)
+      throws Exception
+  {
+    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(byte[] b)
+      throws Exception
+  {
+    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(byte[] b)
+      throws Exception
+  {
+    ByteStringBuilder bsb = new ByteStringBuilder();
+    bsb.append(ASN1Constants.UNIVERSAL_OCTET_STRING_TYPE);
+    bsb.appendBERLength(b.length);
+    bsb.append(b);
+
+    assertEquals(
+        getReader(bsb.toByteArray(), 0).readOctetStringAsString("UTF-8"),
+        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(byte[] b)
+      throws Exception
+  {
+    ByteStringBuilder bsb = new ByteStringBuilder();
+    bsb.append(ASN1Constants.UNIVERSAL_OCTET_STRING_TYPE);
+    bsb.appendBERLength(b.length);
+    bsb.append(b);
+
+    ByteStringBuilder bsb2 = new ByteStringBuilder();
+    getReader(bsb.toByteArray(), 0).readOctetString(bsb2);
+    assertEquals(bsb2.toByteString(), ByteString.wrap(b));
+  }
+
+
+
+  /**
+   * Tests the <CODE>decodeAsOctetString</CODE> method that takes a byte array
+   * using a short array.
+   *
+   * @throws  Exception  If an unexpected problem occurs.
+   */
+  @Test(expectedExceptions  = { ASN1Exception.class })
+  public void testDecodeShortArrayAsOctetString()
+      throws Exception
+  {
+    byte[] b = new byte[1];
+    getReader(b, 0).readOctetString();
+  }
+
+
+
+  /**
+   * 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  = { ASN1Exception.class })
+  public void testDecodeLongLengthArrayAsOctetString()
+      throws Exception
+  {
+    byte[] b = { 0x04, (byte) 0x85, 0x00, 0x00, 0x00, 0x00, 0x00 };
+    getReader(b, 0).readOctetString();
+  }
+
+
+
+  /**
+   * 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  = { ASN1Exception.class })
+  public void testDecodeTruncatedLengthArrayAsOctetString()
+      throws Exception
+  {
+    byte[] b = { 0x04, (byte) 0x82, 0x00 };
+    getReader(b, 0).readOctetString();
+  }
+
+
+
+  /**
+   * 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  = { ASN1Exception.class })
+  public void testDecodeLengthMismatchArrayAsOctetString()
+      throws Exception
+  {
+    byte[] b = { 0x04, 0x02, 0x00 };
+    getReader(b, 0).readOctetString();
+  }
+
+  /**
+   * 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(byte[] encodedElements)
+      throws Exception
+  {
+    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);
+
+    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>decodeAsSequence</CODE> method that takes a byte array
+   * argument with a short array.
+   *
+   * @throws  Exception  If an unexpected problem occurs.
+   */
+  @Test(expectedExceptions = { ASN1Exception.class })
+  public void testDecodeShortArrayAsSequence()
+      throws Exception
+  {
+    byte[] b = new byte[1];
+    getReader(b, 0).readStartSequence();
+  }
+
+
+
+  /**
+   * 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 = { ASN1Exception.class })
+  public void testDecodeLongLengthArrayAsSequence()
+      throws Exception
+  {
+    byte[] b = { 0x30, (byte) 0x85, 0x00, 0x00, 0x00, 0x00, 0x00 };
+    getReader(b, 0).readStartSequence();
+  }
+
+
+
+  /**
+   * 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 = { ASN1Exception.class })
+  public void testDecodeTruncatedLengthArrayAsSequence()
+      throws Exception
+  {
+    byte[] b = { 0x30, (byte) 0x82, 0x00 };
+    getReader(b, 0).readStartSequence();
+  }
+
+
+
+  /**
+   * Tests the <CODE>readOctetString</CODE> method when the max element size
+   * is exceeded.
+   *
+   * @throws  Exception  If an unexpected problem occurs.
+   */
+  @Test(expectedExceptions = { ASN1Exception.class })
+  public void testDecodeOctetStringExceedMaxSize()
+      throws Exception
+  {
+    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 = { ASN1Exception.class })
+  public void testDecodeSequenceExceedMaxSize()
+      throws Exception
+  {
+    byte[] b = new byte[] { 0x30, 0x07, 0x04, 0x05, 0x48, 0x65, 0x6C, 0x6C, 0x6F };
+    getReader(b, 3).readOctetString();
+  }
+
+  /**
+   * Tests to make sure a premature EOF while reading a sub sequence can be
+   * detected.
+   *
+   * @throws  Exception  If an unexpected problem occurs.
+   */
+  @Test(expectedExceptions = { ASN1Exception.class })
+  public void testDecodeSequencePrematureEof()
+      throws Exception
+  {
+    // An ASN.1 sequence of booleans missing one boolean element at the end
+    byte[] b = new byte[] { 0x30, 0x09, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00 };
+    ASN1Reader reader = getReader(b, 0);
+    reader.readStartSequence();
+    while(reader.hasNextElement())
+    {
+      reader.readBoolean();
+    }
+    reader.readEndSequence();
+  }
+
+  /**
+   * Tests to make sure not reading all elements in a sub sequence can be
+   * detected.
+   *
+   * @throws  Exception  If an unexpected problem occurs.
+   */
+  @Test(expectedExceptions = { ASN1Exception.class })
+  public void testDecodeSequenceIncompleteRead()
+      throws Exception
+  {
+    // An ASN.1 sequence of booleans missing one boolean element at the end
+    byte[] b = new byte[] { 0x30, 0x06, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00 };
+    ASN1Reader reader = getReader(b, 0);
+    reader.readStartSequence();
+    reader.readBoolean();
+    reader.readEndSequence();
+  }
+
+  /**
+   * Tests the <CODE>skipElement</CODE> method.
+   *
+   * @throws  Exception  If an unexpected problem occurs.
+   */
+  @Test(expectedExceptions = { ASN1Exception.class })
+  public void testSkipElementIncompleteRead()
+      throws Exception
+  {
+    // An ASN.1 sequence of booleans missing one boolean element at the end
+    byte[] b = new byte[] { 0x30, 0x09, 0x01, 0x01, 0x00, 0x01, 0x02 };
+    ASN1Reader reader = getReader(b, 0);
+    reader.readStartSequence();
+    reader.readBoolean();
+    reader.skipElement();
+    reader.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
+    byte[] b = new byte[] { 0x30, 0x09, 0x02, 0x01, 0x00, 0x02, 0x01, 0x01,
+        0x02, 0x01, 0x02 };
+    ASN1Reader reader = getReader(b, 0);
+    reader.readStartSequence();
+    reader.readInteger();
+    reader.skipElement();
+    assertEquals(reader.readInteger(), 2);
+    reader.readEndSequence();
+  }
+
+  /**
+   * 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 = { ASN1Exception.class })
+  public void testReadEndSequenceNoStartSequence()
+      throws Exception
+  {
+    byte[] b = { 0x30, 0x01, 0x00 };
+    getReader(b, 0).readEndSequence();
+  }
+}
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/asn1/ASN1WriterTestCase.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/asn1/ASN1WriterTestCase.java
new file mode 100644
index 0000000..0befcdd
--- /dev/null
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/asn1/ASN1WriterTestCase.java
@@ -0,0 +1,709 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License").  You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE
+ * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
+ * add the following below this CDDL 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.server.protocols.asn1;
+
+import org.opends.server.DirectoryServerTestCase;
+import static org.opends.server.protocols.asn1.ASN1Constants.*;
+import org.opends.server.util.StaticUtils;
+import org.opends.server.types.ByteString;
+import org.opends.server.types.ByteStringBuilder;
+import org.testng.annotations.Test;
+import org.testng.annotations.DataProvider;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertTrue;
+import static org.testng.Assert.assertFalse;
+
+import java.io.IOException;
+
+/**
+ * An abstract base class for all ASN1Writer test cases.
+ */
+@Test(groups = { "precommit", "asn1" }, sequential = true)
+public abstract class ASN1WriterTestCase extends DirectoryServerTestCase {
+
+  // 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.
+  byte[] testTypes = new byte[0xFF];
+  {
+    for (int i=0x00; i < 0xFF; i++)
+    {
+      testTypes[i] = (byte) (i & 0xFF);
+    }
+  }
+
+
+  /**
+   * 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 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
+        };
+  }
+
+  /**
+   * 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?" }
+        };
+  }
+
+  abstract ASN1Writer getWriter() throws IOException;
+
+  abstract ASN1Reader getReader(byte[] encodedBytes) throws ASN1Exception, IOException;
+
+  abstract byte[] getEncodedBytes() throws IOException, ASN1Exception;
+
+  /**
+   * Tests the <CODE>write/readBoolean</CODE> methods.
+   *
+   * @param  b  The boolean value to use in the test.
+   */
+  @Test(dataProvider = "booleanValues")
+  public void testEncodeDecodeBoolean(boolean b) throws Exception
+  {
+    getWriter().writeBoolean(b);
+
+    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(boolean b) throws Exception
+  {
+    for(byte type : testTypes)
+    {
+      getWriter().writeBoolean(type, b);
+
+      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(int i, int length) throws Exception
+  {
+    getWriter().writeEnumerated(i);
+
+    ASN1Reader r = getReader(getEncodedBytes());
+    assertEquals(r.peekLength(), length);
+    assertEquals(r.peekType(), UNIVERSAL_ENUMERATED_TYPE);
+    assertEquals(r.readInteger(), i);
+  }
+
+  /**
+   * 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);
+  }
+
+
+  /**
+   * 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(int i, int length) throws Exception
+  {
+    getWriter().writeInteger(i);
+
+    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 ints.
+   *
+   * @param  i  The integer value to use for the test.
+   */
+  @Test(dataProvider = "intValues")
+  public void testEncodeDecodeIntegerType(int i, int length) throws Exception
+  {
+    for(byte type : testTypes)
+    {
+      getWriter().writeInteger(type, i);
+
+      ASN1Reader r = getReader(getEncodedBytes());
+      assertEquals(r.peekLength(), length);
+      assertEquals(r.peekType(), 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(long l, int length) throws Exception
+  {
+    getWriter().writeInteger(l);
+
+    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 wiht JavaLongs.
+   *
+   * @param  l The long value to use for the test.
+   */
+  @Test(dataProvider = "longValues")
+  public void testEncodeDecodeIntegerType(long l, int length) throws Exception
+  {
+    for(byte type : testTypes)
+    {
+      getWriter().writeInteger(type, l);
+
+      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();
+
+    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(byte type : testTypes)
+    {
+      getWriter().writeNull(type);
+
+      ASN1Reader r = getReader(getEncodedBytes());
+      assertEquals(r.peekLength(), 0);
+      assertEquals(r.peekType(), type);
+      r.readNull();
+    }
+  }
+
+  /**
+   * Tests the <CODE>write/readOctetString</CODE> methods.
+   */
+  @Test
+  public void testEncodeDecodeOctetStringOffLen() throws Exception
+  {
+    byte[] b = new byte[]{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07};
+
+    for(int i = 0; i < 5; i+=2)
+    {
+      byte[] bsb = new byte[3];
+      System.arraycopy(b, i, bsb, 0, 3);
+      ByteString bs = ByteString.wrap(bsb);
+      getWriter().writeOctetString(b, i, 3);
+
+      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 testEncodeDecodeOctetString(byte[] b) throws Exception
+  {
+    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 = "binaryValues")
+  public void testEncodeDecodeOctetStringType(byte[] b) throws Exception
+  {
+    ByteString bs = ByteString.wrap(b);
+    ByteStringBuilder bsb = new ByteStringBuilder();
+
+    for(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 testEncodeDecodeOctetString(String s) throws Exception
+  {
+    getWriter().writeOctetString(s);
+
+    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("UTF-8").equals(""));
+    }
+    else
+    {
+      assertTrue(s.equals(r.readOctetStringAsString("UTF-8")));
+    }
+  }
+
+  /**
+   * Tests the <CODE>write/readOctetString</CODE> methods.
+   */
+  @Test(dataProvider = "stringValues")
+  public void testEncodeDecodeOctetStringType(String s) throws Exception
+  {
+    for(byte type : testTypes)
+    {
+      getWriter().writeOctetString(type, s);
+
+      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("UTF-8").equals(""));
+      }
+      else
+      {
+        assertTrue(s.equals(r.readOctetStringAsString("UTF-8")));
+      }
+    }
+  }
+
+  @Test
+  public void testEncodeDecodeSequence() throws Exception
+  {
+    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();
+
+    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());
+  }
+}
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/asn1/SocketReadThread.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/asn1/SocketReadThread.java
deleted file mode 100644
index 8a51d56..0000000
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/asn1/SocketReadThread.java
+++ /dev/null
@@ -1,156 +0,0 @@
-/*
- * CDDL HEADER START
- *
- * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
- *
- * You can obtain a copy of the license at
- * trunk/opends/resource/legal-notices/OpenDS.LICENSE
- * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
- * See the License for the specific language governing permissions
- * and limitations under the License.
- *
- * When distributing Covered Code, include this CDDL HEADER in each
- * file and include the License file at
- * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
- * add the following below this CDDL 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.server.protocols.asn1;
-
-
-
-import java.net.InetSocketAddress;
-import java.net.ServerSocket;
-import java.net.Socket;
-
-
-
-/**
- * This class defines a thread that will create a server socket, read data from
- * it, and make that data available in a byte array.
- */
-public class SocketReadThread
-       extends Thread
-{
-  // The server socket that we will use to accept the connection.
-  private ServerSocket serverSocket;
-
-  // The client socket accepted by this thread.
-  private Socket clientSocket;
-
-
-
-  /**
-   * Creates a new server socket on an arbitrarily-selected available port.
-   *
-   * @param  testCaseName  The name of the test case with which this thread is
-   *                       associated.
-   *
-   * @throws  Exception  If a problem occurs while creating the server socket.
-   */
-  public SocketReadThread(String testCaseName)
-         throws Exception
-  {
-    setName("Socket Read Thread -- " + testCaseName);
-    setDaemon(true);
-
-    serverSocket = new ServerSocket();
-    serverSocket.setReuseAddress(true);
-    serverSocket.bind(new InetSocketAddress("127.0.0.1", 0));
-  }
-
-
-
-  /**
-   * Retrieves the port on which the server socket is listening.
-   *
-   * @return  The port on which the server socket is listening.
-   */
-  public int getListenPort()
-  {
-    return serverSocket.getLocalPort();
-  }
-
-
-
-  /**
-   * Accepts a single connection and consumes anything written on that
-   * connection.
-   */
-  public void run()
-  {
-    try
-    {
-      clientSocket = serverSocket.accept();
-    }
-    catch (Exception e)
-    {
-      // FIXME -- What to do here?
-    }
-  }
-
-
-
-  /**
-   * Retrieves the data read from the socket and clears the output stream.
-   *
-   * @param  length  The number of bytes to read.
-   *
-   * @return  The data read from the socket.
-   *
-   * @throws  Exception  If an unexpected problem occurs.
-   */
-  public byte[] getDataRead(int length)
-         throws Exception
-  {
-    while (clientSocket == null)
-    {
-      Thread.sleep(1);
-    }
-
-
-    byte[] buffer = new byte[length];
-    int pos = 0;
-    while (pos < length)
-    {
-      int bytesRead = clientSocket.getInputStream().read(buffer, pos,
-                                                         length-pos);
-      if (bytesRead < 0)
-      {
-        throw new Exception("Hit the end of the stream");
-      }
-
-      pos += bytesRead;
-    }
-
-    return buffer;
-  }
-
-
-
-  /**
-   * Closes the client and server sockets.
-   */
-  public void close()
-  {
-    try
-    {
-      clientSocket.close();
-    } catch (Exception e) {}
-
-    try
-    {
-      serverSocket.close();
-    } catch (Exception e) {}
-  }
-}
-
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/asn1/SocketWriteThread.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/asn1/SocketWriteThread.java
deleted file mode 100644
index 2260e6b..0000000
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/asn1/SocketWriteThread.java
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
- * CDDL HEADER START
- *
- * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
- *
- * You can obtain a copy of the license at
- * trunk/opends/resource/legal-notices/OpenDS.LICENSE
- * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
- * See the License for the specific language governing permissions
- * and limitations under the License.
- *
- * When distributing Covered Code, include this CDDL HEADER in each
- * file and include the License file at
- * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
- * add the following below this CDDL 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.server.protocols.asn1;
-
-
-
-import java.net.Socket;
-
-
-
-/**
- * This class defines a thread that will establish a connection to a server and
- * send it a specified data set.
- */
-public class SocketWriteThread
-       extends Thread
-{
-  // The data to write to the server.
-  private byte[] data;
-
-  // The port to use to connect to the server.
-  private int serverPort;
-
-  // The socket to use to communicate with the server.
-  private Socket socket;
-
-
-
-  /**
-   * Creates a new instance of this write thread that will send data to the
-   * specified server port.
-   *
-   * @param  testCaseName  The name of the test case with which this thread is
-   *                       associated.
-   * @param  serverPort    The port to use to connect to the server.
-   * @param  data          The data to write.
-   */
-  public SocketWriteThread(String testCaseName, int serverPort, byte[] data)
-  {
-    setName("Socket Write Thread -- " + testCaseName);
-    setDaemon(true);
-
-    this.serverPort = serverPort;
-    this.data       = data;
-  }
-
-
-
-  /**
-   * Accepts a single connection and consumes anything written on that
-   * connection.
-   */
-  public void run()
-  {
-    try
-    {
-      socket = new Socket("127.0.0.1", serverPort);
-      socket.getOutputStream().write(data);
-    }
-    catch (Exception e)
-    {
-      // FIXME -- What to do here?
-    }
-  }
-
-
-
-  /**
-   * Closes the connection to the server.
-   */
-  public void close()
-  {
-    try
-    {
-      socket.close();
-    } catch (Exception e) {}
-  }
-}
-
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/asn1/TestASN1Boolean.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/asn1/TestASN1Boolean.java
deleted file mode 100644
index 28cb4b4..0000000
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/asn1/TestASN1Boolean.java
+++ /dev/null
@@ -1,473 +0,0 @@
-/*
- * CDDL HEADER START
- *
- * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
- *
- * You can obtain a copy of the license at
- * trunk/opends/resource/legal-notices/OpenDS.LICENSE
- * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
- * See the License for the specific language governing permissions
- * and limitations under the License.
- *
- * When distributing Covered Code, include this CDDL HEADER in each
- * file and include the License file at
- * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
- * add the following below this CDDL 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.server.protocols.asn1;
-
-
-
-import org.testng.annotations.DataProvider;
-import org.testng.annotations.Test;
-
-import static org.testng.Assert.*;
-
-
-
-/**
- * This class defines a set of tests for the
- * org.opends.server.protocols.asn1.ASN1Boolean class.
- */
-public class TestASN1Boolean
-       extends ASN1TestCase
-{
-  /**
-   * 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 }
-    };
-  }
-
-
-
-  /**
-   * Tests the first constructor, which takes a single boolean argument.
-   *
-   * @param  b  The boolean value to use in the test.
-   */
-  @Test(dataProvider = "booleanValues")
-  public void testConstructor1(boolean b)
-  {
-    new ASN1Boolean(b);
-  }
-
-
-
-  /**
-   * Tests the second constructor, which takes byte and boolean arguments.
-   *
-   * @param  b  The boolean value to use in the test.
-   */
-  @Test(dataProvider = "booleanValues")
-  public void testConstructor2(boolean b)
-  {
-    new ASN1Boolean((byte) 0x50, b);
-  }
-
-
-
-  /**
-   * Tests the <CODE>booleanValue</CODE> method.
-   *
-   * @param  b  The boolean value to use in the test.
-   */
-  @Test(dataProvider = "booleanValues")
-  public void testBooleanValue(boolean b)
-  {
-    assertEquals(new ASN1Boolean(b).booleanValue(), b);
-  }
-
-
-
-  /**
-   * Tests the <CODE>setValue</CODE> method that takes a boolean argument.
-   *
-   * @param  b  The boolean value to use in the test.
-   */
-  @Test(dataProvider = "booleanValues")
-  public void testSetBooleanValue(boolean b)
-  {
-    ASN1Boolean booleanElement = new ASN1Boolean(!b);
-    booleanElement.setValue(b);
-    assertEquals(booleanElement.booleanValue(), b);
-  }
-
-
-
-  /**
-   * 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()
-  {
-    Object[][] array = new Object[256][1];
-    for (int i=0; i < 256; i++)
-    {
-      array[i] = new Object[] { new byte[] { (byte) (i & 0xFF) } };
-    }
-
-    return array;
-  }
-
-
-
-  /**
-   * Tests the <CODE>setValue</CODE> method that takes a byte array argument
-   * with valid values.
-   *
-   * @param  b  The byte array to use in the test.
-   *
-   * @throws  Exception  If an unexpected problem occurs.
-   */
-  @Test(dataProvider = "byteValues")
-  public void testSetValidByteValue(byte[] b)
-         throws Exception
-  {
-    ASN1Boolean booleanElement = new ASN1Boolean(false);
-    booleanElement.setValue(b);
-    assertEquals(booleanElement.booleanValue(), (b[0] != 0x00));
-  }
-
-
-
-  /**
-   * Tests the <CODE>setValue</CODE> method that takes a byte array argument
-   * with a null value.
-   *
-   * @throws  Exception  If an unexpected problem occurs.
-   */
-  @Test(expectedExceptions = { ASN1Exception.class })
-  public void testSetNullByteValue()
-         throws Exception
-  {
-    ASN1Boolean booleanElement = new ASN1Boolean(false);
-    byte[] b = null;
-    booleanElement.setValue(b);
-  }
-
-
-
-  /**
-   * Tests the <CODE>setValue</CODE> method that takes a byte array argument
-   * with an empty array value.
-   *
-   * @throws  Exception  If an unexpected problem occurs.
-   */
-  @Test(expectedExceptions = { ASN1Exception.class })
-  public void testSetZeroByteValue()
-         throws Exception
-  {
-    ASN1Boolean booleanElement = new ASN1Boolean(false);
-    byte[] b = new byte[0];
-    booleanElement.setValue(b);
-  }
-
-
-
-  /**
-   * Tests the <CODE>setValue</CODE> method that takes a byte array argument
-   * with a multi-byte array value.
-   *
-   * @throws  Exception  If an unexpected problem occurs.
-   */
-  @Test(expectedExceptions = { ASN1Exception.class })
-  public void testSetMultiByteValue()
-         throws Exception
-  {
-    ASN1Boolean booleanElement = new ASN1Boolean(false);
-    byte[] b = new byte[2];
-    booleanElement.setValue(b);
-  }
-
-
-
-  /**
-   * Tests the <CODE>decodeAsBoolean</CODE> method that takes an ASN1Element
-   * argument with valid elements.
-   *
-   * @param  b  The byte array to use for the element values.
-   *
-   * @throws  Exception  If an unexpected problem occurs.
-   */
-  @Test(dataProvider = "byteValues")
-  public void testDecodeValidElementAsBoolean(byte[] b)
-         throws Exception
-  {
-    // First, try with an actual boolean element.
-    ASN1Element e = new ASN1Boolean(false);
-    e.setValue(b);
-    ASN1Boolean booleanElement = ASN1Boolean.decodeAsBoolean(e);
-    assertEquals(booleanElement.booleanValue(), (b[0] != 0x00));
-
-    e = new ASN1Boolean((byte) 0x50, false);
-    e.setValue(b);
-    booleanElement = ASN1Boolean.decodeAsBoolean(e);
-    assertEquals(booleanElement.booleanValue(), (b[0] != 0x00));
-
-
-    // Next, test with a generic ASN.1 element.
-    e = new ASN1Element(ASN1Constants.UNIVERSAL_BOOLEAN_TYPE, b);
-    booleanElement = ASN1Boolean.decodeAsBoolean(e);
-    assertEquals(booleanElement.booleanValue(), (b[0] != 0x00));
-
-    e = new ASN1Element((byte) 0x50, b);
-    booleanElement = ASN1Boolean.decodeAsBoolean(e);
-    assertEquals(booleanElement.booleanValue(), (b[0] != 0x00));
-  }
-
-
-
-  /**
-   * Tests the <CODE>decodeAsBoolean</CODE> method that takes an ASN1Element
-   * argument with a null element.
-   *
-   * @throws  Exception  If an unexpected problem occurs.
-   */
-  @Test(expectedExceptions = { ASN1Exception.class })
-  public void testDecodeNullElementAsBoolean()
-         throws Exception
-  {
-    ASN1Element e = null;
-    ASN1Boolean.decodeAsBoolean(e);
-  }
-
-
-
-  /**
-   * Tests the <CODE>decodeAsBoolean</CODE> method that takes an ASN1Element
-   * argument with a zero-byte element.
-   *
-   * @throws  Exception  If an unexpected problem occurs.
-   */
-  @Test(expectedExceptions = { ASN1Exception.class })
-  public void testDecodeZeroByteElementAsBoolean()
-         throws Exception
-  {
-    ASN1Element e = new ASN1Element((byte) 0x50, new byte[0]);
-    ASN1Boolean.decodeAsBoolean(e);
-  }
-
-
-
-  /**
-   * Tests the <CODE>decodeAsBoolean</CODE> method that takes an ASN1Element
-   * argument with a multi-byte element.
-   *
-   * @throws  Exception  If an unexpected problem occurs.
-   */
-  @Test(expectedExceptions = { ASN1Exception.class })
-  public void testDecodeMultiByteElementAsBoolean()
-         throws Exception
-  {
-    ASN1Element e = new ASN1Element((byte) 0x50, new byte[2]);
-    ASN1Boolean.decodeAsBoolean(e);
-  }
-
-
-
-  /**
-   * 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(byte[] b)
-         throws Exception
-  {
-    // First, test with the standard Boolean type.
-    byte[] elementArray = new byte[] { 0x01, 0x01, b[0] };
-    ASN1Boolean booleanElement = ASN1Boolean.decodeAsBoolean(elementArray);
-    assertEquals(booleanElement.booleanValue(), (b[0] != 0x00));
-
-
-    // Next, test with a nonstandard Boolean type.
-    elementArray[0] = (byte) 0x50;
-    booleanElement = ASN1Boolean.decodeAsBoolean(elementArray);
-    assertEquals(booleanElement.booleanValue(), (b[0] != 0x00));
-  }
-
-
-
-  /**
-   * 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(byte[] b)
-         throws Exception
-  {
-    // First, test with the standard Boolean type.
-    byte[] elementArray = new byte[] { 0x01, (byte) 0x81, 0x01, b[0] };
-    ASN1Boolean booleanElement = ASN1Boolean.decodeAsBoolean(elementArray);
-    assertEquals(booleanElement.booleanValue(), (b[0] != 0x00));
-
-
-    // Next, test with a nonstandard Boolean type.
-    elementArray[0] = (byte) 0x50;
-    booleanElement = ASN1Boolean.decodeAsBoolean(elementArray);
-    assertEquals(booleanElement.booleanValue(), (b[0] != 0x00));
-  }
-
-
-
-  /**
-   * Tests the <CODE>decodeAsBoolean</CODE> method that takes a byte array
-   * argument with a null array.
-   *
-   * @throws  Exception  If an unexpected problem occurs.
-   */
-  @Test(expectedExceptions = { ASN1Exception.class })
-  public void testDecodeNullArrayAsBoolean()
-         throws Exception
-  {
-    byte[] b = null;
-    ASN1Boolean.decodeAsBoolean(b);
-  }
-
-
-
-  /**
-   * 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 = { ASN1Exception.class })
-  public void testDecodeShortArrayAsBoolean()
-         throws Exception
-  {
-    byte[] b = new byte[1];
-    ASN1Boolean.decodeAsBoolean(b);
-  }
-
-
-
-  /**
-   * 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 = { ASN1Exception.class })
-  public void testDecodeLongLengthArrayAsBoolean()
-         throws Exception
-  {
-    byte[] b = { 0x01, (byte) 0x85, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00 };
-    ASN1Boolean.decodeAsBoolean(b);
-  }
-
-
-
-  /**
-   * 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 = { ASN1Exception.class })
-  public void testDecodeTruncatedLengthArrayAsBoolean()
-         throws Exception
-  {
-    byte[] b = { 0x01, (byte) 0x82, 0x00 };
-    ASN1Boolean.decodeAsBoolean(b);
-  }
-
-
-
-  /**
-   * Tests the <CODE>decodeAsBoolean</CODE> method that takes a byte array
-   * argument with an array that has more bytes than indicated by the length.
-   *
-   * @throws  Exception  If an unexpected problem occurs.
-   */
-  @Test(expectedExceptions = { ASN1Exception.class })
-  public void testDecodeLengthMismatchArrayAsBoolean()
-         throws Exception
-  {
-    byte[] b = { 0x01, 0x01, 0x00, 0x00 };
-    ASN1Boolean.decodeAsBoolean(b);
-  }
-
-
-
-  /**
-   * 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 = { ASN1Exception.class })
-  public void testDecodeLongValueArrayAsBoolean()
-         throws Exception
-  {
-    byte[] b = { 0x01, 0x02, 0x00, 0x00 };
-    ASN1Boolean.decodeAsBoolean(b);
-  }
-
-
-
-  /**
-   * Tests the first <CODE>toString</CODE> method which takes a string builder
-   * argument.
-   *
-   * @param  b  The byte array to use as the element value.
-   *
-   * @throws  Exception  If an unexpected problem occurs.
-   */
-  @Test(dataProvider = "byteValues")
-  public void testToString1(byte[] b)
-         throws Exception
-  {
-    ASN1Boolean booleanElement = new ASN1Boolean(false);
-    booleanElement.setValue(b);
-    booleanElement.toString(new StringBuilder());
-  }
-
-
-
-  /**
-   * Tests the second <CODE>toString</CODE> method which takes string builder
-   * and integer arguments.
-   *
-   * @param  b  The byte array to use as the element value.
-   *
-   * @throws  Exception  If an unexpected problem occurs.
-   */
-  @Test(dataProvider = "byteValues")
-  public void testToString2(byte[] b)
-         throws Exception
-  {
-    ASN1Boolean booleanElement = new ASN1Boolean(false);
-    booleanElement.setValue(b);
-    booleanElement.toString(new StringBuilder(), 1);
-  }
-}
-
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/asn1/TestASN1Element.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/asn1/TestASN1Element.java
deleted file mode 100644
index c896cf9..0000000
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/asn1/TestASN1Element.java
+++ /dev/null
@@ -1,1383 +0,0 @@
-/*
- * CDDL HEADER START
- *
- * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
- *
- * You can obtain a copy of the license at
- * trunk/opends/resource/legal-notices/OpenDS.LICENSE
- * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
- * See the License for the specific language governing permissions
- * and limitations under the License.
- *
- * When distributing Covered Code, include this CDDL HEADER in each
- * file and include the License file at
- * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
- * add the following below this CDDL 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.server.protocols.asn1;
-
-
-
-import java.util.ArrayList;
-import java.util.LinkedList;
-import java.util.List;
-
-import org.testng.annotations.DataProvider;
-import org.testng.annotations.Test;
-
-import org.opends.server.types.ByteString;
-
-import static org.testng.Assert.*;
-
-
-
-
-/**
- * This class defines a set of tests for the
- * org.opends.server.protocols.asn1.ASN1Element class.
- */
-public class TestASN1Element
-       extends ASN1TestCase
-{
-  /**
-   * Create the values that can be used for testing BER types.
-   *
-   * @return  The values that can be used for testing BER types.
-   */
-  @DataProvider(name = "testTypes")
-  public Object[][] getTestTypes()
-  {
-    // 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.
-    Object[][] testTypes = new Object[0xFF][1];
-    for (int i=0x00; i < 0xFF; i++)
-    {
-      testTypes[i] = new Object[] { (byte) (i & 0xFF) };
-    }
-
-    return testTypes;
-  }
-
-
-
-  /**
-   * Tests the <CODE>getType</CODE> and <CODE>setType</CODE> methods.
-   *
-   * @param  type  The BER type to use in the test.
-   */
-  @Test(dataProvider = "testTypes")
-  public void testGetAndSetType(byte type)
-  {
-    ASN1Element e = new ASN1Element((byte) 0x00);
-    e.setType(type);
-    assertEquals(e.getType(), type);
-  }
-
-
-
-  /**
-   * Tests the <CODE>isUniversal</CODE> method.
-   *
-   * @param  type  The BER type to use in the test.
-   */
-  @Test(dataProvider = "testTypes")
-  public void testIsUniversal(byte type)
-  {
-    boolean isUniversal = (((type & 0xFF) >> 6) == 0x00);
-    assertEquals(new ASN1Element(type).isUniversal(), isUniversal);
-  }
-
-
-
-  /**
-   * Tests the <CODE>isApplicationSpecific</CODE> method.
-   *
-   * @param  type  The BER type to use in the test.
-   */
-  @Test(dataProvider = "testTypes")
-  public void testIsApplicationSpecific(byte type)
-  {
-    boolean isApplicationSpecific = (((type & 0xFF) >> 6) == 0x01);
-    assertEquals(new ASN1Element(type).isApplicationSpecific(),
-                 isApplicationSpecific);
-  }
-
-
-
-  /**
-   * Tests the <CODE>isContextSpecific</CODE> method.
-   *
-   * @param  type  The BER type to use in the test.
-   */
-  @Test(dataProvider = "testTypes")
-  public void testIsContextSpecific(byte type)
-  {
-    boolean isContextSpecific = (((type & 0xFF) >> 6) == 0x02);
-    assertEquals(new ASN1Element(type).isContextSpecific(), isContextSpecific);
-  }
-
-
-
-  /**
-   * Tests the <CODE>isPrivate</CODE> method.
-   *
-   * @param  type  The BER type to use in the test.
-   */
-  @Test(dataProvider = "testTypes")
-  public void testIsPrivate(byte type)
-  {
-    boolean isPrivate = (((type & 0xFF) >> 6) == 0x03);
-    assertEquals(new ASN1Element(type).isPrivate(), isPrivate);
-  }
-
-
-
-  /**
-   * Tests the <CODE>isPrimitive</CODE> method.
-   *
-   * @param  type  The BER type to use in the test.
-   */
-  @Test(dataProvider = "testTypes")
-  public void testIsPrimitive(byte type)
-  {
-    boolean isPrimitive = ((type & 0xDF) == (type & 0xFF));
-    assertEquals(new ASN1Element(type).isPrimitive(), isPrimitive);
-  }
-
-
-
-  /**
-   * Tests the <CODE>isConstructed</CODE> method.
-   *
-   * @param  type  The BER type to use in the test.
-   */
-  @Test(dataProvider = "testTypes")
-  public void testIsConstructed(byte type)
-  {
-    boolean isConstructed = ((type & 0xDF) != (type & 0xFF));
-    assertEquals(new ASN1Element(type).isConstructed(), isConstructed);
-  }
-
-
-
-  /**
-   * Create byte arrays to use for element values.
-   *
-   * @return  A list of byte arrays that can be used as element values.
-   */
-  @DataProvider(name = "testValues")
-  public Object[][] getTestValues()
-  {
-    // NOTE -- Don't make these arrays too big since they consume memory.
-    return new Object[][]
-    {
-      new Object[] { null },              // The null value
-      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
-    };
-  }
-
-
-
-  /**
-   * Tests the <CODE>getValue</CODE> and <CODE>setValue</CODE> methods.
-   *
-   * @param  value  The value to use in the test.
-   *
-   * @throws  Exception  If the test failed unexpectedly.
-   */
-  @Test(dataProvider = "testValues")
-  public void testGetAndSetValue(byte[] value)
-         throws Exception
-  {
-    ASN1Element e = new ASN1Element((byte) 0x00);
-    e.setValue(value);
-
-    if (value == null)
-    {
-      assertEquals(e.value(), new byte[0]);
-    }
-    else
-    {
-      assertEquals(e.value(), value);
-    }
-  }
-
-
-
-  /**
-   * Create decoded and encoded lengths.
-   *
-   * @return  A list of decoded and encoded lengths.
-   */
-  @DataProvider(name = "testLengths")
-  public Object[][] getTestLengths()
-  {
-    return new Object[][]
-    {
-      new Object[] { 0x00, new byte[] { 0x00 } },
-      new Object[] { 0x01, new byte[] { 0x01 } },
-      new Object[] { 0x7F, new byte[] { 0x7F } },
-      new Object[] { 0x80, new byte[] { (byte) 0x81, (byte) 0x80 } },
-      new Object[] { 0xFF, new byte[] { (byte) 0x81, (byte) 0xFF } },
-      new Object[] { 0x0100, new byte[] { (byte) 0x82, 0x01, 0x00 } },
-      new Object[] { 0xFFFF,
-                     new byte[] { (byte) 0x82, (byte) 0xFF, (byte) 0xFF } },
-      new Object[] { 0x010000, new byte[] { (byte) 0x83, 0x01, 0x00, 0x00 } },
-      new Object[] { 0xFFFFFF,
-                     new byte[] { (byte) 0x83, (byte) 0xFF, (byte) 0xFF,
-                                  (byte) 0xFF } },
-      new Object[] { 0x01000000,
-                     new byte[] { (byte) 0x84, 0x01, 0x00, 0x00, 0x00 } },
-      new Object[] { 0x7FFFFFFF,
-                     new byte[] { (byte) 0x84, (byte) 0x7F, (byte) 0xFF,
-                                  (byte) 0xFF, (byte) 0xFF } },
-    };
-  }
-
-
-  /**
-   * Tests the <CODE>encodeLength</CODE> method.
-   *
-   * @param  decodedLength  The decoded length to encode.
-   * @param  encodedLength  The encoded representation of the length.
-   */
-  @Test(dataProvider = "testLengths")
-  public void testEncodeLength(int decodedLength, byte[] encodedLength)
-  {
-    assertEquals(ASN1Element.encodeLength(decodedLength), encodedLength);
-  }
-
-
-
-  /**
-   * Tests the <CODE>encode</CODE> and <CODE>decode</CODE> methods.
-   *
-   * @param  value  The value to use in the test.
-   *
-   * @throws  Exception  If the test failed unexpectedly.
-   */
-  @Test(dataProvider = "testValues")
-  public void testEncodeAndDecode(byte[] value)
-         throws Exception
-  {
-    for (int i=0x00; i < 0xFF; i++)
-    {
-      byte type = (byte) i;
-      ASN1Element e = new ASN1Element(type, value);
-      byte[] encodedElement = e.encode();
-
-      ASN1Element d = ASN1Element.decode(encodedElement);
-      assertEquals(e, d);
-      assertEquals(d.getType(), type);
-      assertTrue(e.equalsElement(d));
-
-      if (value == null)
-      {
-        assertEquals(d.value(), new byte[0]);
-      }
-      else
-      {
-        assertEquals(d.value(), value);
-      }
-
-      d = ASN1Element.decode(encodedElement, 0, encodedElement.length);
-      assertEquals(e, d);
-      assertEquals(d.getType(), type);
-      assertTrue(e.equalsElement(d));
-
-      if (value == null)
-      {
-        assertEquals(d.value(), new byte[0]);
-      }
-      else
-      {
-        assertEquals(d.value(), value);
-      }
-    }
-  }
-
-
-
-  /**
-   * Tests to ensure that there is a failure when trying to decode a null as an
-   * element.
-   *
-   * @throws  Exception  If the test failed unexpectedly.
-   */
-  @Test(expectedExceptions = { ASN1Exception.class })
-  public void testDecodeFailureNull()
-         throws Exception
-  {
-    ASN1Element.decode(null);
-  }
-
-
-
-  /**
-   * Tests the <CODE>decodeAsBoolean</CODE> method.
-   *
-   * @throws  Exception  If the test failed unexpectedly.
-   */
-  @Test()
-  public void testDecodeAsBoolean()
-         throws Exception
-  {
-    // First, make sure that we can decode actual Boolean elements as Boolean
-    // elements, using both the standard type as well as a nonstandard type.
-    boolean[] booleanValues = new boolean[] { true, false };
-    for (boolean b : booleanValues)
-    {
-      ASN1Element e = new ASN1Boolean(b);
-      ASN1Boolean booleanElement = e.decodeAsBoolean();
-      assertEquals(booleanElement.booleanValue(), b);
-
-      e = new ASN1Boolean((byte) 0x50, b);
-      booleanElement = e.decodeAsBoolean();
-      assertEquals(booleanElement.booleanValue(), b);
-    }
-
-
-    // Next, make sure we can decode generic ASN.1 elements with a single-byte
-    // value as a Boolean element.
-    for (int i=0; i < 256; i++)
-    {
-      ASN1Element e = new ASN1Element(ASN1Constants.UNIVERSAL_BOOLEAN_TYPE,
-                                      new byte[] { (byte) i });
-      ASN1Boolean b = e.decodeAsBoolean();
-      assertEquals(b.booleanValue(), (i != 0));
-
-      e = new ASN1Element((byte) 0x50, new byte[] { (byte) i });
-      b = e.decodeAsBoolean();
-      assertEquals(b.booleanValue(), (i != 0));
-    }
-  }
-
-
-
-  /**
-   * Tests the <CODE>decodeAsEnumerated</CODE> method.
-   *
-   * @throws  Exception  If the test failed unexpectedly.
-   */
-  @Test()
-  public void testDecodeAsEnumerated()
-         throws Exception
-  {
-    int[] intValues =
-    {
-      0x00000000,
-      0x00000001,
-      0x0000000F,
-      0x00000010,
-      0x0000007F,
-      0x00000080,
-      0x000000FF,
-      0x00000100,
-      0x00000FFF,
-      0x00001000,
-      0x0000FFFF,
-      0x00010000,
-      0x000FFFFF,
-      0x00100000,
-      0x00FFFFFF,
-      0x01000000,
-      0x0FFFFFFF,
-      0x10000000,
-      0x7FFFFFFF
-    };
-
-    // First, make sure that we can decode actual enumerated elements as
-    // enumerated elements, using both the standard type as well as a
-    // nonstandard type.
-    for (int i : intValues)
-    {
-      ASN1Element e = new ASN1Enumerated(i);
-      ASN1Enumerated enumeratedElement = e.decodeAsEnumerated();
-      assertEquals(enumeratedElement.intValue(), i);
-
-      e = new ASN1Enumerated((byte) 0x50, i);
-      enumeratedElement = e.decodeAsEnumerated();
-      assertEquals(enumeratedElement.intValue(), i);
-    }
-
-
-    // Next, make sure we can decode generic ASN.1 elements as enumerated
-    // elements.
-    for (int i : intValues)
-    {
-      byte[] encoding;
-      if ((i & 0xFF) == i)
-      {
-        encoding = new byte[1];
-        encoding[0] = (byte) (i & 0xFF);
-      }
-      else if ((i & 0xFFFF) == i)
-      {
-        encoding = new byte[2];
-        encoding[0] = (byte) ((i >> 8) & 0xFF);
-        encoding[1] = (byte) (i & 0xFF);
-      }
-      else if ((i & 0xFFFFFF) == i)
-      {
-        encoding = new byte[3];
-        encoding[0] = (byte) ((i >> 16) & 0xFF);
-        encoding[1] = (byte) ((i >> 8) & 0xFF);
-        encoding[2] = (byte) (i & 0xFF);
-      }
-      else
-      {
-        encoding = new byte[4];
-        encoding[0] = (byte) ((i >> 24) & 0xFF);
-        encoding[1] = (byte) ((i >> 16) & 0xFF);
-        encoding[2] = (byte) ((i >> 8) & 0xFF);
-        encoding[3] = (byte) (i & 0xFF);
-      }
-
-      ASN1Element e = new ASN1Element(ASN1Constants.UNIVERSAL_ENUMERATED_TYPE,
-                                      encoding);
-      ASN1Enumerated enumeratedElement = e.decodeAsEnumerated();
-      assertEquals(enumeratedElement.intValue(), i);
-
-      e = new ASN1Element((byte) 0x50, encoding);
-      enumeratedElement = e.decodeAsEnumerated();
-      assertEquals(enumeratedElement.intValue(), i);
-    }
-  }
-
-
-
-  /**
-   * Tests the <CODE>decodeAsInteger</CODE> method.
-   *
-   * @throws  Exception  If the test failed unexpectedly.
-   */
-  @Test()
-  public void testDecodeAsInteger()
-         throws Exception
-  {
-    int[] intValues =
-    {
-      0x00000000,
-      0x00000001,
-      0x0000000F,
-      0x00000010,
-      0x0000007F,
-      0x00000080,
-      0x000000FF,
-      0x00000100,
-      0x00000FFF,
-      0x00001000,
-      0x0000FFFF,
-      0x00010000,
-      0x000FFFFF,
-      0x00100000,
-      0x00FFFFFF,
-      0x01000000,
-      0x0FFFFFFF,
-      0x10000000,
-      0x7FFFFFFF,
-      -0x00000001,
-      -0x0000000F,
-      -0x00000010,
-      -0x0000007F,
-      -0x00000080,
-      -0x000000FF,
-      -0x00000100,
-      -0x00000FFF,
-      -0x00001000,
-      -0x0000FFFF,
-      -0x00010000,
-      -0x000FFFFF,
-      -0x00100000,
-      -0x00FFFFFF,
-      -0x01000000,
-      -0x0FFFFFFF,
-      -0x10000000,
-      -0x7FFFFFFF,
-      0x80000000
-    };
-
-    // First, make sure that we can decode actual integer elements as integer
-    // elements, using both the standard type as well as a nonstandard type.
-    for (int i : intValues)
-    {
-      ASN1Element e = new ASN1Integer(i);
-      ASN1Integer integerElement = e.decodeAsInteger();
-      assertEquals(integerElement.intValue(), i);
-
-      e = new ASN1Integer((byte) 0x50, i);
-      integerElement = e.decodeAsInteger();
-      assertEquals(integerElement.intValue(), i);
-    }
-
-
-    // Next, make sure we can decode generic ASN.1 elements as integer elements.
-    for (int i : intValues)
-    {
-      byte[] encoding;
-      if ((i & 0x7F) == i)
-      {
-        encoding = new byte[1];
-        encoding[0] = (byte) (i & 0xFF);
-      }
-      else if ((i & 0x7FFF) == i)
-      {
-        encoding = new byte[2];
-        encoding[0] = (byte) ((i >> 8) & 0xFF);
-        encoding[1] = (byte) (i & 0xFF);
-      }
-      else if ((i & 0x7FFFFF) == i)
-      {
-        encoding = new byte[3];
-        encoding[0] = (byte) ((i >> 16) & 0xFF);
-        encoding[1] = (byte) ((i >> 8) & 0xFF);
-        encoding[2] = (byte) (i & 0xFF);
-      }
-      else
-      {
-        encoding = new byte[4];
-        encoding[0] = (byte) ((i >> 24) & 0xFF);
-        encoding[1] = (byte) ((i >> 16) & 0xFF);
-        encoding[2] = (byte) ((i >> 8) & 0xFF);
-        encoding[3] = (byte) (i & 0xFF);
-      }
-
-      ASN1Element e = new ASN1Element(ASN1Constants.UNIVERSAL_INTEGER_TYPE,
-                                      encoding);
-      ASN1Integer integerElement = e.decodeAsInteger();
-      assertEquals(integerElement.intValue(), i);
-
-      e = new ASN1Element((byte) 0x50, encoding);
-      integerElement = e.decodeAsInteger();
-      assertEquals(integerElement.intValue(), i);
-    }
-  }
-
-
-
-  /**
-   * Tests the <CODE>decodeAsLong</CODE> method.
-   *
-   * @throws  Exception  If the test failed unexpectedly.
-   */
-  @Test()
-  public void testDecodeAsLong()
-         throws Exception
-  {
-    long[] longValues =
-    {
-      0x0000000000000000L,
-      0x0000000000000001L,
-      0x000000000000007FL,
-      0x0000000000000080L,
-      0x00000000000000FFL,
-      0x0000000000000100L,
-      0x000000000000FFFFL,
-      0x0000000000010000L,
-      0x0000000000FFFFFFL,
-      0x0000000001000000L,
-      0x00000000FFFFFFFFL,
-      0x0000000100000000L,
-      0x000000FFFFFFFFFFL,
-      0x0000010000000000L,
-      0x0000FFFFFFFFFFFFL,
-      0x0001000000000000L,
-      0x00FFFFFFFFFFFFFFL,
-      0x0100000000000000L,
-      0x7FFFFFFFFFFFFFFFL,
-      -0x0000000000000001L,
-      -0x000000000000007FL,
-      -0x0000000000000080L,
-      -0x00000000000000FFL,
-      -0x0000000000000100L,
-      -0x000000000000FFFFL,
-      -0x0000000000010000L,
-      -0x0000000000FFFFFFL,
-      -0x0000000001000000L,
-      -0x00000000FFFFFFFFL,
-      -0x0000000100000000L,
-      -0x000000FFFFFFFFFFL,
-      -0x0000010000000000L,
-      -0x0000FFFFFFFFFFFFL,
-      -0x0001000000000000L,
-      -0x00FFFFFFFFFFFFFFL,
-      -0x0100000000000000L,
-      -0x7FFFFFFFFFFFFFFFL,
-      0x8000000000000000L
-    };
-
-    // First, make sure that we can decode actual long elements as long
-    // elements, using both the standard type as well as a nonstandard type.
-    for (long l : longValues)
-    {
-      ASN1Element e = new ASN1Long(l);
-      ASN1Long longElement = e.decodeAsLong();
-      assertEquals(longElement.longValue(), l);
-
-      e = new ASN1Long((byte) 0x50, l);
-      longElement = e.decodeAsLong();
-      assertEquals(longElement.longValue(), l);
-    }
-
-
-    // Next, make sure we can decode generic ASN.1 elements as long elements.
-    for (long l : longValues)
-    {
-      byte[] encoding;
-      if ((l & 0x7FL) == l)
-      {
-        encoding = new byte[1];
-        encoding[0] = (byte) (l & 0xFF);
-      }
-      else if ((l & 0x7FFFL) == l)
-      {
-        encoding = new byte[2];
-        encoding[0] = (byte) ((l >> 8) & 0xFF);
-        encoding[1] = (byte) (l & 0xFF);
-      }
-      else if ((l & 0x7FFFFFL) == l)
-      {
-        encoding = new byte[3];
-        encoding[0] = (byte) ((l >> 16) & 0xFF);
-        encoding[1] = (byte) ((l >> 8) & 0xFF);
-        encoding[2] = (byte) (l & 0xFF);
-      }
-      else if ((l & 0x7FFFFFFFL) == l)
-      {
-        encoding = new byte[4];
-        encoding[0] = (byte) ((l >> 24) & 0xFF);
-        encoding[1] = (byte) ((l >> 16) & 0xFF);
-        encoding[2] = (byte) ((l >> 8) & 0xFF);
-        encoding[3] = (byte) (l & 0xFF);
-      }
-      else if ((l & 0x7FFFFFFFFFL) == l)
-      {
-        encoding = new byte[5];
-        encoding[0] = (byte) ((l >> 32) & 0xFF);
-        encoding[1] = (byte) ((l >> 24) & 0xFF);
-        encoding[2] = (byte) ((l >> 16) & 0xFF);
-        encoding[3] = (byte) ((l >> 8) & 0xFF);
-        encoding[4] = (byte) (l & 0xFF);
-      }
-      else if ((l & 0x7FFFFFFFFFFFL) == l)
-      {
-        encoding = new byte[6];
-        encoding[0] = (byte) ((l >> 40) & 0xFF);
-        encoding[1] = (byte) ((l >> 32) & 0xFF);
-        encoding[2] = (byte) ((l >> 24) & 0xFF);
-        encoding[3] = (byte) ((l >> 16) & 0xFF);
-        encoding[4] = (byte) ((l >> 8) & 0xFF);
-        encoding[5] = (byte) (l & 0xFF);
-      }
-      else if ((l & 0x7FFFFFFFFFFFFFL) == l)
-      {
-        encoding = new byte[7];
-        encoding[0] = (byte) ((l >> 48) & 0xFF);
-        encoding[1] = (byte) ((l >> 40) & 0xFF);
-        encoding[2] = (byte) ((l >> 32) & 0xFF);
-        encoding[3] = (byte) ((l >> 24) & 0xFF);
-        encoding[4] = (byte) ((l >> 16) & 0xFF);
-        encoding[5] = (byte) ((l >> 8) & 0xFF);
-        encoding[6] = (byte) (l & 0xFF);
-      }
-      else
-      {
-        encoding = new byte[8];
-        encoding[0] = (byte) ((l >> 56) & 0xFF);
-        encoding[1] = (byte) ((l >> 48) & 0xFF);
-        encoding[2] = (byte) ((l >> 40) & 0xFF);
-        encoding[3] = (byte) ((l >> 32) & 0xFF);
-        encoding[4] = (byte) ((l >> 24) & 0xFF);
-        encoding[5] = (byte) ((l >> 16) & 0xFF);
-        encoding[6] = (byte) ((l >> 8) & 0xFF);
-        encoding[7] = (byte) (l & 0xFF);
-      }
-
-      ASN1Element e = new ASN1Element(ASN1Constants.UNIVERSAL_INTEGER_TYPE,
-                                      encoding);
-      ASN1Long longElement = e.decodeAsLong();
-      assertEquals(longElement.longValue(), l);
-
-      e = new ASN1Element((byte) 0x50, encoding);
-      longElement = e.decodeAsLong();
-      assertEquals(longElement.longValue(), l);
-    }
-  }
-
-
-
-  /**
-   * Tests the <CODE>decodeAsNull</CODE> method.
-   *
-   * @throws  Exception  If the test failed unexpectedly.
-   */
-  @Test()
-  public void testDecodeAsNull()
-         throws Exception
-  {
-    // First, make sure that we can decode actual null elements as null
-    // elements, using both the standard type as well as a nonstandard type.
-    ASN1Element e = new ASN1Null();
-    e.decodeAsNull();
-
-    e = new ASN1Null((byte) 0x50);
-    e.decodeAsNull();
-
-
-    // Next, make sure we can decode generic ASN.1 elements with a zero-byte
-    // value as a null element.
-    e = new ASN1Element(ASN1Constants.UNIVERSAL_NULL_TYPE);
-    e.decodeAsNull();
-
-    e = new ASN1Element(ASN1Constants.UNIVERSAL_NULL_TYPE, null);
-    e.decodeAsNull();
-
-    e = new ASN1Element(ASN1Constants.UNIVERSAL_NULL_TYPE, new byte[0]);
-    e.decodeAsNull();
-
-    e = new ASN1Element((byte) 0x50);
-    e.decodeAsNull();
-
-    e = new ASN1Element((byte) 0x50, null);
-    e.decodeAsNull();
-
-    e = new ASN1Element((byte) 0x50, new byte[0]);
-    e.decodeAsNull();
-  }
-
-
-
-  /**
-   * Tests the <CODE>decodeAsOctetString</CODE> method.
-   *
-   * @param  value  The value to use for the octet string element.
-   *
-   * @throws  Exception  If the test failed unexpectedly.
-   */
-  @Test(dataProvider = "testValues")
-  public void testDecodeAsOctetString(byte[] value)
-         throws Exception
-  {
-    // First, make sure that we can decode actual octet string elements as octet
-    // string elements, using both the standard type as well as a nonstandard
-    // type.
-    ASN1Element e = new ASN1OctetString(value);
-    ASN1OctetString octetStringElement = e.decodeAsOctetString();
-    if (value == null)
-    {
-      assertEquals(octetStringElement.value(), new byte[0]);
-    }
-    else
-    {
-      assertEquals(octetStringElement.value(), value);
-    }
-
-    e = new ASN1OctetString((byte) 0x50, value);
-    octetStringElement = e.decodeAsOctetString();
-    if (value == null)
-    {
-      assertEquals(octetStringElement.value(), new byte[0]);
-    }
-    else
-    {
-      assertEquals(octetStringElement.value(), value);
-    }
-
-
-    // Next, make sure that we can decode a generic ASN.1 element as an octet
-    // string element.
-    e = new ASN1Element(ASN1Constants.UNIVERSAL_OCTET_STRING_TYPE, value);
-    octetStringElement = e.decodeAsOctetString();
-    if (value == null)
-    {
-      assertEquals(octetStringElement.value(), new byte[0]);
-    }
-    else
-    {
-      assertEquals(octetStringElement.value(), value);
-    }
-
-    e = new ASN1Element((byte) 0x50, value);
-    octetStringElement = e.decodeAsOctetString();
-    if (value == null)
-    {
-      assertEquals(octetStringElement.value(), new byte[0]);
-    }
-    else
-    {
-      assertEquals(octetStringElement.value(), value);
-    }
-  }
-
-
-
-  /**
-   * Retrieves arrays of ASN.1 elements for use in testing with sequences and
-   * sets.
-   *
-   * @return  Arrays of ASN.1 elements for use in testing with sequences and
-   *          sets.
-   */
-  @DataProvider(name = "elementArrays")
-  public Object[][] getElementArrays()
-  {
-    ArrayList<ASN1Element[]> arrays = new ArrayList<ASN1Element[]>();
-    arrays.add(null);
-    arrays.add(new ASN1Element[0]);
-    arrays.add(new ASN1Element[] { new ASN1Element((byte) 0x50) });
-    arrays.add(new ASN1Element[] { new ASN1Element((byte) 0x50, null) });
-    arrays.add(new ASN1Element[] { new ASN1Element((byte) 0x50, new byte[0]) });
-    arrays.add(new ASN1Element[] { new ASN1Element((byte) 0x50, new byte[1]) });
-    arrays.add(new ASN1Element[] { new ASN1Boolean(true) });
-    arrays.add(new ASN1Element[] { new ASN1Enumerated(0) });
-    arrays.add(new ASN1Element[] { new ASN1Integer(0) });
-    arrays.add(new ASN1Element[] { new ASN1Long(0) });
-    arrays.add(new ASN1Element[] { new ASN1OctetString() });
-    arrays.add(new ASN1Element[] { new ASN1OctetString(),
-                                   new ASN1OctetString() });
-    arrays.add(new ASN1Element[] { new ASN1OctetString(),
-                                   new ASN1OctetString(),
-                                   new ASN1OctetString() });
-    arrays.add(new ASN1Element[] { new ASN1OctetString(),
-                                   new ASN1OctetString(),
-                                   new ASN1OctetString(),
-                                   new ASN1OctetString() });
-    arrays.add(new ASN1Element[] { new ASN1OctetString(),
-                                   new ASN1OctetString(),
-                                   new ASN1OctetString(),
-                                   new ASN1OctetString(),
-                                   new ASN1OctetString() });
-    arrays.add(new ASN1Element[] { new ASN1Integer(1),
-                                   new ASN1Null((byte) 0x42) });
-
-    Object[][] objects = new Object[arrays.size()][];
-    for (int i=0; i < arrays.size(); i++)
-    {
-      objects[i] = new Object[] { arrays.get(i) };
-    }
-
-    return objects;
-  }
-
-
-
-  /**
-   * Tests the <CODE>decodeAsSequence</CODE> method.
-   *
-   * @param  elements  The set of ASN.1 elements to use in the tests.
-   *
-   * @throws  Exception  If the test failed unexpectedly.
-   */
-  @Test(dataProvider = "elementArrays")
-  public void testDecodeAsSequence(ASN1Element[] elements)
-         throws Exception
-  {
-    ArrayList<ASN1Element> elementList = new ArrayList<ASN1Element>();
-    if (elements == null)
-    {
-      elementList = null;
-    }
-    else
-    {
-      for (ASN1Element e : elements)
-      {
-        elementList.add(e);
-      }
-    }
-
-
-    // First, make sure that we can decode actual sequence elements as sequence
-    // elements, using both the standard type as well as a nonstandard type.
-    ASN1Element e = new ASN1Sequence(elementList);
-    ASN1Sequence sequenceElement = e.decodeAsSequence();
-    if (elements == null)
-    {
-      assertEquals(sequenceElement.elements(), new ArrayList<ASN1Element>());
-    }
-    else
-    {
-      assertEquals(sequenceElement.elements(), elementList);
-    }
-
-    e = new ASN1Sequence((byte) 0x50, elementList);
-    sequenceElement = e.decodeAsSequence();
-    if (elements == null)
-    {
-      assertEquals(sequenceElement.elements(), new ArrayList<ASN1Element>());
-    }
-    else
-    {
-      assertEquals(sequenceElement.elements(), elementList);
-    }
-
-
-    // Next, make sure that we can decode a generic ASN.1 element as an octet
-    // string element.
-    e = new ASN1Element(ASN1Constants.UNIVERSAL_SEQUENCE_TYPE,
-                        ASN1Element.encodeValue(elementList));
-    sequenceElement = e.decodeAsSequence();
-    if (elements == null)
-    {
-      assertEquals(sequenceElement.elements(), new ArrayList<ASN1Element>());
-    }
-    else
-    {
-      assertEquals(sequenceElement.elements(), elementList);
-    }
-
-    e = new ASN1Element((byte) 0x50, ASN1Element.encodeValue(elementList));
-    sequenceElement = e.decodeAsSequence();
-    if (elements == null)
-    {
-      assertEquals(sequenceElement.elements(), new ArrayList<ASN1Element>());
-    }
-    else
-    {
-      assertEquals(sequenceElement.elements(), elementList);
-    }
-  }
-
-
-
-  /**
-   * Tests the <CODE>decodeAsSet</CODE> method.
-   *
-   * @param  elements  The set of ASN.1 elements to use in the tests.
-   *
-   * @throws  Exception  If the test failed unexpectedly.
-   */
-  @Test(dataProvider = "elementArrays")
-  public void testDecodeAsSet(ASN1Element[] elements)
-         throws Exception
-  {
-    ArrayList<ASN1Element> elementList = new ArrayList<ASN1Element>();
-    if (elements == null)
-    {
-      elementList = null;
-    }
-    else
-    {
-      for (ASN1Element e : elements)
-      {
-        elementList.add(e);
-      }
-    }
-
-
-    // First, make sure that we can decode actual set elements as set elements,
-    // using both the standard type as well as a nonstandard type.
-    ASN1Element e = new ASN1Set(elementList);
-    ASN1Set setElement = e.decodeAsSet();
-    if (elements == null)
-    {
-      assertEquals(setElement.elements(), new ArrayList<ASN1Element>());
-    }
-    else
-    {
-      assertEquals(setElement.elements(), elementList);
-    }
-
-    e = new ASN1Set((byte) 0x50, elementList);
-    setElement = e.decodeAsSet();
-    if (elements == null)
-    {
-      assertEquals(setElement.elements(), new ArrayList<ASN1Element>());
-    }
-    else
-    {
-      assertEquals(setElement.elements(), elementList);
-    }
-
-
-    // Next, make sure that we can decode a generic ASN.1 element as an octet
-    // string element.
-    e = new ASN1Element(ASN1Constants.UNIVERSAL_SET_TYPE,
-                        ASN1Element.encodeValue(elementList));
-    setElement = e.decodeAsSet();
-    if (elements == null)
-    {
-      assertEquals(setElement.elements(), new ArrayList<ASN1Element>());
-    }
-    else
-    {
-      assertEquals(setElement.elements(), elementList);
-    }
-
-    e = new ASN1Element((byte) 0x50, ASN1Element.encodeValue(elementList));
-    setElement = e.decodeAsSet();
-    if (elements == null)
-    {
-      assertEquals(setElement.elements(), new ArrayList<ASN1Element>());
-    }
-    else
-    {
-      assertEquals(setElement.elements(), elementList);
-    }
-  }
-
-
-
-  /**
-   * Tests the <CODE>equals</CODE>, <CODE>equalsElement</CODE>, and
-   * <CODE>equalsIgnoreType</CODE> methods.
-   *
-   * @param  value  The value to use in the test.
-   */
-  @Test(dataProvider = "testValues")
-  public void testEquals(byte[] value)
-  {
-    ASN1Element controlElement = new ASN1Element((byte) 0x00, value);
-
-    for (int i=0x00; i < 0xFF; i++)
-    {
-      ASN1Element e = new ASN1Element((byte) i, value);
-
-      if (i == 0x00)
-      {
-        assertTrue(controlElement.equals(e));
-        assertTrue(e.equals(controlElement));
-        assertTrue(controlElement.equalsElement(e));
-        assertTrue(e.equalsElement(controlElement));
-      }
-      else
-      {
-        assertFalse(controlElement.equals(e));
-        assertFalse(e.equals(controlElement));
-        assertFalse(controlElement.equalsElement(e));
-        assertFalse(e.equalsElement(controlElement));
-      }
-
-      assertTrue(e.equals(e));
-      assertTrue(e.equalsElement(e));
-      assertTrue(e.equalsIgnoreType(e));
-      assertTrue(e.equalsIgnoreType((ByteString) new ASN1OctetString(value)));
-      assertTrue(controlElement.equalsIgnoreType(e));
-      assertTrue(e.equalsIgnoreType(controlElement));
-      assertFalse(e.equals(null));
-      assertFalse(e.equals("notanelement"));
-    }
-  }
-
-
-
-  /**
-   * Tests the <CODE>decode</CODE> method taking an array argument with an
-   * invalid element that is too short to be valid.
-   *
-   * @throws  Exception  If the test failed unexpectedly.
-   */
-  @Test(expectedExceptions = { ASN1Exception.class })
-  public void testDecodeShortElement1()
-         throws Exception
-  {
-    ASN1Element.decode(new byte[1]);
-  }
-
-
-
-  /**
-   * Tests the <CODE>decode</CODE> method taking an array and two integer
-   * arguments with an invalid element that is too short to be valid.
-   *
-   * @throws  Exception  If the test failed unexpectedly.
-   */
-  @Test(expectedExceptions = { ASN1Exception.class })
-  public void testDecodeShortElement2()
-         throws Exception
-  {
-    ASN1Element.decode(new byte[1], 0, 1);
-  }
-
-
-
-  /**
-   * Tests the <CODE>decode</CODE> method taking an array argument with a null
-   * element.
-   *
-   * @throws  Exception  If the test failed unexpectedly.
-   */
-  @Test(expectedExceptions = { ASN1Exception.class })
-  public void testDecodeNull1()
-         throws Exception
-  {
-    ASN1Element.decode(null);
-  }
-
-
-
-  /**
-   * Tests the <CODE>decode</CODE> method taking an array and two integer
-   * arguments with a null element.
-   *
-   * @throws  Exception  If the test failed unexpectedly.
-   */
-  @Test(expectedExceptions = { ASN1Exception.class })
-  public void testDecodeNull2()
-         throws Exception
-  {
-    ASN1Element.decode(null, 0, 0);
-  }
-
-
-
-  /**
-   * Tests the <CODE>decode</CODE> method taking an array argument with an
-   * element indicating that it takes more than four bytes to describe the
-   * length.
-   *
-   * @throws  Exception  If the test failed unexpectedly.
-   */
-  @Test(expectedExceptions = { ASN1Exception.class })
-  public void testDecodeLongLength1()
-         throws Exception
-  {
-    byte[] elementBytes =
-    {
-      0x04,
-      (byte) 0x85,
-      0x00,
-      0x00,
-      0x00,
-      0x00,
-      0x00
-    };
-
-    ASN1Element.decode(elementBytes);
-  }
-
-
-
-  /**
-   * Tests the <CODE>decode</CODE> method taking an array and two integer
-   * arguments with an indicating that it takes more than four bytes to describe
-   * the length.
-   *
-   * @throws  Exception  If the test failed unexpectedly.
-   */
-  @Test(expectedExceptions = { ASN1Exception.class })
-  public void testDecodeLongLength2()
-         throws Exception
-  {
-    byte[] elementBytes =
-    {
-      0x04,
-      (byte) 0x85,
-      0x00,
-      0x00,
-      0x00,
-      0x00,
-      0x00
-    };
-
-    ASN1Element.decode(elementBytes, 0, elementBytes.length);
-  }
-
-
-
-  /**
-   * Tests the <CODE>decode</CODE> method taking an array argument with an
-   * element that isn't long enough to fully decode the length.
-   *
-   * @throws  Exception  If the test failed unexpectedly.
-   */
-  @Test(expectedExceptions = { ASN1Exception.class })
-  public void testDecodeTruncatedLength1()
-         throws Exception
-  {
-    byte[] elementBytes =
-    {
-      0x04,
-      (byte) 0x82,
-      0x00
-   };
-
-    ASN1Element.decode(elementBytes);
-  }
-
-
-
-  /**
-   * Tests the <CODE>decode</CODE> method taking an array and two integer
-   * arguments with an element that isn't long enough to fully decode the
-   * length.
-   *
-   * @throws  Exception  If the test failed unexpectedly.
-   */
-  @Test(expectedExceptions = { ASN1Exception.class })
-  public void testDecodeTruncatedLength2()
-         throws Exception
-  {
-    byte[] elementBytes =
-    {
-      0x04,
-      (byte) 0x82,
-      0x00
-   };
-
-    ASN1Element.decode(elementBytes, 0, elementBytes.length);
-  }
-
-
-
-  /**
-   * Tests the <CODE>decode</CODE> method taking an array argument with an
-   * element whose decoded length doesn't match the number of bytes remaining.
-   *
-   * @throws  Exception  If the test failed unexpectedly.
-   */
-  @Test(expectedExceptions = { ASN1Exception.class })
-  public void testDecodeLengthMismatch1()
-         throws Exception
-  {
-    byte[] elementBytes =
-    {
-      0x04,
-      0x01,
-      0x00,
-      0x00
-   };
-
-    ASN1Element.decode(elementBytes);
-  }
-
-
-
-  /**
-   * Tests the <CODE>decode</CODE> method taking an array and two integer
-   * arguments with an element whose decoded length doesn't match the number of
-   * bytes remaining.
-   *
-   * @throws  Exception  If the test failed unexpectedly.
-   */
-  @Test(expectedExceptions = { ASN1Exception.class })
-  public void testDecodeLengthMismatch2()
-         throws Exception
-  {
-    byte[] elementBytes =
-    {
-      0x04,
-      0x01,
-      0x00,
-      0x00
-   };
-
-    ASN1Element.decode(elementBytes, 0, elementBytes.length);
-  }
-
-
-
-  /**
-   * Tests the <CODE>decodeElements</CODE> method taking an array with a null
-   * array.
-   *
-   * @throws  Exception  If the test failed unexpectedly.
-   */
-  @Test(expectedExceptions = { ASN1Exception.class })
-  public void testDecodeElementsNull()
-         throws Exception
-  {
-    ASN1Element.decodeElements(null);
-  }
-
-
-
-  /**
-   * Tests the <CODE>decodeElements</CODE> method taking an array with an array
-   * containing an element with too many bytes used to describe the length.
-   *
-   * @throws  Exception  If the test failed unexpectedly.
-   */
-  @Test(expectedExceptions = { ASN1Exception.class })
-  public void testDecodeElementsLongLength()
-         throws Exception
-  {
-    byte[] elementBytes =
-    {
-      0x04,
-      (byte) 0x85,
-      0x00,
-      0x00,
-      0x00,
-      0x00,
-      0x00
-    };
-
-    ASN1Element.decodeElements(elementBytes);
-  }
-
-
-
-  /**
-   * Tests the <CODE>decodeElements</CODE> method taking an array with an array
-   * containing an element without enough bytes to fully decode the length.
-   *
-   * @throws  Exception  If the test failed unexpectedly.
-   */
-  @Test(expectedExceptions = { ASN1Exception.class })
-  public void testDecodeElementsTruncatedLength()
-         throws Exception
-  {
-    byte[] elementBytes =
-    {
-      0x04,
-      (byte) 0x82,
-      0x00,
-    };
-
-    ASN1Element.decodeElements(elementBytes);
-  }
-
-
-
-  /**
-   * Tests the <CODE>equalsElement</CODE> method taking an array with a null
-   * array.
-   *
-   * @throws  Exception  If the test failed unexpectedly.
-   */
-  @Test()
-  public void testEqualsElementNull()
-         throws Exception
-  {
-    ASN1Element e = new ASN1OctetString();
-    assertFalse(e.equalsElement(null));
-  }
-
-
-
-  /**
-   * Tests miscellaneous methods, including <CODE>toString</CODE> and
-   * <CODE>getProtocolElementName</CODE> that don't fit in anywhere else.
-   *
-   * @param  value  The value to use in the test.
-   */
-  @Test(dataProvider = "testValues")
-  public void testMiscellaneous(byte[] value)
-  {
-    for (int i=0x00; i < 0xFF; i++)
-    {
-      byte type = (byte) i;
-      ASN1Element e = new ASN1Element(type, value);
-      e.toString();
-      e.toString(new StringBuilder());
-      e.toString(new StringBuilder(), 1);
-      assertEquals(e.getProtocolElementName(), "ASN.1");
-    }
-  }
-}
-
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/asn1/TestASN1Enumerated.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/asn1/TestASN1Enumerated.java
deleted file mode 100644
index 94db01b..0000000
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/asn1/TestASN1Enumerated.java
+++ /dev/null
@@ -1,573 +0,0 @@
-/*
- * CDDL HEADER START
- *
- * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
- *
- * You can obtain a copy of the license at
- * trunk/opends/resource/legal-notices/OpenDS.LICENSE
- * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
- * See the License for the specific language governing permissions
- * and limitations under the License.
- *
- * When distributing Covered Code, include this CDDL HEADER in each
- * file and include the License file at
- * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
- * add the following below this CDDL 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.server.protocols.asn1;
-
-
-
-import org.testng.annotations.DataProvider;
-import org.testng.annotations.Test;
-
-import static org.testng.Assert.*;
-
-
-
-/**
- * This class defines a set of tests for the
- * org.opends.server.protocols.asn1.ASN1Enumerated class.
- */
-public class TestASN1Enumerated
-       extends ASN1TestCase
-{
-  /**
-   * 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 },
-      new Object[] { 0x00000001 },
-      new Object[] { 0x0000000F },
-      new Object[] { 0x00000010 },
-      new Object[] { 0x0000007F },
-      new Object[] { 0x00000080 },
-      new Object[] { 0x000000FF },
-      new Object[] { 0x00000100 },
-      new Object[] { 0x00000FFF },
-      new Object[] { 0x00001000 },
-      new Object[] { 0x0000FFFF },
-      new Object[] { 0x00010000 },
-      new Object[] { 0x000FFFFF },
-      new Object[] { 0x00100000 },
-      new Object[] { 0x00FFFFFF },
-      new Object[] { 0x01000000 },
-      new Object[] { 0x0FFFFFFF },
-      new Object[] { 0x10000000 },
-      new Object[] { 0x7FFFFFFF }
-    };
-  }
-
-
-
-  /**
-   * Tests the first constructor, which takes a single integer argument.
-   *
-   * @param  i  The integer value to use to create the element.
-   */
-  @Test(dataProvider = "intValues")
-  public void testConstructor1(int i)
-  {
-    new ASN1Enumerated(i);
-  }
-
-
-
-  /**
-   * Tests the second constructor, which takes byte and integer arguments.
-   *
-   * @param  i  The integer value to use to create the element.
-   */
-  @Test(dataProvider = "intValues")
-  public void testConstructor2(int i)
-  {
-    new ASN1Enumerated((byte) 0x50, i);
-  }
-
-
-
-  /**
-   * Tests the <CODE>intValue</CODE> method.
-   *
-   * @param  i  The integer value to use for the test.
-   */
-  @Test(dataProvider = "intValues")
-  public void testIntValue(int i)
-  {
-    assertEquals(new ASN1Enumerated(i).intValue(), i);
-  }
-
-
-
-  /**
-   * Tests the <CODE>setValue</CODE> method that takes an int argument.
-   *
-   * @param  i  The integer value to use for the test.
-   */
-  @Test(dataProvider = "intValues")
-  public void testSetIntValue(int i)
-  {
-    ASN1Enumerated enumeratedElement = new ASN1Enumerated(0);
-    enumeratedElement.setValue(i);
-    assertEquals(enumeratedElement.intValue(), i);
-  }
-
-
-
-  /**
-   * Tests the <CODE>setValue</CODE> method that takes a byte array argument
-   * with a valid array.
-   *
-   * @param  i  The integer value to use for the test.
-   *
-   * @throws  Exception  If an unexpected problem occurs.
-   */
-  @Test(dataProvider = "intValues")
-  public void testSetByteValue(int i)
-         throws Exception
-  {
-    ASN1Enumerated enumeratedElement = new ASN1Enumerated(0);
-
-    byte[] encoding;
-    if ((i & 0xFF) == i)
-    {
-      encoding = new byte[1];
-      encoding[0] = (byte) (i & 0xFF);
-    }
-    else if ((i & 0xFFFF) == i)
-    {
-      encoding = new byte[2];
-      encoding[0] = (byte) ((i >> 8) & 0xFF);
-      encoding[1] = (byte) (i & 0xFF);
-    }
-    else if ((i & 0xFFFFFF) == i)
-    {
-      encoding = new byte[3];
-      encoding[0] = (byte) ((i >> 16) & 0xFF);
-      encoding[1] = (byte) ((i >> 8) & 0xFF);
-      encoding[2] = (byte) (i & 0xFF);
-    }
-    else
-    {
-      encoding = new byte[4];
-      encoding[0] = (byte) ((i >> 24) & 0xFF);
-      encoding[1] = (byte) ((i >> 16) & 0xFF);
-      encoding[2] = (byte) ((i >> 8) & 0xFF);
-      encoding[3] = (byte) (i & 0xFF);
-    }
-
-    enumeratedElement.setValue(encoding);
-    assertEquals(enumeratedElement.intValue(), i);
-  }
-
-
-
-  /**
-   * Tests the <CODE>setValue</CODE> method that takes a byte array argument
-   * with a null array.
-   *
-   * @throws  Exception  If an unexpected problem occurs.
-   */
-  @Test(expectedExceptions = { ASN1Exception.class })
-  public void testSetByteValueNull()
-         throws Exception
-  {
-    ASN1Enumerated enumeratedElement = new ASN1Enumerated(0);
-
-    byte[] b = null;
-    enumeratedElement.setValue(b);
-  }
-
-
-
-  /**
-   * Tests the <CODE>setValue</CODE> method that takes a byte array argument
-   * with an empty array.
-   *
-   * @throws  Exception  If an unexpected problem occurs.
-   */
-  @Test(expectedExceptions = { ASN1Exception.class })
-  public void testSetByteValueEmptyArray()
-         throws Exception
-  {
-    ASN1Enumerated enumeratedElement = new ASN1Enumerated(0);
-
-    byte[] b = new byte[0];
-    enumeratedElement.setValue(b);
-  }
-
-
-
-  /**
-   * Tests the <CODE>setValue</CODE> method that takes a byte array argument
-   * with a long array.
-   *
-   * @throws  Exception  If an unexpected problem occurs.
-   */
-  @Test(expectedExceptions = { ASN1Exception.class })
-  public void testSetByteValueLongArray()
-         throws Exception
-  {
-    ASN1Enumerated enumeratedElement = new ASN1Enumerated(0);
-
-    byte[] b = new byte[5];
-    enumeratedElement.setValue(b);
-  }
-
-
-
-  /**
-   * Tests the <CODE>decodeAsEnumerated</CODE> method that takes an ASN1Element
-   * arguent using a valid value.
-   *
-   * @param i  The integer value to use in the test.
-   *
-   * @throws  Exception  If an unexpected problem occurs.
-   */
-  @Test(dataProvider = "intValues")
-  public void testDecodeValidElementAsEnumerated(int i)
-         throws Exception
-  {
-    // First, make sure that we can decode an integer element as an integer.
-    ASN1Element e = new ASN1Enumerated(i);
-    ASN1Enumerated enumeratedElement = ASN1Enumerated.decodeAsEnumerated(e);
-    assertEquals(enumeratedElement.intValue(), i);
-
-    e = new ASN1Enumerated((byte) 0x50, i);
-    enumeratedElement = ASN1Enumerated.decodeAsEnumerated(e);
-    assertEquals(enumeratedElement.intValue(), i);
-
-
-    // Next, make sure that we can decode a generic element as an integer.
-    byte[] encoding;
-    if ((i & 0xFF) == i)
-    {
-      encoding = new byte[1];
-      encoding[0] = (byte) (i & 0xFF);
-    }
-    else if ((i & 0xFFFF) == i)
-    {
-      encoding = new byte[2];
-      encoding[0] = (byte) ((i >> 8) & 0xFF);
-      encoding[1] = (byte) (i & 0xFF);
-    }
-    else if ((i & 0xFFFFFF) == i)
-    {
-      encoding = new byte[3];
-      encoding[0] = (byte) ((i >> 16) & 0xFF);
-      encoding[1] = (byte) ((i >> 8) & 0xFF);
-      encoding[2] = (byte) (i & 0xFF);
-    }
-    else
-    {
-      encoding = new byte[4];
-      encoding[0] = (byte) ((i >> 24) & 0xFF);
-      encoding[1] = (byte) ((i >> 16) & 0xFF);
-      encoding[2] = (byte) ((i >> 8) & 0xFF);
-      encoding[3] = (byte) (i & 0xFF);
-    }
-
-    e = new ASN1Element(ASN1Constants.UNIVERSAL_ENUMERATED_TYPE, encoding);
-    enumeratedElement = ASN1Enumerated.decodeAsEnumerated(e);
-    assertEquals(enumeratedElement.intValue(), i);
-
-    e = new ASN1Element((byte) 0x50, encoding);
-    enumeratedElement = ASN1Enumerated.decodeAsEnumerated(e);
-    assertEquals(enumeratedElement.intValue(), i);
-  }
-
-
-
-  /**
-   * Tests the <CODE>decodeAsEnumerated</CODE> method that takes an ASN1Element
-   * arguent using a valid value.
-   *
-   * @throws  Exception  If an unexpected problem occurs.
-   */
-  @Test(expectedExceptions = { ASN1Exception.class })
-  public void testDecodeNullElementAsEnumerated()
-         throws Exception
-  {
-    ASN1Element e = null;
-    ASN1Enumerated.decodeAsEnumerated(e);
-  }
-
-
-
-  /**
-   * Tests the <CODE>decodeAsEnumerated</CODE> method that takes an ASN1Element
-   * arguent a zero-length element.
-   *
-   * @throws  Exception  If an unexpected problem occurs.
-   */
-  @Test(expectedExceptions = { ASN1Exception.class })
-  public void testDecodeZeroLengthElementAsEnumerated()
-         throws Exception
-  {
-    ASN1Element e = new ASN1Element(ASN1Constants.UNIVERSAL_ENUMERATED_TYPE);
-    ASN1Enumerated.decodeAsEnumerated(e);
-  }
-
-
-
-  /**
-   * Tests the <CODE>decodeAsEnumerated</CODE> method that takes an ASN1Element
-   * arguent a long value element.
-   *
-   * @throws  Exception  If an unexpected problem occurs.
-   */
-  @Test(expectedExceptions = { ASN1Exception.class })
-  public void testDecodeLongValueElementAsEnumerated()
-         throws Exception
-  {
-    ASN1Element e = new ASN1Element(ASN1Constants.UNIVERSAL_ENUMERATED_TYPE,
-                                    new byte[5]);
-    ASN1Enumerated.decodeAsEnumerated(e);
-  }
-
-
-
-  /**
-   * Tests the <CODE>decodeAsEnumerated</CODE> method that takes a byte array
-   * with a valid array.
-   *
-   * @param i  The integer value to use in the test.
-   *
-   * @throws  Exception  If an unexpected problem occurs.
-   */
-  @Test(dataProvider = "intValues")
-  public void testDecodeValidArrayAsEnumerated(int i)
-         throws Exception
-  {
-    byte[] encoding;
-    if ((i & 0xFF) == i)
-    {
-      encoding = new byte[1];
-      encoding[0] = (byte) (i & 0xFF);
-    }
-    else if ((i & 0xFFFF) == i)
-    {
-      encoding = new byte[2];
-      encoding[0] = (byte) ((i >> 8) & 0xFF);
-      encoding[1] = (byte) (i & 0xFF);
-    }
-    else if ((i & 0xFFFFFF) == i)
-    {
-      encoding = new byte[3];
-      encoding[0] = (byte) ((i >> 16) & 0xFF);
-      encoding[1] = (byte) ((i >> 8) & 0xFF);
-      encoding[2] = (byte) (i & 0xFF);
-    }
-    else
-    {
-      encoding = new byte[4];
-      encoding[0] = (byte) ((i >> 24) & 0xFF);
-      encoding[1] = (byte) ((i >> 16) & 0xFF);
-      encoding[2] = (byte) ((i >> 8) & 0xFF);
-      encoding[3] = (byte) (i & 0xFF);
-    }
-
-    byte[] encodedElement = new byte[2 + encoding.length];
-    encodedElement[0] = ASN1Constants.UNIVERSAL_ENUMERATED_TYPE;
-    encodedElement[1] = (byte) encoding.length;
-    System.arraycopy(encoding, 0, encodedElement, 2, encoding.length);
-
-    ASN1Enumerated enumeratedElement =
-         ASN1Enumerated.decodeAsEnumerated(encodedElement);
-    assertEquals(enumeratedElement.intValue(), i);
-  }
-
-
-
-  /**
-   * Tests the <CODE>decodeAsEnumerated</CODE> method that takes a byte array
-   * with a valid extended length array.
-   *
-   * @param i  The integer value to use in the test.
-   *
-   * @throws  Exception  If an unexpected problem occurs.
-   */
-  @Test(dataProvider = "intValues")
-  public void testDecodeValidExtendedLengthArrayAsEnumerated(int i)
-         throws Exception
-  {
-    byte[] encoding;
-    if ((i & 0xFF) == i)
-    {
-      encoding = new byte[1];
-      encoding[0] = (byte) (i & 0xFF);
-    }
-    else if ((i & 0xFFFF) == i)
-    {
-      encoding = new byte[2];
-      encoding[0] = (byte) ((i >> 8) & 0xFF);
-      encoding[1] = (byte) (i & 0xFF);
-    }
-    else if ((i & 0xFFFFFF) == i)
-    {
-      encoding = new byte[3];
-      encoding[0] = (byte) ((i >> 16) & 0xFF);
-      encoding[1] = (byte) ((i >> 8) & 0xFF);
-      encoding[2] = (byte) (i & 0xFF);
-    }
-    else
-    {
-      encoding = new byte[4];
-      encoding[0] = (byte) ((i >> 24) & 0xFF);
-      encoding[1] = (byte) ((i >> 16) & 0xFF);
-      encoding[2] = (byte) ((i >> 8) & 0xFF);
-      encoding[3] = (byte) (i & 0xFF);
-    }
-
-    byte[] encodedElement = new byte[3 + encoding.length];
-    encodedElement[0] = ASN1Constants.UNIVERSAL_ENUMERATED_TYPE;
-    encodedElement[1] = (byte) 0x81;
-    encodedElement[2] = (byte) encoding.length;
-    System.arraycopy(encoding, 0, encodedElement, 3, encoding.length);
-
-    ASN1Enumerated enumeratedElement =
-         ASN1Enumerated.decodeAsEnumerated(encodedElement);
-    assertEquals(enumeratedElement.intValue(),i);
-  }
-
-
-
-  /**
-   * Tests the <CODE>decodeAsEnumerated</CODE> method that takes a byte array
-   * with a null array.
-   *
-   * @throws  Exception  If an unexpected problem occurs.
-   */
-  @Test(expectedExceptions = { ASN1Exception.class })
-  public void testDecodeNullArrayAsEnumerated()
-         throws Exception
-  {
-    byte[] b = null;
-    ASN1Enumerated.decodeAsEnumerated(b);
-  }
-
-
-
-  /**
-   * Tests the <CODE>decodeAsEnumerated</CODE> method that takes a byte array
-   * with a short array.
-   *
-   * @throws  Exception  If an unexpected problem occurs.
-   */
-  @Test(expectedExceptions = { ASN1Exception.class })
-  public void testDecodeShortArrayAsEnumerated()
-         throws Exception
-  {
-    byte[] b = new byte[0];
-    ASN1Enumerated.decodeAsEnumerated(b);
-  }
-
-
-
-  /**
-   * Tests the <CODE>decodeAsEnumerated</CODE> method that takes a byte array
-   * with a long length array.
-   *
-   * @throws  Exception  If an unexpected problem occurs.
-   */
-  @Test(expectedExceptions = { ASN1Exception.class })
-  public void testDecodeLongLengthArrayAsEnumerated()
-         throws Exception
-  {
-    byte[] b = { 0x02, (byte) 0x85, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00 };
-    ASN1Enumerated.decodeAsEnumerated(b);
-  }
-
-
-
-  /**
-   * Tests the <CODE>decodeAsEnumerated</CODE> method that takes a byte array
-   * with a truncated length array.
-   *
-   * @throws  Exception  If an unexpected problem occurs.
-   */
-  @Test(expectedExceptions = { ASN1Exception.class })
-  public void testDecodeTruncatedLengthArrayAsEnumerated()
-         throws Exception
-  {
-    byte[] b = { 0x02, (byte) 0x82, 0x00 };
-    ASN1Enumerated.decodeAsEnumerated(b);
-  }
-
-
-
-  /**
-   * Tests the <CODE>decodeAsEnumerated</CODE> method that takes a byte array
-   * with a length mismatch.
-   *
-   * @throws  Exception  If an unexpected problem occurs.
-   */
-  @Test(expectedExceptions = { ASN1Exception.class })
-  public void testDecodeLengthMismatchArrayAsEnumerated()
-         throws Exception
-  {
-    byte[] b = { 0x02, (byte) 0x81, 0x01 };
-    ASN1Enumerated.decodeAsEnumerated(b);
-  }
-
-
-
-  /**
-   * Tests the <CODE>decodeAsEnumerated</CODE> method that takes a byte array
-   * with a value too long for an integer.
-   *
-   * @throws  Exception  If an unexpected problem occurs.
-   */
-  @Test(expectedExceptions = { ASN1Exception.class })
-  public void testDecodeLongIntLengthArrayAsEnumerated()
-         throws Exception
-  {
-    byte[] b = { 0x02, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00 };
-    ASN1Enumerated.decodeAsEnumerated(b);
-  }
-
-
-
-  /**
-   * Tests the first <CODE>toString</CODE> method that takes a string builder
-   * argument.
-   *
-   * @param  i  The integer value to use in the test.
-   */
-  @Test(dataProvider = "intValues")
-  public void testToString1(int i)
-  {
-    new ASN1Enumerated(i).toString(new StringBuilder());
-  }
-
-
-
-  /**
-   * Tests the second <CODE>toString</CODE> method that takes string builder and
-   * integer arguments.
-   *
-   * @param  i  The integer value to use in the test.
-   */
-  @Test(dataProvider = "intValues")
-  public void testToString2(int i)
-  {
-    new ASN1Enumerated(i).toString(new StringBuilder(), 1);
-  }
-}
-
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/asn1/TestASN1Exception.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/asn1/TestASN1Exception.java
deleted file mode 100644
index 3a41840..0000000
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/asn1/TestASN1Exception.java
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * CDDL HEADER START
- *
- * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
- *
- * You can obtain a copy of the license at
- * trunk/opends/resource/legal-notices/OpenDS.LICENSE
- * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
- * See the License for the specific language governing permissions
- * and limitations under the License.
- *
- * When distributing Covered Code, include this CDDL HEADER in each
- * file and include the License file at
- * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
- * add the following below this CDDL 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.server.protocols.asn1;
-
-
-
-import org.testng.annotations.Test;
-
-import static org.testng.Assert.*;
-import org.opends.messages.Message;
-
-
-/**
- * This class defines a set of tests for the
- * org.opends.server.protocols.asn1.ASN1Exception class.
- */
-public class TestASN1Exception
-       extends ASN1TestCase
-{
-  /**
-   * Tests the first constructor, which takes integer and string arguments.
-   */
-  @Test()
-  public void testConstructor1()
-  {
-    new ASN1Exception(Message.raw("Test"));
-  }
-
-
-
-  /**
-   * Tests the second constructor, which takes integer, string, and throwable
-   * arguments.
-   */
-  @Test()
-  public void testConstructor2()
-  {
-    new ASN1Exception(Message.raw("Test"), new Exception());
-  }
-
-}
-
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/asn1/TestASN1Integer.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/asn1/TestASN1Integer.java
deleted file mode 100644
index d3b1247..0000000
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/asn1/TestASN1Integer.java
+++ /dev/null
@@ -1,639 +0,0 @@
-/*
- * CDDL HEADER START
- *
- * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
- *
- * You can obtain a copy of the license at
- * trunk/opends/resource/legal-notices/OpenDS.LICENSE
- * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
- * See the License for the specific language governing permissions
- * and limitations under the License.
- *
- * When distributing Covered Code, include this CDDL HEADER in each
- * file and include the License file at
- * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
- * add the following below this CDDL 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.server.protocols.asn1;
-
-
-
-import org.testng.annotations.DataProvider;
-import org.testng.annotations.Test;
-
-import static org.testng.Assert.*;
-
-
-
-/**
- * This class defines a set of tests for the
- * org.opends.server.protocols.asn1.ASN1Integer class.
- */
-public class TestASN1Integer
-       extends ASN1TestCase
-{
-  /**
-   * 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 },
-      new Object[] { 0x00000001 },
-      new Object[] { 0x0000000F },
-      new Object[] { 0x00000010 },
-      new Object[] { 0x0000007F },
-      new Object[] { 0x00000080 },
-      new Object[] { 0x000000FF },
-      new Object[] { 0x00000100 },
-      new Object[] { 0x00000FFF },
-      new Object[] { 0x00001000 },
-      new Object[] { 0x0000FFFF },
-      new Object[] { 0x00010000 },
-      new Object[] { 0x000FFFFF },
-      new Object[] { 0x00100000 },
-      new Object[] { 0x00FFFFFF },
-      new Object[] { 0x01000000 },
-      new Object[] { 0x0FFFFFFF },
-      new Object[] { 0x10000000 },
-      new Object[] { 0x7FFFFFFF },
-      new Object[] { -0x00000001 },
-      new Object[] { -0x0000000F },
-      new Object[] { -0x00000010 },
-      new Object[] { -0x0000007F },
-      new Object[] { -0x00000080 },
-      new Object[] { -0x000000FF },
-      new Object[] { -0x00000100 },
-      new Object[] { -0x00000FFF },
-      new Object[] { -0x00001000 },
-      new Object[] { -0x0000FFFF },
-      new Object[] { -0x00010000 },
-      new Object[] { -0x000FFFFF },
-      new Object[] { -0x00100000 },
-      new Object[] { -0x00FFFFFF },
-      new Object[] { -0x01000000 },
-      new Object[] { -0x0FFFFFFF },
-      new Object[] { -0x10000000 },
-      new Object[] { -0x7FFFFFFF },
-      new Object[] { 0x80000000 }
-    };
-  }
-
-
-
-  /**
-   * Tests the first constructor, which takes a single integer argument.
-   *
-   * @param  i  The integer value to use to create the element.
-   */
-  @Test(dataProvider = "intValues")
-  public void testConstructor1(int i)
-  {
-    new ASN1Integer(i);
-  }
-
-
-
-  /**
-   * Tests the second constructor, which takes byte and integer arguments.
-   *
-   * @param  i  The integer value to use to create the element.
-   */
-  @Test(dataProvider = "intValues")
-  public void testConstructor2(int i)
-  {
-    new ASN1Integer((byte) 0x50, i);
-  }
-
-
-
-  /**
-   * Tests the <CODE>intValue</CODE> method.
-   *
-   * @param  i  The integer value to use for the test.
-   */
-  @Test(dataProvider = "intValues")
-  public void testIntValue(int i)
-  {
-    assertEquals(new ASN1Integer(i).intValue(), i);
-  }
-
-
-
-  /**
-   * 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
-  {
-    byte[] value = null;
-    // Some negative integers of interest
-    // to test specific ranges/boundaries.
-    value = ASN1Integer.encodeValue(-1);
-    assertEquals(value[0], (byte) 0xFF);
-    value = ASN1Integer.encodeValue(-2);
-    assertEquals(value[0], (byte) 0xFE);
-    value = ASN1Integer.encodeValue(-127);
-    assertEquals(value[0], (byte) 0x81);
-    value = ASN1Integer.encodeValue(-128);
-    assertEquals(value[0], (byte) 0x80);
-    value = ASN1Integer.encodeValue(-255);
-    assertEquals(value[0], (byte) 0xFF);
-    assertEquals(value[1], (byte) 0x01);
-    value = ASN1Integer.encodeValue(-256);
-    assertEquals(value[0], (byte) 0xFF);
-    assertEquals(value[1], (byte) 0x00);
-    value = ASN1Integer.encodeValue(-65535);
-    assertEquals(value[0], (byte) 0xFF);
-    assertEquals(value[1], (byte) 0x00);
-    assertEquals(value[2], (byte) 0x01);
-    value = ASN1Integer.encodeValue(-65536);
-    assertEquals(value[0], (byte) 0xFF);
-    assertEquals(value[1], (byte) 0x00);
-    assertEquals(value[2], (byte) 0x00);
-    value = ASN1Integer.encodeValue(-2147483647);
-    assertEquals(value[0], (byte) 0x80);
-    assertEquals(value[1], (byte) 0x00);
-    assertEquals(value[2], (byte) 0x00);
-    assertEquals(value[3], (byte) 0x01);
-    value = ASN1Integer.encodeValue(-2147483648);
-    assertEquals(value[0], (byte) 0x80);
-    assertEquals(value[1], (byte) 0x00);
-    assertEquals(value[2], (byte) 0x00);
-    assertEquals(value[3], (byte) 0x00);
-  }
-
-
-
-  /**
-   * Tests the <CODE>setValue</CODE> method that takes an int argument.
-   *
-   * @param  i  The integer value to use for the test.
-   */
-  @Test(dataProvider = "intValues")
-  public void testSetIntValue(int i)
-  {
-    ASN1Integer integerElement = new ASN1Integer(0);
-    integerElement.setValue(i);
-    assertEquals(integerElement.intValue(), i);
-  }
-
-
-
-  /**
-   * Tests the <CODE>setValue</CODE> method that takes a byte array argument
-   * with a valid array.
-   *
-   * @param  i  The integer value to use for the test.
-   *
-   * @throws  Exception  If an unexpected problem occurs.
-   */
-  @Test(dataProvider = "intValues")
-  public void testSetByteValue(int i)
-         throws Exception
-  {
-    ASN1Integer integerElement = new ASN1Integer(0);
-
-    byte[] encoding;
-    if ((i & 0x7F) == i)
-    {
-      encoding = new byte[1];
-      encoding[0] = (byte) (i & 0xFF);
-    }
-    else if ((i & 0x7FFF) == i)
-    {
-      encoding = new byte[2];
-      encoding[0] = (byte) ((i >> 8) & 0xFF);
-      encoding[1] = (byte) (i & 0xFF);
-    }
-    else if ((i & 0x7FFFFF) == i)
-    {
-      encoding = new byte[3];
-      encoding[0] = (byte) ((i >> 16) & 0xFF);
-      encoding[1] = (byte) ((i >> 8) & 0xFF);
-      encoding[2] = (byte) (i & 0xFF);
-    }
-    else
-    {
-      encoding = new byte[4];
-      encoding[0] = (byte) ((i >> 24) & 0xFF);
-      encoding[1] = (byte) ((i >> 16) & 0xFF);
-      encoding[2] = (byte) ((i >> 8) & 0xFF);
-      encoding[3] = (byte) (i & 0xFF);
-    }
-
-    integerElement.setValue(encoding);
-    assertEquals(integerElement.intValue(), i);
-  }
-
-
-
-  /**
-   * Tests the <CODE>setValue</CODE> method that takes a byte array argument
-   * with a null array.
-   *
-   * @throws  Exception  If an unexpected problem occurs.
-   */
-  @Test(expectedExceptions = { ASN1Exception.class })
-  public void testSetByteValueNull()
-         throws Exception
-  {
-    ASN1Integer integerElement = new ASN1Integer(0);
-
-    byte[] b = null;
-    integerElement.setValue(b);
-  }
-
-
-
-  /**
-   * Tests the <CODE>setValue</CODE> method that takes a byte array argument
-   * with an empty array.
-   *
-   * @throws  Exception  If an unexpected problem occurs.
-   */
-  @Test(expectedExceptions = { ASN1Exception.class })
-  public void testSetByteValueEmptyArray()
-         throws Exception
-  {
-    ASN1Integer integerElement = new ASN1Integer(0);
-
-    byte[] b = new byte[0];
-    integerElement.setValue(b);
-  }
-
-
-
-  /**
-   * Tests the <CODE>setValue</CODE> method that takes a byte array argument
-   * with a long array.
-   *
-   * @throws  Exception  If an unexpected problem occurs.
-   */
-  @Test(expectedExceptions = { ASN1Exception.class })
-  public void testSetByteValueLongArray()
-         throws Exception
-  {
-    ASN1Integer integerElement = new ASN1Integer(0);
-
-    byte[] b = new byte[5];
-    integerElement.setValue(b);
-  }
-
-
-
-  /**
-   * Tests the <CODE>decodeAsInteger</CODE> method that takes an ASN1Element
-   * arguent using a valid value.
-   *
-   * @param i  The integer value to use in the test.
-   *
-   * @throws  Exception  If an unexpected problem occurs.
-   */
-  @Test(dataProvider = "intValues")
-  public void testDecodeValidElementAsInteger(int i)
-         throws Exception
-  {
-    // First, make sure that we can decode an integer element as an integer.
-    ASN1Element e = new ASN1Integer(i);
-    ASN1Integer integerElement = ASN1Integer.decodeAsInteger(e);
-    assertEquals(integerElement.intValue(), i);
-
-    e = new ASN1Integer((byte) 0x50, i);
-    integerElement = ASN1Integer.decodeAsInteger(e);
-    assertEquals(integerElement.intValue(), i);
-
-
-    // Next, make sure that we can decode a generic element as an integer.
-    byte[] encoding;
-    if ((i & 0x7F) == i)
-    {
-      encoding = new byte[1];
-      encoding[0] = (byte) (i & 0xFF);
-    }
-    else if ((i & 0x7FFF) == i)
-    {
-      encoding = new byte[2];
-      encoding[0] = (byte) ((i >> 8) & 0xFF);
-      encoding[1] = (byte) (i & 0xFF);
-    }
-    else if ((i & 0x7FFFFF) == i)
-    {
-      encoding = new byte[3];
-      encoding[0] = (byte) ((i >> 16) & 0xFF);
-      encoding[1] = (byte) ((i >> 8) & 0xFF);
-      encoding[2] = (byte) (i & 0xFF);
-    }
-    else
-    {
-      encoding = new byte[4];
-      encoding[0] = (byte) ((i >> 24) & 0xFF);
-      encoding[1] = (byte) ((i >> 16) & 0xFF);
-      encoding[2] = (byte) ((i >> 8) & 0xFF);
-      encoding[3] = (byte) (i & 0xFF);
-    }
-
-    e = new ASN1Element(ASN1Constants.UNIVERSAL_INTEGER_TYPE, encoding);
-    integerElement = ASN1Integer.decodeAsInteger(e);
-    assertEquals(integerElement.intValue(), i);
-
-    e = new ASN1Element((byte) 0x50, encoding);
-    integerElement = ASN1Integer.decodeAsInteger(e);
-    assertEquals(integerElement.intValue(), i);
-  }
-
-
-
-  /**
-   * Tests the <CODE>decodeAsInteger</CODE> method that takes an ASN1Element
-   * arguent using a valid value.
-   *
-   * @throws  Exception  If an unexpected problem occurs.
-   */
-  @Test(expectedExceptions = { ASN1Exception.class })
-  public void testDecodeNullElementAsInteger()
-         throws Exception
-  {
-    ASN1Element e = null;
-    ASN1Integer.decodeAsInteger(e);
-  }
-
-
-
-  /**
-   * Tests the <CODE>decodeAsInteger</CODE> method that takes an ASN1Element
-   * arguent a zero-length element.
-   *
-   * @throws  Exception  If an unexpected problem occurs.
-   */
-  @Test(expectedExceptions = { ASN1Exception.class })
-  public void testDecodeZeroLengthElementAsInteger()
-         throws Exception
-  {
-    ASN1Element e = new ASN1Element(ASN1Constants.UNIVERSAL_INTEGER_TYPE);
-    ASN1Integer.decodeAsInteger(e);
-  }
-
-
-
-  /**
-   * Tests the <CODE>decodeAsInteger</CODE> method that takes an ASN1Element
-   * arguent a long value element.
-   *
-   * @throws  Exception  If an unexpected problem occurs.
-   */
-  @Test(expectedExceptions = { ASN1Exception.class })
-  public void testDecodeLongValueElementAsInteger()
-         throws Exception
-  {
-    ASN1Element e = new ASN1Element(ASN1Constants.UNIVERSAL_INTEGER_TYPE,
-                                    new byte[5]);
-    ASN1Integer.decodeAsInteger(e);
-  }
-
-
-
-  /**
-   * Tests the <CODE>decodeAsInteger</CODE> method that takes a byte array with
-   * a valid array.
-   *
-   * @param i  The integer value to use in the test.
-   *
-   * @throws  Exception  If an unexpected problem occurs.
-   */
-  @Test(dataProvider = "intValues")
-  public void testDecodeValidArrayAsInteger(int i)
-         throws Exception
-  {
-    byte[] encoding;
-    if ((i & 0x7F) == i)
-    {
-      encoding = new byte[1];
-      encoding[0] = (byte) (i & 0xFF);
-    }
-    else if ((i & 0x7FFF) == i)
-    {
-      encoding = new byte[2];
-      encoding[0] = (byte) ((i >> 8) & 0xFF);
-      encoding[1] = (byte) (i & 0xFF);
-    }
-    else if ((i & 0x7FFFFF) == i)
-    {
-      encoding = new byte[3];
-      encoding[0] = (byte) ((i >> 16) & 0xFF);
-      encoding[1] = (byte) ((i >> 8) & 0xFF);
-      encoding[2] = (byte) (i & 0xFF);
-    }
-    else
-    {
-      encoding = new byte[4];
-      encoding[0] = (byte) ((i >> 24) & 0xFF);
-      encoding[1] = (byte) ((i >> 16) & 0xFF);
-      encoding[2] = (byte) ((i >> 8) & 0xFF);
-      encoding[3] = (byte) (i & 0xFF);
-    }
-
-    byte[] encodedElement = new byte[2 + encoding.length];
-    encodedElement[0] = ASN1Constants.UNIVERSAL_INTEGER_TYPE;
-    encodedElement[1] = (byte) encoding.length;
-    System.arraycopy(encoding, 0, encodedElement, 2, encoding.length);
-
-    ASN1Integer integerElement = ASN1Integer.decodeAsInteger(encodedElement);
-    assertEquals(integerElement.intValue(), i);
-  }
-
-
-
-  /**
-   * Tests the <CODE>decodeAsInteger</CODE> method that takes a byte array with
-   * a valid extended length array.
-   *
-   * @param i  The integer value to use in the test.
-   *
-   * @throws  Exception  If an unexpected problem occurs.
-   */
-  @Test(dataProvider = "intValues")
-  public void testDecodeValidExtendedLengthArrayAsInteger(int i)
-         throws Exception
-  {
-    byte[] encoding;
-    if ((i & 0x7F) == i)
-    {
-      encoding = new byte[1];
-      encoding[0] = (byte) (i & 0xFF);
-    }
-    else if ((i & 0x7FFF) == i)
-    {
-      encoding = new byte[2];
-      encoding[0] = (byte) ((i >> 8) & 0xFF);
-      encoding[1] = (byte) (i & 0xFF);
-    }
-    else if ((i & 0x7FFFFF) == i)
-    {
-      encoding = new byte[3];
-      encoding[0] = (byte) ((i >> 16) & 0xFF);
-      encoding[1] = (byte) ((i >> 8) & 0xFF);
-      encoding[2] = (byte) (i & 0xFF);
-    }
-    else
-    {
-      encoding = new byte[4];
-      encoding[0] = (byte) ((i >> 24) & 0xFF);
-      encoding[1] = (byte) ((i >> 16) & 0xFF);
-      encoding[2] = (byte) ((i >> 8) & 0xFF);
-      encoding[3] = (byte) (i & 0xFF);
-    }
-
-    byte[] encodedElement = new byte[3 + encoding.length];
-    encodedElement[0] = ASN1Constants.UNIVERSAL_INTEGER_TYPE;
-    encodedElement[1] = (byte) 0x81;
-    encodedElement[2] = (byte) encoding.length;
-    System.arraycopy(encoding, 0, encodedElement, 3, encoding.length);
-
-    ASN1Integer integerElement = ASN1Integer.decodeAsInteger(encodedElement);
-    assertEquals(integerElement.intValue(), i);
-  }
-
-
-
-  /**
-   * Tests the <CODE>decodeAsInteger</CODE> method that takes a byte array with
-   * a null array.
-   *
-   * @throws  Exception  If an unexpected problem occurs.
-   */
-  @Test(expectedExceptions = { ASN1Exception.class })
-  public void testDecodeNullArrayAsInteger()
-         throws Exception
-  {
-    byte[] b = null;
-    ASN1Integer.decodeAsInteger(b);
-  }
-
-
-
-  /**
-   * Tests the <CODE>decodeAsInteger</CODE> method that takes a byte array with
-   * a short array.
-   *
-   * @throws  Exception  If an unexpected problem occurs.
-   */
-  @Test(expectedExceptions = { ASN1Exception.class })
-  public void testDecodeShortArrayAsInteger()
-         throws Exception
-  {
-    byte[] b = new byte[0];
-    ASN1Integer.decodeAsInteger(b);
-  }
-
-
-
-  /**
-   * 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 = { ASN1Exception.class })
-  public void testDecodeLongLengthArrayAsInteger()
-         throws Exception
-  {
-    byte[] b = { 0x02, (byte) 0x85, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00 };
-    ASN1Integer.decodeAsInteger(b);
-  }
-
-
-
-  /**
-   * 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 = { ASN1Exception.class })
-  public void testDecodeTruncatedLengthArrayAsInteger()
-         throws Exception
-  {
-    byte[] b = { 0x02, (byte) 0x82, 0x00 };
-    ASN1Integer.decodeAsInteger(b);
-  }
-
-
-
-  /**
-   * Tests the <CODE>decodeAsInteger</CODE> method that takes a byte array with
-   * a length mismatch.
-   *
-   * @throws  Exception  If an unexpected problem occurs.
-   */
-  @Test(expectedExceptions = { ASN1Exception.class })
-  public void testDecodeLengthMismatchArrayAsInteger()
-         throws Exception
-  {
-    byte[] b = { 0x02, (byte) 0x81, 0x01 };
-    ASN1Integer.decodeAsInteger(b);
-  }
-
-
-
-  /**
-   * Tests the <CODE>decodeAsInteger</CODE> method that takes a byte array with
-   * a value too long for an integer.
-   *
-   * @throws  Exception  If an unexpected problem occurs.
-   */
-  @Test(expectedExceptions = { ASN1Exception.class })
-  public void testDecodeLongIntLengthArrayAsInteger()
-         throws Exception
-  {
-    byte[] b = { 0x02, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00 };
-    ASN1Integer.decodeAsInteger(b);
-  }
-
-
-
-  /**
-   * Tests the first <CODE>toString</CODE> method that takes a string builder
-   * argument.
-   *
-   * @param  i  The integer value to use in the test.
-   */
-  @Test(dataProvider = "intValues")
-  public void testToString1(int i)
-  {
-    new ASN1Integer(i).toString(new StringBuilder());
-  }
-
-
-
-  /**
-   * Tests the second <CODE>toString</CODE> method that takes string builder and
-   * integer arguments.
-   *
-   * @param  i  The integer value to use in the test.
-   */
-  @Test(dataProvider = "intValues")
-  public void testToString2(int i)
-  {
-    new ASN1Integer(i).toString(new StringBuilder(), 1);
-  }
-}
-
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/asn1/TestASN1Long.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/asn1/TestASN1Long.java
deleted file mode 100644
index 1a3b31a..0000000
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/asn1/TestASN1Long.java
+++ /dev/null
@@ -1,808 +0,0 @@
-/*
- * CDDL HEADER START
- *
- * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
- *
- * You can obtain a copy of the license at
- * trunk/opends/resource/legal-notices/OpenDS.LICENSE
- * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
- * See the License for the specific language governing permissions
- * and limitations under the License.
- *
- * When distributing Covered Code, include this CDDL HEADER in each
- * file and include the License file at
- * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
- * add the following below this CDDL 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.server.protocols.asn1;
-
-
-
-import org.testng.annotations.DataProvider;
-import org.testng.annotations.Test;
-
-import static org.testng.Assert.*;
-
-
-
-/**
- * This class defines a set of tests for the
- * org.opends.server.protocols.asn1.ASN1Long class.
- */
-public class TestASN1Long
-       extends ASN1TestCase
-{
-  /**
-   * 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 },
-      new Object[] { 0x0000000000000001L },
-      new Object[] { 0x000000000000007FL },
-      new Object[] { 0x0000000000000080L },
-      new Object[] { 0x00000000000000FFL },
-      new Object[] { 0x0000000000000100L },
-      new Object[] { 0x000000000000FFFFL },
-      new Object[] { 0x0000000000010000L },
-      new Object[] { 0x0000000000FFFFFFL },
-      new Object[] { 0x0000000001000000L },
-      new Object[] { 0x00000000FFFFFFFFL },
-      new Object[] { 0x0000000100000000L },
-      new Object[] { 0x000000FFFFFFFFFFL },
-      new Object[] { 0x0000010000000000L },
-      new Object[] { 0x0000FFFFFFFFFFFFL },
-      new Object[] { 0x0001000000000000L },
-      new Object[] { 0x00FFFFFFFFFFFFFFL },
-      new Object[] { 0x0100000000000000L },
-      new Object[] { 0x7FFFFFFFFFFFFFFFL },
-      new Object[] { -0x0000000000000001L },
-      new Object[] { -0x000000000000007FL },
-      new Object[] { -0x0000000000000080L },
-      new Object[] { -0x00000000000000FFL },
-      new Object[] { -0x0000000000000100L },
-      new Object[] { -0x000000000000FFFFL },
-      new Object[] { -0x0000000000010000L },
-      new Object[] { -0x0000000000FFFFFFL },
-      new Object[] { -0x0000000001000000L },
-      new Object[] { -0x00000000FFFFFFFFL },
-      new Object[] { -0x0000000100000000L },
-      new Object[] { -0x000000FFFFFFFFFFL },
-      new Object[] { -0x0000010000000000L },
-      new Object[] { -0x0000FFFFFFFFFFFFL },
-      new Object[] { -0x0001000000000000L },
-      new Object[] { -0x00FFFFFFFFFFFFFFL },
-      new Object[] { -0x0100000000000000L },
-      new Object[] { -0x7FFFFFFFFFFFFFFFL },
-      new Object[] { 0x8000000000000000L }
-    };
-  }
-
-
-
-  /**
-   * Tests the first constructor, which takes a single long argument.
-   *
-   * @param  l  The long value to use to create the element.
-   */
-  @Test(dataProvider = "longValues")
-  public void testConstructor1(long l)
-  {
-    new ASN1Long(l);
-  }
-
-
-
-  /**
-   * Tests the second constructor, which takes byte and long arguments.
-   *
-   * @param  l  The long value to use to create the element.
-   */
-  @Test(dataProvider = "longValues")
-  public void testConstructor2(long l)
-  {
-    new ASN1Long((byte) 0x50, l);
-  }
-
-
-
-  /**
-   * Tests the <CODE>longValue</CODE> method.
-   *
-   * @param  l  The long value to use for the test.
-   */
-  @Test(dataProvider = "longValues")
-  public void testLongValue(long l)
-  {
-    assertEquals(new ASN1Long(l).longValue(), l);
-  }
-
-
-
-  /**
-   * 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
-  {
-    byte[] value = null;
-    // Some negative integers of interest
-    // to test specific ranges/boundaries.
-    value = ASN1Long.encodeLongValue(-1L);
-    assertEquals(value[0], (byte) 0xFF);
-    value = ASN1Long.encodeLongValue(-2L);
-    assertEquals(value[0], (byte) 0xFE);
-    value = ASN1Long.encodeLongValue(-127L);
-    assertEquals(value[0], (byte) 0x81);
-    value = ASN1Long.encodeLongValue(-128L);
-    assertEquals(value[0], (byte) 0x80);
-    value = ASN1Long.encodeLongValue(-255L);
-    assertEquals(value[0], (byte) 0xFF);
-    assertEquals(value[1], (byte) 0x01);
-    value = ASN1Long.encodeLongValue(-256L);
-    assertEquals(value[0], (byte) 0xFF);
-    assertEquals(value[1], (byte) 0x00);
-    value = ASN1Long.encodeLongValue(-65535L);
-    assertEquals(value[0], (byte) 0xFF);
-    assertEquals(value[1], (byte) 0x00);
-    assertEquals(value[2], (byte) 0x01);
-    value = ASN1Long.encodeLongValue(-65536L);
-    assertEquals(value[0], (byte) 0xFF);
-    assertEquals(value[1], (byte) 0x00);
-    assertEquals(value[2], (byte) 0x00);
-    value = ASN1Long.encodeLongValue(-2147483647L);
-    assertEquals(value[0], (byte) 0x80);
-    assertEquals(value[1], (byte) 0x00);
-    assertEquals(value[2], (byte) 0x00);
-    assertEquals(value[3], (byte) 0x01);
-    value = ASN1Long.encodeLongValue(-2147483648L);
-    assertEquals(value[0], (byte) 0x80);
-    assertEquals(value[1], (byte) 0x00);
-    assertEquals(value[2], (byte) 0x00);
-    assertEquals(value[3], (byte) 0x00);
-  }
-
-
-
-  /**
-   * Tests the <CODE>setValue</CODE> method that takes a long argument.
-   *
-   * @param  l  The long value to use for the test.
-   */
-  @Test(dataProvider = "longValues")
-  public void testSetLongValue(long l)
-  {
-    ASN1Long longElement = new ASN1Long(0);
-    longElement.setValue(l);
-    assertEquals(longElement.longValue(), l);
-  }
-
-
-
-  /**
-   * Tests the <CODE>setValue</CODE> method that takes a byte array argument
-   * with a valid array.
-   *
-   * @param  l  The long value to use for the test.
-   *
-   * @throws  Exception  If an unexpected problem occurs.
-   */
-  @Test(dataProvider = "longValues")
-  public void testSetByteValue(long l)
-         throws Exception
-  {
-    ASN1Long longElement = new ASN1Long(0);
-
-    byte[] encoding;
-    if ((l & 0x7FL) == l)
-    {
-      encoding = new byte[1];
-      encoding[0] = (byte) (l & 0xFF);
-    }
-    else if ((l & 0x7FFFL) == l)
-    {
-      encoding = new byte[2];
-      encoding[0] = (byte) ((l >> 8) & 0xFF);
-      encoding[1] = (byte) (l & 0xFF);
-    }
-    else if ((l & 0x7FFFFFL) == l)
-    {
-      encoding = new byte[3];
-      encoding[0] = (byte) ((l >> 16) & 0xFF);
-      encoding[1] = (byte) ((l >> 8) & 0xFF);
-      encoding[2] = (byte) (l & 0xFF);
-    }
-    else if ((l & 0x7FFFFFFFL) == l)
-    {
-      encoding = new byte[4];
-      encoding[0] = (byte) ((l >> 24) & 0xFF);
-      encoding[1] = (byte) ((l >> 16) & 0xFF);
-      encoding[2] = (byte) ((l >> 8) & 0xFF);
-      encoding[3] = (byte) (l & 0xFF);
-    }
-    else if ((l & 0x7FFFFFFFFFL) == l)
-    {
-      encoding = new byte[5];
-      encoding[0] = (byte) ((l >> 32) & 0xFF);
-      encoding[1] = (byte) ((l >> 24) & 0xFF);
-      encoding[2] = (byte) ((l >> 16) & 0xFF);
-      encoding[3] = (byte) ((l >> 8) & 0xFF);
-      encoding[4] = (byte) (l & 0xFF);
-    }
-    else if ((l & 0x7FFFFFFFFFFFL) == l)
-    {
-      encoding = new byte[6];
-      encoding[0] = (byte) ((l >> 40) & 0xFF);
-      encoding[1] = (byte) ((l >> 32) & 0xFF);
-      encoding[2] = (byte) ((l >> 24) & 0xFF);
-      encoding[3] = (byte) ((l >> 16) & 0xFF);
-      encoding[4] = (byte) ((l >> 8) & 0xFF);
-      encoding[5] = (byte) (l & 0xFF);
-    }
-    else if ((l & 0x7FFFFFFFFFFFFFL) == l)
-    {
-      encoding = new byte[7];
-      encoding[0] = (byte) ((l >> 48) & 0xFF);
-      encoding[1] = (byte) ((l >> 40) & 0xFF);
-      encoding[2] = (byte) ((l >> 32) & 0xFF);
-      encoding[3] = (byte) ((l >> 24) & 0xFF);
-      encoding[4] = (byte) ((l >> 16) & 0xFF);
-      encoding[5] = (byte) ((l >> 8) & 0xFF);
-      encoding[6] = (byte) (l & 0xFF);
-    }
-    else
-    {
-      encoding = new byte[8];
-      encoding[0] = (byte) ((l >> 56) & 0xFF);
-      encoding[1] = (byte) ((l >> 48) & 0xFF);
-      encoding[2] = (byte) ((l >> 40) & 0xFF);
-      encoding[3] = (byte) ((l >> 32) & 0xFF);
-      encoding[4] = (byte) ((l >> 24) & 0xFF);
-      encoding[5] = (byte) ((l >> 16) & 0xFF);
-      encoding[6] = (byte) ((l >> 8) & 0xFF);
-      encoding[7] = (byte) (l & 0xFF);
-    }
-
-    longElement.setValue(encoding);
-    assertEquals(longElement.longValue(), l);
-  }
-
-
-
-  /**
-   * Tests the <CODE>setValue</CODE> method that takes a byte array argument
-   * with a null array.
-   *
-   * @throws  Exception  If an unexpected problem occurs.
-   */
-  @Test(expectedExceptions = { ASN1Exception.class })
-  public void testSetByteValueNull()
-         throws Exception
-  {
-    ASN1Long longElement = new ASN1Long(0);
-
-    byte[] b = null;
-    longElement.setValue(b);
-  }
-
-
-
-  /**
-   * Tests the <CODE>setValue</CODE> method that takes a byte array argument
-   * with an empty array.
-   *
-   * @throws  Exception  If an unexpected problem occurs.
-   */
-  @Test(expectedExceptions = { ASN1Exception.class })
-  public void testSetByteValueEmptyArray()
-         throws Exception
-  {
-    ASN1Long longElement = new ASN1Long(0);
-
-    byte[] b = new byte[0];
-    longElement.setValue(b);
-  }
-
-
-
-  /**
-   * Tests the <CODE>setValue</CODE> method that takes a byte array argument
-   * with a long array.
-   *
-   * @throws  Exception  If an unexpected problem occurs.
-   */
-  @Test(expectedExceptions = { ASN1Exception.class })
-  public void testSetByteValueLongArray()
-         throws Exception
-  {
-    ASN1Long longElement = new ASN1Long(0);
-
-    byte[] b = new byte[9];
-    longElement.setValue(b);
-  }
-
-
-
-  /**
-   * Tests the <CODE>decodeAsLong</CODE> method that takes an ASN1Element
-   * arguent using a valid value.
-   *
-   * @param  l  The long value to use in the test.
-   *
-   * @throws  Exception  If an unexpected problem occurs.
-   */
-  @Test(dataProvider = "longValues")
-  public void testDecodeValidElementAsLong(long l)
-         throws Exception
-  {
-    // First, make sure that we can decode a long element as a long.
-    ASN1Element e = new ASN1Long(l);
-    ASN1Long longElement = ASN1Long.decodeAsLong(e);
-    assertEquals(longElement.longValue(), l);
-
-    e = new ASN1Long((byte) 0x50, l);
-    longElement = ASN1Long.decodeAsLong(e);
-    assertEquals(longElement.longValue(), l);
-
-
-    // Next, make sure that we can decode a generic element as a long.
-    byte[] encoding;
-    if ((l & 0x7FL) == l)
-    {
-      encoding = new byte[1];
-      encoding[0] = (byte) (l & 0xFF);
-    }
-    else if ((l & 0x7FFFL) == l)
-    {
-      encoding = new byte[2];
-      encoding[0] = (byte) ((l >> 8) & 0xFF);
-      encoding[1] = (byte) (l & 0xFF);
-    }
-    else if ((l & 0x7FFFFFL) == l)
-    {
-      encoding = new byte[3];
-      encoding[0] = (byte) ((l >> 16) & 0xFF);
-      encoding[1] = (byte) ((l >> 8) & 0xFF);
-      encoding[2] = (byte) (l & 0xFF);
-    }
-    else if ((l & 0x7FFFFFFFL) == l)
-    {
-      encoding = new byte[4];
-      encoding[0] = (byte) ((l >> 24) & 0xFF);
-      encoding[1] = (byte) ((l >> 16) & 0xFF);
-      encoding[2] = (byte) ((l >> 8) & 0xFF);
-      encoding[3] = (byte) (l & 0xFF);
-    }
-    else if ((l & 0x7FFFFFFFFFL) == l)
-    {
-      encoding = new byte[5];
-      encoding[0] = (byte) ((l >> 32) & 0xFF);
-      encoding[1] = (byte) ((l >> 24) & 0xFF);
-      encoding[2] = (byte) ((l >> 16) & 0xFF);
-      encoding[3] = (byte) ((l >> 8) & 0xFF);
-      encoding[4] = (byte) (l & 0xFF);
-    }
-    else if ((l & 0x7FFFFFFFFFFFL) == l)
-    {
-      encoding = new byte[6];
-      encoding[0] = (byte) ((l >> 40) & 0xFF);
-      encoding[1] = (byte) ((l >> 32) & 0xFF);
-      encoding[2] = (byte) ((l >> 24) & 0xFF);
-      encoding[3] = (byte) ((l >> 16) & 0xFF);
-      encoding[4] = (byte) ((l >> 8) & 0xFF);
-      encoding[5] = (byte) (l & 0xFF);
-    }
-    else if ((l & 0x7FFFFFFFFFFFFFL) == l)
-    {
-      encoding = new byte[7];
-      encoding[0] = (byte) ((l >> 48) & 0xFF);
-      encoding[1] = (byte) ((l >> 40) & 0xFF);
-      encoding[2] = (byte) ((l >> 32) & 0xFF);
-      encoding[3] = (byte) ((l >> 24) & 0xFF);
-      encoding[4] = (byte) ((l >> 16) & 0xFF);
-      encoding[5] = (byte) ((l >> 8) & 0xFF);
-      encoding[6] = (byte) (l & 0xFF);
-    }
-    else
-    {
-      encoding = new byte[8];
-      encoding[0] = (byte) ((l >> 56) & 0xFF);
-      encoding[1] = (byte) ((l >> 48) & 0xFF);
-      encoding[2] = (byte) ((l >> 40) & 0xFF);
-      encoding[3] = (byte) ((l >> 32) & 0xFF);
-      encoding[4] = (byte) ((l >> 24) & 0xFF);
-      encoding[5] = (byte) ((l >> 16) & 0xFF);
-      encoding[6] = (byte) ((l >> 8) & 0xFF);
-      encoding[7] = (byte) (l & 0xFF);
-    }
-
-    e = new ASN1Element(ASN1Constants.UNIVERSAL_INTEGER_TYPE, encoding);
-    longElement = ASN1Long.decodeAsLong(e);
-    assertEquals(longElement.longValue(), l);
-
-    e = new ASN1Element((byte) 0x50, encoding);
-    longElement = ASN1Long.decodeAsLong(e);
-    assertEquals(longElement.longValue(), l);
-  }
-
-
-
-  /**
-   * Tests the <CODE>decodeAsLong</CODE> method that takes an ASN1Element
-   * arguent using a valid value.
-   *
-   * @throws  Exception  If an unexpected problem occurs.
-   */
-  @Test(expectedExceptions = { ASN1Exception.class })
-  public void testDecodeNullElementAsLong()
-         throws Exception
-  {
-    ASN1Element e = null;
-    ASN1Long.decodeAsLong(e);
-  }
-
-
-
-  /**
-   * Tests the <CODE>decodeAsLong</CODE> method that takes an ASN1Element
-   * arguent a zero-length element.
-   *
-   * @throws  Exception  If an unexpected problem occurs.
-   */
-  @Test(expectedExceptions = { ASN1Exception.class })
-  public void testDecodeZeroLengthElementAsLong()
-         throws Exception
-  {
-    ASN1Element e = new ASN1Element(ASN1Constants.UNIVERSAL_INTEGER_TYPE);
-    ASN1Long.decodeAsLong(e);
-  }
-
-
-
-  /**
-   * Tests the <CODE>decodeAsLong</CODE> method that takes an ASN1Element
-   * arguent a long value element.
-   *
-   * @throws  Exception  If an unexpected problem occurs.
-   */
-  @Test(expectedExceptions = { ASN1Exception.class })
-  public void testDecodeLongValueElementAsLong()
-         throws Exception
-  {
-    ASN1Element e = new ASN1Element(ASN1Constants.UNIVERSAL_INTEGER_TYPE,
-                                    new byte[9]);
-    ASN1Long.decodeAsLong(e);
-  }
-
-
-
-  /**
-   * Tests the <CODE>decodeAsLong</CODE> method that takes a byte array with
-   * a valid array.
-   *
-   * @param  l  The long value to use in the test.
-   *
-   * @throws  Exception  If an unexpected problem occurs.
-   */
-  @Test(dataProvider = "longValues")
-  public void testDecodeValidArrayAsLong(long l)
-         throws Exception
-  {
-    byte[] encoding;
-    if ((l & 0x7FL) == l)
-    {
-      encoding = new byte[1];
-      encoding[0] = (byte) (l & 0xFF);
-    }
-    else if ((l & 0x7FFFL) == l)
-    {
-      encoding = new byte[2];
-      encoding[0] = (byte) ((l >> 8) & 0xFF);
-      encoding[1] = (byte) (l & 0xFF);
-    }
-    else if ((l & 0x7FFFFFL) == l)
-    {
-      encoding = new byte[3];
-      encoding[0] = (byte) ((l >> 16) & 0xFF);
-      encoding[1] = (byte) ((l >> 8) & 0xFF);
-      encoding[2] = (byte) (l & 0xFF);
-    }
-    else if ((l & 0x7FFFFFFFL) == l)
-    {
-      encoding = new byte[4];
-      encoding[0] = (byte) ((l >> 24) & 0xFF);
-      encoding[1] = (byte) ((l >> 16) & 0xFF);
-      encoding[2] = (byte) ((l >> 8) & 0xFF);
-      encoding[3] = (byte) (l & 0xFF);
-    }
-    else if ((l & 0x7FFFFFFFFFL) == l)
-    {
-      encoding = new byte[5];
-      encoding[0] = (byte) ((l >> 32) & 0xFF);
-      encoding[1] = (byte) ((l >> 24) & 0xFF);
-      encoding[2] = (byte) ((l >> 16) & 0xFF);
-      encoding[3] = (byte) ((l >> 8) & 0xFF);
-      encoding[4] = (byte) (l & 0xFF);
-    }
-    else if ((l & 0x7FFFFFFFFFFFL) == l)
-    {
-      encoding = new byte[6];
-      encoding[0] = (byte) ((l >> 40) & 0xFF);
-      encoding[1] = (byte) ((l >> 32) & 0xFF);
-      encoding[2] = (byte) ((l >> 24) & 0xFF);
-      encoding[3] = (byte) ((l >> 16) & 0xFF);
-      encoding[4] = (byte) ((l >> 8) & 0xFF);
-      encoding[5] = (byte) (l & 0xFF);
-    }
-    else if ((l & 0x7FFFFFFFFFFFFFL) == l)
-    {
-      encoding = new byte[7];
-      encoding[0] = (byte) ((l >> 48) & 0xFF);
-      encoding[1] = (byte) ((l >> 40) & 0xFF);
-      encoding[2] = (byte) ((l >> 32) & 0xFF);
-      encoding[3] = (byte) ((l >> 24) & 0xFF);
-      encoding[4] = (byte) ((l >> 16) & 0xFF);
-      encoding[5] = (byte) ((l >> 8) & 0xFF);
-      encoding[6] = (byte) (l & 0xFF);
-    }
-    else
-    {
-      encoding = new byte[8];
-      encoding[0] = (byte) ((l >> 56) & 0xFF);
-      encoding[1] = (byte) ((l >> 48) & 0xFF);
-      encoding[2] = (byte) ((l >> 40) & 0xFF);
-      encoding[3] = (byte) ((l >> 32) & 0xFF);
-      encoding[4] = (byte) ((l >> 24) & 0xFF);
-      encoding[5] = (byte) ((l >> 16) & 0xFF);
-      encoding[6] = (byte) ((l >> 8) & 0xFF);
-      encoding[7] = (byte) (l & 0xFF);
-    }
-
-    byte[] encodedElement = new byte[2 + encoding.length];
-    encodedElement[0] = ASN1Constants.UNIVERSAL_INTEGER_TYPE;
-    encodedElement[1] = (byte) encoding.length;
-    System.arraycopy(encoding, 0, encodedElement, 2, encoding.length);
-
-    ASN1Long longElement = ASN1Long.decodeAsLong(encodedElement);
-    assertEquals(longElement.longValue(), l);
-  }
-
-
-
-  /**
-   * Tests the <CODE>decodeAsLong</CODE> method that takes a byte array with
-   * a valid extended length array.
-   *
-   * @param  l  The long value to use in the test.
-   *
-   * @throws  Exception  If an unexpected problem occurs.
-   */
-  @Test(dataProvider = "longValues")
-  public void testDecodeValidExtendedLengthArrayAsLong(long l)
-         throws Exception
-  {
-    byte[] encoding;
-    if ((l & 0x7FL) == l)
-    {
-      encoding = new byte[1];
-      encoding[0] = (byte) (l & 0xFF);
-    }
-    else if ((l & 0x7FFFL) == l)
-    {
-      encoding = new byte[2];
-      encoding[0] = (byte) ((l >> 8) & 0xFF);
-      encoding[1] = (byte) (l & 0xFF);
-    }
-    else if ((l & 0x7FFFFFL) == l)
-    {
-      encoding = new byte[3];
-      encoding[0] = (byte) ((l >> 16) & 0xFF);
-      encoding[1] = (byte) ((l >> 8) & 0xFF);
-      encoding[2] = (byte) (l & 0xFF);
-    }
-    else if ((l & 0x7FFFFFFFL) == l)
-    {
-      encoding = new byte[4];
-      encoding[0] = (byte) ((l >> 24) & 0xFF);
-      encoding[1] = (byte) ((l >> 16) & 0xFF);
-      encoding[2] = (byte) ((l >> 8) & 0xFF);
-      encoding[3] = (byte) (l & 0xFF);
-    }
-    else if ((l & 0x7FFFFFFFFFL) == l)
-    {
-      encoding = new byte[5];
-      encoding[0] = (byte) ((l >> 32) & 0xFF);
-      encoding[1] = (byte) ((l >> 24) & 0xFF);
-      encoding[2] = (byte) ((l >> 16) & 0xFF);
-      encoding[3] = (byte) ((l >> 8) & 0xFF);
-      encoding[4] = (byte) (l & 0xFF);
-    }
-    else if ((l & 0x7FFFFFFFFFFFL) == l)
-    {
-      encoding = new byte[6];
-      encoding[0] = (byte) ((l >> 40) & 0xFF);
-      encoding[1] = (byte) ((l >> 32) & 0xFF);
-      encoding[2] = (byte) ((l >> 24) & 0xFF);
-      encoding[3] = (byte) ((l >> 16) & 0xFF);
-      encoding[4] = (byte) ((l >> 8) & 0xFF);
-      encoding[5] = (byte) (l & 0xFF);
-    }
-    else if ((l & 0x7FFFFFFFFFFFFFL) == l)
-    {
-      encoding = new byte[7];
-      encoding[0] = (byte) ((l >> 48) & 0xFF);
-      encoding[1] = (byte) ((l >> 40) & 0xFF);
-      encoding[2] = (byte) ((l >> 32) & 0xFF);
-      encoding[3] = (byte) ((l >> 24) & 0xFF);
-      encoding[4] = (byte) ((l >> 16) & 0xFF);
-      encoding[5] = (byte) ((l >> 8) & 0xFF);
-      encoding[6] = (byte) (l & 0xFF);
-    }
-    else
-    {
-      encoding = new byte[8];
-      encoding[0] = (byte) ((l >> 56) & 0xFF);
-      encoding[1] = (byte) ((l >> 48) & 0xFF);
-      encoding[2] = (byte) ((l >> 40) & 0xFF);
-      encoding[3] = (byte) ((l >> 32) & 0xFF);
-      encoding[4] = (byte) ((l >> 24) & 0xFF);
-      encoding[5] = (byte) ((l >> 16) & 0xFF);
-      encoding[6] = (byte) ((l >> 8) & 0xFF);
-      encoding[7] = (byte) (l & 0xFF);
-    }
-
-    byte[] encodedElement = new byte[3 + encoding.length];
-    encodedElement[0] = ASN1Constants.UNIVERSAL_INTEGER_TYPE;
-    encodedElement[1] = (byte) 0x81;
-    encodedElement[2] = (byte) encoding.length;
-    System.arraycopy(encoding, 0, encodedElement, 3, encoding.length);
-
-    ASN1Long longElement = ASN1Long.decodeAsLong(encodedElement);
-    assertEquals(longElement.longValue(), l);
-  }
-
-
-
-  /**
-   * Tests the <CODE>decodeAsLong</CODE> method that takes a byte array with
-   * a null array.
-   *
-   * @throws  Exception  If an unexpected problem occurs.
-   */
-  @Test(expectedExceptions = { ASN1Exception.class })
-  public void testDecodeNullArrayAsLong()
-         throws Exception
-  {
-    byte[] b = null;
-    ASN1Long.decodeAsLong(b);
-  }
-
-
-
-  /**
-   * Tests the <CODE>decodeAsLong</CODE> method that takes a byte array with
-   * a short array.
-   *
-   * @throws  Exception  If an unexpected problem occurs.
-   */
-  @Test(expectedExceptions = { ASN1Exception.class })
-  public void testDecodeShortArrayAsLong()
-         throws Exception
-  {
-    byte[] b = new byte[0];
-    ASN1Long.decodeAsLong(b);
-  }
-
-
-
-  /**
-   * Tests the <CODE>decodeAsLong</CODE> method that takes a byte array with
-   * a long length array.
-   *
-   * @throws  Exception  If an unexpected problem occurs.
-   */
-  @Test(expectedExceptions = { ASN1Exception.class })
-  public void testDecodeLongLengthArrayAsLong()
-         throws Exception
-  {
-    byte[] b = { 0x02, (byte) 0x85, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00 };
-    ASN1Long.decodeAsLong(b);
-  }
-
-
-
-  /**
-   * Tests the <CODE>decodeAsLong</CODE> method that takes a byte array with
-   * a truncated length array.
-   *
-   * @throws  Exception  If an unexpected problem occurs.
-   */
-  @Test(expectedExceptions = { ASN1Exception.class })
-  public void testDecodeTruncatedLengthArrayAsLong()
-         throws Exception
-  {
-    byte[] b = { 0x02, (byte) 0x82, 0x00 };
-    ASN1Long.decodeAsLong(b);
-  }
-
-
-
-  /**
-   * Tests the <CODE>decodeAsLong</CODE> method that takes a byte array with
-   * a length mismatch.
-   *
-   * @throws  Exception  If an unexpected problem occurs.
-   */
-  @Test(expectedExceptions = { ASN1Exception.class })
-  public void testDecodeLengthMismatchArrayAsLong()
-         throws Exception
-  {
-    byte[] b = { 0x02, (byte) 0x81, 0x01 };
-    ASN1Long.decodeAsLong(b);
-  }
-
-
-
-  /**
-   * Tests the <CODE>decodeAsLong</CODE> method that takes a byte array with
-   * a value too long for a long.
-   *
-   * @throws  Exception  If an unexpected problem occurs.
-   */
-  @Test(expectedExceptions = { ASN1Exception.class })
-  public void testDecodeLongIntLengthArrayAsLong()
-         throws Exception
-  {
-    byte[] b = { 0x02, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-                 0x00 };
-    ASN1Long.decodeAsLong(b);
-  }
-
-
-
-  /**
-   * Tests the first <CODE>toString</CODE> method that takes a string builder
-   * argument.
-   *
-   * @param  l  The long value to use in the test.
-   */
-  @Test(dataProvider = "longValues")
-  public void testToString1(long l)
-  {
-    new ASN1Long(l).toString(new StringBuilder());
-  }
-
-
-
-  /**
-   * Tests the second <CODE>toString</CODE> method that takes string builder and
-   * integer arguments.
-   *
-   * @param  l  The long value to use in the test.
-   */
-  @Test(dataProvider = "longValues")
-  public void testToString2(long l)
-  {
-    new ASN1Long(l).toString(new StringBuilder(), 1);
-  }
-}
-
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/asn1/TestASN1Null.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/asn1/TestASN1Null.java
deleted file mode 100644
index c19ec9b..0000000
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/asn1/TestASN1Null.java
+++ /dev/null
@@ -1,311 +0,0 @@
-/*
- * CDDL HEADER START
- *
- * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
- *
- * You can obtain a copy of the license at
- * trunk/opends/resource/legal-notices/OpenDS.LICENSE
- * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
- * See the License for the specific language governing permissions
- * and limitations under the License.
- *
- * When distributing Covered Code, include this CDDL HEADER in each
- * file and include the License file at
- * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
- * add the following below this CDDL 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.server.protocols.asn1;
-
-
-
-import org.testng.annotations.Test;
-
-
-
-/**
- * This class defines a set of tests for the
- * org.opends.server.protocols.asn1.ASN1Null class.
- */
-public class TestASN1Null
-       extends ASN1TestCase
-{
-  /**
-   * Tests the first constructor, which doesn't take any arguments.
-   */
-  @Test()
-  public void testConstructor1()
-  {
-    new ASN1Null();
-  }
-
-
-
-  /**
-   * Tests the second constructor, which takes a single byte argument.
-   */
-  @Test()
-  public void testConstructor2()
-  {
-    for (int i=0; i < 254; i++)
-    {
-      new ASN1Null((byte) (i & 0xFF));
-    }
-  }
-
-
-
-  /**
-   * Tests the <CODE>setValue</CODE> method with a null argument.
-   *
-   * @throws  Exception  If an unexpected problem occurs.
-   */
-  @Test()
-  public void testSetNullValue()
-         throws Exception
-  {
-    ASN1Null n = new ASN1Null();
-    n.setValue(null);
-  }
-
-
-
-  /**
-   * Tests the <CODE>setValue</CODE> method with an empty byte array argument.
-   *
-   * @throws  Exception  If an unexpected problem occurs.
-   */
-  @Test()
-  public void testSetEmptyValue()
-         throws Exception
-  {
-    ASN1Null n = new ASN1Null();
-    n.setValue(new byte[0]);
-  }
-
-
-
-  /**
-   * Tests the <CODE>setValue</CODE> method with a non-empty byte array
-   * argument.
-   *
-   * @throws  Exception  If an unexpected problem occurs.
-   */
-  @Test(expectedExceptions = { ASN1Exception.class })
-  public void testSetNonEmptyValue()
-         throws Exception
-  {
-    ASN1Null n = new ASN1Null();
-    n.setValue(new byte[1]);
-  }
-
-
-
-  /**
-   * Tests the <CODE>decodeAsNull</CODE> method that takes an ASN1Element
-   * argument with a null argument.
-   *
-   * @throws  Exception  If an unexpected problem occurs.
-   */
-  @Test(expectedExceptions = { ASN1Exception.class })
-  public void testDecodeNullElementAsNull()
-         throws Exception
-  {
-    ASN1Element e = null;
-    ASN1Null.decodeAsNull(e);
-  }
-
-
-
-  /**
-   * Tests the <CODE>decodeAsNull</CODE> method that takes an ASN1Element
-   * argument with an element with a zero-length value.
-   *
-   * @throws  Exception  If an unexpected problem occurs.
-   */
-  @Test()
-  public void testDecodeZeroLengthElementAsNull()
-         throws Exception
-  {
-    ASN1Element e = new ASN1OctetString(new byte[0]);
-    ASN1Null.decodeAsNull(e);
-  }
-
-
-
-  /**
-   * Tests the <CODE>decodeAsNull</CODE> method that takes an ASN1Element
-   * argument with an element with a nonzero-length value.
-   *
-   * @throws  Exception  If an unexpected problem occurs.
-   */
-  @Test(expectedExceptions = { ASN1Exception.class })
-  public void testDecodeNonZeroLengthElementAsNull()
-         throws Exception
-  {
-    ASN1Element e = new ASN1OctetString(new byte[1]);
-    ASN1Null.decodeAsNull(e);
-  }
-
-
-
-  /**
-   * Tests the <CODE>decodeAsNull</CODE> method that takes a byte array argument
-   * with a null array.
-   *
-   * @throws  Exception  If an unexpected problem occurs.
-   */
-  @Test(expectedExceptions = { ASN1Exception.class })
-  public void testDecodeNullArrayAsNull()
-         throws Exception
-  {
-    byte[] b = null;
-    ASN1Null.decodeAsNull(b);
-  }
-
-
-
-  /**
-   * 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 = { ASN1Exception.class })
-  public void testDecodeShortArrayAsNull()
-         throws Exception
-  {
-    byte[] b = new byte[1];
-    ASN1Null.decodeAsNull(b);
-  }
-
-
-
-  /**
-   * 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 = { ASN1Exception.class })
-  public void testDecodeLongLengthArrayAsNull()
-         throws Exception
-  {
-    byte[] b = new byte[] { 0x05, (byte) 0x85, 0x00, 0x00, 0x00, 0x00, 0x00 };
-    ASN1Null.decodeAsNull(b);
-  }
-
-
-
-  /**
-   * 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 = { ASN1Exception.class })
-  public void testDecodeTruncatedLengthArrayAsNull()
-         throws Exception
-  {
-    byte[] b = new byte[] { 0x05, (byte) 0x82, 0x00 };
-    ASN1Null.decodeAsNull(b);
-  }
-
-
-
-  /**
-   * Tests the <CODE>decodeAsNull</CODE> method that takes a byte array argument
-   * with an array with a length mismatch.
-   *
-   * @throws  Exception  If an unexpected problem occurs.
-   */
-  @Test(expectedExceptions = { ASN1Exception.class })
-  public void testDecodeLengthMismatchArrayAsNull()
-         throws Exception
-  {
-    byte[] b = new byte[] { 0x05, 0x00, 0x00 };
-    ASN1Null.decodeAsNull(b);
-  }
-
-
-
-  /**
-   * 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 = { ASN1Exception.class })
-  public void testDecodeNonZeroLengthArrayAsNull()
-         throws Exception
-  {
-    byte[] b = new byte[] { 0x05, 0x01, 0x00 };
-    ASN1Null.decodeAsNull(b);
-  }
-
-
-
-  /**
-   * 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
-  {
-    byte[] b = new byte[] { 0x05, 0x00 };
-    ASN1Null.decodeAsNull(b);
-  }
-
-
-
-  /**
-   * 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
-  {
-    byte[] b = new byte[] { 0x05, (byte) 0x81, 0x00 };
-    ASN1Null.decodeAsNull(b);
-  }
-
-
-
-  /**
-   * Tests the <CODE>toString</CODE> method that takes a string builder
-   * argument.
-   */
-  @Test()
-  public void testToString1()
-  {
-    new ASN1Null().toString(new StringBuilder());
-  }
-
-
-
-  /**
-   * Tests the <CODE>toString</CODE> method that takes string builder and
-   * integer arguments.
-   */
-  @Test()
-  public void testToString2()
-  {
-    new ASN1Null().toString(new StringBuilder(), 1);
-  }
-}
-
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/asn1/TestASN1OctetString.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/asn1/TestASN1OctetString.java
deleted file mode 100644
index 1b993f9..0000000
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/asn1/TestASN1OctetString.java
+++ /dev/null
@@ -1,671 +0,0 @@
-/*
- * CDDL HEADER START
- *
- * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
- *
- * You can obtain a copy of the license at
- * trunk/opends/resource/legal-notices/OpenDS.LICENSE
- * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
- * See the License for the specific language governing permissions
- * and limitations under the License.
- *
- * When distributing Covered Code, include this CDDL HEADER in each
- * file and include the License file at
- * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
- * add the following below this CDDL 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.server.protocols.asn1;
-
-
-
-import org.testng.annotations.DataProvider;
-import org.testng.annotations.Test;
-
-import static org.testng.Assert.*;
-
-
-
-/**
- * This class defines a set of tests for the
- * org.opends.server.protocols.asn1.ASN1OctetString class.
- */
-public class TestASN1OctetString
-       extends ASN1TestCase
-{
-  /**
-   * Tests the first constructor, which doesn't take any arguments.
-   */
-  @Test()
-  public void testConstructor1()
-  {
-    new ASN1OctetString();
-  }
-
-
-
-  /**
-   * Create the values that can be used for testing BER types.
-   *
-   * @return  The values that can be used for testing BER types.
-   */
-  @DataProvider(name = "types")
-  public Object[][] getTypes()
-  {
-    // 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.
-    Object[][] testTypes = new Object[0xFF][1];
-    for (int i=0x00; i < 0xFF; i++)
-    {
-      testTypes[i] = new Object[] { (byte) (i & 0xFF) };
-    }
-
-    return testTypes;
-  }
-
-
-
-  /**
-   * Tests the second constructor, which takes a byte argument.
-   *
-   * @param  type  The BER type to use for the test.
-   */
-  @Test(dataProvider = "types")
-  public void testConstructor2(byte type)
-  {
-    ASN1OctetString os = new ASN1OctetString(type);
-    assertEquals(os.getType(), type);
-  }
-
-
-
-  /**
-   * 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[] { null },              // The null value
-      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
-    };
-  }
-
-
-
-  /**
-   * Tests the third constructor, which takes a byte array argument.
-   *
-   * @param  value  The value to use for the test.
-   */
-  @Test(dataProvider = "binaryValues")
-  public void testConstructor3(byte[] value)
-  {
-    ASN1OctetString os = new ASN1OctetString(value);
-    if (value == null)
-    {
-      assertEquals(os.value(), new byte[0]);
-    }
-    else
-    {
-      assertEquals(os.value(), value);
-    }
-  }
-
-
-
-  /**
-   * 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 fourth constructor, which takes a string argument.
-   *
-   * @param  value  The value to use for the test.
-   *
-   * @throws  Exception  If an unexpected problem occurs.
-   */
-  @Test(dataProvider = "stringValues")
-  public void testConstructor4(String value)
-         throws Exception
-  {
-    ASN1OctetString os = new ASN1OctetString(value);
-    if (value == null)
-    {
-      assertEquals(os.stringValue(), "");
-      assertEquals(os.value(), new byte[0]);
-    }
-    else
-    {
-      assertEquals(os.stringValue(), value);
-      assertEquals(os.value(), value.getBytes("UTF-8"));
-    }
-  }
-
-
-
-  /**
-   * Tests the fifth constructor, which takes byte and byte array arguments.
-   *
-   * @param  value  The value to use for the test.
-   */
-  @Test(dataProvider = "binaryValues")
-  public void testConstructor5(byte[] value)
-  {
-    for (int i=0; i < 255; i++)
-    {
-      ASN1OctetString os = new ASN1OctetString((byte) (i & 0xFF), value);
-      if (value == null)
-      {
-        assertEquals(os.value(), new byte[0]);
-      }
-      else
-      {
-        assertEquals(os.value(), value);
-      }
-    }
-  }
-
-
-
-  /**
-   * Tests the sixth constructor, which takes byte and string arguments.
-   *
-   * @param  value  The value to use for the test.
-   */
-  @Test(dataProvider = "stringValues")
-  public void testConstructor6(String value)
-  {
-    for (int i=0; i < 255; i++)
-    {
-      ASN1OctetString os = new ASN1OctetString((byte) (i & 0xFF), value);
-      if (value == null)
-      {
-        assertEquals(os.stringValue(), "");
-      }
-      else
-      {
-        assertEquals(os.stringValue(), value);
-      }
-    }
-  }
-
-
-
-  /**
-   * Tests the <CODE>stringValue</CODE> methods for the case in which the octet
-   * string was created using a string representation.
-   *
-   * @param  value  The value to use for the test.
-   */
-  @Test(dataProvider = "stringValues")
-  public void testStringValueFromStrings(String value)
-  {
-    ASN1OctetString os = new ASN1OctetString(value);
-    if (value == null)
-    {
-      assertEquals(os.stringValue(), "");
-    }
-    else
-    {
-      assertEquals(os.stringValue(), value);
-    }
-
-    os = new ASN1OctetString(value);
-    StringBuilder valueBuffer = new StringBuilder();
-    os.stringValue(valueBuffer);
-    if (value == null)
-    {
-      assertEquals(valueBuffer.toString(), "");
-    }
-    else
-    {
-      assertEquals(valueBuffer.toString(), value);
-    }
-  }
-
-
-
-  /**
-   * Tests the <CODE>stringValue</CODE> methods for the case in which the octet
-   * string was created using a binary representation.
-   *
-   * @param  value  The value to use for the test.
-   *
-   * @throws  Exception  If an unexpected problem occurs.
-   */
-  @Test(dataProvider = "stringValues")
-  public void testStringValueFromBytes(String value)
-         throws Exception
-  {
-    byte[] valueBytes;
-    if (value == null)
-    {
-      valueBytes = null;
-    }
-    else
-    {
-      valueBytes = value.getBytes("UTF-8");
-    }
-
-    ASN1OctetString os = new ASN1OctetString(valueBytes);
-    if (value == null)
-    {
-      assertEquals(os.stringValue(), "");
-    }
-    else
-    {
-      assertEquals(os.stringValue(), value);
-    }
-
-    os = new ASN1OctetString(valueBytes);
-    StringBuilder valueBuffer = new StringBuilder();
-    os.stringValue(valueBuffer);
-    if (value == null)
-    {
-      assertEquals(valueBuffer.toString(), "");
-    }
-    else
-    {
-      assertEquals(valueBuffer.toString(), value);
-    }
-  }
-
-
-
-  /**
-   * Tests the <CODE>setValue</CODE> method that takes a string argument.
-   *
-   * @param  value  The value to use for the test.
-   *
-   * @throws  Exception  If an unexpected problem occurs.
-   */
-  @Test(dataProvider = "stringValues")
-  public void testSetStringValue(String value)
-         throws Exception
-  {
-    ASN1OctetString os = new ASN1OctetString();
-    os.setValue(value);
-    if (value == null)
-    {
-      assertEquals(os.stringValue(), "");
-      assertEquals(os.value(), new byte[0]);
-    }
-    else
-    {
-      assertEquals(os.stringValue(), value);
-      assertEquals(os.value(), value.getBytes("UTF-8"));
-    }
-  }
-
-
-
-  /**
-   * Tests the <CODE>setValue</CODE> method that takes a byte array argument.
-   *
-   * @param  value  The value to use for the test.
-   *
-   * @throws  Exception  If an unexpected problem occurs.
-   */
-  @Test(dataProvider = "binaryValues")
-  public void testSetBinaryValue(byte[] value)
-         throws Exception
-  {
-    ASN1OctetString os = new ASN1OctetString();
-    os.setValue(value);
-    if (value == null)
-    {
-      assertEquals(os.stringValue(), "");
-      assertEquals(os.value(), new byte[0]);
-    }
-    else
-    {
-      assertEquals(os.stringValue(), new String(value, "UTF-8"));
-      assertEquals(os.value(), value);
-    }
-  }
-
-
-
-  /**
-   * Create ASN.1 elements to test decoding them as octet strings.
-   *
-   * @return  A list of ASN.1 elements that can be decoded as octet strings.
-   *
-   * @throws  Exception  If an unexpected problem occurs.
-   */
-  @DataProvider(name = "elements")
-  public Object[][] getElements()
-  {
-    return new Object[][]
-    {
-      new Object[] { new ASN1OctetString() },
-      new Object[] { new ASN1OctetString((byte) 0x50) },
-      new Object[] { new ASN1OctetString(new byte[50]) },
-      new Object[] { new ASN1OctetString("Hello") },
-      new Object[] { new ASN1Element((byte) 0x50) },
-      new Object[] { new ASN1Element((byte) 0x50, new byte[50]) },
-      new Object[] { new ASN1Boolean(false) },
-      new Object[] { new ASN1Boolean(true) },
-      new Object[] { new ASN1Enumerated(0) },
-      new Object[] { new ASN1Enumerated(1) },
-      new Object[] { new ASN1Enumerated(127) },
-      new Object[] { new ASN1Enumerated(128) },
-      new Object[] { new ASN1Enumerated(255) },
-      new Object[] { new ASN1Enumerated(256) },
-      new Object[] { new ASN1Integer(0) },
-      new Object[] { new ASN1Integer(1) },
-      new Object[] { new ASN1Integer(127) },
-      new Object[] { new ASN1Integer(128) },
-      new Object[] { new ASN1Integer(255) },
-      new Object[] { new ASN1Integer(256) },
-      new Object[] { new ASN1Long(0) },
-      new Object[] { new ASN1Long(1) },
-      new Object[] { new ASN1Long(127) },
-      new Object[] { new ASN1Long(128) },
-      new Object[] { new ASN1Long(255) },
-      new Object[] { new ASN1Long(256) },
-      new Object[] { new ASN1Null() },
-      new Object[] { new ASN1Sequence() },
-      new Object[] { new ASN1Set() }
-    };
-  }
-
-
-
-  /**
-   * Test the <CODE>decodeAsOctetString</CODE> method that takes an ASN.1
-   * element using valid elements.
-   *
-   * @param  element  The element to decode.
-   *
-   * @throws  Exception  If an unexpected problem occurs.
-   */
-  @Test(dataProvider = "elements")
-  public void testDecodeValidElementAsOctetString(ASN1Element element)
-         throws Exception
-  {
-    ASN1OctetString.decodeAsOctetString(element);
-  }
-
-
-
-  /**
-   * Test the <CODE>decodeAsOctetString</CODE> method that takes an ASN.1
-   * element using a null element.
-   *
-   * @throws  Exception  If an unexpected problem occurs.
-   */
-  @Test(expectedExceptions = { ASN1Exception.class })
-  public void testDecodeNullElementAsOctetString()
-         throws Exception
-  {
-    ASN1Element e = null;
-    ASN1OctetString.decodeAsOctetString(e);
-  }
-
-
-
-  /**
-   * 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.
-   *
-   * @throws  Exception  If an unexpected problem occurs.
-   */
-  @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>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(byte[] b)
-         throws Exception
-  {
-    ASN1OctetString.decodeAsOctetString(b);
-  }
-
-
-
-  /**
-   * Tests the <CODE>decodeAsOctetString</CODE> method that takes a byte array
-   * using a null array.
-   *
-   * @throws  Exception  If an unexpected problem occurs.
-   */
-  @Test(expectedExceptions  = { ASN1Exception.class })
-  public void testDecodeNullArrayAsOctetString()
-         throws Exception
-  {
-    byte[] b = null;
-    ASN1OctetString.decodeAsOctetString(b);
-  }
-
-
-
-  /**
-   * Tests the <CODE>decodeAsOctetString</CODE> method that takes a byte array
-   * using a short array.
-   *
-   * @throws  Exception  If an unexpected problem occurs.
-   */
-  @Test(expectedExceptions  = { ASN1Exception.class })
-  public void testDecodeShortArrayAsOctetString()
-         throws Exception
-  {
-    byte[] b = new byte[1];
-    ASN1OctetString.decodeAsOctetString(b);
-  }
-
-
-
-  /**
-   * 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  = { ASN1Exception.class })
-  public void testDecodeLongLengthArrayAsOctetString()
-         throws Exception
-  {
-    byte[] b = { 0x04, (byte) 0x85, 0x00, 0x00, 0x00, 0x00, 0x00 };
-    ASN1OctetString.decodeAsOctetString(b);
-  }
-
-
-
-  /**
-   * 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  = { ASN1Exception.class })
-  public void testDecodeTruncatedLengthArrayAsOctetString()
-         throws Exception
-  {
-    byte[] b = { 0x04, (byte) 0x82, 0x00 };
-    ASN1OctetString.decodeAsOctetString(b);
-  }
-
-
-
-  /**
-   * 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  = { ASN1Exception.class })
-  public void testDecodeLengthMismatchArrayAsOctetString()
-         throws Exception
-  {
-    byte[] b = { 0x04, 0x00, 0x00 };
-    ASN1OctetString.decodeAsOctetString(b);
-  }
-
-
-
-  /**
-   * Tests the <CODE>duplicate</CODE> method.
-   *
-   * @param  b  The byte array to decode as an octet string.
-   *
-   * @throws  Exception  If an unexpected problem occurs.
-   */
-  @Test(dataProvider = "elementArrays")
-  public void testDuplicate(byte[] b)
-         throws Exception
-  {
-    ASN1OctetString os1 = ASN1OctetString.decodeAsOctetString(b);
-    ASN1OctetString os2 = os1.duplicate();
-    assertTrue(os1.equals(os2));
-    assertNotSame(os1, os2);
-
-    os1.setValue(new byte[50]);
-    assertFalse(os1.equals(os2));
-  }
-
-
-
-  /**
-   * Tests the <CODE>toString</CODE> method that takes a string builder
-   * argument.
-   *
-   * @param  b  The byte array to decode as an octet string.
-   *
-   * @throws  Exception  If an unexpected problem occurs.
-   */
-  @Test(dataProvider = "elementArrays")
-  public void testToString1(byte[] b)
-         throws Exception
-  {
-    ASN1OctetString os = ASN1OctetString.decodeAsOctetString(b);
-    os.toString(new StringBuilder());
-  }
-
-
-
-  /**
-   * Tests the <CODE>toString</CODE> method that takes a string builder and
-   * integer arguments.
-   *
-   * @param  b  The byte array to decode as an octet string.
-   *
-   * @throws  Exception  If an unexpected problem occurs.
-   */
-  @Test(dataProvider = "elementArrays")
-  public void testToString2(byte[] b)
-         throws Exception
-  {
-    ASN1OctetString os = ASN1OctetString.decodeAsOctetString(b);
-    os.toString(new StringBuilder(), 1);
-  }
-
-
-
-  /**
-   * Tests the <CODE>toASN1OctetString</CODE> method.
-   *
-   * @param  b  The byte array to decode as an octet string.
-   *
-   * @throws  Exception  If an unexpected problem occurs.
-   */
-  @Test(dataProvider = "elementArrays")
-  public void testToASN1OctetString(byte[] b)
-         throws Exception
-  {
-    ASN1OctetString os1 = ASN1OctetString.decodeAsOctetString(b);
-    ASN1OctetString os2 = os1.toASN1OctetString();
-    assertEquals(os2.value(), os1.value());
-  }
-}
-
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/asn1/TestASN1ReaderAndWriter.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/asn1/TestASN1ReaderAndWriter.java
deleted file mode 100644
index 9591b63..0000000
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/asn1/TestASN1ReaderAndWriter.java
+++ /dev/null
@@ -1,367 +0,0 @@
-/*
- * CDDL HEADER START
- *
- * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
- *
- * You can obtain a copy of the license at
- * trunk/opends/resource/legal-notices/OpenDS.LICENSE
- * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
- * See the License for the specific language governing permissions
- * and limitations under the License.
- *
- * When distributing Covered Code, include this CDDL HEADER in each
- * file and include the License file at
- * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
- * add the following below this CDDL 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.server.protocols.asn1;
-
-
-
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.net.InetSocketAddress;
-import java.net.ServerSocket;
-import java.net.Socket;
-
-import org.testng.annotations.DataProvider;
-import org.testng.annotations.Test;
-
-import static org.testng.Assert.*;
-import org.opends.messages.Message;
-
-
-/**
- * This class defines a set of tests for the
- * org.opends.server.protocols.asn1.ASN1Reader and
- * org.opends.server.protocols.asn1.ASN1Writer classes.
- */
-public class TestASN1ReaderAndWriter
-       extends ASN1TestCase
-{
-  /**
-   * 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.
-   *
-   * @throws  Exception  If an unexpected problem occurs.
-   */
-  @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 } },
-    };
-  }
-
-
-
-  /**
-   * Tests writing elements to an output stream.
-   *
-   * @param  elementBytes  The byte array that makes up an encoded element.
-   *
-   * @throws  Exception  If an unexpected problem occurs.
-   */
-  @Test(dataProvider = "elementArrays")
-  public void testWriteToStream(byte[] elementBytes)
-         throws Exception
-  {
-    ASN1Element e = ASN1Element.decode(elementBytes);
-
-    ByteArrayOutputStream baos = new ByteArrayOutputStream();
-    ASN1Writer writer = new ASN1Writer(baos);
-    writer.writeElement(e);
-
-    assertEquals(baos.toByteArray(), elementBytes);
-    writer.close();
-  }
-
-
-
-  /**
-   * Tests writing elements to a socket.
-   *
-   * @param  elementBytes  The byte array that makes up an encoded element.
-   *
-   * @throws  Exception  If an unexpected problem occurs.
-   */
-  @Test(dataProvider = "elementArrays")
-  public void testWriteToSocket(byte[] elementBytes)
-         throws Exception
-  {
-    ASN1Element e = ASN1Element.decode(elementBytes);
-
-    SocketReadThread readThread = new SocketReadThread("testWriteToSocket");
-    readThread.start();
-
-    Socket s = new Socket("127.0.0.1", readThread.getListenPort());
-    ASN1Writer writer = new ASN1Writer(s);
-    int bytesWritten = writer.writeElement(e);
-
-    assertEquals(readThread.getDataRead(bytesWritten), elementBytes);
-    writer.close();
-    readThread.close();
-  }
-
-
-
-  /**
-   * Tests reading elements from an input stream.
-   *
-   * @param  elementBytes  The byte array that makes up an encoded element.
-   *
-   * @throws  Exception  If an unexpected problem occurs.
-   */
-  @Test(dataProvider = "elementArrays")
-  public void testReadFromStream(byte[] elementBytes)
-         throws Exception
-  {
-    ByteArrayInputStream bais = new ByteArrayInputStream(elementBytes);
-    ASN1Reader reader = new ASN1Reader(bais);
-
-    reader.setIOTimeout(30000);
-    assertEquals(reader.getIOTimeout(), -1);
-
-    ASN1Element e = reader.readElement();
-    assertEquals(e.encode(), elementBytes);
-    assertEquals(ASN1Element.decode(elementBytes), e);
-
-    assertNull(reader.readElement());
-    reader.close();
-  }
-
-
-
-  /**
-   * Tests reading elements from a socket.
-   *
-   * @param  elementBytes  The byte array that makes up an encoded element.
-   *
-   * @throws  Exception  If an unexpected problem occurs.
-   */
-  @Test(dataProvider = "elementArrays")
-  public void testReadFromSocket(byte[] elementBytes)
-         throws Exception
-  {
-    SocketWriteThread writeThread  = null;
-    Socket            socket       = null;
-    ServerSocket      serverSocket = null;
-
-    try
-    {
-      ASN1Element element = ASN1Element.decode(elementBytes);
-
-      serverSocket = new ServerSocket();
-      serverSocket.setReuseAddress(true);
-      serverSocket.bind(new InetSocketAddress("127.0.0.1", 0));
-
-      writeThread = new SocketWriteThread("testReadFromSocket",
-                                          serverSocket.getLocalPort(),
-                                          elementBytes);
-      writeThread.start();
-
-      socket = serverSocket.accept();
-      ASN1Reader reader = new ASN1Reader(socket);
-      reader.setIOTimeout(30000);
-      assertEquals(reader.getIOTimeout(), 30000);
-
-      ASN1Element element2 = reader.readElement();
-
-      assertEquals(element2, element);
-      assertEquals(element2.encode(), elementBytes);
-    }
-    finally
-    {
-      try
-      {
-        writeThread.close();
-      } catch (Exception e) {}
-
-      try
-      {
-        socket.close();
-      } catch (Exception e) {}
-
-      try
-      {
-        serverSocket.close();
-      } catch (Exception e) {}
-    }
-  }
-
-
-
-  /**
-   * Tests reading elements from an input stream with all elements falling below
-   * the maximum element size.
-   *
-   * @param  elementBytes  The byte array that makes up an encoded element.
-   *
-   * @throws  Exception  If an unexpected problem occurs.
-   */
-  @Test(dataProvider = "elementArrays")
-  public void testReadSuccessWithMaxElementSize(byte[] elementBytes)
-         throws Exception
-  {
-    ByteArrayInputStream bais = new ByteArrayInputStream(elementBytes);
-    ASN1Reader reader = new ASN1Reader(bais);
-
-    reader.setMaxElementSize(elementBytes.length);
-    assertEquals(reader.getMaxElementSize(), elementBytes.length);
-
-    ASN1Element e = reader.readElement();
-    assertEquals(e.encode(), elementBytes);
-    assertEquals(ASN1Element.decode(elementBytes), e);
-
-    assertNull(reader.readElement());
-    reader.close();
-  }
-
-
-
-  /**
-   * Tests reading elements from an input stream with all elements falling above
-   * the maximum element size.
-   *
-   * @param  elementBytes  The byte array that makes up an encoded element.
-   *
-   * @throws  Exception  If an unexpected problem occurs.
-   */
-  @Test(dataProvider = "elementArrays",
-        expectedExceptions = { ASN1Exception.class, IOException.class })
-  public void testReadFailureWithMaxElementSize(byte[] elementBytes)
-         throws Exception
-  {
-    ByteArrayInputStream bais = new ByteArrayInputStream(elementBytes);
-    ASN1Reader reader = new ASN1Reader(bais);
-
-    reader.setMaxElementSize(1);
-    assertEquals(reader.getMaxElementSize(), 1);
-
-    try
-    {
-      ASN1Element e = reader.readElement();
-      if (e.value().length <= 1)
-      {
-        throw new ASN1Exception(Message.raw("Too small to trip the max element size"));
-      }
-    }
-    finally
-    {
-      reader.close();
-    }
-  }
-
-
-
-  /**
-   * Tests to ensure that attempting to read an element with a length encoded in
-   * too many bytes will fail.
-   *
-   * @throws  Exception  If an unexpected problem occurs.
-   */
-  @Test(expectedExceptions = { ASN1Exception.class, IOException.class })
-  public void testReadFailureLongLength()
-         throws Exception
-  {
-    byte[] elementBytes = { 0x04, (byte) 0x85, 0x00, 0x00, 0x00, 0x00, 0x00 };
-    ByteArrayInputStream bais = new ByteArrayInputStream(elementBytes);
-    ASN1Reader reader = new ASN1Reader(bais);
-
-    try
-    {
-      ASN1Element e = reader.readElement();
-    }
-    finally
-    {
-      reader.close();
-    }
-  }
-
-
-
-  /**
-   * Tests to ensure that attempting to read an element with a truncated length
-   * will fail.
-   *
-   * @throws  Exception  If an unexpected problem occurs.
-   */
-  @Test(expectedExceptions = { ASN1Exception.class, IOException.class })
-  public void testReadFailureTruncatedLength()
-         throws Exception
-  {
-    byte[] elementBytes = { 0x04, (byte) 0x82, 0x00 };
-    ByteArrayInputStream bais = new ByteArrayInputStream(elementBytes);
-    ASN1Reader reader = new ASN1Reader(bais);
-
-    try
-    {
-      ASN1Element e = reader.readElement();
-    }
-    finally
-    {
-      reader.close();
-    }
-  }
-
-
-
-  /**
-   * Tests to ensure that attempting to read an element with a truncated value
-   * will fail.
-   *
-   * @throws  Exception  If an unexpected problem occurs.
-   */
-  @Test(expectedExceptions = { ASN1Exception.class, IOException.class })
-  public void testReadFailureTruncatedValue()
-         throws Exception
-  {
-    byte[] elementBytes = { 0x04, 0x02, 0x00 };
-    ByteArrayInputStream bais = new ByteArrayInputStream(elementBytes);
-    ASN1Reader reader = new ASN1Reader(bais);
-
-    try
-    {
-      ASN1Element e = reader.readElement();
-    }
-    finally
-    {
-      reader.close();
-    }
-  }
-}
-
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/asn1/TestASN1Sequence.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/asn1/TestASN1Sequence.java
deleted file mode 100644
index 9b58e48..0000000
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/asn1/TestASN1Sequence.java
+++ /dev/null
@@ -1,638 +0,0 @@
-/*
- * CDDL HEADER START
- *
- * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
- *
- * You can obtain a copy of the license at
- * trunk/opends/resource/legal-notices/OpenDS.LICENSE
- * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
- * See the License for the specific language governing permissions
- * and limitations under the License.
- *
- * When distributing Covered Code, include this CDDL HEADER in each
- * file and include the License file at
- * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
- * add the following below this CDDL 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.server.protocols.asn1;
-
-
-
-import java.util.ArrayList;
-
-import org.testng.annotations.BeforeClass;
-import org.testng.annotations.DataProvider;
-import org.testng.annotations.Test;
-
-import static org.testng.Assert.*;
-
-
-
-/**
- * This class defines a set of tests for the
- * org.opends.server.protocols.asn1.ASN1Sequence class.
- */
-public class TestASN1Sequence
-       extends ASN1TestCase
-{
-  // The array of element arrays to use for the testing.  Each element is a
-  // single-element array containing a byte[] with the encoded elements.
-  private Object[][] elementArrays;
-
-  // The array of elements to use for the testing.  Each element is a
-  // single-element array containing an ArrayList<ASN1Element>.
-  private Object[][] elementLists;
-
-
-
-  /**
-   * Constructs the element lists that will be used to perform the testing.
-   */
-  @BeforeClass()
-  public void populateElementLists()
-  {
-    ArrayList<ArrayList<ASN1Element>> lists =
-         new ArrayList<ArrayList<ASN1Element>>();
-
-    // Add a null element.
-    lists.add(null);
-
-    // Add an empty list.
-    lists.add(new ArrayList<ASN1Element>());
-
-    // Create an array of single elements, and add each of them in their own
-    // lists.
-    ASN1Element[] elementArray =
-    {
-      new ASN1OctetString(),
-      new ASN1OctetString((byte) 0x50),
-      new ASN1OctetString(new byte[50]),
-      new ASN1OctetString("Hello"),
-      new ASN1Element((byte) 0x50),
-      new ASN1Element((byte) 0x50, new byte[50]),
-      new ASN1Boolean(false),
-      new ASN1Boolean(true),
-      new ASN1Enumerated(0),
-      new ASN1Enumerated(1),
-      new ASN1Enumerated(127),
-      new ASN1Enumerated(128),
-      new ASN1Enumerated(255),
-      new ASN1Enumerated(256),
-      new ASN1Integer(0),
-      new ASN1Integer(1),
-      new ASN1Integer(127),
-      new ASN1Integer(128),
-      new ASN1Integer(255),
-      new ASN1Integer(256),
-      new ASN1Long(0),
-      new ASN1Long(1),
-      new ASN1Long(127),
-      new ASN1Long(128),
-      new ASN1Long(255),
-      new ASN1Long(256),
-      new ASN1Null(),
-      new ASN1Sequence(),
-      new ASN1Set()
-    };
-
-    // Add lists of single elements.
-    for (ASN1Element e : elementArray)
-    {
-      ArrayList<ASN1Element> list = new ArrayList<ASN1Element>(1);
-      list.add(e);
-      lists.add(list);
-    }
-
-
-    // Create multi-element lists based on the single-element lists.
-    for (int i=0; i < elementArray.length; i++)
-    {
-      ArrayList<ASN1Element> list = new ArrayList<ASN1Element>(i+1);
-      for (int j=0; j <=i; j++)
-      {
-        list.add(elementArray[j]);
-      }
-      lists.add(list);
-    }
-
-
-    // Convert the lists into object arrays.
-    elementLists = new Object[lists.size()][1];
-    for (int i=0; i < elementLists.length; i++)
-    {
-      elementLists[i] = new Object[] { lists.get(i) };
-    }
-
-    lists.remove(null);
-    elementArrays = new Object[lists.size()][1];
-    for (int i=0; i < elementArrays.length; i++)
-    {
-      elementArrays[i] = new Object[] { ASN1Element.encodeValue(lists.get(i)) };
-    }
-  }
-
-
-
-  /**
-   * Retrieves lists of byte arrays that can be used to construct sequences.
-   *
-   * @return  Lists of byte arrays that can be used to construct sequences.
-   */
-  @DataProvider(name = "elementArrays")
-  public Object[][] getElementArrays()
-  {
-    return elementArrays;
-  }
-
-
-
-  /**
-   * Retrieves lists of ASN.1 elements that can be used to construct sequences.
-   *
-   * @return  Lists of ASN.1 elements that can be used to construct sequences.
-   */
-  @DataProvider(name = "elementLists")
-  public Object[][] getElementLists()
-  {
-    return elementLists;
-  }
-
-
-
-  /**
-   * Tests the first constructor, which doesn't take any arguments.
-   */
-  @Test()
-  public void testConstructor1()
-  {
-    new ASN1Sequence();
-  }
-
-
-
-  /**
-   * Create the values that can be used for testing BER types.
-   *
-   * @return  The values that can be used for testing BER types.
-   */
-  @DataProvider(name = "types")
-  public Object[][] getTypes()
-  {
-    // 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.
-    Object[][] testTypes = new Object[0xFF][1];
-    for (int i=0x00; i < 0xFF; i++)
-    {
-      testTypes[i] = new Object[] { (byte) (i & 0xFF) };
-    }
-
-    return testTypes;
-  }
-
-
-
-  /**
-   * Tests the second constructor, which takes a byte argument.
-   *
-   * @param  b  The BER type to use for the sequence.
-   */
-  @Test(dataProvider = "types")
-  public void testConstructor2(byte b)
-  {
-    new ASN1Sequence(b);
-  }
-
-
-
-  /**
-   * Tests the third constructor, which takes a list of elements.
-   *
-   * @param  elements  The list of elements to use to create the sequence.
-   */
-  @Test(dataProvider = "elementLists")
-  public void testConstructor3(ArrayList<ASN1Element> elements)
-  {
-    new ASN1Sequence(elements);
-  }
-
-
-
-  /**
-   * Tests the third constructor, which takes a byte and a list of elements.
-   *
-   * @param  elements  The list of elements to use to create the sequence.
-   */
-  @Test(dataProvider = "elementLists")
-  public void testConstructor4(ArrayList<ASN1Element> elements)
-  {
-    for (int i=0; i < 255; i++)
-    {
-      new ASN1Sequence((byte) (i & 0xFF), elements);
-    }
-  }
-
-
-
-  /**
-   * Tests the <CODE>elements</CODE> method.
-   *
-   * @param  elements  The list of elements to use to create the sequence.
-   */
-  @Test(dataProvider = "elementLists")
-  public void testGetElements(ArrayList<ASN1Element> elements)
-  {
-    ASN1Sequence s = new ASN1Sequence(elements);
-    if (elements == null)
-    {
-      assertEquals(s.elements(), new ArrayList<ASN1Element>());
-    }
-    else
-    {
-      assertEquals(s.elements(), elements);
-    }
-  }
-
-
-
-  /**
-   * Tests the <CODE>setElements</CODE> method.
-   *
-   * @param  elements  The list of elements to use to create the sequence.
-   */
-  @Test(dataProvider = "elementLists")
-  public void testSetElements(ArrayList<ASN1Element> elements)
-  {
-    ASN1Sequence s = new ASN1Sequence();
-    s.setElements(elements);
-    if (elements == null)
-    {
-      assertEquals(s.elements(), new ArrayList<ASN1Element>());
-    }
-    else
-    {
-      assertEquals(s.elements(), elements);
-    }
-  }
-
-
-
-  /**
-   * Tests the <CODE>setValue</CODE> method with valid values.
-   *
-   * @param  encodedElements  The byte array containing the encoded elements to
-   *                          use in the value.
-   *
-   * @throws  Exception  If an unexpected problem occurs.
-   */
-  @Test(dataProvider = "elementArrays")
-  public void testSetValueValid(byte[] encodedElements)
-         throws Exception
-  {
-    ASN1Sequence s = new ASN1Sequence();
-    s.setValue(encodedElements);
-  }
-
-
-
-  /**
-   * Tests the <CODE>setValue</CODE> method with a null array.
-   *
-   * @throws  Exception  If an unexpected problem occurs.
-   */
-  @Test(expectedExceptions = { ASN1Exception.class })
-  public void testSetValueNull()
-         throws Exception
-  {
-    ASN1Sequence s = new ASN1Sequence();
-    s.setValue(null);
-  }
-
-
-
-  /**
-   * Retrieves a set of byte arrays containing invalid element value encodings.
-   *
-   * @return  A set of byte arrays containing invalid element value encodings.
-   */
-  @DataProvider(name = "invalidElementArrays")
-  public Object[][] getInvalidArrays()
-  {
-    return new Object[][]
-    {
-      new Object[] { new byte[] { 0x05 } },
-      new Object[] { new byte[] { 0x05, 0x01 } },
-      new Object[] { new byte[] { 0x05, (byte) 0x85, 0x00, 0x00, 0x00, 0x00,
-                                  0x00 } },
-      new Object[] { new byte[] { 0x05, (byte) 0x82, 0x00 } },
-      new Object[] { new byte[] { 0x05, 0x00, 0x05 } },
-      new Object[] { new byte[] { 0x05, 0x00, 0x05, 0x01 } },
-    };
-  }
-
-
-
-  /**
-   * Tests the <CODE>setValue</CODE> method with valid values.
-   *
-   * @param  encodedElements  The byte array containing the encoded elements to
-   *                          use in the value.
-   *
-   * @throws  Exception  If an unexpected problem occurs.
-   */
-  @Test(dataProvider = "invalidElementArrays",
-        expectedExceptions = { ASN1Exception.class })
-  public void testSetValueInvalid(byte[] invalidElements)
-         throws Exception
-  {
-    ASN1Sequence s = new ASN1Sequence();
-    s.setValue(invalidElements);
-  }
-
-
-
-  /**
-   * Tests the <CODE>decodeAsSequence</CODE> method that takes an ASN1Element
-   * argument with valid elements.
-   *
-   * @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 testDecodeValidElementAsSequence(byte[] encodedElements)
-         throws Exception
-  {
-    ASN1Element e = new ASN1Element(ASN1Constants.UNIVERSAL_SEQUENCE_TYPE,
-                                    encodedElements);
-    ASN1Sequence.decodeAsSequence(e);
-  }
-
-
-
-  /**
-   * Tests the <CODE>decodeAsSequence</CODE> method that takes an ASN1Element
-   * argument with valid elements.
-   *
-   * @throws  Exception  If an unexpected problem occurs.
-   */
-  @Test(expectedExceptions = { ASN1Exception.class })
-  public void testDecodeNullElementAsSequence()
-         throws Exception
-  {
-    ASN1Element e = null;
-    ASN1Sequence.decodeAsSequence(e);
-  }
-
-
-
-  /**
-   * 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(byte[] encodedElements)
-         throws Exception
-  {
-    byte[] encodedLength = ASN1Element.encodeLength(encodedElements.length);
-    byte[] elementBytes  =
-         new byte[1 + encodedLength.length + encodedElements.length];
-    elementBytes[0] = ASN1Constants.UNIVERSAL_SEQUENCE_TYPE;
-    System.arraycopy(encodedLength, 0, elementBytes, 1, encodedLength.length);
-    System.arraycopy(encodedElements, 0, elementBytes, 1+encodedLength.length,
-                     encodedElements.length);
-    ASN1Sequence.decodeAsSequence(elementBytes);
-  }
-
-
-
-  /**
-   * Tests the <CODE>decodeAsSequence</CODE> method that takes a byte array
-   * argument with a null array.
-   *
-   * @throws  Exception  If an unexpected problem occurs.
-   */
-  @Test(expectedExceptions = { ASN1Exception.class })
-  public void testDecodeNullArrayAsSequence()
-         throws Exception
-  {
-    byte[] b = null;
-    ASN1Sequence.decodeAsSequence(b);
-  }
-
-
-
-  /**
-   * 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 = { ASN1Exception.class })
-  public void testDecodeShortArrayAsSequence()
-         throws Exception
-  {
-    byte[] b = new byte[1];
-    ASN1Sequence.decodeAsSequence(b);
-  }
-
-
-
-  /**
-   * 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 = { ASN1Exception.class })
-  public void testDecodeLongLengthArrayAsSequence()
-         throws Exception
-  {
-    byte[] b = { 0x30, (byte) 0x85, 0x00, 0x00, 0x00, 0x00, 0x00 };
-    ASN1Sequence.decodeAsSequence(b);
-  }
-
-
-
-  /**
-   * 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 = { ASN1Exception.class })
-  public void testDecodeTruncatedLengthArrayAsSequence()
-         throws Exception
-  {
-    byte[] b = { 0x30, (byte) 0x82, 0x00 };
-    ASN1Sequence.decodeAsSequence(b);
-  }
-
-
-
-  /**
-   * Tests the <CODE>decodeAsSequence</CODE> method that takes a byte array
-   * argument with an array whose decoded length doesn't match the real length.
-   *
-   * @throws  Exception  If an unexpected problem occurs.
-   */
-  @Test(expectedExceptions = { ASN1Exception.class })
-  public void testDecodeLengthMismatchArrayAsSequence()
-         throws Exception
-  {
-    byte[] b = { 0x30, 0x01 };
-    ASN1Sequence.decodeAsSequence(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 testDecodeTypeAndValidArrayAsSequence(byte[] encodedElements)
-         throws Exception
-  {
-    for (int i=0; i < 255; i++)
-    {
-      byte[] encodedLength = ASN1Element.encodeLength(encodedElements.length);
-      byte[] elementBytes  =
-           new byte[1 + encodedLength.length + encodedElements.length];
-      elementBytes[0] = ASN1Constants.UNIVERSAL_SEQUENCE_TYPE;
-      System.arraycopy(encodedLength, 0, elementBytes, 1, encodedLength.length);
-      System.arraycopy(encodedElements, 0, elementBytes, 1+encodedLength.length,
-                       encodedElements.length);
-      ASN1Sequence.decodeAsSequence((byte) (i & 0xFF), elementBytes);
-    }
-  }
-
-
-
-  /**
-   * Tests the <CODE>decodeAsSequence</CODE> method that takes a byte array
-   * argument with a null array.
-   *
-   * @throws  Exception  If an unexpected problem occurs.
-   */
-  @Test(expectedExceptions = { ASN1Exception.class })
-  public void testDecodeTypeAndNullArrayAsSequence()
-         throws Exception
-  {
-    byte[] b = null;
-    ASN1Sequence.decodeAsSequence((byte) 0x50, b);
-  }
-
-
-
-  /**
-   * 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 = { ASN1Exception.class })
-  public void testDecodeTypeAndShortArrayAsSequence()
-         throws Exception
-  {
-    byte[] b = new byte[1];
-    ASN1Sequence.decodeAsSequence((byte) 0x50, b);
-  }
-
-
-
-  /**
-   * 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 = { ASN1Exception.class })
-  public void testDecodeTypeAndLongLengthArrayAsSequence()
-         throws Exception
-  {
-    byte[] b = { 0x30, (byte) 0x85, 0x00, 0x00, 0x00, 0x00, 0x00 };
-    ASN1Sequence.decodeAsSequence((byte) 0x50, b);
-  }
-
-
-
-  /**
-   * 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 = { ASN1Exception.class })
-  public void testDecodeTypeAndTruncatedLengthArrayAsSequence()
-         throws Exception
-  {
-    byte[] b = { 0x30, (byte) 0x82, 0x00 };
-    ASN1Sequence.decodeAsSequence((byte) 0x50, b);
-  }
-
-
-
-  /**
-   * Tests the <CODE>decodeAsSequence</CODE> method that takes a byte array
-   * argument with an array whose decoded length doesn't match the real length.
-   *
-   * @throws  Exception  If an unexpected problem occurs.
-   */
-  @Test(expectedExceptions = { ASN1Exception.class })
-  public void testDecodeTypeAndLengthMismatchArrayAsSequence()
-         throws Exception
-  {
-    byte[] b = { 0x30, 0x01 };
-    ASN1Sequence.decodeAsSequence((byte) 0x50, b);
-  }
-
-
-
-  /**
-   * Tests the <CODE>toString</CODE> method that takes a string builder
-   * argument.
-   *
-   * @param  elements  The list of elements to use to create the sequence.
-   */
-  @Test(dataProvider = "elementLists")
-  public void testToString1(ArrayList<ASN1Element> elements)
-  {
-    new ASN1Sequence(elements).toString(new StringBuilder());
-  }
-
-
-
-  /**
-   * Tests the <CODE>toString</CODE> method that takes string builder and
-   * integer arguments.
-   *
-   * @param  elements  The list of elements to use to create the sequence.
-   */
-  @Test(dataProvider = "elementLists")
-  public void testToString2(ArrayList<ASN1Element> elements)
-  {
-    new ASN1Sequence(elements).toString(new StringBuilder(), 1);
-  }
-}
-
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/asn1/TestASN1Set.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/asn1/TestASN1Set.java
deleted file mode 100644
index a854c5a..0000000
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/asn1/TestASN1Set.java
+++ /dev/null
@@ -1,530 +0,0 @@
-/*
- * CDDL HEADER START
- *
- * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
- *
- * You can obtain a copy of the license at
- * trunk/opends/resource/legal-notices/OpenDS.LICENSE
- * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
- * See the License for the specific language governing permissions
- * and limitations under the License.
- *
- * When distributing Covered Code, include this CDDL HEADER in each
- * file and include the License file at
- * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
- * add the following below this CDDL 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.server.protocols.asn1;
-
-
-
-import java.util.ArrayList;
-
-import org.testng.annotations.BeforeClass;
-import org.testng.annotations.DataProvider;
-import org.testng.annotations.Test;
-
-import static org.testng.Assert.*;
-
-
-
-/**
- * This class defines a set of tests for the
- * org.opends.server.protocols.asn1.ASN1Set class.
- */
-public class TestASN1Set
-       extends ASN1TestCase
-{
-  // The array of element arrays to use for the testing.  Each element is a
-  // single-element array containing a byte[] with the encoded elements.
-  private Object[][] elementArrays;
-
-  // The array of elements to use for the testing.  Each element is a
-  // single-element array containing an ArrayList<ASN1Element>.
-  private Object[][] elementLists;
-
-
-
-  /**
-   * Constructs the element lists that will be used to perform the testing.
-   */
-  @BeforeClass()
-  public void populateElementLists()
-  {
-    ArrayList<ArrayList<ASN1Element>> lists =
-         new ArrayList<ArrayList<ASN1Element>>();
-
-    // Add a null element.
-    lists.add(null);
-
-    // Add an empty list.
-    lists.add(new ArrayList<ASN1Element>());
-
-    // Create an array of single elements, and add each of them in their own
-    // lists.
-    ASN1Element[] elementArray =
-    {
-      new ASN1OctetString(),
-      new ASN1OctetString((byte) 0x50),
-      new ASN1OctetString(new byte[50]),
-      new ASN1OctetString("Hello"),
-      new ASN1Element((byte) 0x50),
-      new ASN1Element((byte) 0x50, new byte[50]),
-      new ASN1Boolean(false),
-      new ASN1Boolean(true),
-      new ASN1Enumerated(0),
-      new ASN1Enumerated(1),
-      new ASN1Enumerated(127),
-      new ASN1Enumerated(128),
-      new ASN1Enumerated(255),
-      new ASN1Enumerated(256),
-      new ASN1Integer(0),
-      new ASN1Integer(1),
-      new ASN1Integer(127),
-      new ASN1Integer(128),
-      new ASN1Integer(255),
-      new ASN1Integer(256),
-      new ASN1Long(0),
-      new ASN1Long(1),
-      new ASN1Long(127),
-      new ASN1Long(128),
-      new ASN1Long(255),
-      new ASN1Long(256),
-      new ASN1Null(),
-      new ASN1Sequence(),
-      new ASN1Set()
-    };
-
-    // Add lists of single elements.
-    for (ASN1Element e : elementArray)
-    {
-      ArrayList<ASN1Element> list = new ArrayList<ASN1Element>(1);
-      list.add(e);
-      lists.add(list);
-    }
-
-
-    // Create multi-element lists based on the single-element lists.
-    for (int i=0; i < elementArray.length; i++)
-    {
-      ArrayList<ASN1Element> list = new ArrayList<ASN1Element>(i+1);
-      for (int j=0; j <=i; j++)
-      {
-        list.add(elementArray[j]);
-      }
-      lists.add(list);
-    }
-
-
-    // Convert the lists into object arrays.
-    elementLists = new Object[lists.size()][1];
-    for (int i=0; i < elementLists.length; i++)
-    {
-      elementLists[i] = new Object[] { lists.get(i) };
-    }
-
-    lists.remove(null);
-    elementArrays = new Object[lists.size()][1];
-    for (int i=0; i < elementArrays.length; i++)
-    {
-      elementArrays[i] = new Object[] { ASN1Element.encodeValue(lists.get(i)) };
-    }
-  }
-
-
-
-  /**
-   * Retrieves lists of byte arrays that can be used to construct sets.
-   *
-   * @return  Lists of byte arrays that can be used to construct sets.
-   */
-  @DataProvider(name = "elementArrays")
-  public Object[][] getElementArrays()
-  {
-    return elementArrays;
-  }
-
-
-
-  /**
-   * Retrieves lists of ASN.1 elements that can be used to construct sets.
-   *
-   * @return  Lists of ASN.1 elements that can be used to construct sets.
-   */
-  @DataProvider(name = "elementLists")
-  public Object[][] getElementLists()
-  {
-    return elementLists;
-  }
-
-
-
-  /**
-   * Tests the first constructor, which doesn't take any arguments.
-   */
-  @Test()
-  public void testConstructor1()
-  {
-    new ASN1Set();
-  }
-
-
-
-  /**
-   * Create the values that can be used for testing BER types.
-   *
-   * @return  The values that can be used for testing BER types.
-   */
-  @DataProvider(name = "types")
-  public Object[][] getTypes()
-  {
-    // 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.
-    Object[][] testTypes = new Object[0xFF][1];
-    for (int i=0x00; i < 0xFF; i++)
-    {
-      testTypes[i] = new Object[] { (byte) (i & 0xFF) };
-    }
-
-    return testTypes;
-  }
-
-
-
-  /**
-   * Tests the second constructor, which takes a byte argument.
-   *
-   * @param  b  The BER type to use for the set.
-   */
-  @Test(dataProvider = "types")
-  public void testConstructor2(byte b)
-  {
-    new ASN1Set(b);
-  }
-
-
-
-  /**
-   * Tests the third constructor, which takes a list of elements.
-   *
-   * @param  elements  The list of elements to use to create the set.
-   */
-  @Test(dataProvider = "elementLists")
-  public void testConstructor3(ArrayList<ASN1Element> elements)
-  {
-    new ASN1Set(elements);
-  }
-
-
-
-  /**
-   * Tests the third constructor, which takes a byte and a list of elements.
-   *
-   * @param  elements  The list of elements to use to create the set.
-   */
-  @Test(dataProvider = "elementLists")
-  public void testConstructor4(ArrayList<ASN1Element> elements)
-  {
-    for (int i=0; i < 255; i++)
-    {
-      new ASN1Set((byte) (i & 0xFF), elements);
-    }
-  }
-
-
-
-  /**
-   * Tests the <CODE>elements</CODE> method.
-   *
-   * @param  elements  The list of elements to use to create the set.
-   */
-  @Test(dataProvider = "elementLists")
-  public void testGetElements(ArrayList<ASN1Element> elements)
-  {
-    ASN1Set s = new ASN1Set(elements);
-    if (elements == null)
-    {
-      assertEquals(s.elements(), new ArrayList<ASN1Element>());
-    }
-    else
-    {
-      assertEquals(s.elements(), elements);
-    }
-  }
-
-
-
-  /**
-   * Tests the <CODE>setElements</CODE> method.
-   *
-   * @param  elements  The list of elements to use to create the set.
-   */
-  @Test(dataProvider = "elementLists")
-  public void testSetElements(ArrayList<ASN1Element> elements)
-  {
-    ASN1Set s = new ASN1Set();
-    s.setElements(elements);
-    if (elements == null)
-    {
-      assertEquals(s.elements(), new ArrayList<ASN1Element>());
-    }
-    else
-    {
-      assertEquals(s.elements(), elements);
-    }
-  }
-
-
-
-  /**
-   * Tests the <CODE>setValue</CODE> method with valid values.
-   *
-   * @param  encodedElements  The byte array containing the encoded elements to
-   *                          use in the value.
-   *
-   * @throws  Exception  If an unexpected problem occurs.
-   */
-  @Test(dataProvider = "elementArrays")
-  public void testSetValueValid(byte[] encodedElements)
-         throws Exception
-  {
-    ASN1Set s = new ASN1Set();
-    s.setValue(encodedElements);
-  }
-
-
-
-  /**
-   * Tests the <CODE>setValue</CODE> method with a null array.
-   *
-   * @throws  Exception  If an unexpected problem occurs.
-   */
-  @Test(expectedExceptions = { ASN1Exception.class })
-  public void testSetValueNull()
-         throws Exception
-  {
-    ASN1Set s = new ASN1Set();
-    s.setValue(null);
-  }
-
-
-
-  /**
-   * Retrieves a set of byte arrays containing invalid element value encodings.
-   *
-   * @return  A set of byte arrays containing invalid element value encodings.
-   */
-  @DataProvider(name = "invalidElementArrays")
-  public Object[][] getInvalidArrays()
-  {
-    return new Object[][]
-    {
-      new Object[] { new byte[] { 0x05 } },
-      new Object[] { new byte[] { 0x05, 0x01 } },
-      new Object[] { new byte[] { 0x05, (byte) 0x85, 0x00, 0x00, 0x00, 0x00,
-                                  0x00 } },
-      new Object[] { new byte[] { 0x05, (byte) 0x82, 0x00 } },
-      new Object[] { new byte[] { 0x05, 0x00, 0x05 } },
-      new Object[] { new byte[] { 0x05, 0x00, 0x05, 0x01 } },
-    };
-  }
-
-
-
-  /**
-   * Tests the <CODE>setValue</CODE> method with valid values.
-   *
-   * @param  encodedElements  The byte array containing the encoded elements to
-   *                          use in the value.
-   *
-   * @throws  Exception  If an unexpected problem occurs.
-   */
-  @Test(dataProvider = "invalidElementArrays",
-        expectedExceptions = { ASN1Exception.class })
-  public void testSetValueInvalid(byte[] invalidElements)
-         throws Exception
-  {
-    ASN1Set s = new ASN1Set();
-    s.setValue(invalidElements);
-  }
-
-
-
-  /**
-   * Tests the <CODE>decodeAsSet</CODE> method that takes an ASN1Element
-   * argument with valid elements.
-   *
-   * @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 testDecodeValidElementAsSet(byte[] encodedElements)
-         throws Exception
-  {
-    ASN1Element e = new ASN1Element(ASN1Constants.UNIVERSAL_SET_TYPE,
-                                    encodedElements);
-    ASN1Set.decodeAsSet(e);
-  }
-
-
-
-  /**
-   * Tests the <CODE>decodeAsSet</CODE> method that takes an ASN1Element
-   * argument with valid elements.
-   *
-   * @throws  Exception  If an unexpected problem occurs.
-   */
-  @Test(expectedExceptions = { ASN1Exception.class })
-  public void testDecodeNullElementAsSet()
-         throws Exception
-  {
-    ASN1Element e = null;
-    ASN1Set.decodeAsSet(e);
-  }
-
-
-
-  /**
-   * Tests the <CODE>decodeAsSet</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 testDecodeValidArrayAsSet(byte[] encodedElements)
-         throws Exception
-  {
-    byte[] encodedLength = ASN1Element.encodeLength(encodedElements.length);
-    byte[] elementBytes  =
-         new byte[1 + encodedLength.length + encodedElements.length];
-    elementBytes[0] = ASN1Constants.UNIVERSAL_SET_TYPE;
-    System.arraycopy(encodedLength, 0, elementBytes, 1, encodedLength.length);
-    System.arraycopy(encodedElements, 0, elementBytes, 1+encodedLength.length,
-                     encodedElements.length);
-    ASN1Set.decodeAsSet(elementBytes);
-  }
-
-
-
-  /**
-   * Tests the <CODE>decodeAsSet</CODE> method that takes a byte array argument
-   * with a null array.
-   *
-   * @throws  Exception  If an unexpected problem occurs.
-   */
-  @Test(expectedExceptions = { ASN1Exception.class })
-  public void testDecodeNullArrayAsSet()
-         throws Exception
-  {
-    byte[] b = null;
-    ASN1Set.decodeAsSet(b);
-  }
-
-
-
-  /**
-   * Tests the <CODE>decodeAsSet</CODE> method that takes a byte array argument
-   * with a short array.
-   *
-   * @throws  Exception  If an unexpected problem occurs.
-   */
-  @Test(expectedExceptions = { ASN1Exception.class })
-  public void testDecodeShortArrayAsSet()
-         throws Exception
-  {
-    byte[] b = new byte[1];
-    ASN1Set.decodeAsSet(b);
-  }
-
-
-
-  /**
-   * Tests the <CODE>decodeAsSet</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 = { ASN1Exception.class })
-  public void testDecodeLongLengthArrayAsSet()
-         throws Exception
-  {
-    byte[] b = { 0x30, (byte) 0x85, 0x00, 0x00, 0x00, 0x00, 0x00 };
-    ASN1Set.decodeAsSet(b);
-  }
-
-
-
-  /**
-   * Tests the <CODE>decodeAsSet</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 = { ASN1Exception.class })
-  public void testDecodeTruncatedLengthArrayAsSet()
-         throws Exception
-  {
-    byte[] b = { 0x30, (byte) 0x82, 0x00 };
-    ASN1Set.decodeAsSet(b);
-  }
-
-
-
-  /**
-   * Tests the <CODE>decodeAsSet</CODE> method that takes a byte array argument
-   * with an array whose decoded length doesn't match the real length.
-   *
-   * @throws  Exception  If an unexpected problem occurs.
-   */
-  @Test(expectedExceptions = { ASN1Exception.class })
-  public void testDecodeLengthMismatchArrayAsSet()
-         throws Exception
-  {
-    byte[] b = { 0x30, 0x01 };
-    ASN1Set.decodeAsSet(b);
-  }
-
-
-
-  /**
-   * Tests the <CODE>toString</CODE> method that takes a string builder
-   * argument.
-   *
-   * @param  elements  The list of elements to use to create the set.
-   */
-  @Test(dataProvider = "elementLists")
-  public void testToString1(ArrayList<ASN1Element> elements)
-  {
-    new ASN1Set(elements).toString(new StringBuilder());
-  }
-
-
-
-  /**
-   * Tests the <CODE>toString</CODE> method that takes string builder and
-   * integer arguments.
-   *
-   * @param  elements  The list of elements to use to create the set.
-   */
-  @Test(dataProvider = "elementLists")
-  public void testToString2(ArrayList<ASN1Element> elements)
-  {
-    new ASN1Set(elements).toString(new StringBuilder(), 1);
-  }
-}
-
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/internal/InternalClientConnectionTestCase.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/internal/InternalClientConnectionTestCase.java
index ac5386e..c379d5f 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/internal/InternalClientConnectionTestCase.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/internal/InternalClientConnectionTestCase.java
@@ -41,7 +41,6 @@
 
 import org.opends.server.TestCaseUtils;
 import org.opends.messages.Message;
-import org.opends.server.api.ConnectionSecurityProvider;
 import org.opends.server.core.AddOperation;
 import org.opends.server.core.BindOperation;
 import org.opends.server.core.CompareOperation;
@@ -50,28 +49,10 @@
 import org.opends.server.core.ExtendedOperation;
 import org.opends.server.core.ModifyDNOperation;
 import org.opends.server.core.ModifyOperation;
-import org.opends.server.protocols.asn1.ASN1OctetString;
 import org.opends.server.protocols.ldap.LDAPAttribute;
 import org.opends.server.protocols.ldap.LDAPFilter;
 import org.opends.server.protocols.ldap.LDAPModification;
-import org.opends.server.types.Attributes;
-import org.opends.server.types.AuthenticationInfo;
-import org.opends.server.types.CancelRequest;
-import org.opends.server.types.CancelResult;
-import org.opends.server.types.DN;
-import org.opends.server.types.DereferencePolicy;
-import org.opends.server.types.DisconnectReason;
-import org.opends.server.types.Entry;
-import org.opends.server.types.Modification;
-import org.opends.server.types.ModificationType;
-import org.opends.server.types.Operation;
-import org.opends.server.types.RawAttribute;
-import org.opends.server.types.RawModification;
-import org.opends.server.types.RDN;
-import org.opends.server.types.ResultCode;
-import org.opends.server.types.SearchFilter;
-import org.opends.server.types.SearchResultReference;
-import org.opends.server.types.SearchScope;
+import org.opends.server.types.*;
 import org.testng.annotations.BeforeClass;
 import org.testng.annotations.DataProvider;
 import org.testng.annotations.Test;
@@ -285,12 +266,14 @@
    *
    * @param  conn  The internal client connection to use for the test.
    */
-  @Test(dataProvider = "internalConns")
+ /*MPD
+  *  @Test(dataProvider = "internalConns")
+
   public void testGetConnectionSecurityProvider(InternalClientConnection conn)
   {
     assertNotNull(conn.getConnectionSecurityProvider());
   }
-
+*/
 
 
   /**
@@ -298,6 +281,7 @@
    *
    * @param  conn  The internal client connection to use for the test.
    */
+  /* MPD
   @Test(dataProvider = "internalConns")
   public void testSetConnectionSecurityProvider(InternalClientConnection conn)
   {
@@ -306,20 +290,7 @@
     assertNotNull(securityProvider);
     conn.setConnectionSecurityProvider(securityProvider);
   }
-
-
-
-  /**
-   * Tests the <CODE>getSecurityMechanism</CODE> method.
-   *
-   * @param  conn  The internal client connection to use for the test.
-   */
-  @Test(dataProvider = "internalConns")
-  public void testGetSecurityMechanism(InternalClientConnection conn)
-  {
-    assertNotNull(conn.getSecurityMechanism());
-  }
-
+*/
 
 
   /**
@@ -346,17 +317,17 @@
   {
     TestCaseUtils.initializeTestBackend(true);
 
-    ASN1OctetString dn = new ASN1OctetString("cn=test,o=test");
+    ByteString dn = ByteString.valueOf("cn=test,o=test");
 
     ArrayList<RawAttribute> attrs = new ArrayList<RawAttribute>();
 
-    ArrayList<ASN1OctetString> values = new ArrayList<ASN1OctetString>();
-    values.add(new ASN1OctetString("top"));
-    values.add(new ASN1OctetString("device"));
+    ArrayList<ByteString> values = new ArrayList<ByteString>();
+    values.add(ByteString.valueOf("top"));
+    values.add(ByteString.valueOf("device"));
     attrs.add(new LDAPAttribute("objectClass", values));
 
-    values = new ArrayList<ASN1OctetString>();
-    values.add(new ASN1OctetString("test"));
+    values = new ArrayList<ByteString>();
+    values.add(ByteString.valueOf("test"));
     attrs.add(new LDAPAttribute("cn", values));
 
     InternalClientConnection conn =
@@ -407,8 +378,8 @@
     InternalClientConnection conn =
          InternalClientConnection.getRootConnection();
     BindOperation bindOperation =
-         conn.processSimpleBind(new ASN1OctetString("cn=Directory Manager"),
-                                new ASN1OctetString("password"));
+         conn.processSimpleBind(ByteString.valueOf("cn=Directory Manager"),
+                                ByteString.valueOf("password"));
     assertEquals(bindOperation.getResultCode(), ResultCode.SUCCESS);
   }
 
@@ -428,7 +399,7 @@
          InternalClientConnection.getRootConnection();
     BindOperation bindOperation =
          conn.processSimpleBind(DN.decode("cn=Directory Manager"),
-                                new ASN1OctetString("password"));
+                                ByteString.valueOf("password"));
     assertEquals(bindOperation.getResultCode(), ResultCode.SUCCESS);
   }
 
@@ -444,13 +415,13 @@
   public void testProcessSASLBind1()
          throws Exception
   {
-    ASN1OctetString creds =
-         new ASN1OctetString("\u0000dn:cn=Directory Manager\u0000password");
+    ByteString creds =
+         ByteString.valueOf("\u0000dn:cn=Directory Manager\u0000password");
 
     InternalClientConnection conn =
          InternalClientConnection.getRootConnection();
     BindOperation bindOperation =
-         conn.processSASLBind(new ASN1OctetString(), "PLAIN", creds);
+         conn.processSASLBind(ByteString.empty(), "PLAIN", creds);
     assertEquals(bindOperation.getResultCode(), ResultCode.SUCCESS);
   }
 
@@ -466,8 +437,8 @@
   public void testProcessSASLBind2()
          throws Exception
   {
-    ASN1OctetString creds =
-         new ASN1OctetString("\u0000dn:cn=Directory Manager\u0000password");
+    ByteString creds =
+         ByteString.valueOf("\u0000dn:cn=Directory Manager\u0000password");
 
     InternalClientConnection conn =
          InternalClientConnection.getRootConnection();
@@ -504,8 +475,8 @@
 
 
     CompareOperation compareOperation =
-         conn.processCompare(new ASN1OctetString("cn=test,o=test"), "cn",
-                             new ASN1OctetString("test"));
+         conn.processCompare(ByteString.valueOf("cn=test,o=test"), "cn",
+                             ByteString.valueOf("test"));
     assertEquals(compareOperation.getResultCode(), ResultCode.COMPARE_TRUE);
   }
 
@@ -539,7 +510,7 @@
     CompareOperation compareOperation =
          conn.processCompare(DN.decode("cn=test,o=test"),
                              DirectoryServer.getAttributeType("cn", true),
-                             new ASN1OctetString("test"));
+                             ByteString.valueOf("test"));
     assertEquals(compareOperation.getResultCode(), ResultCode.COMPARE_TRUE);
   }
 
@@ -571,7 +542,7 @@
 
 
     DeleteOperation deleteOperation =
-         conn.processDelete(new ASN1OctetString("cn=test,o=test"));
+         conn.processDelete(ByteString.valueOf("cn=test,o=test"));
     assertEquals(deleteOperation.getResultCode(), ResultCode.SUCCESS);
   }
 
@@ -652,15 +623,15 @@
     assertEquals(addOperation.getResultCode(), ResultCode.SUCCESS);
 
 
-    ArrayList<ASN1OctetString> values = new ArrayList<ASN1OctetString>();
-    values.add(new ASN1OctetString("This is a test"));
+    ArrayList<ByteString> values = new ArrayList<ByteString>();
+    values.add(ByteString.valueOf("This is a test"));
 
     ArrayList<RawModification> mods = new ArrayList<RawModification>();
     mods.add(new LDAPModification(ModificationType.REPLACE,
                                   new LDAPAttribute("description", values)));
 
     ModifyOperation modifyOperation =
-         conn.processModify(new ASN1OctetString("cn=test,o=test"), mods);
+         conn.processModify(ByteString.valueOf("cn=test,o=test"), mods);
     assertEquals(modifyOperation.getResultCode(), ResultCode.SUCCESS);
   }
 
@@ -728,8 +699,8 @@
 
 
     ModifyDNOperation modifyDNOperation =
-         conn.processModifyDN(new ASN1OctetString("cn=test,o=test"),
-                              new ASN1OctetString("cn=test2"), true);
+         conn.processModifyDN(ByteString.valueOf("cn=test,o=test"),
+                              ByteString.valueOf("cn=test2"), true);
     assertEquals(modifyDNOperation.getResultCode(), ResultCode.SUCCESS);
   }
 
@@ -761,9 +732,9 @@
 
 
     ModifyDNOperation modifyDNOperation =
-         conn.processModifyDN(new ASN1OctetString("cn=test,o=test"),
-                              new ASN1OctetString("cn=test2"), true,
-                              new ASN1OctetString("dc=example,dc=com"));
+         conn.processModifyDN(ByteString.valueOf("cn=test,o=test"),
+                              ByteString.valueOf("cn=test2"), true,
+                              ByteString.valueOf("dc=example,dc=com"));
     assertEquals(modifyDNOperation.getResultCode(),
                  ResultCode.UNWILLING_TO_PERFORM);
   }
@@ -851,7 +822,7 @@
     InternalClientConnection conn =
          InternalClientConnection.getRootConnection();
     InternalSearchOperation searchOperation =
-         conn.processSearch(new ASN1OctetString(""), SearchScope.BASE_OBJECT,
+         conn.processSearch(ByteString.valueOf(""), SearchScope.BASE_OBJECT,
                             LDAPFilter.decode("(objectClass=*)"));
     assertEquals(searchOperation.getResultCode(), ResultCode.SUCCESS);
     assertFalse(searchOperation.getSearchEntries().isEmpty());
@@ -873,7 +844,7 @@
     InternalClientConnection conn =
          InternalClientConnection.getRootConnection();
     InternalSearchOperation searchOperation =
-         conn.processSearch(new ASN1OctetString(""), SearchScope.BASE_OBJECT,
+         conn.processSearch(ByteString.valueOf(""), SearchScope.BASE_OBJECT,
                             DereferencePolicy.NEVER_DEREF_ALIASES, 0, 0, false,
                             LDAPFilter.decode("(objectClass=*)"),
                             new LinkedHashSet<String>());
@@ -901,7 +872,7 @@
     InternalClientConnection conn =
          InternalClientConnection.getRootConnection();
     InternalSearchOperation searchOperation =
-         conn.processSearch(new ASN1OctetString(""), SearchScope.BASE_OBJECT,
+         conn.processSearch(ByteString.valueOf(""), SearchScope.BASE_OBJECT,
                             DereferencePolicy.NEVER_DEREF_ALIASES, 0, 0, false,
                             LDAPFilter.decode("(objectClass=*)"),
                             new LinkedHashSet<String>(), searchListener);
@@ -998,7 +969,7 @@
     InternalClientConnection conn =
          InternalClientConnection.getRootConnection();
     InternalSearchOperation searchOperation =
-         conn.processSearch(new ASN1OctetString(""), SearchScope.BASE_OBJECT,
+         conn.processSearch(ByteString.valueOf(""), SearchScope.BASE_OBJECT,
                             LDAPFilter.decode("(objectClass=*)"));
     assertEquals(searchOperation.getResultCode(), ResultCode.SUCCESS);
     assertFalse(searchOperation.getSearchEntries().isEmpty());
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/internal/InternalLDAPSocketTestCase.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/internal/InternalLDAPSocketTestCase.java
index 8d303df..916dbdd 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/internal/InternalLDAPSocketTestCase.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/internal/InternalLDAPSocketTestCase.java
@@ -46,7 +46,6 @@
 
 import org.opends.server.TestCaseUtils;
 import org.opends.server.core.DirectoryServer;
-import org.opends.server.protocols.asn1.ASN1OctetString;
 import org.opends.server.protocols.ldap.*;
 import org.opends.server.tools.LDAPReader;
 import org.opends.server.tools.LDAPWriter;
@@ -97,8 +96,8 @@
     LDAPWriter writer = new LDAPWriter(socket);
 
     BindRequestProtocolOp bindRequest =
-         new BindRequestProtocolOp(new ASN1OctetString("cn=Directory Manager"),
-                                   3, new ASN1OctetString("password"));
+         new BindRequestProtocolOp(ByteString.valueOf("cn=Directory Manager"),
+                                   3, ByteString.valueOf("password"));
     LDAPMessage message = new LDAPMessage(1, bindRequest);
     writer.writeMessage(message);
 
@@ -112,7 +111,7 @@
     attrList.add(RawAttribute.create("o", "test"));
 
     AddRequestProtocolOp addRequest =
-         new AddRequestProtocolOp(new ASN1OctetString("o=test"), attrList);
+         new AddRequestProtocolOp(ByteString.valueOf("o=test"), attrList);
     writer.writeMessage(new LDAPMessage(2, addRequest));
 
     message = reader.readMessage();
@@ -151,6 +150,7 @@
     env.put(Context.SECURITY_AUTHENTICATION, "simple");
     env.put(Context.SECURITY_PRINCIPAL, "cn=Directory Manager");
     env.put(Context.SECURITY_CREDENTIALS, "password");
+    env.put("com.sun.jndi.ldap.connect.pool.debug", "fine");
 
     DirContext context = new InitialDirContext(env);
 
@@ -191,8 +191,8 @@
     LDAPWriter writer = new LDAPWriter(socket);
 
     BindRequestProtocolOp bindRequest =
-         new BindRequestProtocolOp(new ASN1OctetString("cn=Directory Manager"),
-                                   3, new ASN1OctetString("password"));
+         new BindRequestProtocolOp(ByteString.valueOf("cn=Directory Manager"),
+                                   3, ByteString.valueOf("password"));
     LDAPMessage message = new LDAPMessage(1, bindRequest);
     writer.writeMessage(message);
 
@@ -202,8 +202,8 @@
 
 
     CompareRequestProtocolOp compareRequest =
-         new CompareRequestProtocolOp(new ASN1OctetString("o=test"), "o",
-                                      new ASN1OctetString("test"));
+         new CompareRequestProtocolOp(ByteString.valueOf("o=test"), "o",
+                                      ByteString.valueOf("test"));
     writer.writeMessage(new LDAPMessage(2, compareRequest));
 
     message = reader.readMessage();
@@ -277,8 +277,8 @@
     LDAPWriter writer = new LDAPWriter(socket);
 
     BindRequestProtocolOp bindRequest =
-         new BindRequestProtocolOp(new ASN1OctetString("cn=Directory Manager"),
-                                   3, new ASN1OctetString("password"));
+         new BindRequestProtocolOp(ByteString.valueOf("cn=Directory Manager"),
+                                   3, ByteString.valueOf("password"));
     LDAPMessage message = new LDAPMessage(1, bindRequest);
     writer.writeMessage(message);
 
@@ -288,7 +288,7 @@
 
 
     DeleteRequestProtocolOp deleteRequest =
-         new DeleteRequestProtocolOp(new ASN1OctetString("o=test"));
+         new DeleteRequestProtocolOp(ByteString.valueOf("o=test"));
     writer.writeMessage(new LDAPMessage(2, deleteRequest));
 
     message = reader.readMessage();
@@ -353,8 +353,8 @@
     LDAPWriter writer = new LDAPWriter(socket);
 
     BindRequestProtocolOp bindRequest =
-         new BindRequestProtocolOp(new ASN1OctetString("cn=Directory Manager"),
-                                   3, new ASN1OctetString("password"));
+         new BindRequestProtocolOp(ByteString.valueOf("cn=Directory Manager"),
+                                   3, ByteString.valueOf("password"));
     LDAPMessage message = new LDAPMessage(1, bindRequest);
     writer.writeMessage(message);
 
@@ -373,7 +373,7 @@
     ExtendedResponseProtocolOp extendedResponse =
          message.getExtendedResponseProtocolOp();
     assertEquals(extendedResponse.getResultCode(), LDAPResultCode.SUCCESS);
-    assertTrue(extendedResponse.getValue().stringValue().equalsIgnoreCase(
+    assertTrue(extendedResponse.getValue().toString().equalsIgnoreCase(
                     "dn:cn=Directory Manager,cn=Root DNs,cn=config"));
 
     reader.close();
@@ -401,8 +401,8 @@
     LDAPWriter writer = new LDAPWriter(socket);
 
     BindRequestProtocolOp bindRequest =
-         new BindRequestProtocolOp(new ASN1OctetString("cn=Directory Manager"),
-                                   3, new ASN1OctetString("password"));
+         new BindRequestProtocolOp(ByteString.valueOf("cn=Directory Manager"),
+                                   3, ByteString.valueOf("password"));
     LDAPMessage message = new LDAPMessage(1, bindRequest);
     writer.writeMessage(message);
 
@@ -416,7 +416,7 @@
                                     "foo"));
 
     ModifyRequestProtocolOp modifyRequest =
-         new ModifyRequestProtocolOp(new ASN1OctetString("o=test"), mods);
+         new ModifyRequestProtocolOp(ByteString.valueOf("o=test"), mods);
     writer.writeMessage(new LDAPMessage(2, modifyRequest));
 
     message = reader.readMessage();
@@ -494,8 +494,8 @@
     LDAPWriter writer = new LDAPWriter(socket);
 
     BindRequestProtocolOp bindRequest =
-         new BindRequestProtocolOp(new ASN1OctetString("cn=Directory Manager"),
-                                   3, new ASN1OctetString("password"));
+         new BindRequestProtocolOp(ByteString.valueOf("cn=Directory Manager"),
+                                   3, ByteString.valueOf("password"));
     LDAPMessage message = new LDAPMessage(1, bindRequest);
     writer.writeMessage(message);
 
@@ -505,8 +505,8 @@
 
 
     ModifyDNRequestProtocolOp modifyDNRequest =
-         new ModifyDNRequestProtocolOp(new ASN1OctetString("ou=People,o=test"),
-                                       new ASN1OctetString("ou=Users"), true);
+         new ModifyDNRequestProtocolOp(ByteString.valueOf("ou=People,o=test"),
+                                       ByteString.valueOf("ou=Users"), true);
     writer.writeMessage(new LDAPMessage(2, modifyDNRequest));
 
     message = reader.readMessage();
@@ -585,8 +585,8 @@
     LDAPWriter writer = new LDAPWriter(socket);
 
     BindRequestProtocolOp bindRequest =
-         new BindRequestProtocolOp(new ASN1OctetString("cn=Directory Manager"),
-                                   3, new ASN1OctetString("password"));
+         new BindRequestProtocolOp(ByteString.valueOf("cn=Directory Manager"),
+                                   3, ByteString.valueOf("password"));
     LDAPMessage message = new LDAPMessage(1, bindRequest);
     writer.writeMessage(message);
 
@@ -596,7 +596,7 @@
 
 
     SearchRequestProtocolOp searchRequest =
-         new SearchRequestProtocolOp(new ASN1OctetString("o=test"),
+         new SearchRequestProtocolOp(ByteString.valueOf("o=test"),
                                      SearchScope.BASE_OBJECT,
                                      DereferencePolicy.NEVER_DEREF_ALIASES,
                                      0, 0, false,
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/internal/InternalSearchOperationTestCase.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/internal/InternalSearchOperationTestCase.java
index a6aaa90..2c66b73 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/internal/InternalSearchOperationTestCase.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/internal/InternalSearchOperationTestCase.java
@@ -34,17 +34,8 @@
 import org.testng.annotations.Test;
 
 import org.opends.server.TestCaseUtils;
-import org.opends.server.protocols.asn1.ASN1OctetString;
 import org.opends.server.protocols.ldap.LDAPFilter;
-import org.opends.server.types.Control;
-import org.opends.server.types.DereferencePolicy;
-import org.opends.server.types.DN;
-import org.opends.server.types.Entry;
-import org.opends.server.types.ResultCode;
-import org.opends.server.types.SearchScope;
-import org.opends.server.types.SearchFilter;
-import org.opends.server.types.SearchResultEntry;
-import org.opends.server.types.SearchResultReference;
+import org.opends.server.types.*;
 
 import static org.testng.Assert.*;
 
@@ -85,7 +76,7 @@
          InternalClientConnection.getRootConnection();
     new InternalSearchOperation(conn, conn.nextOperationID(),
                                 conn.nextMessageID(), new ArrayList<Control>(),
-                                new ASN1OctetString(), SearchScope.BASE_OBJECT,
+                                ByteString.empty(), SearchScope.BASE_OBJECT,
                                 DereferencePolicy.NEVER_DEREF_ALIASES, 0, 0,
                                 false, LDAPFilter.decode("(objectClass=*)"),
                                 new LinkedHashSet<String>(), null);
@@ -107,7 +98,7 @@
          InternalClientConnection.getRootConnection();
     new InternalSearchOperation(conn, conn.nextOperationID(),
                                 conn.nextMessageID(), new ArrayList<Control>(),
-                                new ASN1OctetString(), SearchScope.BASE_OBJECT,
+                                ByteString.empty(), SearchScope.BASE_OBJECT,
                                 DereferencePolicy.NEVER_DEREF_ALIASES, 0, 0,
                                 false, LDAPFilter.decode("(objectClass=*)"),
                                 new LinkedHashSet<String>(),
@@ -180,7 +171,7 @@
     InternalClientConnection conn =
          InternalClientConnection.getRootConnection();
     InternalSearchOperation searchOperation =
-         conn.processSearch(new ASN1OctetString(""), SearchScope.BASE_OBJECT,
+         conn.processSearch(ByteString.valueOf(""), SearchScope.BASE_OBJECT,
                             LDAPFilter.decode("(objectClass=*)"));
     assertEquals(searchOperation.getResultCode(), ResultCode.SUCCESS);
     assertFalse(searchOperation.getSearchEntries().isEmpty());
@@ -204,7 +195,7 @@
          new InternalSearchOperation(conn, conn.nextOperationID(),
                                      conn.nextMessageID(),
                                      new ArrayList<Control>(),
-                                     new ASN1OctetString(),
+                                     ByteString.empty(),
                                      SearchScope.BASE_OBJECT,
                                      DereferencePolicy.NEVER_DEREF_ALIASES, 0,
                                      0, false,
@@ -234,7 +225,7 @@
          new InternalSearchOperation(conn, conn.nextOperationID(),
                                      conn.nextMessageID(),
                                      new ArrayList<Control>(),
-                                     new ASN1OctetString(),
+                                     ByteString.empty(),
                                      SearchScope.BASE_OBJECT,
                                      DereferencePolicy.NEVER_DEREF_ALIASES, 0,
                                      0, false,
@@ -265,7 +256,7 @@
          new InternalSearchOperation(conn, conn.nextOperationID(),
                                      conn.nextMessageID(),
                                      new ArrayList<Control>(),
-                                     new ASN1OctetString(),
+                                     ByteString.empty(),
                                      SearchScope.BASE_OBJECT,
                                      DereferencePolicy.NEVER_DEREF_ALIASES, 0,
                                      0, false,
@@ -294,7 +285,7 @@
          new InternalSearchOperation(conn, conn.nextOperationID(),
                                      conn.nextMessageID(),
                                      new ArrayList<Control>(),
-                                     new ASN1OctetString(),
+                                     ByteString.empty(),
                                      SearchScope.BASE_OBJECT,
                                      DereferencePolicy.NEVER_DEREF_ALIASES, 0,
                                      0, false,
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/jmx/JmxPrivilegeTestCase.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/jmx/JmxPrivilegeTestCase.java
index 953cfbb..059d2bc 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/jmx/JmxPrivilegeTestCase.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/jmx/JmxPrivilegeTestCase.java
@@ -61,24 +61,10 @@
 import org.opends.server.core.ModifyOperation;
 import org.opends.server.core.ModifyOperationBasis;
 import org.opends.server.core.SchemaConfigManager;
-import org.opends.server.protocols.asn1.ASN1OctetString;
 import org.opends.server.protocols.ldap.LDAPFilter;
 import org.opends.server.protocols.internal.InternalClientConnection;
 import org.opends.server.protocols.internal.InternalSearchOperation;
-import org.opends.server.types.Attributes;
-import org.opends.server.types.AuthenticationInfo;
-import org.opends.server.types.ByteStringFactory;
-import org.opends.server.types.Control;
-import org.opends.server.types.DN;
-import org.opends.server.types.DereferencePolicy;
-import org.opends.server.types.Entry;
-import org.opends.server.types.Modification;
-import org.opends.server.types.ModificationType;
-import org.opends.server.types.Privilege;
-import org.opends.server.types.RDN;
-import org.opends.server.types.ResultCode;
-import org.opends.server.types.SearchFilter;
-import org.opends.server.types.SearchScope;
+import org.opends.server.types.*;
 import org.testng.annotations.AfterClass;
 import org.testng.annotations.BeforeClass;
 import org.testng.annotations.DataProvider;
@@ -512,7 +498,7 @@
   {
     assertEquals(conn.hasPrivilege(Privilege.JMX_READ, null), hasPrivilege);
 
-    ASN1OctetString dn = new ASN1OctetString(DN.decode("cn=config").toString());
+    ByteString dn = ByteString.valueOf("cn=config");
     LDAPFilter filter = new LDAPFilter(SearchFilter
         .createFilterFromString("(objectClass=*)"));
     InternalSearchOperation searchOperation = conn.processSearch(dn,
@@ -549,9 +535,8 @@
   {
     assertEquals(conn.hasPrivilege(Privilege.JMX_READ, null), hasPrivilege);
 
-    ASN1OctetString asn1 = new ASN1OctetString(DN.decode("cn=config")
-        .toString());
-    ASN1OctetString value = new ASN1OctetString("config");
+    ByteString asn1 = ByteString.valueOf("cn=config");
+    ByteString value = ByteString.valueOf("config");
     CompareOperation compareOperation =
          conn.processCompare(asn1,
                              "cn",
@@ -1269,7 +1254,7 @@
          new CompareOperationBasis(conn, conn.nextOperationID(),
                               conn.nextMessageID(), controls, targetDN,
                               DirectoryServer.getAttributeType("cn", true),
-                              ByteStringFactory.create("PWReset Target"));
+                              ByteString.valueOf("PWReset Target"));
     compareOperation.run();
 
     if (hasProxyPrivilege)
@@ -1341,7 +1326,7 @@
 
     ArrayList<Control> controls = new ArrayList<Control>(1);
     controls.add(new ProxiedAuthV2Control(
-                          new ASN1OctetString("dn:cn=PWReset Target,o=test")));
+                          ByteString.valueOf("dn:cn=PWReset Target,o=test")));
 
 
     // Try to add the entry.  If this fails with the proxy control, then add it
@@ -1468,7 +1453,7 @@
     DN targetDN = DN.decode("cn=PWReset Target,o=test");
     ArrayList<Control> controls = new ArrayList<Control>(1);
     controls.add(new ProxiedAuthV2Control(
-                          new ASN1OctetString("dn:" + targetDN.toString())));
+                          ByteString.valueOf("dn:" + targetDN.toString())));
 
 
     // Test a compare operation against the PWReset Target user.
@@ -1476,7 +1461,7 @@
          new CompareOperationBasis(conn, conn.nextOperationID(),
                               conn.nextMessageID(), controls, targetDN,
                               DirectoryServer.getAttributeType("cn", true),
-                              ByteStringFactory.create("PWReset Target"));
+                              ByteString.valueOf("PWReset Target"));
     compareOperation.run();
 
     if (hasProxyPrivilege)
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/ldap/LDAPBinaryOptionTestCase.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/ldap/LDAPBinaryOptionTestCase.java
index 5846951..c6b09e2 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/ldap/LDAPBinaryOptionTestCase.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/ldap/LDAPBinaryOptionTestCase.java
@@ -38,23 +38,12 @@
 import org.opends.server.TestCaseUtils;
 import org.opends.server.api.Backend;
 import org.opends.server.core.DirectoryServer;
-import org.opends.server.protocols.asn1.ASN1Element;
-import org.opends.server.protocols.asn1.ASN1OctetString;
 import org.opends.server.protocols.asn1.ASN1Reader;
 import org.opends.server.protocols.asn1.ASN1Writer;
 import org.opends.server.protocols.internal.InternalClientConnection;
-import org.opends.server.types.ResultCode;
 import org.opends.server.protocols.internal.InternalSearchOperation;
 import org.opends.server.tools.*;
-import org.opends.server.types.Attribute;
-import org.opends.server.types.Control;
-import org.opends.server.types.DereferencePolicy;
-import org.opends.server.types.ExistingFileBehavior;
-import org.opends.server.types.LDIFExportConfig;
-import org.opends.server.types.LDIFImportConfig;
-import org.opends.server.types.RawAttribute;
-import org.opends.server.types.SearchResultEntry;
-import org.opends.server.types.SearchScope;
+import org.opends.server.types.*;
 import org.testng.annotations.*;
 import static org.testng.Assert.*;
 
@@ -209,7 +198,7 @@
               InternalClientConnection.nextOperationID(),
               InternalClientConnection.nextMessageID(),
               new ArrayList<Control>(),
-              new ASN1OctetString("o=test"),
+              ByteString.valueOf("o=test"),
               SearchScope.WHOLE_SUBTREE,
               DereferencePolicy.NEVER_DEREF_ALIASES,
               Integer.MAX_VALUE,
@@ -251,7 +240,7 @@
               InternalClientConnection.nextOperationID(),
               InternalClientConnection.nextMessageID(),
               new ArrayList<Control>(),
-              new ASN1OctetString("o=test"),
+              ByteString.valueOf("o=test"),
               SearchScope.WHOLE_SUBTREE,
               DereferencePolicy.NEVER_DEREF_ALIASES,
               Integer.MAX_VALUE,
@@ -281,19 +270,19 @@
   {
     //Construct a V2 connection.
     Socket     s = new Socket("127.0.0.1", TestCaseUtils.getServerLdapPort());
-    ASN1Reader r = new ASN1Reader(s);
-    ASN1Writer w = new ASN1Writer(s);
+    org.opends.server.tools.LDAPReader r = new org.opends.server.tools.LDAPReader(s);
+    org.opends.server.tools.LDAPWriter w = new org.opends.server.tools.LDAPWriter(s);
 
     try
     {
       BindRequestProtocolOp bindRequest =
            new BindRequestProtocolOp(
-                    new ASN1OctetString("cn=Directory Manager"), 2,
-                    new ASN1OctetString("password"));
+                    ByteString.valueOf("cn=Directory Manager"), 2,
+                    ByteString.valueOf("password"));
       LDAPMessage message = new LDAPMessage(1, bindRequest);
-      w.writeElement(message.encode());
+      w.writeMessage(message);
 
-      message = LDAPMessage.decode(r.readElement().decodeAsSequence());
+      message = r.readMessage();
       BindResponseProtocolOp bindResponse = message.getBindResponseProtocolOp();
       assertEquals(bindResponse.getResultCode(), 0);
       ArrayList<RawAttribute> addAttrs = new ArrayList<RawAttribute>();
@@ -306,12 +295,12 @@
       addAttrs.add(RawAttribute.create("userCertificate;binary", CERT));
 
       AddRequestProtocolOp addRequest =
-           new AddRequestProtocolOp(new ASN1OctetString("uid=user.7,o=test"),
+           new AddRequestProtocolOp(ByteString.valueOf("uid=user.7,o=test"),
                                     addAttrs);
       message = new LDAPMessage(2, addRequest);
-      w.writeElement(message.encode());
+      w.writeMessage(message);
 
-      message = LDAPMessage.decode(r.readElement().decodeAsSequence());
+      message = r.readMessage();
       AddResponseProtocolOp addResponse = message.getAddResponseProtocolOp();
       assertEquals(addResponse.getResultCode(),0);
 
@@ -321,22 +310,20 @@
       attrs.add("sn");
       attrs.add("userCertificate;binary");
       SearchRequestProtocolOp searchRequest =
-         new SearchRequestProtocolOp(new ASN1OctetString("o=test"),
+         new SearchRequestProtocolOp(ByteString.valueOf("o=test"),
                                      SearchScope.WHOLE_SUBTREE,
                                      DereferencePolicy.NEVER_DEREF_ALIASES, 0,
                                      0, false,
                                      LDAPFilter.decode("(uid=user.7)"),
                                      attrs);
       message = new LDAPMessage(2, searchRequest);
-      w.writeElement(message.encode());
-      //message = LDAPMessage.decode(r.readElement().decodeAsSequence());
+      w.writeMessage(message);
 
       SearchResultEntryProtocolOp searchResultEntry = null;
       SearchResultDoneProtocolOp searchResultDone = null;
-      ASN1Element element = null;
-      while (searchResultDone == null && (element = r.readElement()) != null)
+      while (searchResultDone == null && message != null)
       {
-        message = LDAPMessage.decode(element.decodeAsSequence());
+        message = r.readMessage();
         switch (message.getProtocolOpType())
         {
           case LDAPConstants.OP_TYPE_SEARCH_RESULT_ENTRY:
@@ -359,10 +346,10 @@
           certWithNoOption=true;
         else if(a.getAttributeType().equalsIgnoreCase("sn"))
         {
-          List<ASN1OctetString> lVal = a.getValues();
-          for(ASN1OctetString v:lVal)
+          List<ByteString> lVal = a.getValues();
+          for(ByteString v:lVal)
           {
-            String val = v.stringValue();
+            String val = v.toString();
             if(val.equals("sn#1") || val.equals("sn#2")
                     || val.equals("sn#3"))
             {
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/ldap/LDAPv2TestCase.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/ldap/LDAPv2TestCase.java
index 3981edf..029c6a7 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/ldap/LDAPv2TestCase.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/ldap/LDAPv2TestCase.java
@@ -35,14 +35,8 @@
 import org.testng.annotations.Test;
 
 import org.opends.server.TestCaseUtils;
-import org.opends.server.protocols.asn1.ASN1OctetString;
-import org.opends.server.protocols.asn1.ASN1Reader;
-import org.opends.server.protocols.asn1.ASN1Writer;
-import org.opends.server.types.DereferencePolicy;
-import org.opends.server.types.ModificationType;
-import org.opends.server.types.RawAttribute;
-import org.opends.server.types.RawModification;
-import org.opends.server.types.SearchScope;
+import org.opends.server.tools.LDAPWriter;
+import org.opends.server.types.*;
 
 import static org.testng.Assert.*;
 
@@ -89,19 +83,19 @@
       "ds-cfg-allow-ldap-v2: false");
 
     Socket     s = new Socket("127.0.0.1", TestCaseUtils.getServerLdapPort());
-    ASN1Reader r = new ASN1Reader(s);
-    ASN1Writer w = new ASN1Writer(s);
+    org.opends.server.tools.LDAPReader r = new org.opends.server.tools.LDAPReader(s);
+    LDAPWriter w = new LDAPWriter(s);
 
     try
     {
       BindRequestProtocolOp bindRequest =
            new BindRequestProtocolOp(
-                    new ASN1OctetString("cn=Directory Manager"), 2,
-                    new ASN1OctetString("password"));
+                    ByteString.valueOf("cn=Directory Manager"), 2,
+                    ByteString.valueOf("password"));
       LDAPMessage message = new LDAPMessage(1, bindRequest);
-      w.writeElement(message.encode());
+      w.writeMessage(message);
 
-      message = LDAPMessage.decode(r.readElement().decodeAsSequence());
+      message = r.readMessage();
       BindResponseProtocolOp bindResponse = message.getBindResponseProtocolOp();
       assertEquals(bindResponse.getResultCode(),
                    LDAPResultCode.INAPPROPRIATE_AUTHENTICATION);
@@ -142,28 +136,28 @@
          throws Exception
   {
     Socket     s = new Socket("127.0.0.1", TestCaseUtils.getServerLdapPort());
-    ASN1Reader r = new ASN1Reader(s);
-    ASN1Writer w = new ASN1Writer(s);
+    org.opends.server.tools.LDAPReader r = new org.opends.server.tools.LDAPReader(s);
+    LDAPWriter w = new LDAPWriter(s);
 
     try
     {
       BindRequestProtocolOp bindRequest =
            new BindRequestProtocolOp(
-                    new ASN1OctetString("cn=Directory Manager"), 2,
-                    new ASN1OctetString("password"));
+                    ByteString.valueOf("cn=Directory Manager"), 2,
+                    ByteString.valueOf("password"));
       LDAPMessage message = new LDAPMessage(1, bindRequest);
-      w.writeElement(message.encode());
+      w.writeMessage(message);
 
-      message = LDAPMessage.decode(r.readElement().decodeAsSequence());
+      message = r.readMessage();
       BindResponseProtocolOp bindResponse = message.getBindResponseProtocolOp();
       assertEquals(bindResponse.getResultCode(), 0);
 
       ExtendedRequestProtocolOp extendedRequest =
            new ExtendedRequestProtocolOp(OID_START_TLS_REQUEST);
       message = new LDAPMessage(2, extendedRequest);
-      w.writeElement(message.encode());
+      w.writeMessage(message);
 
-      assertNull(r.readElement());
+      assertNull(r.readMessage());
     }
     finally
     {
@@ -195,19 +189,19 @@
          throws Exception
   {
     Socket     s = new Socket("127.0.0.1", TestCaseUtils.getServerLdapPort());
-    ASN1Reader r = new ASN1Reader(s);
-    ASN1Writer w = new ASN1Writer(s);
+    org.opends.server.tools.LDAPReader r = new org.opends.server.tools.LDAPReader(s);
+    LDAPWriter w = new LDAPWriter(s);
 
     try
     {
       BindRequestProtocolOp bindRequest =
            new BindRequestProtocolOp(
-                    new ASN1OctetString("cn=Directory Manager"), 2,
-                    new ASN1OctetString("password"));
+                    ByteString.valueOf("cn=Directory Manager"), 2,
+                    ByteString.valueOf("password"));
       LDAPMessage message = new LDAPMessage(1, bindRequest);
-      w.writeElement(message.encode());
+      w.writeMessage(message);
 
-      message = LDAPMessage.decode(r.readElement().decodeAsSequence());
+      message = r.readMessage();
       BindResponseProtocolOp bindResponse = message.getBindResponseProtocolOp();
       assertEquals(bindResponse.getResultCode(), 0);
 
@@ -216,14 +210,14 @@
       addAttrs.add(RawAttribute.create("ou", "People"));
 
       AddRequestProtocolOp addRequest =
-           new AddRequestProtocolOp(new ASN1OctetString("ou=People,o=test"),
+           new AddRequestProtocolOp(ByteString.valueOf("ou=People,o=test"),
                                     addAttrs);
-      ArrayList<LDAPControl> controls = new ArrayList<LDAPControl>(1);
+      ArrayList<Control> controls = new ArrayList<Control>(1);
       controls.add(new LDAPControl(OID_MANAGE_DSAIT_CONTROL, true));
       message = new LDAPMessage(2, addRequest, controls);
-      w.writeElement(message.encode());
+      w.writeMessage(message);
 
-      message = LDAPMessage.decode(r.readElement().decodeAsSequence());
+      message = r.readMessage();
       AddResponseProtocolOp addResponse = message.getAddResponseProtocolOp();
       assertEquals(addResponse.getResultCode(), LDAPResultCode.PROTOCOL_ERROR);
     }
@@ -257,21 +251,21 @@
          throws Exception
   {
     Socket     s = new Socket("127.0.0.1", TestCaseUtils.getServerLdapPort());
-    ASN1Reader r = new ASN1Reader(s);
-    ASN1Writer w = new ASN1Writer(s);
+    org.opends.server.tools.LDAPReader r = new org.opends.server.tools.LDAPReader(s);
+    LDAPWriter w = new LDAPWriter(s);
 
     try
     {
       BindRequestProtocolOp bindRequest =
            new BindRequestProtocolOp(
-                    new ASN1OctetString("cn=Directory Manager"), 2,
-                    new ASN1OctetString("password"));
-      ArrayList<LDAPControl> controls = new ArrayList<LDAPControl>(1);
+                    ByteString.valueOf("cn=Directory Manager"), 2,
+                    ByteString.valueOf("password"));
+      ArrayList<Control> controls = new ArrayList<Control>(1);
       controls.add(new LDAPControl(OID_MANAGE_DSAIT_CONTROL, true));
       LDAPMessage message = new LDAPMessage(1, bindRequest, controls);
-      w.writeElement(message.encode());
+      w.writeMessage(message);
 
-      message = LDAPMessage.decode(r.readElement().decodeAsSequence());
+      message = r.readMessage();
       BindResponseProtocolOp bindResponse = message.getBindResponseProtocolOp();
       assertEquals(bindResponse.getResultCode(), LDAPResultCode.PROTOCOL_ERROR);
     }
@@ -305,31 +299,31 @@
          throws Exception
   {
     Socket     s = new Socket("127.0.0.1", TestCaseUtils.getServerLdapPort());
-    ASN1Reader r = new ASN1Reader(s);
-    ASN1Writer w = new ASN1Writer(s);
+    org.opends.server.tools.LDAPReader r = new org.opends.server.tools.LDAPReader(s);
+    LDAPWriter w = new LDAPWriter(s);
 
     try
     {
       BindRequestProtocolOp bindRequest =
            new BindRequestProtocolOp(
-                    new ASN1OctetString("cn=Directory Manager"), 2,
-                    new ASN1OctetString("password"));
+                    ByteString.valueOf("cn=Directory Manager"), 2,
+                    ByteString.valueOf("password"));
       LDAPMessage message = new LDAPMessage(1, bindRequest);
-      w.writeElement(message.encode());
+      w.writeMessage(message);
 
-      message = LDAPMessage.decode(r.readElement().decodeAsSequence());
+      message = r.readMessage();
       BindResponseProtocolOp bindResponse = message.getBindResponseProtocolOp();
       assertEquals(bindResponse.getResultCode(), 0);
 
       CompareRequestProtocolOp compareRequest =
-           new CompareRequestProtocolOp(new ASN1OctetString("o=test"),
-                                        "o", new ASN1OctetString("test"));
-      ArrayList<LDAPControl> controls = new ArrayList<LDAPControl>(1);
+           new CompareRequestProtocolOp(ByteString.valueOf("o=test"),
+                                        "o", ByteString.valueOf("test"));
+      ArrayList<Control> controls = new ArrayList<Control>(1);
       controls.add(new LDAPControl(OID_MANAGE_DSAIT_CONTROL, true));
       message = new LDAPMessage(2, compareRequest, controls);
-      w.writeElement(message.encode());
+      w.writeMessage(message);
 
-      message = LDAPMessage.decode(r.readElement().decodeAsSequence());
+      message = r.readMessage();
       CompareResponseProtocolOp compareResponse =
            message.getCompareResponseProtocolOp();
       assertEquals(compareResponse.getResultCode(),
@@ -365,30 +359,30 @@
          throws Exception
   {
     Socket     s = new Socket("127.0.0.1", TestCaseUtils.getServerLdapPort());
-    ASN1Reader r = new ASN1Reader(s);
-    ASN1Writer w = new ASN1Writer(s);
+    org.opends.server.tools.LDAPReader r = new org.opends.server.tools.LDAPReader(s);
+    LDAPWriter w = new LDAPWriter(s);
 
     try
     {
       BindRequestProtocolOp bindRequest =
            new BindRequestProtocolOp(
-                    new ASN1OctetString("cn=Directory Manager"), 2,
-                    new ASN1OctetString("password"));
+                    ByteString.valueOf("cn=Directory Manager"), 2,
+                    ByteString.valueOf("password"));
       LDAPMessage message = new LDAPMessage(1, bindRequest);
-      w.writeElement(message.encode());
+      w.writeMessage(message);
 
-      message = LDAPMessage.decode(r.readElement().decodeAsSequence());
+      message = r.readMessage();
       BindResponseProtocolOp bindResponse = message.getBindResponseProtocolOp();
       assertEquals(bindResponse.getResultCode(), 0);
 
       DeleteRequestProtocolOp deleteRequest =
-           new DeleteRequestProtocolOp(new ASN1OctetString("o=test"));
-      ArrayList<LDAPControl> controls = new ArrayList<LDAPControl>(1);
+           new DeleteRequestProtocolOp(ByteString.valueOf("o=test"));
+      ArrayList<Control> controls = new ArrayList<Control>(1);
       controls.add(new LDAPControl(OID_MANAGE_DSAIT_CONTROL, true));
       message = new LDAPMessage(2, deleteRequest, controls);
-      w.writeElement(message.encode());
+      w.writeMessage(message);
 
-      message = LDAPMessage.decode(r.readElement().decodeAsSequence());
+      message = r.readMessage();
       DeleteResponseProtocolOp deleteResponse =
            message.getDeleteResponseProtocolOp();
       assertEquals(deleteResponse.getResultCode(),
@@ -424,19 +418,19 @@
          throws Exception
   {
     Socket     s = new Socket("127.0.0.1", TestCaseUtils.getServerLdapPort());
-    ASN1Reader r = new ASN1Reader(s);
-    ASN1Writer w = new ASN1Writer(s);
+    org.opends.server.tools.LDAPReader r = new org.opends.server.tools.LDAPReader(s);
+    LDAPWriter w = new LDAPWriter(s);
 
     try
     {
       BindRequestProtocolOp bindRequest =
            new BindRequestProtocolOp(
-                    new ASN1OctetString("cn=Directory Manager"), 2,
-                    new ASN1OctetString("password"));
+                    ByteString.valueOf("cn=Directory Manager"), 2,
+                    ByteString.valueOf("password"));
       LDAPMessage message = new LDAPMessage(1, bindRequest);
-      w.writeElement(message.encode());
+      w.writeMessage(message);
 
-      message = LDAPMessage.decode(r.readElement().decodeAsSequence());
+      message = r.readMessage();
       BindResponseProtocolOp bindResponse = message.getBindResponseProtocolOp();
       assertEquals(bindResponse.getResultCode(), 0);
 
@@ -445,13 +439,13 @@
                                       "description", "foo"));
 
       ModifyRequestProtocolOp modifyRequest =
-           new ModifyRequestProtocolOp(new ASN1OctetString("o=test"), mods);
-      ArrayList<LDAPControl> controls = new ArrayList<LDAPControl>(1);
+           new ModifyRequestProtocolOp(ByteString.valueOf("o=test"), mods);
+      ArrayList<Control> controls = new ArrayList<Control>(1);
       controls.add(new LDAPControl(OID_MANAGE_DSAIT_CONTROL, true));
       message = new LDAPMessage(2, modifyRequest, controls);
-      w.writeElement(message.encode());
+      w.writeMessage(message);
 
-      message = LDAPMessage.decode(r.readElement().decodeAsSequence());
+      message = r.readMessage();
       ModifyResponseProtocolOp modifyResponse =
            message.getModifyResponseProtocolOp();
       assertEquals(modifyResponse.getResultCode(),
@@ -487,31 +481,31 @@
          throws Exception
   {
     Socket     s = new Socket("127.0.0.1", TestCaseUtils.getServerLdapPort());
-    ASN1Reader r = new ASN1Reader(s);
-    ASN1Writer w = new ASN1Writer(s);
+    org.opends.server.tools.LDAPReader r = new org.opends.server.tools.LDAPReader(s);
+    LDAPWriter w = new LDAPWriter(s);
 
     try
     {
       BindRequestProtocolOp bindRequest =
            new BindRequestProtocolOp(
-                    new ASN1OctetString("cn=Directory Manager"), 2,
-                    new ASN1OctetString("password"));
+                    ByteString.valueOf("cn=Directory Manager"), 2,
+                    ByteString.valueOf("password"));
       LDAPMessage message = new LDAPMessage(1, bindRequest);
-      w.writeElement(message.encode());
+      w.writeMessage(message);
 
-      message = LDAPMessage.decode(r.readElement().decodeAsSequence());
+      message = r.readMessage();
       BindResponseProtocolOp bindResponse = message.getBindResponseProtocolOp();
       assertEquals(bindResponse.getResultCode(), 0);
 
       ModifyDNRequestProtocolOp modifyDNRequest =
-           new ModifyDNRequestProtocolOp(new ASN1OctetString("o=test"),
-                                         new ASN1OctetString("cn=test"), false);
-      ArrayList<LDAPControl> controls = new ArrayList<LDAPControl>(1);
+           new ModifyDNRequestProtocolOp(ByteString.valueOf("o=test"),
+                                         ByteString.valueOf("cn=test"), false);
+      ArrayList<Control> controls = new ArrayList<Control>(1);
       controls.add(new LDAPControl(OID_MANAGE_DSAIT_CONTROL, true));
       message = new LDAPMessage(2, modifyDNRequest, controls);
-      w.writeElement(message.encode());
+      w.writeMessage(message);
 
-      message = LDAPMessage.decode(r.readElement().decodeAsSequence());
+      message = r.readMessage();
       ModifyDNResponseProtocolOp modifyDNResponse =
            message.getModifyDNResponseProtocolOp();
       assertEquals(modifyDNResponse.getResultCode(),
@@ -547,33 +541,33 @@
          throws Exception
   {
     Socket     s = new Socket("127.0.0.1", TestCaseUtils.getServerLdapPort());
-    ASN1Reader r = new ASN1Reader(s);
-    ASN1Writer w = new ASN1Writer(s);
+    org.opends.server.tools.LDAPReader r = new org.opends.server.tools.LDAPReader(s);
+    LDAPWriter w = new LDAPWriter(s);
 
     try
     {
       BindRequestProtocolOp bindRequest =
            new BindRequestProtocolOp(
-                    new ASN1OctetString("cn=Directory Manager"), 2,
-                    new ASN1OctetString("password"));
+                    ByteString.valueOf("cn=Directory Manager"), 2,
+                    ByteString.valueOf("password"));
       LDAPMessage message = new LDAPMessage(1, bindRequest);
-      w.writeElement(message.encode());
+      w.writeMessage(message);
 
-      message = LDAPMessage.decode(r.readElement().decodeAsSequence());
+      message = r.readMessage();
       BindResponseProtocolOp bindResponse = message.getBindResponseProtocolOp();
       assertEquals(bindResponse.getResultCode(), 0);
 
       SearchRequestProtocolOp searchRequest =
-           new SearchRequestProtocolOp(new ASN1OctetString(),
+           new SearchRequestProtocolOp(ByteString.empty(),
                     SearchScope.BASE_OBJECT,
                     DereferencePolicy.NEVER_DEREF_ALIASES, 0, 0, false,
                     LDAPFilter.decode("(objectClass=*)"), null);
-      ArrayList<LDAPControl> controls = new ArrayList<LDAPControl>(1);
+      ArrayList<Control> controls = new ArrayList<Control>(1);
       controls.add(new LDAPControl(OID_MANAGE_DSAIT_CONTROL, true));
       message = new LDAPMessage(2, searchRequest, controls);
-      w.writeElement(message.encode());
+      w.writeMessage(message);
 
-      message = LDAPMessage.decode(r.readElement().decodeAsSequence());
+      message = r.readMessage();
       SearchResultDoneProtocolOp searchDone =
            message.getSearchResultDoneProtocolOp();
       assertEquals(searchDone.getResultCode(), LDAPResultCode.PROTOCOL_ERROR);
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/ldap/LdapTestCase.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/ldap/LdapTestCase.java
index 4fccf12..1c976db 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/ldap/LdapTestCase.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/ldap/LdapTestCase.java
@@ -35,10 +35,6 @@
 import org.opends.server.admin.std.meta.LDAPConnectionHandlerCfgDefn;
 import org.opends.server.admin.std.server.LDAPConnectionHandlerCfg;
 import org.opends.server.config.ConfigException;
-import org.opends.server.protocols.asn1.ASN1Boolean;
-import org.opends.server.protocols.asn1.ASN1Element;
-import org.opends.server.protocols.asn1.ASN1Long;
-import org.opends.server.protocols.asn1.ASN1Sequence;
 import org.opends.server.types.Attribute;
 import org.testng.annotations.Test;
 
@@ -95,51 +91,6 @@
   }
 
   /**
-   * Generate an exception by writing a long into a integer element.
-   * @param op The op.
-   * @param type The type of sequence.
-   * @param index The index into the element to write to.
-   * @throws Exception If the protocol op decode can't write the sequence.
-   */
-  static void 
-  badIntegerElement(ProtocolOp op, byte type, int index) throws Exception {
-	  ASN1Element element = op.encode();
-	  ArrayList<ASN1Element> elements = ((ASN1Sequence)element).elements();
-	  elements.set(index, new ASN1Long(Long.MAX_VALUE));
-	  ProtocolOp.decode(new ASN1Sequence(type, elements));
-  }
-
-  /**
-   * Generate an exception by adding an element.
-   * @param op The op.
-   * @param type The type of sequence.
-   * @throws Exception If the protocol op decode has too many elements.
-   */
-  static void 
-  tooManyElements(ProtocolOp op, byte type) throws Exception
-  {
-	  ASN1Element element = op.encode();
-	  ArrayList<ASN1Element> elements = ((ASN1Sequence)element).elements();
-	  elements.add(new ASN1Boolean(true));
-	  ProtocolOp.decode(new ASN1Sequence(type, elements));
-  }
-
-  /**
-   * Generate an exception by removing an element.
-   * @param op The op.
-   * @param type The type of sequence.
-   * @throws Exception If the protocol op decode has too few elements.
-   */
-  static void 
-  tooFewElements(ProtocolOp op, byte type) throws Exception
-  {
-	  ASN1Element element = op.encode();
-	  ArrayList<ASN1Element> elements = ((ASN1Sequence)element).elements();
-	  elements.remove(0);
-	  ProtocolOp.decode(new ASN1Sequence(type, elements));
-  }
-
-  /**
    * Test toString methods.
    * @param op The op.
    * @throws Exception If the toString method fails.
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/ldap/TestAbandonRequestProtocolOp.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/ldap/TestAbandonRequestProtocolOp.java
index 9d71509..e91282a 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/ldap/TestAbandonRequestProtocolOp.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/ldap/TestAbandonRequestProtocolOp.java
@@ -26,12 +26,13 @@
  */
 package org.opends.server.protocols.ldap;
 
-import org.opends.server.protocols.asn1.ASN1Element;
-import org.opends.server.protocols.asn1.ASN1Long;
-import org.opends.server.protocols.ldap.AbandonRequestProtocolOp;
 import org.opends.server.types.LDAPException;
+import org.opends.server.types.ByteStringBuilder;
 import org.testng.annotations.Test;
 import static org.opends.server.protocols.ldap.LDAPConstants.OP_TYPE_ABANDON_REQUEST;
+import org.opends.server.protocols.asn1.ASN1;
+import org.opends.server.protocols.asn1.ASN1Writer;
+import org.opends.server.protocols.asn1.ASN1Reader;
 import static org.testng.Assert.*;
 
 public class
@@ -47,27 +48,24 @@
 
   @Test()
   public void testAbandonRequestEncodeDecode() throws Exception {
+    ByteStringBuilder builder = new ByteStringBuilder();
+    ASN1Writer writer = ASN1.getWriter(builder);
     AbandonRequestProtocolOp req = new AbandonRequestProtocolOp(id);
-    ASN1Element reqElem=req.encode();
-    ProtocolOp reqOp= ProtocolOp.decode(reqElem);
+    req.write(writer);
+
+    ASN1Reader reader = ASN1.getReader(builder.toByteString());
+    ProtocolOp reqOp= LDAPReader.readProtocolOp(reader);
     assertTrue(reqOp.getProtocolOpName() == req.getProtocolOpName());
     assertTrue(reqOp.getType() == req.getType());
   }
 
-  @Test()
-  public void testSetters() throws Exception {
-    AbandonRequestProtocolOp req = new AbandonRequestProtocolOp(id);
-    req.encode();
-    req.setIDToAbandon(id+1);
-    ASN1Element reqElem=req.encode();
-    ProtocolOp reqDec= ProtocolOp.decode(reqElem);
-    AbandonRequestProtocolOp reqOp =
-      (AbandonRequestProtocolOp)reqDec;
-    assertTrue(reqOp.getIDToAbandon() == req.getIDToAbandon());
-  }
-
   @Test (expectedExceptions = LDAPException.class)
   public void testAbandonRequestBadID() throws Exception {
-    ProtocolOp.decode(new ASN1Long(OP_TYPE_ABANDON_REQUEST, Long.MAX_VALUE));
+    ByteStringBuilder builder = new ByteStringBuilder();
+    ASN1Writer writer = ASN1.getWriter(builder);
+    writer.writeOctetString(OP_TYPE_ABANDON_REQUEST, "invalid value");
+
+    ASN1Reader reader = ASN1.getReader(builder.toByteString());
+    LDAPReader.readProtocolOp(reader);
   }
 }
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/ldap/TestAddRequestProtocolOp.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/ldap/TestAddRequestProtocolOp.java
index 30141a8..17210da 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/ldap/TestAddRequestProtocolOp.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/ldap/TestAddRequestProtocolOp.java
@@ -26,13 +26,15 @@
  */
 package org.opends.server.protocols.ldap;
 
-import org.opends.server.protocols.asn1.ASN1OctetString;
-import org.opends.server.protocols.asn1.ASN1Element;
-import org.opends.server.protocols.asn1.ASN1Sequence;
 import org.opends.server.types.LDAPException;
 import org.opends.server.types.RawAttribute;
+import org.opends.server.types.ByteString;
+import org.opends.server.types.ByteStringBuilder;
 import static org.opends.server.util.ServerConstants.EOL;
 import org.opends.server.util.Base64;
+import org.opends.server.protocols.asn1.ASN1Writer;
+import org.opends.server.protocols.asn1.ASN1;
+import org.opends.server.protocols.asn1.ASN1Reader;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -64,14 +66,14 @@
   /**
    * The DN for add requests in this test case.
    */
-  private static final ASN1OctetString dn =
-      new ASN1OctetString("dc=example,dc=com");
+  private static final ByteString dn =
+      ByteString.valueOf("dc=example,dc=com");
 
   /**
    * The alternative DN for add requests in this test case.
    */
-  private static final ASN1OctetString dnAlt =
-      new ASN1OctetString("dc=sun,dc=com");
+  private static final ByteString dnAlt =
+      ByteString.valueOf("dc=sun,dc=com");
 
   /**
    * Generate attributes for use in test cases. Attributes will have names
@@ -93,15 +95,15 @@
   {
     ArrayList<RawAttribute> attributes = new ArrayList<RawAttribute>();
     LDAPAttribute attribute;
-    ASN1OctetString value;
+    ByteString value;
     int i, j;
 
     for(i = 0; i < numAttributes; i++)
     {
-      ArrayList<ASN1OctetString> values = new ArrayList<ASN1OctetString>();
+      ArrayList<ByteString> values = new ArrayList<ByteString>();
       for(j = 0; j < numValues; j++)
       {
-        value = new ASN1OctetString(prefix + "Value"+i+"."+j);
+        value = ByteString.valueOf(prefix + "Value"+i+"."+j);
         values.add(value);
       }
       attribute = new LDAPAttribute("testAttribute"+i, values);
@@ -122,8 +124,8 @@
     int i, j;
     RawAttribute attribute1;
     RawAttribute attribute2;
-    ArrayList<ASN1OctetString> values1;
-    ArrayList<ASN1OctetString> values2;
+    ArrayList<ByteString> values1;
+    ArrayList<ByteString> values2;
 
     for(i = 0; i < attributes1.size(); i++)
     {
@@ -207,22 +209,6 @@
   }
 
   /**
-   * Test to make sure that setter methods work.
-   *
-   * @throws Exception If the test failed unexpectedly.
-   */
-  @Test
-  public void testSetMethods() throws Exception
-  {
-    AddRequestProtocolOp addRequest;
-
-    addRequest = new AddRequestProtocolOp(dn);
-    assertEquals(addRequest.getDN(), dn);
-    addRequest.setDN(dnAlt);
-    assertEquals(addRequest.getDN(), dnAlt);
-  }
-
-  /**
    * Test the decode method when an null element is passed
    *
    * @throws Exception If the test failed unexpectedly.
@@ -230,7 +216,7 @@
   @Test(expectedExceptions = LDAPException.class)
   public void testDecodeNullElement() throws Exception
   {
-    AddRequestProtocolOp.decodeAddRequest(null);
+    LDAPReader.readProtocolOp(null);
   }
 
   /**
@@ -241,9 +227,13 @@
   @Test(expectedExceptions = LDAPException.class)
   public void testDecodeEmptyElement() throws Exception
   {
-    ArrayList<ASN1Element> elements = new ArrayList<ASN1Element>();
-    AddRequestProtocolOp.decode(new ASN1Sequence(OP_TYPE_ADD_REQUEST,
-                                                 elements));
+    ByteStringBuilder builder = new ByteStringBuilder();
+    ASN1Writer writer = ASN1.getWriter(builder);
+    writer.writeStartSequence(OP_TYPE_ADD_REQUEST);
+    writer.writeEndSequence();
+
+    ASN1Reader reader = ASN1.getReader(builder.toByteString());
+    LDAPReader.readProtocolOp(reader);
   }
 
   /**
@@ -254,13 +244,16 @@
   @Test(expectedExceptions = LDAPException.class)
   public void testDecodeInvalidElement() throws Exception
   {
-    ArrayList<ASN1Element> elements = new ArrayList<ASN1Element>(2);
-    ArrayList<ASN1Element> attrElements =
-         new ArrayList<ASN1Element>();
-    elements.add(new ASN1Sequence(attrElements));
-    elements.add(dn);
-    AddRequestProtocolOp.decode(new ASN1Sequence(OP_TYPE_ADD_REQUEST,
-                                                 elements));
+    ByteStringBuilder builder = new ByteStringBuilder();
+    ASN1Writer writer = ASN1.getWriter(builder);
+    writer.writeStartSequence(OP_TYPE_ADD_REQUEST);
+    writer.writeStartSequence();
+    writer.writeEndSequence();
+    writer.writeOctetString(dn);
+    writer.writeEndSequence();
+
+    ASN1Reader reader = ASN1.getReader(builder.toByteString());
+    LDAPReader.readProtocolOp(reader);
   }
 
   /**
@@ -271,13 +264,16 @@
   @Test(expectedExceptions = LDAPException.class)
   public void testDecodeWrongElementType() throws Exception
   {
-    ArrayList<ASN1Element> elements = new ArrayList<ASN1Element>(2);
-    ArrayList<ASN1Element> attrElements =
-         new ArrayList<ASN1Element>();
-    elements.add(dn);
-    elements.add(new ASN1Sequence(attrElements));
-    AddRequestProtocolOp.decode(new ASN1Sequence(OP_TYPE_ADD_RESPONSE,
-                                                 elements));
+    ByteStringBuilder builder = new ByteStringBuilder();
+    ASN1Writer writer = ASN1.getWriter(builder);
+    writer.writeStartSequence(OP_TYPE_ADD_RESPONSE);
+    writer.writeOctetString(dn);
+    writer.writeStartSequence();
+    writer.writeEndSequence();
+    writer.writeEndSequence();
+
+    ASN1Reader reader = ASN1.getReader(builder.toByteString());
+    LDAPReader.readProtocolOp(reader);
   }
 
   /**
@@ -288,13 +284,16 @@
   @Test(expectedExceptions = Exception.class)
   public void testNullEncodeDecode() throws Exception
   {
+    ByteStringBuilder builder = new ByteStringBuilder();
+    ASN1Writer writer = ASN1.getWriter(builder);
     AddRequestProtocolOp addEncoded;
     AddRequestProtocolOp addDecoded;
-    ASN1Element element;
 
     addEncoded = new AddRequestProtocolOp(null, null);
-    element = addEncoded.encode();
-    addDecoded = (AddRequestProtocolOp)AddRequestProtocolOp.decode(element);
+    addEncoded.write(writer);
+
+    ASN1Reader reader = ASN1.getReader(builder.toByteString());
+    addDecoded = (AddRequestProtocolOp)LDAPReader.readProtocolOp(reader);
   }
 
   /**
@@ -305,17 +304,19 @@
   @Test
   public void testEncodeDecode() throws Exception
   {
+    ByteStringBuilder builder = new ByteStringBuilder();
+    ASN1Writer writer = ASN1.getWriter(builder);
     AddRequestProtocolOp addEncoded;
     AddRequestProtocolOp addDecoded;
-    ASN1Element element;
     ArrayList<RawAttribute> attributes;
 
 
     //Test case for a full encode decode operation with normal params.
     attributes = generateAttributes(10,5, "test");
     addEncoded = new AddRequestProtocolOp(dn, attributes);
-    element = addEncoded.encode();
-    addDecoded = (AddRequestProtocolOp)AddRequestProtocolOp.decode(element);
+    addEncoded.write(writer);
+    ASN1Reader reader = ASN1.getReader(builder.toByteString());
+    addDecoded = (AddRequestProtocolOp)LDAPReader.readProtocolOp(reader);
 
     assertEquals(addEncoded.getType(), OP_TYPE_ADD_REQUEST);
     assertEquals(addEncoded.getDN(), addDecoded.getDN());
@@ -325,8 +326,10 @@
     //Test case for a full encode decode operation with large attributes.
     attributes = generateAttributes(100,50, "test");
     addEncoded = new AddRequestProtocolOp(dn, attributes);
-    element = addEncoded.encode();
-    addDecoded = (AddRequestProtocolOp)AddRequestProtocolOp.decode(element);
+    builder.clear();
+    addEncoded.write(writer);
+    reader = ASN1.getReader(builder.toByteString());
+    addDecoded = (AddRequestProtocolOp)LDAPReader.readProtocolOp(reader);
 
     assertEquals(addEncoded.getDN(), addDecoded.getDN());
     assertTrue(attributesEquals(addEncoded.getAttributes(),
@@ -334,8 +337,10 @@
 
     //Test case for a full encode decode operation with no attributes.
     addEncoded = new AddRequestProtocolOp(dn, null);
-    element = addEncoded.encode();
-    addDecoded = (AddRequestProtocolOp)AddRequestProtocolOp.decode(element);
+    builder.clear();
+    addEncoded.write(writer);
+    reader = ASN1.getReader(builder.toByteString());
+    addDecoded = (AddRequestProtocolOp)LDAPReader.readProtocolOp(reader);
 
     assertEquals(addEncoded.getDN(), addDecoded.getDN());
     assertTrue(attributesEquals(addEncoded.getAttributes(),
@@ -398,15 +403,15 @@
     numValues = 5;
     attributes = generateAttributes(numAttributes, numValues, " test");
 
-    ASN1OctetString dnNeedsBase64 =
-      new ASN1OctetString("dc=example,dc=com ");
+    ByteString dnNeedsBase64 =
+      ByteString.valueOf("dc=example,dc=com ");
 
     addRequest = new AddRequestProtocolOp(dnNeedsBase64, attributes);
     addRequest.toLDIF(buffer, 80);
 
     reader = new BufferedReader(new StringReader(buffer.toString()));
     line = reader.readLine();
-    assertEquals(line, "dn:: "+Base64.encode(dnNeedsBase64.value()));
+    assertEquals(line, "dn:: "+Base64.encode(dnNeedsBase64));
     for(i = 0; i < numAttributes; i++)
     {
       for(j = 0; j < numValues; j++)
@@ -487,7 +492,7 @@
 
     key.append(indentBuf);
     key.append("  DN:  ");
-    dn.toString(key);
+    key.append(dn.toString());
     key.append(EOL);
 
     key.append("  Attributes:");
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/ldap/TestAddResponseProtocolOp.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/ldap/TestAddResponseProtocolOp.java
index 5b3a493..5a4af02 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/ldap/TestAddResponseProtocolOp.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/ldap/TestAddResponseProtocolOp.java
@@ -28,11 +28,7 @@
 
 import org.opends.server.protocols.asn1.*;
 import static org.opends.server.util.ServerConstants.EOL;
-import org.opends.server.types.DN;
-import org.opends.server.types.RDN;
-import org.opends.server.types.AttributeType;
-import org.opends.server.types.AttributeValue;
-import org.opends.server.types.LDAPException;
+import org.opends.server.types.*;
 import org.opends.server.core.DirectoryServer;
 import org.opends.server.DirectoryServerTestCase;
 import org.opends.messages.Message;
@@ -82,7 +78,7 @@
     AttributeType attribute =
         DirectoryServer.getDefaultAttributeType("testAttribute");
 
-    AttributeValue attributeValue = new AttributeValue(attribute, "testValue");
+    AttributeValue attributeValue = AttributeValues.create(attribute, "testValue");
 
     RDN[] rdns = new RDN[1];
     rdns[0] = RDN.create(attribute, attributeValue);
@@ -151,34 +147,6 @@
   }
 
   /**
-   * Test to make sure that setter methods work.
-   *
-   * @throws Exception If the test failed unexpectedly.
-   */
-  @Test
-  public void testSetMethods() throws Exception
-  {
-    AddResponseProtocolOp addResponse;
-    addResponse = new AddResponseProtocolOp(resultCode);
-
-    addResponse.setResultCode(resultCode + 1);
-    assertEquals(addResponse.getResultCode(), resultCode + 1);
-
-    addResponse.setErrorMessage(resultMsg);
-    assertEquals(addResponse.getErrorMessage(), resultMsg);
-
-    addResponse.setMatchedDN(dn);
-    assertEquals(addResponse.getMatchedDN(), dn);
-
-    ArrayList<String> referralURLs = new ArrayList<String>();
-    referralURLs.add("ds1.example.com");
-    referralURLs.add("ds2.example.com");
-    referralURLs.add("ds3.example.com");
-    addResponse.setReferralURLs(referralURLs);
-    assertEquals(addResponse.getReferralURLs(), referralURLs);
-  }
-
-  /**
    * Test the decode method when an empty element is passed
    *
    * @throws Exception If the test failed unexpectedly.
@@ -186,9 +154,13 @@
   @Test(expectedExceptions = LDAPException.class)
   public void testDecodeEmptyElement() throws Exception
   {
-    ArrayList<ASN1Element> elements = new ArrayList<ASN1Element>();
-    AddResponseProtocolOp.decode(new ASN1Sequence(OP_TYPE_ADD_RESPONSE,
-                                                 elements));
+    ByteStringBuilder builder = new ByteStringBuilder();
+    ASN1Writer writer = ASN1.getWriter(builder);
+    writer.writeStartSequence(OP_TYPE_ADD_RESPONSE);
+    writer.writeEndSequence();
+
+    ASN1Reader reader = ASN1.getReader(builder.toByteString());
+    LDAPReader.readProtocolOp(reader);
   }
 
   /**
@@ -200,12 +172,16 @@
   @Test(expectedExceptions = LDAPException.class)
   public void testDecodeInvalidResultCode() throws Exception
   {
-    ArrayList<ASN1Element> elements = new ArrayList<ASN1Element>(2);
-    elements.add(new ASN1OctetString("Invalid Data"));
-    elements.add(new ASN1Null());
-    elements.add(new ASN1Null());
-    AddRequestProtocolOp.decode(new ASN1Sequence(OP_TYPE_ADD_RESPONSE,
-                                                 elements));
+    ByteStringBuilder builder = new ByteStringBuilder();
+    ASN1Writer writer = ASN1.getWriter(builder);
+    writer.writeStartSequence(OP_TYPE_ADD_RESPONSE);
+    writer.writeOctetString("Invalid Data");
+    writer.writeNull();
+    writer.writeNull();
+    writer.writeEndSequence();
+
+    ASN1Reader reader = ASN1.getReader(builder.toByteString());
+    LDAPReader.readProtocolOp(reader);
   }
 
   /**
@@ -218,12 +194,16 @@
   @Test
   public void testDecodeInvalidDN() throws Exception
   {
-    ArrayList<ASN1Element> elements = new ArrayList<ASN1Element>(2);
-    elements.add(new ASN1Enumerated(resultCode));
-    elements.add(new ASN1Null());
-    elements.add(new ASN1Null());
-    AddRequestProtocolOp.decode(new ASN1Sequence(OP_TYPE_ADD_RESPONSE,
-                                                 elements));
+    ByteStringBuilder builder = new ByteStringBuilder();
+    ASN1Writer writer = ASN1.getWriter(builder);
+    writer.writeStartSequence(OP_TYPE_ADD_RESPONSE);
+    writer.writeInteger(resultCode);
+    writer.writeNull();
+    writer.writeNull();
+    writer.writeEndSequence();
+
+    ASN1Reader reader = ASN1.getReader(builder.toByteString());
+    LDAPReader.readProtocolOp(reader);
   }
 
   /**
@@ -236,12 +216,16 @@
   @Test
   public void testDecodeInvalidResultMsg() throws Exception
   {
-    ArrayList<ASN1Element> elements = new ArrayList<ASN1Element>(2);
-    elements.add(new ASN1Enumerated(resultCode));
-    elements.add(new ASN1OctetString(dn.toString()));
-    elements.add(new ASN1Null());
-    AddRequestProtocolOp.decode(new ASN1Sequence(OP_TYPE_ADD_RESPONSE,
-                                                 elements));
+    ByteStringBuilder builder = new ByteStringBuilder();
+    ASN1Writer writer = ASN1.getWriter(builder);
+    writer.writeStartSequence(OP_TYPE_ADD_RESPONSE);
+    writer.writeInteger(resultCode);
+    writer.writeOctetString(dn.toString());
+    writer.writeNull();
+    writer.writeEndSequence();
+
+    ASN1Reader reader = ASN1.getReader(builder.toByteString());
+    LDAPReader.readProtocolOp(reader);
   }
 
   /**
@@ -254,13 +238,17 @@
   @Test
   public void testDecodeInvalidReferralURLs() throws Exception
   {
-    ArrayList<ASN1Element> elements = new ArrayList<ASN1Element>(2);
-    elements.add(new ASN1Enumerated(resultCode));
-    elements.add(new ASN1OctetString(dn.toString()));
-    elements.add(new ASN1OctetString(resultMsg));
-    elements.add(new ASN1Null());
-    AddRequestProtocolOp.decode(new ASN1Sequence(OP_TYPE_ADD_RESPONSE,
-                                                 elements));
+    ByteStringBuilder builder = new ByteStringBuilder();
+    ASN1Writer writer = ASN1.getWriter(builder);
+    writer.writeStartSequence(OP_TYPE_ADD_RESPONSE);
+    writer.writeInteger(resultCode);
+    writer.writeOctetString(dn.toString());
+    writer.writeOctetString(resultMsg.toString());
+    writer.writeNull();
+    writer.writeEndSequence();
+
+    ASN1Reader reader = ASN1.getReader(builder.toByteString());
+    LDAPReader.readProtocolOp(reader);
   }
 
   /**
@@ -271,9 +259,10 @@
   @Test
   public void testEncodeDecode() throws Exception
   {
+    ByteStringBuilder builder = new ByteStringBuilder();
+    ASN1Writer writer = ASN1.getWriter(builder);
     AddResponseProtocolOp addEncoded;
     AddResponseProtocolOp addDecoded;
-    ASN1Element element;
 
     ArrayList<String> referralURLs = new ArrayList<String>();
     referralURLs.add("ds1.example.com");
@@ -284,8 +273,9 @@
     //Test case for a full encode decode operation with normal params.
     addEncoded = new AddResponseProtocolOp(resultCode, resultMsg, dn,
                                            referralURLs);
-    element = addEncoded.encode();
-    addDecoded = (AddResponseProtocolOp)AddResponseProtocolOp.decode(element);
+    addEncoded.write(writer);
+    ASN1Reader reader = ASN1.getReader(builder.toByteString());
+    addDecoded = (AddResponseProtocolOp)LDAPReader.readProtocolOp(reader);
 
     assertEquals(addEncoded.getType(), OP_TYPE_ADD_RESPONSE);
     assertEquals(addEncoded.getMatchedDN().compareTo(addDecoded.getMatchedDN()),
@@ -298,22 +288,28 @@
     //Test case for a full encode decode operation with an empty DN params.
     addEncoded = new AddResponseProtocolOp(resultCode, resultMsg, DN.nullDN(),
                                            referralURLs);
-    element = addEncoded.encode();
-    addDecoded = (AddResponseProtocolOp)AddResponseProtocolOp.decode(element);
+    builder.clear();
+    addEncoded.write(writer);
+    reader = ASN1.getReader(builder.toByteString());
+    addDecoded = (AddResponseProtocolOp)LDAPReader.readProtocolOp(reader);
     assertEquals(addDecoded.getMatchedDN(), null);
 
     //Test case for a full empty referral url param.
     ArrayList<String> emptyReferralURLs = new ArrayList<String>();
     addEncoded = new AddResponseProtocolOp(resultCode, resultMsg, dn,
                                            emptyReferralURLs);
-    element = addEncoded.encode();
-    addDecoded = (AddResponseProtocolOp)AddResponseProtocolOp.decode(element);
+    builder.clear();
+    addEncoded.write(writer);
+    reader = ASN1.getReader(builder.toByteString());
+    addDecoded = (AddResponseProtocolOp)LDAPReader.readProtocolOp(reader);
     assertTrue(addDecoded.getReferralURLs() == null);
 
     //Test case for a full encode decode operation with resultCode param only.
     addEncoded = new AddResponseProtocolOp(resultCode);
-    element = addEncoded.encode();
-    addDecoded = (AddResponseProtocolOp)AddResponseProtocolOp.decode(element);
+    builder.clear();
+    addEncoded.write(writer);
+    reader = ASN1.getReader(builder.toByteString());
+    addDecoded = (AddResponseProtocolOp)LDAPReader.readProtocolOp(reader);
 
     assertEquals(addDecoded.getMatchedDN(), null);
     assertEquals(addDecoded.getErrorMessage(), null);
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/ldap/TestBindRequestProtocolOp.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/ldap/TestBindRequestProtocolOp.java
index 543b81f..3676c68 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/ldap/TestBindRequestProtocolOp.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/ldap/TestBindRequestProtocolOp.java
@@ -26,18 +26,14 @@
  */
 package org.opends.server.protocols.ldap;
 
-import java.util.ArrayList;
-
-import org.opends.server.protocols.asn1.ASN1Element;
-import org.opends.server.protocols.asn1.ASN1Integer;
-import org.opends.server.protocols.asn1.ASN1Long;
-import org.opends.server.protocols.asn1.ASN1OctetString;
-import org.opends.server.protocols.asn1.ASN1Sequence;
-import org.opends.server.protocols.ldap.BindRequestProtocolOp;
-import org.opends.server.types.AuthenticationType;
 import org.opends.server.types.LDAPException;
+import org.opends.server.types.ByteString;
+import org.opends.server.types.ByteStringBuilder;
 import org.testng.annotations.Test;
 import static org.opends.server.protocols.ldap.LDAPConstants.*;
+import org.opends.server.protocols.asn1.ASN1;
+import org.opends.server.protocols.asn1.ASN1Reader;
+import org.opends.server.protocols.asn1.ASN1Writer;
 import static org.opends.server.util.ServerConstants.*;
 import static org.testng.Assert.*;
 //import org.testng.Reporter;
@@ -51,17 +47,23 @@
 
   @Test()
   public void testBindRequestEncodeDecode() throws Exception {
-    ASN1OctetString bindDn=new ASN1OctetString(dn);
-    ASN1OctetString pw=new ASN1OctetString(pwd);
+    ByteStringBuilder simpleBuilder = new ByteStringBuilder();
+    ASN1Writer simpleWriter = ASN1.getWriter(simpleBuilder);
+    ByteStringBuilder saslBuilder = new ByteStringBuilder();
+    ASN1Writer saslWriter = ASN1.getWriter(saslBuilder);
+    ByteString bindDn=ByteString.valueOf(dn);
+    ByteString pw=ByteString.valueOf(pwd);
     BindRequestProtocolOp simple =
       new BindRequestProtocolOp(bindDn, 3, pw);
     BindRequestProtocolOp sasl =
       new BindRequestProtocolOp(bindDn, SASL_MECHANISM_PLAIN, pw);
-    ASN1Element simpleElement = simple.encode();
-    ASN1Element saslElement = sasl.encode();
+    simple.write(simpleWriter);
+    sasl.write(saslWriter);
     // Decode to a new protocol op.
-    ProtocolOp simpleDecodedOp = ProtocolOp.decode(simpleElement);
-    ProtocolOp saslDecodedOp = ProtocolOp.decode(saslElement);
+    ASN1Reader simpleReader = ASN1.getReader(simpleBuilder.toByteString());
+    ASN1Reader saslReader = ASN1.getReader(saslBuilder.toByteString());
+    ProtocolOp simpleDecodedOp = LDAPReader.readProtocolOp(simpleReader);
+    ProtocolOp saslDecodedOp = LDAPReader.readProtocolOp(saslReader);
     assertTrue(saslDecodedOp instanceof BindRequestProtocolOp);
     assertTrue(simpleDecodedOp instanceof BindRequestProtocolOp);
     BindRequestProtocolOp simpleOp =
@@ -98,8 +100,8 @@
   @Test ()
   public void testBindRequestToString() throws Exception
   {
-    ASN1OctetString bindDn=new ASN1OctetString(dn);
-    ASN1OctetString pw=new ASN1OctetString(pwd);
+    ByteString bindDn=ByteString.valueOf(dn);
+    ByteString pw=ByteString.valueOf(pwd);
     BindRequestProtocolOp sasl =
       new BindRequestProtocolOp(bindDn, SASL_MECHANISM_PLAIN, pw);
     StringBuilder sb = new StringBuilder();
@@ -110,86 +112,68 @@
    @Test (expectedExceptions = LDAPException.class)
     public void testBadBindRequestSequence() throws Exception
     {
-      ProtocolOp.decode(new ASN1Integer(OP_TYPE_BIND_REQUEST, 0));
+    ByteStringBuilder builder = new ByteStringBuilder();
+    ASN1Writer writer = ASN1.getWriter(builder);
+    writer.writeInteger(OP_TYPE_BIND_REQUEST, 0);
+
+    ASN1Reader reader = ASN1.getReader(builder.toByteString());
+    LDAPReader.readProtocolOp(reader);
     }
 
    @Test (expectedExceptions = LDAPException.class)
    public void testInvalidBindRequestTooManyElements() throws Exception
    {
-       ASN1OctetString bindDn=new ASN1OctetString(dn);
-       ASN1OctetString pw=new ASN1OctetString(pwd);
-       BindRequestProtocolOp sasl =
-           new BindRequestProtocolOp(bindDn, SASL_MECHANISM_PLAIN, pw);
-       tooManyElements(sasl, OP_TYPE_BIND_REQUEST);
+     ByteStringBuilder builder = new ByteStringBuilder();
+     ASN1Writer writer = ASN1.getWriter(builder);
+
+     writer.writeStartSequence(OP_TYPE_BIND_REQUEST);
+     writer.writeInteger(3);
+     writer.writeOctetString(dn);
+     writer.writeBoolean(true);
+     writer.writeStartSequence(TYPE_AUTHENTICATION_SASL);
+     writer.writeOctetString(SASL_MECHANISM_PLAIN);
+     writer.writeOctetString(pwd);
+     writer.writeEndSequence();
+     writer.writeEndSequence();
+
+     ASN1Reader reader = ASN1.getReader(builder.toByteString());
+     LDAPReader.readProtocolOp(reader);
    }
 
    @Test (expectedExceptions = LDAPException.class)
    public void testInvalidBindRequestTooFewElements() throws Exception
    {
-       ASN1OctetString bindDn=new ASN1OctetString(dn);
-       ASN1OctetString pw=new ASN1OctetString(pwd);
-       BindRequestProtocolOp sasl =
-           new BindRequestProtocolOp(bindDn, SASL_MECHANISM_PLAIN, pw);
-       tooFewElements(sasl, OP_TYPE_BIND_REQUEST);
+     ByteStringBuilder builder = new ByteStringBuilder();
+     ASN1Writer writer = ASN1.getWriter(builder);
+
+     writer.writeStartSequence(OP_TYPE_BIND_REQUEST);
+     writer.writeOctetString(dn);
+     writer.writeStartSequence(TYPE_AUTHENTICATION_SASL);
+     writer.writeOctetString(SASL_MECHANISM_PLAIN);
+     writer.writeOctetString(pwd);
+     writer.writeEndSequence();
+     writer.writeEndSequence();
+
+    ASN1Reader reader = ASN1.getReader(builder.toByteString());
+    LDAPReader.readProtocolOp(reader);
    }
 
    @Test (expectedExceptions = LDAPException.class)
    public void testInvalidBindRequestProtoVersion() throws Exception
    {
-     ASN1OctetString bindDn=new ASN1OctetString(dn);
-     ASN1OctetString pw=new ASN1OctetString(pwd);
-     BindRequestProtocolOp sasl =
-       new BindRequestProtocolOp(bindDn, SASL_MECHANISM_PLAIN, pw);
-     ASN1Element element = sasl.encode();
-     ArrayList<ASN1Element> elements = ((ASN1Sequence)element).elements();
-     elements.set(0, new ASN1Long(Long.MAX_VALUE));
-     ProtocolOp.decode(new ASN1Sequence(OP_TYPE_BIND_REQUEST, elements));
-   }
+     ByteStringBuilder builder = new ByteStringBuilder();
+     ASN1Writer writer = ASN1.getWriter(builder);
 
-   @Test()
-   public void testBindRequestSetters()  throws Exception {
-       ASN1OctetString bindDn=new ASN1OctetString(dn);
-       ASN1OctetString pw=new ASN1OctetString(pwd);
-       ASN1OctetString newBindDn=new ASN1OctetString(newDn);
-       ASN1OctetString newPw=new ASN1OctetString(newPwd);
-         ASN1OctetString saslCreds=new ASN1OctetString(creds);
+     writer.writeStartSequence(OP_TYPE_BIND_REQUEST);
+     writer.writeOctetString("invalid element");
+     writer.writeOctetString(dn);
+     writer.writeStartSequence(TYPE_AUTHENTICATION_SASL);
+     writer.writeOctetString(SASL_MECHANISM_PLAIN);
+     writer.writeOctetString(pwd);
+     writer.writeEndSequence();
+     writer.writeEndSequence();
 
-       BindRequestProtocolOp sasl =
-           new BindRequestProtocolOp(bindDn, SASL_MECHANISM_PLAIN, pw);
-       BindRequestProtocolOp simple =
-           new BindRequestProtocolOp(bindDn, 3, pw);
-       simple.encode();
-       sasl.encode();
-       sasl.setDN(newBindDn);
-       simple.setDN(newBindDn);
-       simple.setSimplePassword(newPw);
-         sasl.setProtocolVersion(2);
-         simple.setProtocolVersion(2);
-         sasl.setSASLAuthenticationInfo(SASL_MECHANISM_GSSAPI, saslCreds);
-
-       ASN1Element simpleElement = simple.encode();
-       ASN1Element saslElement = sasl.encode();
-       // Decode to a new protocol op.
-       ProtocolOp simpleDecodedOp = ProtocolOp.decode(simpleElement);
-       ProtocolOp saslDecodedOp = ProtocolOp.decode(saslElement);
-       assertTrue(saslDecodedOp instanceof BindRequestProtocolOp);
-       assertTrue(simpleDecodedOp instanceof BindRequestProtocolOp);
-       BindRequestProtocolOp simpleOp =
-           (BindRequestProtocolOp)simpleDecodedOp;
-       BindRequestProtocolOp saslOp =
-           (BindRequestProtocolOp)saslDecodedOp;
-
-       assertTrue(saslOp.getDN().equals(sasl.getDN()));
-       assertTrue(simpleOp.getDN().equals(simple.getDN()));
-       ASN1OctetString sPwd=simple.getSimplePassword();
-         int sProtoVer=simple.getProtocolVersion();
-       assertTrue(simpleOp.getSimplePassword().equals(sPwd));
-         assertTrue(simpleOp.getProtocolVersion() == sProtoVer);
-         assertTrue(saslOp.getProtocolVersion() == sasl.getProtocolVersion());
-         String  saslTypeStr=sasl.getAuthenticationType().toString();
-         String saslOpTypeStr=saslOp.getAuthenticationType().toString();
- //        Reporter.log(saslTypeStr);
- //        Reporter.log(saslOpTypeStr);
-         assertTrue(saslOpTypeStr.equals(saslTypeStr));
+    ASN1Reader reader = ASN1.getReader(builder.toByteString());
+    LDAPReader.readProtocolOp(reader);
    }
 }
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/ldap/TestBindResponseProtocolOp.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/ldap/TestBindResponseProtocolOp.java
index ddc22a3..ed90701 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/ldap/TestBindResponseProtocolOp.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/ldap/TestBindResponseProtocolOp.java
@@ -31,13 +31,11 @@
 import java.util.List;
 import org.opends.server.TestCaseUtils;
 import org.opends.messages.Message;
-import org.opends.server.protocols.asn1.ASN1Element;
-import org.opends.server.protocols.asn1.ASN1OctetString;
-import org.opends.server.protocols.ldap.BindResponseProtocolOp;
 import static org.opends.server.protocols.ldap.LDAPConstants.*;
-import org.opends.server.types.DN;
-import org.opends.server.types.LDAPException;
-import org.opends.server.types.ResultCode;
+import org.opends.server.protocols.asn1.ASN1Writer;
+import org.opends.server.protocols.asn1.ASN1;
+import org.opends.server.protocols.asn1.ASN1Reader;
+import org.opends.server.types.*;
 import org.testng.annotations.BeforeClass;
 import org.testng.annotations.Test;
 import static org.testng.Assert.*;
@@ -76,8 +74,8 @@
         List<String> referralURLs=new ArrayList<String>();
         referralURLs.add(url);
         DN responseDn = DN.decode(dn);
-        ASN1OctetString serverSASLCredentials =
-            new ASN1OctetString(saslCreds);
+        ByteString serverSASLCredentials =
+            ByteString.valueOf(saslCreds);
         BindResponseProtocolOp r =
             new BindResponseProtocolOp(okCode.getIntValue(),
                     message, responseDn, referralURLs,
@@ -87,37 +85,65 @@
 
     @Test (expectedExceptions = LDAPException.class)
     public void testBindResponseTooFew() throws Exception {
-        BindResponseProtocolOp busyResp =
-            new BindResponseProtocolOp(busyCode.getIntValue());
-        tooFewElements(busyResp, OP_TYPE_BIND_RESPONSE);
+      ByteStringBuilder bsb = new ByteStringBuilder();
+      ASN1Writer writer = ASN1.getWriter(bsb);
+      writer.writeStartSequence(OP_TYPE_BIND_RESPONSE);
+      writer.writeOctetString((String)null);
+      writer.writeOctetString((String)null);
+      writer.writeEndSequence();
+
+      ASN1Reader reader = ASN1.getReader(bsb.toByteString());
+      LDAPReader.readProtocolOp(reader);
     }
 
     @Test (expectedExceptions = LDAPException.class)
-    public void testBindResponseTooMany() throws Exception {
-        BindResponseProtocolOp busyResp =
-            new BindResponseProtocolOp(busyCode.getIntValue());
-        tooManyElements(busyResp, OP_TYPE_BIND_RESPONSE);
+    public void testBindResponseTooMany() throws Exception {      
+      ByteStringBuilder bsb = new ByteStringBuilder();
+      ASN1Writer writer = ASN1.getWriter(bsb);
+      writer.writeStartSequence(OP_TYPE_BIND_RESPONSE);
+      writer.writeInteger(okCode.getIntValue());
+      writer.writeOctetString((String)null);
+      writer.writeOctetString((String)null);
+      writer.writeBoolean(true);
+      writer.writeEndSequence();
+
+      ASN1Reader reader = ASN1.getReader(bsb.toByteString());
+      LDAPReader.readProtocolOp(reader);
     }
 
     @Test (expectedExceptions = LDAPException.class)
     public void testBindResponseBadResult() throws Exception {
-        BindResponseProtocolOp busyResp =
-            new BindResponseProtocolOp(busyCode.getIntValue());
-        badIntegerElement(busyResp, OP_TYPE_BIND_RESPONSE,0);
+      ByteStringBuilder bsb = new ByteStringBuilder();
+      ASN1Writer writer = ASN1.getWriter(bsb);
+      writer.writeStartSequence(OP_TYPE_BIND_RESPONSE);
+      writer.writeOctetString("invalid element");
+      writer.writeOctetString((String)null);
+      writer.writeOctetString((String)null);
+      writer.writeEndSequence();
+
+      ASN1Reader reader = ASN1.getReader(bsb.toByteString());
+      LDAPReader.readProtocolOp(reader);
     }
 
     @Test (expectedExceptions = LDAPException.class)
     public void testBindResponseBadReferral() throws Exception {
-        List<String> referralURLs=new ArrayList<String>();
-        referralURLs.add(url);
-        DN responseDn = DN.decode(dn);
-        ASN1OctetString serverSASLCredentials =
-            new ASN1OctetString(saslCreds);
-        BindResponseProtocolOp r =
-            new BindResponseProtocolOp(okCode.getIntValue(),
-                    message, responseDn, referralURLs,
-                    serverSASLCredentials);
-        badIntegerElement(r,OP_TYPE_BIND_RESPONSE,3);
+      DN responseDn = DN.decode(dn);
+      ByteString serverSASLCredentials =
+          ByteString.valueOf(saslCreds);
+
+      ByteStringBuilder bsb = new ByteStringBuilder();
+      ASN1Writer writer = ASN1.getWriter(bsb);
+      writer.writeStartSequence(OP_TYPE_BIND_RESPONSE);
+      writer.writeInteger(okCode.getIntValue());
+      writer.writeOctetString(responseDn.toString());
+      writer.writeOctetString(message.toString());
+      writer.writeInteger(Long.MAX_VALUE);
+      writer.writeOctetString(TYPE_SERVER_SASL_CREDENTIALS,
+          serverSASLCredentials);
+      writer.writeEndSequence();
+
+      ASN1Reader reader = ASN1.getReader(bsb.toByteString());
+      LDAPReader.readProtocolOp(reader);
     }
 
     @Test
@@ -125,8 +151,8 @@
         List<String> referralURLs=new ArrayList<String>();
         referralURLs.add(url);
         DN responseDn = DN.decode(dn);
-        ASN1OctetString serverSASLCredentials =
-            new ASN1OctetString(saslCreds);
+        ByteString serverSASLCredentials =
+            ByteString.valueOf(saslCreds);
 
         BindResponseProtocolOp saslOkResp =
             new BindResponseProtocolOp(okCode.getIntValue(),
@@ -137,13 +163,24 @@
         BindResponseProtocolOp invalidSyntaxResp =
             new BindResponseProtocolOp(invalidSyntaxCode.getIntValue(),
                                                               message);
-        ASN1Element saslOkElem=saslOkResp.encode();
-        ASN1Element busyElem=busyResp.encode();
-        ASN1Element invalidSyntaxElem=invalidSyntaxResp.encode();
 
-        ProtocolOp saslOkDec= ProtocolOp.decode(saslOkElem);
-        ProtocolOp busyDec = ProtocolOp.decode(busyElem);
-        ProtocolOp invalidSyntaxDec = ProtocolOp.decode(invalidSyntaxElem);
+        ByteStringBuilder saslOkBuilder = new ByteStringBuilder();
+        ASN1Writer saslOkWriter = ASN1.getWriter(saslOkBuilder);
+        ByteStringBuilder busyBuilder = new ByteStringBuilder();
+        ASN1Writer busyWriter = ASN1.getWriter(busyBuilder);
+        ByteStringBuilder invalidSyntaxBuilder = new ByteStringBuilder();
+        ASN1Writer invalidSyntaxWriter = ASN1.getWriter(invalidSyntaxBuilder);
+
+        saslOkResp.write(saslOkWriter);
+        busyResp.write(busyWriter);
+        invalidSyntaxResp.write(invalidSyntaxWriter);
+
+        ASN1Reader saslOkReader = ASN1.getReader(saslOkBuilder.toByteString());
+        ASN1Reader busyReader = ASN1.getReader(busyBuilder.toByteString());
+        ASN1Reader invalidSyntaxReader = ASN1.getReader(invalidSyntaxBuilder.toByteString());
+        ProtocolOp saslOkDec= LDAPReader.readProtocolOp(saslOkReader);
+        ProtocolOp busyDec = LDAPReader.readProtocolOp(busyReader);
+        ProtocolOp invalidSyntaxDec = LDAPReader.readProtocolOp(invalidSyntaxReader);
 
         assertTrue(saslOkDec instanceof BindResponseProtocolOp);
         assertTrue(busyDec instanceof BindResponseProtocolOp);
@@ -181,50 +218,4 @@
         DN dn2=saslOkResp.getMatchedDN();
         assertTrue(dn1.equals(dn2));
     }
-    @Test()
-    public void testSetters() throws Exception {
-        List<String> referralURLs=new ArrayList<String>();
-        referralURLs.add(url);
-        List<String> referralURL2s=new ArrayList<String>();
-        referralURL2s.add(url2);
-        DN responseDn = DN.decode(dn);
-        DN responseDn2 = DN.decode(dn2);
-        BindResponseProtocolOp resp =
-            new BindResponseProtocolOp(okCode.getIntValue(),
-                    message, responseDn, referralURLs);
-        resp.encode();
-        resp.setErrorMessage(message2);
-        resp.setMatchedDN(responseDn2);
-        resp.setReferralURLs(referralURL2s);
-        resp.setResultCode(busyCode.getIntValue());
-        ASN1Element respElem=resp.encode();
-        ProtocolOp respDec= ProtocolOp.decode(respElem);
-        BindResponseProtocolOp respOp =
-            (BindResponseProtocolOp)respDec;
-        assertTrue(respOp.getResultCode() == resp.getResultCode());
-        DN dn1=resp.getMatchedDN();
-        DN dn2=respOp.getMatchedDN();
-        assertTrue(dn1.equals(dn2));
-        assertTrue(respOp.getErrorMessage().equals(resp.getErrorMessage()));
-        List<String> list1 = resp.getReferralURLs();
-        List<String> list2 = respOp.getReferralURLs();
-        assertTrue(list1.equals(list2));
-        ASN1OctetString creds =
-            new ASN1OctetString(saslCreds);
-        ASN1OctetString creds2 =
-            new ASN1OctetString(saslCreds2);
-        BindResponseProtocolOp sasl =
-            new BindResponseProtocolOp(okCode.getIntValue(),
-                    message, responseDn, referralURLs,
-                    creds);
-        sasl.encode();
-        sasl.setServerSASLCredentials(creds2);
-        ASN1Element saslElem=sasl.encode();
-        ProtocolOp saslDec= ProtocolOp.decode(saslElem);
-        BindResponseProtocolOp saslOp =
-            (BindResponseProtocolOp)saslDec;
-        String str1=sasl.getServerSASLCredentials().toString();
-        String str2=saslOp.getServerSASLCredentials().toString();
-        assertTrue(str1.equals(str2));
-    }
 }
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/ldap/TestCompareRequestProtocolOp.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/ldap/TestCompareRequestProtocolOp.java
index c4c9518..901a4df 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/ldap/TestCompareRequestProtocolOp.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/ldap/TestCompareRequestProtocolOp.java
@@ -26,12 +26,13 @@
  */
 package org.opends.server.protocols.ldap;
 
-import org.opends.server.protocols.asn1.ASN1OctetString;
-import org.opends.server.protocols.asn1.ASN1Element;
-import org.opends.server.protocols.asn1.ASN1Sequence;
-import org.opends.server.protocols.asn1.ASN1Null;
 import org.opends.server.types.LDAPException;
+import org.opends.server.types.ByteString;
+import org.opends.server.types.ByteStringBuilder;
 import static org.opends.server.util.ServerConstants.EOL;
+import org.opends.server.protocols.asn1.ASN1Writer;
+import org.opends.server.protocols.asn1.ASN1;
+import org.opends.server.protocols.asn1.ASN1Reader;
 import org.testng.annotations.Test;
 import static org.testng.Assert.assertEquals;
 
@@ -56,22 +57,22 @@
   /**
    * The DN for compare requests in this test case.
    */
-  private static final ASN1OctetString dn =
-      new ASN1OctetString("dc=example,dc=com");
+  private static final ByteString dn =
+      ByteString.valueOf("dc=example,dc=com");
 
   /**
    * The alternative DN for compare requests in this test case.
    */
-  private static final ASN1OctetString dnAlt =
-      new ASN1OctetString("dc=sun,dc=com");
+  private static final ByteString dnAlt =
+      ByteString.valueOf("dc=sun,dc=com");
 
   // The assertion value for this compare request.
-  private ASN1OctetString assertionValue =
-      new ASN1OctetString("=test");
+  private ByteString assertionValue =
+      ByteString.valueOf("=test");
 
   // The assertion value for this compare request.
-  private ASN1OctetString assertionValueAlt =
-      new ASN1OctetString("=testAlt");
+  private ByteString assertionValueAlt =
+      ByteString.valueOf("=testAlt");
 
   // The attribute type for this compare request.
   private String attributeType = "testAttribute";
@@ -124,31 +125,6 @@
   }
 
   /**
-   * Test to make sure that setter methods work.
-   *
-   * @throws Exception If the test failed unexpectedly.
-   */
-  @Test
-  public void testSetMethods() throws Exception
-  {
-    CompareRequestProtocolOp compareRequest;
-
-    compareRequest = new CompareRequestProtocolOp(dn, attributeType,
-                                                  assertionValue);
-    assertEquals(compareRequest.getDN(), dn);
-    compareRequest.setDN(dnAlt);
-    assertEquals(compareRequest.getDN(), dnAlt);
-
-    assertEquals(compareRequest.getAttributeType(), attributeType);
-    compareRequest.setAttributeType(attributeTypeAlt);
-    assertEquals(compareRequest.getAttributeType(), attributeTypeAlt);
-
-    assertEquals(compareRequest.getAssertionValue(), assertionValue);
-    compareRequest.setAssertionValue(assertionValueAlt);
-    assertEquals(compareRequest.getAssertionValue(), assertionValueAlt);
-  }
-
-  /**
    * Test the decode method when an null element is passed
    *
    * @throws Exception If the test failed unexpectedly.
@@ -156,7 +132,7 @@
   @Test(expectedExceptions = LDAPException.class)
   public void testDecodeNullElement() throws Exception
   {
-    CompareRequestProtocolOp.decodeCompareRequest(null);
+    LDAPReader.readProtocolOp(null);
   }
 
   /**
@@ -167,9 +143,13 @@
   @Test(expectedExceptions = LDAPException.class)
   public void testDecodeEmptyElement() throws Exception
   {
-    ArrayList<ASN1Element> elements = new ArrayList<ASN1Element>();
-    CompareRequestProtocolOp.decode(new ASN1Sequence(OP_TYPE_COMPARE_REQUEST,
-                                                 elements));
+    ByteStringBuilder builder = new ByteStringBuilder();
+    ASN1Writer writer = ASN1.getWriter(builder);
+    writer.writeStartSequence(OP_TYPE_COMPARE_REQUEST);
+    writer.writeEndSequence();
+
+    ASN1Reader reader = ASN1.getReader(builder.toByteString());
+    LDAPReader.readProtocolOp(reader);
   }
 
   /**
@@ -180,11 +160,15 @@
   @Test(expectedExceptions = LDAPException.class)
   public void testDecodeInvalidElement() throws Exception
   {
-    ArrayList<ASN1Element> elements = new ArrayList<ASN1Element>(2);
-    elements.add(new ASN1Null());
-    elements.add(new ASN1Null());
-    CompareRequestProtocolOp.decode(new ASN1Sequence(OP_TYPE_COMPARE_REQUEST,
-                                                 elements));
+    ByteStringBuilder builder = new ByteStringBuilder();
+    ASN1Writer writer = ASN1.getWriter(builder);
+    writer.writeStartSequence(OP_TYPE_COMPARE_REQUEST);
+    writer.writeNull();
+    writer.writeNull();
+    writer.writeEndSequence();
+
+    ASN1Reader reader = ASN1.getReader(builder.toByteString());
+    LDAPReader.readProtocolOp(reader);
   }
 
   /**
@@ -195,11 +179,15 @@
   @Test(expectedExceptions = LDAPException.class)
   public void testDecodeWrongElementType() throws Exception
   {
-    ArrayList<ASN1Element> elements = new ArrayList<ASN1Element>(2);
-    elements.add(dn);
-    elements.add(new ASN1Null());
-    CompareRequestProtocolOp.decode(new ASN1Sequence(OP_TYPE_COMPARE_RESPONSE,
-                                                 elements));
+    ByteStringBuilder builder = new ByteStringBuilder();
+    ASN1Writer writer = ASN1.getWriter(builder);
+    writer.writeStartSequence(OP_TYPE_COMPARE_REQUEST);
+    writer.writeOctetString(dn);
+    writer.writeNull();
+    writer.writeEndSequence();
+
+    ASN1Reader reader = ASN1.getReader(builder.toByteString());
+    LDAPReader.readProtocolOp(reader);
   }
 
   /**
@@ -210,14 +198,15 @@
   @Test(expectedExceptions = Exception.class)
   public void testNullEncodeDecode() throws Exception
   {
+    ByteStringBuilder builder = new ByteStringBuilder();
+    ASN1Writer writer = ASN1.getWriter(builder);
     CompareRequestProtocolOp compareEncoded;
     CompareRequestProtocolOp compareDecoded;
-    ASN1Element element;
 
     compareEncoded = new CompareRequestProtocolOp(null, null, null);
-    element = compareEncoded.encode();
-    compareDecoded = (CompareRequestProtocolOp)CompareRequestProtocolOp.decode(
-        element);
+    compareEncoded.write(writer);
+    ASN1Reader reader = ASN1.getReader(builder.toByteString());
+    compareDecoded = (CompareRequestProtocolOp)LDAPReader.readProtocolOp(reader);
   }
 
   /**
@@ -228,18 +217,19 @@
   @Test
   public void testEncodeDecode() throws Exception
   {
+    ByteStringBuilder builder = new ByteStringBuilder();
+    ASN1Writer writer = ASN1.getWriter(builder);
     CompareRequestProtocolOp compareEncoded;
     CompareRequestProtocolOp compareDecoded;
-    ASN1Element element;
     ArrayList<LDAPAttribute> attributes;
 
 
     //Test case for a full encode decode operation with normal params.
     compareEncoded = new CompareRequestProtocolOp(dn, attributeType,
                                                   assertionValue);
-    element = compareEncoded.encode();
-    compareDecoded = (CompareRequestProtocolOp)CompareRequestProtocolOp.decode(
-        element);
+    compareEncoded.write(writer);
+    ASN1Reader reader = ASN1.getReader(builder.toByteString());
+    compareDecoded = (CompareRequestProtocolOp)LDAPReader.readProtocolOp(reader);
 
     assertEquals(compareEncoded.getType(), OP_TYPE_COMPARE_REQUEST);
     assertEquals(compareEncoded.getDN(), compareDecoded.getDN());
@@ -304,7 +294,7 @@
 
     key.append(indentBuf);
     key.append("  Target DN:  ");
-    dn.toString(key);
+    key.append(dn);
     key.append(EOL);
 
     key.append(indentBuf);
@@ -315,7 +305,7 @@
     key.append(indentBuf);
     key.append("  Assertion Value:");
     key.append(EOL);
-    assertionValue.toString(key, indent+4);
+    assertionValue.toHexPlusAscii(key, indent+4);
 
     assertEquals(buffer.toString(), key.toString());
   }
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/ldap/TestCompareResponseProtocolOp.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/ldap/TestCompareResponseProtocolOp.java
index f291196..96484b1 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/ldap/TestCompareResponseProtocolOp.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/ldap/TestCompareResponseProtocolOp.java
@@ -26,13 +26,9 @@
  */
 package org.opends.server.protocols.ldap;
 
-import org.opends.server.types.DN;
-import org.opends.server.types.AttributeType;
-import org.opends.server.types.AttributeValue;
-import org.opends.server.types.RDN;
 import org.opends.server.core.DirectoryServer;
 import org.opends.server.protocols.asn1.*;
-import org.opends.server.types.LDAPException;
+import org.opends.server.types.*;
 import static org.opends.server.util.ServerConstants.EOL;
 import org.opends.messages.Message;
 import org.testng.annotations.BeforeClass;
@@ -84,7 +80,7 @@
     AttributeType attribute =
         DirectoryServer.getDefaultAttributeType("testAttribute");
 
-    AttributeValue attributeValue = new AttributeValue(attribute, "testValue");
+    AttributeValue attributeValue = AttributeValues.create(attribute, "testValue");
 
     RDN[] rdns = new RDN[1];
     rdns[0] = RDN.create(attribute, attributeValue);
@@ -154,34 +150,6 @@
   }
 
   /**
-   * Test to make sure that setter methods work.
-   *
-   * @throws Exception If the test failed unexpectedly.
-   */
-  @Test
-  public void testSetMethods() throws Exception
-  {
-    CompareResponseProtocolOp compareResponse;
-    compareResponse = new CompareResponseProtocolOp(resultCode);
-
-    compareResponse.setResultCode(resultCode + 1);
-    assertEquals(compareResponse.getResultCode(), resultCode + 1);
-
-    compareResponse.setErrorMessage(resultMsg);
-    assertEquals(compareResponse.getErrorMessage(), resultMsg);
-
-    compareResponse.setMatchedDN(dn);
-    assertEquals(compareResponse.getMatchedDN(), dn);
-
-    ArrayList<String> referralURLs = new ArrayList<String>();
-    referralURLs.add("ds1.example.com");
-    referralURLs.add("ds2.example.com");
-    referralURLs.add("ds3.example.com");
-    compareResponse.setReferralURLs(referralURLs);
-    assertEquals(compareResponse.getReferralURLs(), referralURLs);
-  }
-
-  /**
    * Test the decode method when an empty element is passed
    *
    * @throws Exception If the test failed unexpectedly.
@@ -189,9 +157,13 @@
   @Test(expectedExceptions = LDAPException.class)
   public void testDecodeEmptyElement() throws Exception
   {
-    ArrayList<ASN1Element> elements = new ArrayList<ASN1Element>();
-    CompareResponseProtocolOp.decode(new ASN1Sequence(OP_TYPE_COMPARE_RESPONSE,
-                                                     elements));
+    ByteStringBuilder builder = new ByteStringBuilder();
+    ASN1Writer writer = ASN1.getWriter(builder);
+    writer.writeStartSequence(OP_TYPE_COMPARE_RESPONSE);
+    writer.writeEndSequence();
+
+    ASN1Reader reader = ASN1.getReader(builder.toByteString());
+    LDAPReader.readProtocolOp(reader);
   }
 
   /**
@@ -203,12 +175,16 @@
   @Test(expectedExceptions = LDAPException.class)
   public void testDecodeInvalidResultCode() throws Exception
   {
-    ArrayList<ASN1Element> elements = new ArrayList<ASN1Element>(2);
-    elements.add(new ASN1OctetString("Invalid Data"));
-    elements.add(new ASN1Null());
-    elements.add(new ASN1Null());
-    DeleteResponseProtocolOp.decode(new ASN1Sequence(OP_TYPE_COMPARE_RESPONSE,
-                                                    elements));
+    ByteStringBuilder builder = new ByteStringBuilder();
+    ASN1Writer writer = ASN1.getWriter(builder);
+    writer.writeStartSequence(OP_TYPE_COMPARE_RESPONSE);
+    writer.writeOctetString("Invalid Data");
+    writer.writeNull();
+    writer.writeNull();
+    writer.writeEndSequence();
+
+    ASN1Reader reader = ASN1.getReader(builder.toByteString());
+    LDAPReader.readProtocolOp(reader);
   }
 
   /**
@@ -221,12 +197,16 @@
   @Test
   public void testDecodeInvalidDN() throws Exception
   {
-    ArrayList<ASN1Element> elements = new ArrayList<ASN1Element>(2);
-    elements.add(new ASN1Enumerated(resultCode));
-    elements.add(new ASN1Null());
-    elements.add(new ASN1Null());
-    DeleteResponseProtocolOp.decode(new ASN1Sequence(OP_TYPE_COMPARE_RESPONSE,
-                                                    elements));
+    ByteStringBuilder builder = new ByteStringBuilder();
+    ASN1Writer writer = ASN1.getWriter(builder);
+    writer.writeStartSequence(OP_TYPE_COMPARE_RESPONSE);
+    writer.writeInteger(resultCode);
+    writer.writeNull();
+    writer.writeNull();
+    writer.writeEndSequence();
+
+    ASN1Reader reader = ASN1.getReader(builder.toByteString());
+    LDAPReader.readProtocolOp(reader);
   }
 
   /**
@@ -239,12 +219,16 @@
   @Test
   public void testDecodeInvalidResultMsg() throws Exception
   {
-    ArrayList<ASN1Element> elements = new ArrayList<ASN1Element>(2);
-    elements.add(new ASN1Enumerated(resultCode));
-    elements.add(new ASN1OctetString(dn.toString()));
-    elements.add(new ASN1Null());
-    DeleteResponseProtocolOp.decode(new ASN1Sequence(OP_TYPE_COMPARE_RESPONSE,
-                                                    elements));
+    ByteStringBuilder builder = new ByteStringBuilder();
+    ASN1Writer writer = ASN1.getWriter(builder);
+    writer.writeStartSequence(OP_TYPE_COMPARE_RESPONSE);
+    writer.writeInteger(resultCode);
+    writer.writeOctetString(dn.toString());
+    writer.writeNull();
+    writer.writeEndSequence();
+
+    ASN1Reader reader = ASN1.getReader(builder.toByteString());
+    LDAPReader.readProtocolOp(reader);
   }
 
   /**
@@ -257,13 +241,17 @@
   @Test
   public void testDecodeInvalidReferralURLs() throws Exception
   {
-    ArrayList<ASN1Element> elements = new ArrayList<ASN1Element>(2);
-    elements.add(new ASN1Enumerated(resultCode));
-    elements.add(new ASN1OctetString(dn.toString()));
-    elements.add(new ASN1OctetString(resultMsg));
-    elements.add(new ASN1Null());
-    DeleteResponseProtocolOp.decode(new ASN1Sequence(OP_TYPE_COMPARE_RESPONSE,
-                                                    elements));
+    ByteStringBuilder builder = new ByteStringBuilder();
+    ASN1Writer writer = ASN1.getWriter(builder);
+    writer.writeStartSequence(OP_TYPE_COMPARE_RESPONSE);
+    writer.writeInteger(resultCode);
+    writer.writeOctetString(dn.toString());
+    writer.writeOctetString(resultMsg.toString());
+    writer.writeNull();
+    writer.writeEndSequence();
+
+    ASN1Reader reader = ASN1.getReader(builder.toByteString());
+    LDAPReader.readProtocolOp(reader);
   }
 
   /**
@@ -274,9 +262,10 @@
   @Test
   public void testEncodeDecode() throws Exception
   {
+    ByteStringBuilder builder = new ByteStringBuilder();
+    ASN1Writer writer = ASN1.getWriter(builder);
     CompareResponseProtocolOp deleteEncoded;
     CompareResponseProtocolOp deleteDecoded;
-    ASN1Element element;
 
     ArrayList<String> referralURLs = new ArrayList<String>();
     referralURLs.add("ds1.example.com");
@@ -287,9 +276,9 @@
     //Test case for a full encode decode operation with normal params.
     deleteEncoded = new CompareResponseProtocolOp(resultCode, resultMsg, dn,
                                                  referralURLs);
-    element = deleteEncoded.encode();
-    deleteDecoded = (CompareResponseProtocolOp)CompareResponseProtocolOp.decode(
-        element);
+    deleteEncoded.write(writer);
+    ASN1Reader reader = ASN1.getReader(builder.toByteString());
+    deleteDecoded = (CompareResponseProtocolOp)LDAPReader.readProtocolOp(reader);
 
     assertEquals(deleteEncoded.getType(), OP_TYPE_COMPARE_RESPONSE);
     assertEquals(deleteEncoded.getMatchedDN().compareTo(
@@ -305,25 +294,28 @@
     //Test case for a full encode decode operation with an empty DN params.
     deleteEncoded = new CompareResponseProtocolOp(resultCode, resultMsg, DN.nullDN(),
                                                  referralURLs);
-    element = deleteEncoded.encode();
-    deleteDecoded = (CompareResponseProtocolOp)CompareResponseProtocolOp.decode(
-        element);
+    builder.clear();
+    deleteEncoded.write(writer);
+    reader = ASN1.getReader(builder.toByteString());
+    deleteDecoded = (CompareResponseProtocolOp)LDAPReader.readProtocolOp(reader);
     assertEquals(deleteDecoded.getMatchedDN(), null);
 
     //Test case for a full empty referral url param.
     ArrayList<String> emptyReferralURLs = new ArrayList<String>();
     deleteEncoded = new CompareResponseProtocolOp(resultCode, resultMsg, dn,
                                                  emptyReferralURLs);
-    element = deleteEncoded.encode();
-    deleteDecoded = (CompareResponseProtocolOp)CompareResponseProtocolOp.decode(
-        element);
+    builder.clear();
+    deleteEncoded.write(writer);
+    reader = ASN1.getReader(builder.toByteString());
+    deleteDecoded = (CompareResponseProtocolOp)LDAPReader.readProtocolOp(reader);
     assertTrue(deleteDecoded.getReferralURLs() == null);
 
     //Test case for a full encode decode operation with resultCode param only.
     deleteEncoded = new CompareResponseProtocolOp(resultCode);
-    element = deleteEncoded.encode();
-    deleteDecoded = (CompareResponseProtocolOp)CompareResponseProtocolOp.decode(
-        element);
+    builder.clear();
+    deleteEncoded.write(writer);
+    reader = ASN1.getReader(builder.toByteString());
+    deleteDecoded = (CompareResponseProtocolOp)LDAPReader.readProtocolOp(reader);
 
     assertEquals(deleteDecoded.getMatchedDN(), null);
     assertEquals(deleteDecoded.getErrorMessage(), null);
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/ldap/TestDeleteRequestProtocolOp.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/ldap/TestDeleteRequestProtocolOp.java
index 59fedf8..45ce830 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/ldap/TestDeleteRequestProtocolOp.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/ldap/TestDeleteRequestProtocolOp.java
@@ -29,10 +29,13 @@
 import static org.testng.Assert.*;
 
 import org.testng.annotations.*;
-import org.opends.server.protocols.asn1.ASN1OctetString;
-import org.opends.server.protocols.asn1.ASN1Element;
 import org.opends.server.types.LDAPException;
+import org.opends.server.types.ByteString;
+import org.opends.server.types.ByteStringBuilder;
 import static org.opends.server.util.ServerConstants.EOL;
+import org.opends.server.protocols.asn1.ASN1Writer;
+import org.opends.server.protocols.asn1.ASN1;
+import org.opends.server.protocols.asn1.ASN1Reader;
 
 /**
  * This class defines a set of tests for the
@@ -55,14 +58,14 @@
   /**
    * The DN for delete requests in this test case.
    */
-  private static final ASN1OctetString dn =
-      new ASN1OctetString("dc=example,dc=com");
+  private static final ByteString dn =
+      ByteString.valueOf("dc=example,dc=com");
 
   /**
    * The alternative DN for delete requests in this test case.
    */
-  private static final ASN1OctetString dnAlt =
-      new ASN1OctetString("dc=sun,dc=com");
+  private static final ByteString dnAlt =
+      ByteString.valueOf("dc=sun,dc=com");
 
   /**
    * Test the constructors to make sure the right objects are constructed.
@@ -77,22 +80,7 @@
     assertEquals(deleteRequest.getDN(), dn);
   }
 
-
   /**
-   * Test to make sure that setter methods work.
-   *
-   * @throws Exception If the test failed unexpectedly.
-   */
-  @Test
-  public void testSetMethods() throws Exception
-  {
-    DeleteRequestProtocolOp deleteRequest = new DeleteRequestProtocolOp(dn);
-
-    deleteRequest.setDN(dnAlt);;
-    assertEquals(deleteRequest.getDN(), dnAlt);
-  }
-
-    /**
    * Test to make sure the class processes the right LDAP op type.
    *
    * @throws Exception If the test failed unexpectedly.
@@ -124,16 +112,18 @@
   @Test
   public void testEncodeDecode() throws Exception
   {
+    ByteStringBuilder builder = new ByteStringBuilder();
+    ASN1Writer writer = ASN1.getWriter(builder);
     DeleteRequestProtocolOp deleteEncoded;
     DeleteRequestProtocolOp deleteDecoded;
-    ASN1Element element;
 
     deleteEncoded = new DeleteRequestProtocolOp(dn);
-    element = deleteEncoded.encode();
-    deleteDecoded = (DeleteRequestProtocolOp)DeleteRequestProtocolOp.decode(
-        element);
+    deleteEncoded.write(writer);
+    ASN1Reader reader = ASN1.getReader(builder.toByteString());
+    assertEquals(reader.peekType(), OP_TYPE_DELETE_REQUEST);
 
-    assertEquals(element.getType(), OP_TYPE_DELETE_REQUEST);
+    deleteDecoded = (DeleteRequestProtocolOp)LDAPReader.readProtocolOp(reader);
+
     assertEquals(deleteDecoded.getDN(), deleteEncoded.getDN());
   }
 
@@ -145,14 +135,15 @@
   @Test(expectedExceptions = Exception.class)
   public void testNullEncodeDecode() throws Exception
   {
+    ByteStringBuilder builder = new ByteStringBuilder();
+    ASN1Writer writer = ASN1.getWriter(builder);
     DeleteRequestProtocolOp deleteEncoded;
     DeleteRequestProtocolOp deleteDecoded;
-    ASN1Element element;
 
     deleteEncoded = new DeleteRequestProtocolOp(null);
-    element = deleteEncoded.encode();
-    deleteDecoded = (DeleteRequestProtocolOp)DeleteRequestProtocolOp.decode(
-        element);
+    deleteEncoded.write(writer);
+    ASN1Reader reader = ASN1.getReader(builder.toByteString());
+    deleteDecoded = (DeleteRequestProtocolOp)LDAPReader.readProtocolOp(reader);
   }
 
   /**
@@ -163,7 +154,7 @@
   @Test(expectedExceptions = LDAPException.class)
   public void testDecodeNullElement() throws Exception
   {
-    DeleteRequestProtocolOp.decode(null);
+    LDAPReader.readProtocolOp(null);
   }
 
   /**
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/ldap/TestDeleteResponseProtocolOp.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/ldap/TestDeleteResponseProtocolOp.java
index 3e15a6f..02f07e2 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/ldap/TestDeleteResponseProtocolOp.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/ldap/TestDeleteResponseProtocolOp.java
@@ -31,11 +31,7 @@
 
 import org.testng.annotations.*;
 import org.opends.server.protocols.asn1.*;
-import org.opends.server.types.DN;
-import org.opends.server.types.AttributeType;
-import org.opends.server.types.AttributeValue;
-import org.opends.server.types.LDAPException;
-import org.opends.server.types.RDN;
+import org.opends.server.types.*;
 import org.opends.server.core.DirectoryServer;
 import static org.opends.server.util.ServerConstants.EOL;
 import org.opends.messages.Message;
@@ -82,7 +78,7 @@
     AttributeType attribute =
         DirectoryServer.getDefaultAttributeType("testAttribute");
 
-    AttributeValue attributeValue = new AttributeValue(attribute, "testValue");
+    AttributeValue attributeValue = AttributeValues.create(attribute, "testValue");
 
     RDN[] rdns = new RDN[1];
     rdns[0] = RDN.create(attribute, attributeValue);
@@ -152,34 +148,6 @@
   }
 
   /**
-   * Test to make sure that setter methods work.
-   *
-   * @throws Exception If the test failed unexpectedly.
-   */
-  @Test
-  public void testSetMethods() throws Exception
-  {
-    DeleteResponseProtocolOp deleteResponse;
-    deleteResponse = new DeleteResponseProtocolOp(resultCode);
-
-    deleteResponse.setResultCode(resultCode + 1);
-    assertEquals(deleteResponse.getResultCode(), resultCode + 1);
-
-    deleteResponse.setErrorMessage(resultMsg);
-    assertEquals(deleteResponse.getErrorMessage(), resultMsg);
-
-    deleteResponse.setMatchedDN(dn);
-    assertEquals(deleteResponse.getMatchedDN(), dn);
-
-    ArrayList<String> referralURLs = new ArrayList<String>();
-    referralURLs.add("ds1.example.com");
-    referralURLs.add("ds2.example.com");
-    referralURLs.add("ds3.example.com");
-    deleteResponse.setReferralURLs(referralURLs);
-    assertEquals(deleteResponse.getReferralURLs(), referralURLs);
-  }
-
-  /**
    * Test the decode method when an empty element is passed
    *
    * @throws Exception If the test failed unexpectedly.
@@ -187,9 +155,13 @@
   @Test(expectedExceptions = LDAPException.class)
   public void testDecodeEmptyElement() throws Exception
   {
-    ArrayList<ASN1Element> elements = new ArrayList<ASN1Element>();
-    DeleteResponseProtocolOp.decode(new ASN1Sequence(OP_TYPE_DELETE_RESPONSE,
-                                                  elements));
+    ByteStringBuilder builder = new ByteStringBuilder();
+    ASN1Writer writer = ASN1.getWriter(builder);
+    writer.writeStartSequence(OP_TYPE_DELETE_RESPONSE);
+    writer.writeEndSequence();
+
+    ASN1Reader reader = ASN1.getReader(builder.toByteString());
+    LDAPReader.readProtocolOp(reader);
   }
 
   /**
@@ -201,12 +173,16 @@
   @Test(expectedExceptions = LDAPException.class)
   public void testDecodeInvalidResultCode() throws Exception
   {
-    ArrayList<ASN1Element> elements = new ArrayList<ASN1Element>(2);
-    elements.add(new ASN1OctetString("Invalid Data"));
-    elements.add(new ASN1Null());
-    elements.add(new ASN1Null());
-    DeleteResponseProtocolOp.decode(new ASN1Sequence(OP_TYPE_DELETE_RESPONSE,
-                                                 elements));
+    ByteStringBuilder builder = new ByteStringBuilder();
+    ASN1Writer writer = ASN1.getWriter(builder);
+    writer.writeStartSequence(OP_TYPE_DELETE_RESPONSE);
+    writer.writeOctetString("Invalid Data");
+    writer.writeNull();
+    writer.writeNull();
+    writer.writeEndSequence();
+
+    ASN1Reader reader = ASN1.getReader(builder.toByteString());
+    LDAPReader.readProtocolOp(reader);
   }
 
   /**
@@ -219,12 +195,16 @@
   @Test
   public void testDecodeInvalidDN() throws Exception
   {
-    ArrayList<ASN1Element> elements = new ArrayList<ASN1Element>(2);
-    elements.add(new ASN1Enumerated(resultCode));
-    elements.add(new ASN1Null());
-    elements.add(new ASN1Null());
-    DeleteResponseProtocolOp.decode(new ASN1Sequence(OP_TYPE_DELETE_RESPONSE,
-                                                 elements));
+    ByteStringBuilder builder = new ByteStringBuilder();
+    ASN1Writer writer = ASN1.getWriter(builder);
+    writer.writeStartSequence(OP_TYPE_DELETE_RESPONSE);
+    writer.writeInteger(resultCode);
+    writer.writeNull();
+    writer.writeNull();
+    writer.writeEndSequence();
+
+    ASN1Reader reader = ASN1.getReader(builder.toByteString());
+    LDAPReader.readProtocolOp(reader);
   }
 
   /**
@@ -237,12 +217,16 @@
   @Test
   public void testDecodeInvalidResultMsg() throws Exception
   {
-    ArrayList<ASN1Element> elements = new ArrayList<ASN1Element>(2);
-    elements.add(new ASN1Enumerated(resultCode));
-    elements.add(new ASN1OctetString(dn.toString()));
-    elements.add(new ASN1Null());
-    DeleteResponseProtocolOp.decode(new ASN1Sequence(OP_TYPE_DELETE_RESPONSE,
-                                                 elements));
+    ByteStringBuilder builder = new ByteStringBuilder();
+    ASN1Writer writer = ASN1.getWriter(builder);
+    writer.writeStartSequence(OP_TYPE_DELETE_RESPONSE);
+    writer.writeInteger(resultCode);
+    writer.writeOctetString(dn.toString());
+    writer.writeNull();
+    writer.writeEndSequence();
+
+    ASN1Reader reader = ASN1.getReader(builder.toByteString());
+    LDAPReader.readProtocolOp(reader);
   }
 
   /**
@@ -255,13 +239,17 @@
   @Test
   public void testDecodeInvalidReferralURLs() throws Exception
   {
-    ArrayList<ASN1Element> elements = new ArrayList<ASN1Element>(2);
-    elements.add(new ASN1Enumerated(resultCode));
-    elements.add(new ASN1OctetString(dn.toString()));
-    elements.add(new ASN1OctetString(String.valueOf(resultMsg)));
-    elements.add(new ASN1Null());
-    DeleteResponseProtocolOp.decode(new ASN1Sequence(OP_TYPE_DELETE_RESPONSE,
-                                                 elements));
+    ByteStringBuilder builder = new ByteStringBuilder();
+    ASN1Writer writer = ASN1.getWriter(builder);
+    writer.writeStartSequence(OP_TYPE_DELETE_RESPONSE);
+    writer.writeInteger(resultCode);
+    writer.writeOctetString(dn.toString());
+    writer.writeOctetString(resultMsg.toString());
+    writer.writeNull();
+    writer.writeEndSequence();
+
+    ASN1Reader reader = ASN1.getReader(builder.toByteString());
+    LDAPReader.readProtocolOp(reader);
   }
 
   /**
@@ -272,9 +260,10 @@
   @Test
   public void testEncodeDecode() throws Exception
   {
+    ByteStringBuilder builder = new ByteStringBuilder();
+    ASN1Writer writer = ASN1.getWriter(builder);
     DeleteResponseProtocolOp deleteEncoded;
     DeleteResponseProtocolOp deleteDecoded;
-    ASN1Element element;
 
     ArrayList<String> referralURLs = new ArrayList<String>();
     referralURLs.add("ds1.example.com");
@@ -285,9 +274,9 @@
     //Test case for a full encode decode operation with normal params.
     deleteEncoded = new DeleteResponseProtocolOp(resultCode, resultMsg, dn,
                                            referralURLs);
-    element = deleteEncoded.encode();
-    deleteDecoded = (DeleteResponseProtocolOp)DeleteResponseProtocolOp.decode(
-        element);
+    deleteEncoded.write(writer);
+    ASN1Reader reader = ASN1.getReader(builder.toByteString());
+    deleteDecoded = (DeleteResponseProtocolOp)LDAPReader.readProtocolOp(reader);
 
     assertEquals(deleteEncoded.getType(), OP_TYPE_DELETE_RESPONSE);
     assertEquals(deleteEncoded.getMatchedDN().compareTo(
@@ -303,25 +292,28 @@
     //Test case for a full encode decode operation with an empty DN params.
     deleteEncoded = new DeleteResponseProtocolOp(resultCode, resultMsg, DN.nullDN(),
                                            referralURLs);
-    element = deleteEncoded.encode();
-    deleteDecoded = (DeleteResponseProtocolOp)DeleteResponseProtocolOp.decode(
-        element);
+    builder.clear();
+    deleteEncoded.write(writer);
+    reader = ASN1.getReader(builder.toByteString());
+    deleteDecoded = (DeleteResponseProtocolOp)LDAPReader.readProtocolOp(reader);
     assertEquals(deleteDecoded.getMatchedDN(), null);
 
     //Test case for a full empty referral url param.
     ArrayList<String> emptyReferralURLs = new ArrayList<String>();
     deleteEncoded = new DeleteResponseProtocolOp(resultCode, resultMsg, dn,
                                            emptyReferralURLs);
-    element = deleteEncoded.encode();
-    deleteDecoded = (DeleteResponseProtocolOp)DeleteResponseProtocolOp.decode(
-        element);
+    builder.clear();
+    deleteEncoded.write(writer);
+    reader = ASN1.getReader(builder.toByteString());
+    deleteDecoded = (DeleteResponseProtocolOp)LDAPReader.readProtocolOp(reader);
     assertTrue(deleteDecoded.getReferralURLs() == null);
 
     //Test case for a full encode decode operation with resultCode param only.
     deleteEncoded = new DeleteResponseProtocolOp(resultCode);
-    element = deleteEncoded.encode();
-    deleteDecoded = (DeleteResponseProtocolOp)DeleteResponseProtocolOp.decode(
-        element);
+    builder.clear();
+    deleteEncoded.write(writer);
+    reader = ASN1.getReader(builder.toByteString());
+    deleteDecoded = (DeleteResponseProtocolOp)LDAPReader.readProtocolOp(reader);
 
     assertEquals(deleteDecoded.getMatchedDN(), null);
     assertEquals(deleteDecoded.getErrorMessage(), null);
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/ldap/TestLDAPFilter.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/ldap/TestLDAPFilter.java
index 1144b20..4fc3016 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/ldap/TestLDAPFilter.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/ldap/TestLDAPFilter.java
@@ -29,14 +29,11 @@
 import org.testng.annotations.DataProvider;
 import org.testng.annotations.Test;
 import org.testng.annotations.BeforeTest;
-import org.opends.server.types.AttributeType;
-import org.opends.server.types.ByteString;
-import org.opends.server.types.FilterType;
-import org.opends.server.types.LDAPException;
-import org.opends.server.types.RawFilter;
-import org.opends.server.types.SearchFilter;
-import org.opends.server.protocols.asn1.ASN1OctetString;
+import org.opends.server.types.*;
 import org.opends.server.TestCaseUtils;
+import org.opends.server.protocols.asn1.ASN1Writer;
+import org.opends.server.protocols.asn1.ASN1;
+import org.opends.server.protocols.asn1.ASN1Reader;
 
 import static org.testng.Assert.assertEquals;
 import static org.testng.Assert.assertSame;
@@ -81,61 +78,61 @@
   public Object[][] getFilterStrings() throws Exception
   {
     LDAPFilter equal = LDAPFilter.createEqualityFilter("objectClass",
-                                        new ASN1OctetString("\\test*(Value)"));
+                                        ByteString.valueOf("\\test*(Value)"));
     LDAPFilter equal2 = LDAPFilter.createEqualityFilter("objectClass",
-                                                      new ASN1OctetString(""));
+                                                      ByteString.valueOf(""));
     LDAPFilter approx = LDAPFilter.createApproximateFilter("sn",
-                                        new ASN1OctetString("\\test*(Value)"));
+                                        ByteString.valueOf("\\test*(Value)"));
     LDAPFilter greater = LDAPFilter.createGreaterOrEqualFilter("employeeNumber",
-                                        new ASN1OctetString("\\test*(Value)"));
+                                        ByteString.valueOf("\\test*(Value)"));
     LDAPFilter less = LDAPFilter.createLessOrEqualFilter("dob",
-                                        new ASN1OctetString("\\test*(Value)"));
+                                        ByteString.valueOf("\\test*(Value)"));
     LDAPFilter presense = LDAPFilter.createPresenceFilter("login");
 
     ArrayList<ByteString> any = new ArrayList<ByteString>(0);
     ArrayList<ByteString> multiAny = new ArrayList<ByteString>(1);
-    multiAny.add(new ASN1OctetString("\\wid*(get)"));
-    multiAny.add(new ASN1OctetString("*"));
+    multiAny.add(ByteString.valueOf("\\wid*(get)"));
+    multiAny.add(ByteString.valueOf("*"));
 
     LDAPFilter substring1 = LDAPFilter.createSubstringFilter("givenName",
-                                                 new ASN1OctetString("\\Jo*()"),
+                                                 ByteString.valueOf("\\Jo*()"),
                                                       any,
-                                                 new ASN1OctetString("\\n*()"));
+                                                 ByteString.valueOf("\\n*()"));
     LDAPFilter substring2 = LDAPFilter.createSubstringFilter("givenName",
-                                                 new ASN1OctetString("\\Jo*()"),
+                                                 ByteString.valueOf("\\Jo*()"),
                                                       multiAny,
-                                                 new ASN1OctetString("\\n*()"));
+                                                 ByteString.valueOf("\\n*()"));
     LDAPFilter substring3 = LDAPFilter.createSubstringFilter("givenName",
-                                                      new ASN1OctetString(""),
+                                                      ByteString.valueOf(""),
                                                       any,
-                                                 new ASN1OctetString("\\n*()"));
+                                                 ByteString.valueOf("\\n*()"));
     LDAPFilter substring4 = LDAPFilter.createSubstringFilter("givenName",
-                                                 new ASN1OctetString("\\Jo*()"),
+                                                 ByteString.valueOf("\\Jo*()"),
                                                       any,
-                                                      new ASN1OctetString(""));
+                                                      ByteString.valueOf(""));
     LDAPFilter substring5 = LDAPFilter.createSubstringFilter("givenName",
-                                                      new ASN1OctetString(""),
+                                                      ByteString.valueOf(""),
                                                       multiAny,
-                                                      new ASN1OctetString(""));
+                                                      ByteString.valueOf(""));
     LDAPFilter extensible1 = LDAPFilter.createExtensibleFilter("2.4.6.8.19",
                                                 "cn",
-                                           new ASN1OctetString("\\John* (Doe)"),
+                                           ByteString.valueOf("\\John* (Doe)"),
                                                 false);
     LDAPFilter extensible2 = LDAPFilter.createExtensibleFilter("2.4.6.8.19",
                                                 "cn",
-                                           new ASN1OctetString("\\John* (Doe)"),
+                                           ByteString.valueOf("\\John* (Doe)"),
                                                 true);
     LDAPFilter extensible3 = LDAPFilter.createExtensibleFilter("2.4.6.8.19",
                                                 null,
-                                           new ASN1OctetString("\\John* (Doe)"),
+                                           ByteString.valueOf("\\John* (Doe)"),
                                                 true);
     LDAPFilter extensible4 = LDAPFilter.createExtensibleFilter(null,
                                                 "cn",
-                                           new ASN1OctetString("\\John* (Doe)"),
+                                           ByteString.valueOf("\\John* (Doe)"),
                                                 true);
     LDAPFilter extensible5 = LDAPFilter.createExtensibleFilter("2.4.6.8.19",
                                                 null,
-                                           new ASN1OctetString("\\John* (Doe)"),
+                                           ByteString.valueOf("\\John* (Doe)"),
                                                 false);
 
     ArrayList<RawFilter> list1 = new ArrayList<RawFilter>();
@@ -224,13 +221,13 @@
     {
       assertEquals(decoded.getSubAnyElements(), filter.getSubAnyElements());
     }
-    if(decoded.getSubFinalElement() != null && decoded.getSubFinalElement().stringValue() != "" ||
-      filter.getSubFinalElement() != null && filter.getSubFinalElement().stringValue() != "")
+    if(decoded.getSubFinalElement() != null && !decoded.getSubFinalElement().toString().equals("") ||
+      filter.getSubFinalElement() != null && !filter.getSubFinalElement().toString().equals(""))
     {
       assertEquals(decoded.getSubFinalElement(), filter.getSubFinalElement());
     }
-    if(decoded.getSubInitialElement() != null && decoded.getSubInitialElement().stringValue() != "" ||
-        filter.getSubInitialElement() != null && filter.getSubInitialElement().stringValue() != "")
+    if(decoded.getSubInitialElement() != null && !decoded.getSubInitialElement().toString().equals("") ||
+        filter.getSubInitialElement() != null && !filter.getSubInitialElement().toString().equals(""))
     {
       assertEquals(decoded.getSubInitialElement(), filter.getSubInitialElement());
     }
@@ -271,7 +268,12 @@
   @Test(dataProvider = "filterstrings")
   public void testEncodeDecode(String filterStr, LDAPFilter filter) throws Exception
   {
-    assertEquals(LDAPFilter.decode(filter.encode()).toString(), filter.toString());
+    ByteStringBuilder builder = new ByteStringBuilder();
+    ASN1Writer writer = ASN1.getWriter(builder);
+    filter.write(writer);
+
+    ASN1Reader reader = ASN1.getReader(builder.toByteString());
+    assertEquals(LDAPFilter.decode(reader).toString(), filter.toString());
   }
 
   @Test
@@ -295,6 +297,11 @@
           "(cn:2.4.6.8.10:=)" +
         ")");
 
-    assertEquals(LDAPFilter.decode(filter.encode()).toString(), filter.toString());
+    ByteStringBuilder builder = new ByteStringBuilder();
+    ASN1Writer writer = ASN1.getWriter(builder);
+    filter.write(writer);
+
+    ASN1Reader reader = ASN1.getReader(builder.toByteString());
+    assertEquals(LDAPFilter.decode(reader).toString(), filter.toString());
   }
 }
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/ldap/TestModifyDNRequestProtocolOp.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/ldap/TestModifyDNRequestProtocolOp.java
index a27438e..2bbc8b0 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/ldap/TestModifyDNRequestProtocolOp.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/ldap/TestModifyDNRequestProtocolOp.java
@@ -28,6 +28,8 @@
 
 import org.opends.server.protocols.asn1.*;
 import org.opends.server.types.LDAPException;
+import org.opends.server.types.ByteString;
+import org.opends.server.types.ByteStringBuilder;
 import static org.opends.server.util.ServerConstants.EOL;
 import org.opends.server.DirectoryServerTestCase;
 import org.testng.annotations.Test;
@@ -55,38 +57,38 @@
   /**
    * The DN for modify DN requests in this test case.
    */
-  private static final ASN1OctetString dn =
-      new ASN1OctetString("dc=example,dc=com");
+  private static final ByteString dn =
+      ByteString.valueOf("dc=example,dc=com");
 
   /**
    * The alt DN for modify DN requests in this test case.
    */
-  private static final ASN1OctetString altDn =
-      new ASN1OctetString("dc=alt,dc=example,dc=com");
+  private static final ByteString altDn =
+      ByteString.valueOf("dc=alt,dc=example,dc=com");
 
   /**
    * The new DN for modify DN requests in this test case.
    */
-  private static final ASN1OctetString newRdn =
-      new ASN1OctetString("dc=example-new");
+  private static final ByteString newRdn =
+      ByteString.valueOf("dc=example-new");
 
   /**
    * The alt new DN for modify DN requests in this test case.
    */
-  private static final ASN1OctetString altNewRdn =
-      new ASN1OctetString("ou=alt,dc=example-new");
+  private static final ByteString altNewRdn =
+      ByteString.valueOf("ou=alt,dc=example-new");
 
   /**
    * The new superiour DN for modify DN requests in this test case.
    */
-  private static final ASN1OctetString newSuperiorDn =
-      new ASN1OctetString("dc=widget,dc=com");
+  private static final ByteString newSuperiorDn =
+      ByteString.valueOf("dc=widget,dc=com");
 
   /**
    * The alt new superiour DN for modify DN requests in this test case.
    */
-  private static final ASN1OctetString altNewSuperiorDn =
-      new ASN1OctetString("dc=alt,dc=widget,dc=com");
+  private static final ByteString altNewSuperiorDn =
+      ByteString.valueOf("dc=alt,dc=widget,dc=com");
 
   /**
    * Test to make sure the class processes the right LDAP op type.
@@ -139,31 +141,6 @@
   }
 
   /**
-   * Test to make sure that setter methods work.
-   *
-   * @throws Exception If the test failed unexpectedly.
-   */
-  @Test
-  public void testSetMethods() throws Exception
-  {
-    ModifyDNRequestProtocolOp modifyRequest;
-    modifyRequest = new ModifyDNRequestProtocolOp(dn, newRdn, true,
-                                                  newSuperiorDn);
-
-    modifyRequest.setEntryDN(altDn);
-    assertEquals(modifyRequest.getEntryDN(), altDn);
-
-    modifyRequest.setNewRDN(altNewRdn);
-    assertEquals(modifyRequest.getNewRDN(), altNewRdn);
-
-    modifyRequest.setNewSuperior(altNewSuperiorDn);
-    assertEquals(modifyRequest.getNewSuperior(), altNewSuperiorDn);
-
-    modifyRequest.setDeleteOldRDN(false);
-    assertEquals(modifyRequest.deleteOldRDN(), false);
-  }
-
-  /**
    * Test the decode method when an null element is passed
    *
    * @throws Exception If the test failed unexpectedly.
@@ -171,7 +148,7 @@
   @Test(expectedExceptions = LDAPException.class)
   public void testDecodeNullElement() throws Exception
   {
-    ModifyDNRequestProtocolOp.decodeModifyDNRequest(null);
+    LDAPReader.readProtocolOp(null);
   }
 
   /**
@@ -182,9 +159,13 @@
   @Test(expectedExceptions = LDAPException.class)
   public void testDecodeEmptyElement() throws Exception
   {
-    ArrayList<ASN1Element> elements = new ArrayList<ASN1Element>();
-    ModifyDNRequestProtocolOp.decode(new ASN1Sequence(OP_TYPE_MODIFY_DN_REQUEST,
-                                                 elements));
+    ByteStringBuilder builder = new ByteStringBuilder();
+    ASN1Writer writer = ASN1.getWriter(builder);
+    writer.writeStartSequence(OP_TYPE_MODIFY_DN_REQUEST);
+    writer.writeEndSequence();
+
+    ASN1Reader reader = ASN1.getReader(builder.toByteString());
+    LDAPReader.readProtocolOp(reader);
   }
 
   /**
@@ -195,11 +176,15 @@
   @Test(expectedExceptions = LDAPException.class)
   public void testDecodeInvalidElementNum() throws Exception
   {
-    ArrayList<ASN1Element> elements = new ArrayList<ASN1Element>(2);
-    elements.add(new ASN1Null());
-    elements.add(new ASN1Null());
-    ModifyDNRequestProtocolOp.decode(new ASN1Sequence(OP_TYPE_MODIFY_DN_REQUEST,
-                                                 elements));
+    ByteStringBuilder builder = new ByteStringBuilder();
+    ASN1Writer writer = ASN1.getWriter(builder);
+    writer.writeStartSequence(OP_TYPE_MODIFY_DN_REQUEST);
+    writer.writeNull();
+    writer.writeNull();
+    writer.writeEndSequence();
+
+    ASN1Reader reader = ASN1.getReader(builder.toByteString());
+    LDAPReader.readProtocolOp(reader);
   }
 
   /**
@@ -210,12 +195,16 @@
   @Test(expectedExceptions = LDAPException.class)
   public void testDecodeInvalidElement() throws Exception
   {
-    ArrayList<ASN1Element> elements = new ArrayList<ASN1Element>(3);
-    elements.add(new ASN1Null());
-    elements.add(new ASN1Null());
-    elements.add(new ASN1Null());
-    ModifyDNRequestProtocolOp.decode(new ASN1Sequence(OP_TYPE_MODIFY_DN_REQUEST,
-                                                 elements));
+    ByteStringBuilder builder = new ByteStringBuilder();
+    ASN1Writer writer = ASN1.getWriter(builder);
+    writer.writeStartSequence(OP_TYPE_MODIFY_DN_REQUEST);
+    writer.writeNull();
+    writer.writeNull();
+    writer.writeNull();
+    writer.writeEndSequence();
+
+    ASN1Reader reader = ASN1.getReader(builder.toByteString());
+    LDAPReader.readProtocolOp(reader);
   }
 
   /**
@@ -226,12 +215,16 @@
   @Test(expectedExceptions = LDAPException.class)
   public void testDecodeWrongElementType() throws Exception
   {
-    ArrayList<ASN1Element> elements = new ArrayList<ASN1Element>(3);
-    elements.add(dn);
-    elements.add(newRdn);
-    elements.add(new ASN1Boolean(true));
-    ModifyDNRequestProtocolOp.decode(new ASN1Sequence(OP_TYPE_MODIFY_DN_RESPONSE,
-                                                 elements));
+    ByteStringBuilder builder = new ByteStringBuilder();
+    ASN1Writer writer = ASN1.getWriter(builder);
+    writer.writeStartSequence(OP_TYPE_MODIFY_DN_RESPONSE);
+    writer.writeOctetString(dn);
+    writer.writeOctetString(newRdn);
+    writer.writeBoolean(true);
+    writer.writeEndSequence();
+
+    ASN1Reader reader = ASN1.getReader(builder.toByteString());
+    LDAPReader.readProtocolOp(reader);
   }
 
   /**
@@ -242,14 +235,16 @@
   @Test(expectedExceptions = Exception.class)
   public void testNullEncodeDecode() throws Exception
   {
+    ByteStringBuilder builder = new ByteStringBuilder();
+    ASN1Writer writer = ASN1.getWriter(builder);
     ModifyDNRequestProtocolOp modifyEncoded;
     ModifyDNRequestProtocolOp modifyDecoded;
-    ASN1Element element;
 
     modifyEncoded = new ModifyDNRequestProtocolOp(null, null, true);
-    element = modifyEncoded.encode();
-    modifyDecoded = (ModifyDNRequestProtocolOp)ModifyDNRequestProtocolOp.decode(
-        element);
+    modifyEncoded.write(writer);
+
+    ASN1Reader reader = ASN1.getReader(builder.toByteString());
+    modifyDecoded = (ModifyDNRequestProtocolOp)LDAPReader.readProtocolOp(reader);
   }
 
   /**
@@ -260,25 +255,29 @@
   @Test
   public void testEncodeDecode() throws Exception
   {
+    ByteStringBuilder builder = new ByteStringBuilder();
+    ASN1Writer writer = ASN1.getWriter(builder);
     ModifyDNRequestProtocolOp modifyEncoded;
     ModifyDNRequestProtocolOp modifyDecoded;
-    ASN1Element element;
 
     modifyEncoded = new ModifyDNRequestProtocolOp(dn, newRdn, true,
                                                   newSuperiorDn);
-    element = modifyEncoded.encode();
-    modifyDecoded = (ModifyDNRequestProtocolOp)ModifyDNRequestProtocolOp.decode(
-        element);
+    modifyEncoded.write(writer);
+
+    ASN1Reader reader = ASN1.getReader(builder.toByteString());
+    modifyDecoded = (ModifyDNRequestProtocolOp)LDAPReader.readProtocolOp(reader);
 
     assertEquals(modifyEncoded.getEntryDN(), modifyDecoded.getEntryDN());
     assertEquals(modifyEncoded.getNewRDN(), modifyDecoded.getNewRDN());
     assertEquals(modifyEncoded.getNewSuperior(), modifyDecoded.getNewSuperior());
     assertEquals(modifyEncoded.deleteOldRDN(), modifyDecoded.deleteOldRDN());
 
+    builder.clear();
     modifyEncoded = new ModifyDNRequestProtocolOp(dn, newRdn, true);
-    element = modifyEncoded.encode();
-    modifyDecoded = (ModifyDNRequestProtocolOp)ModifyDNRequestProtocolOp.decode(
-        element);
+    modifyEncoded.write(writer);
+
+    reader = ASN1.getReader(builder.toByteString());
+    modifyDecoded = (ModifyDNRequestProtocolOp)LDAPReader.readProtocolOp(reader);
 
     assertEquals(modifyEncoded.getEntryDN(), modifyDecoded.getEntryDN());
     assertEquals(modifyEncoded.getNewRDN(), modifyDecoded.getNewRDN());
@@ -339,7 +338,7 @@
 
     key.append(indentBuf);
     key.append("  Entry DN:  ");
-    dn.toString(key);
+    key.append(dn);
     key.append(EOL);
 
     key.append(indentBuf);
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/ldap/TestModifyDNResponseProtocolOp.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/ldap/TestModifyDNResponseProtocolOp.java
index 16a9a00..5dbfb57 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/ldap/TestModifyDNResponseProtocolOp.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/ldap/TestModifyDNResponseProtocolOp.java
@@ -26,11 +26,7 @@
  */
 package org.opends.server.protocols.ldap;
 
-import org.opends.server.types.DN;
-import org.opends.server.types.AttributeType;
-import org.opends.server.types.AttributeValue;
-import org.opends.server.types.LDAPException;
-import org.opends.server.types.RDN;
+import org.opends.server.types.*;
 import org.opends.server.core.DirectoryServer;
 import org.opends.server.protocols.asn1.*;
 import static org.opends.server.util.ServerConstants.EOL;
@@ -84,7 +80,7 @@
     AttributeType attribute =
         DirectoryServer.getDefaultAttributeType("testAttribute");
 
-    AttributeValue attributeValue = new AttributeValue(attribute, "testValue");
+    AttributeValue attributeValue = AttributeValues.create(attribute, "testValue");
 
     RDN[] rdns = new RDN[1];
     rdns[0] = RDN.create(attribute, attributeValue);
@@ -154,34 +150,6 @@
   }
 
   /**
-   * Test to make sure that setter methods work.
-   *
-   * @throws Exception If the test failed unexpectedly.
-   */
-  @Test
-  public void testSetMethods() throws Exception
-  {
-    ModifyDNResponseProtocolOp modifyResponse;
-    modifyResponse = new ModifyDNResponseProtocolOp(resultCode);
-
-    modifyResponse.setResultCode(resultCode + 1);
-    assertEquals(modifyResponse.getResultCode(), resultCode + 1);
-
-    modifyResponse.setErrorMessage(resultMsg);
-    assertEquals(modifyResponse.getErrorMessage(), resultMsg);
-
-    modifyResponse.setMatchedDN(dn);
-    assertEquals(modifyResponse.getMatchedDN(), dn);
-
-    ArrayList<String> referralURLs = new ArrayList<String>();
-    referralURLs.add("ds1.example.com");
-    referralURLs.add("ds2.example.com");
-    referralURLs.add("ds3.example.com");
-    modifyResponse.setReferralURLs(referralURLs);
-    assertEquals(modifyResponse.getReferralURLs(), referralURLs);
-  }
-
-  /**
    * Test the decode method when an empty element is passed
    *
    * @throws Exception If the test failed unexpectedly.
@@ -189,9 +157,13 @@
   @Test(expectedExceptions = LDAPException.class)
   public void testDecodeEmptyElement() throws Exception
   {
-    ArrayList<ASN1Element> elements = new ArrayList<ASN1Element>();
-    ModifyDNResponseProtocolOp.decode(new ASN1Sequence(OP_TYPE_MODIFY_DN_RESPONSE,
-                                                      elements));
+    ByteStringBuilder builder = new ByteStringBuilder();
+    ASN1Writer writer = ASN1.getWriter(builder);
+    writer.writeStartSequence(OP_TYPE_MODIFY_DN_RESPONSE);
+    writer.writeEndSequence();
+
+    ASN1Reader reader = ASN1.getReader(builder.toByteString());
+    LDAPReader.readProtocolOp(reader);
   }
 
   /**
@@ -203,12 +175,16 @@
   @Test(expectedExceptions = LDAPException.class)
   public void testDecodeInvalidResultCode() throws Exception
   {
-    ArrayList<ASN1Element> elements = new ArrayList<ASN1Element>(2);
-    elements.add(new ASN1OctetString("Invalid Data"));
-    elements.add(new ASN1Null());
-    elements.add(new ASN1Null());
-    DeleteResponseProtocolOp.decode(new ASN1Sequence(OP_TYPE_MODIFY_DN_RESPONSE,
-                                                     elements));
+    ByteStringBuilder builder = new ByteStringBuilder();
+    ASN1Writer writer = ASN1.getWriter(builder);
+    writer.writeStartSequence(OP_TYPE_MODIFY_DN_RESPONSE);
+    writer.writeOctetString("Invalid Data");
+    writer.writeNull();
+    writer.writeNull();
+    writer.writeEndSequence();
+
+    ASN1Reader reader = ASN1.getReader(builder.toByteString());
+    LDAPReader.readProtocolOp(reader);
   }
 
   /**
@@ -221,12 +197,16 @@
   @Test
   public void testDecodeInvalidDN() throws Exception
   {
-    ArrayList<ASN1Element> elements = new ArrayList<ASN1Element>(2);
-    elements.add(new ASN1Enumerated(resultCode));
-    elements.add(new ASN1Null());
-    elements.add(new ASN1Null());
-    DeleteResponseProtocolOp.decode(new ASN1Sequence(OP_TYPE_MODIFY_DN_RESPONSE,
-                                                     elements));
+    ByteStringBuilder builder = new ByteStringBuilder();
+    ASN1Writer writer = ASN1.getWriter(builder);
+    writer.writeStartSequence(OP_TYPE_MODIFY_DN_RESPONSE);
+    writer.writeInteger(resultCode);
+    writer.writeNull();
+    writer.writeNull();
+    writer.writeEndSequence();
+
+    ASN1Reader reader = ASN1.getReader(builder.toByteString());
+    LDAPReader.readProtocolOp(reader);
   }
 
   /**
@@ -239,12 +219,16 @@
   @Test
   public void testDecodeInvalidResultMsg() throws Exception
   {
-    ArrayList<ASN1Element> elements = new ArrayList<ASN1Element>(2);
-    elements.add(new ASN1Enumerated(resultCode));
-    elements.add(new ASN1OctetString(dn.toString()));
-    elements.add(new ASN1Null());
-    DeleteResponseProtocolOp.decode(new ASN1Sequence(OP_TYPE_MODIFY_DN_RESPONSE,
-                                                     elements));
+    ByteStringBuilder builder = new ByteStringBuilder();
+    ASN1Writer writer = ASN1.getWriter(builder);
+    writer.writeStartSequence(OP_TYPE_MODIFY_DN_RESPONSE);
+    writer.writeInteger(resultCode);
+    writer.writeOctetString(dn.toString());
+    writer.writeNull();
+    writer.writeEndSequence();
+
+    ASN1Reader reader = ASN1.getReader(builder.toByteString());
+    LDAPReader.readProtocolOp(reader);
   }
 
   /**
@@ -257,13 +241,17 @@
   @Test
   public void testDecodeInvalidReferralURLs() throws Exception
   {
-    ArrayList<ASN1Element> elements = new ArrayList<ASN1Element>(2);
-    elements.add(new ASN1Enumerated(resultCode));
-    elements.add(new ASN1OctetString(dn.toString()));
-    elements.add(new ASN1OctetString(resultMsg));
-    elements.add(new ASN1Null());
-    DeleteResponseProtocolOp.decode(new ASN1Sequence(OP_TYPE_MODIFY_DN_RESPONSE,
-                                                     elements));
+    ByteStringBuilder builder = new ByteStringBuilder();
+    ASN1Writer writer = ASN1.getWriter(builder);
+    writer.writeStartSequence(OP_TYPE_MODIFY_DN_RESPONSE);
+    writer.writeInteger(resultCode);
+    writer.writeOctetString(dn.toString());
+    writer.writeOctetString(resultMsg.toString());
+    writer.writeNull();
+    writer.writeEndSequence();
+
+    ASN1Reader reader = ASN1.getReader(builder.toByteString());
+    LDAPReader.readProtocolOp(reader);
   }
 
   /**
@@ -274,9 +262,10 @@
   @Test
   public void testEncodeDecode() throws Exception
   {
+    ByteStringBuilder builder = new ByteStringBuilder();
+    ASN1Writer writer = ASN1.getWriter(builder);
     ModifyDNResponseProtocolOp deleteEncoded;
     ModifyDNResponseProtocolOp deleteDecoded;
-    ASN1Element element;
 
     ArrayList<String> referralURLs = new ArrayList<String>();
     referralURLs.add("ds1.example.com");
@@ -287,9 +276,9 @@
     //Test case for a full encode decode operation with normal params.
     deleteEncoded = new ModifyDNResponseProtocolOp(resultCode, resultMsg, dn,
                                                   referralURLs);
-    element = deleteEncoded.encode();
-    deleteDecoded = (ModifyDNResponseProtocolOp)ModifyDNResponseProtocolOp.decode(
-        element);
+    deleteEncoded.write(writer);
+    ASN1Reader reader = ASN1.getReader(builder.toByteString());
+    deleteDecoded = (ModifyDNResponseProtocolOp)LDAPReader.readProtocolOp(reader);
 
     assertEquals(deleteEncoded.getType(), OP_TYPE_MODIFY_DN_RESPONSE);
     assertEquals(deleteEncoded.getMatchedDN().compareTo(
@@ -305,25 +294,28 @@
     //Test case for a full encode decode operation with an empty DN params.
     deleteEncoded = new ModifyDNResponseProtocolOp(resultCode, resultMsg, DN.nullDN(),
                                                   referralURLs);
-    element = deleteEncoded.encode();
-    deleteDecoded = (ModifyDNResponseProtocolOp)ModifyDNResponseProtocolOp.decode(
-        element);
+    builder.clear();
+    deleteEncoded.write(writer);
+    reader = ASN1.getReader(builder.toByteString());
+    deleteDecoded = (ModifyDNResponseProtocolOp)LDAPReader.readProtocolOp(reader);
     assertEquals(deleteDecoded.getMatchedDN(), null);
 
     //Test case for a full empty referral url param.
     ArrayList<String> emptyReferralURLs = new ArrayList<String>();
     deleteEncoded = new ModifyDNResponseProtocolOp(resultCode, resultMsg, dn,
                                                   emptyReferralURLs);
-    element = deleteEncoded.encode();
-    deleteDecoded = (ModifyDNResponseProtocolOp)ModifyDNResponseProtocolOp.decode(
-        element);
+    builder.clear();
+    deleteEncoded.write(writer);
+    reader = ASN1.getReader(builder.toByteString());
+    deleteDecoded = (ModifyDNResponseProtocolOp)LDAPReader.readProtocolOp(reader);
     assertTrue(deleteDecoded.getReferralURLs() == null);
 
     //Test case for a full encode decode operation with resultCode param only.
     deleteEncoded = new ModifyDNResponseProtocolOp(resultCode);
-    element = deleteEncoded.encode();
-    deleteDecoded = (ModifyDNResponseProtocolOp)ModifyDNResponseProtocolOp.decode(
-        element);
+    builder.clear();
+    deleteEncoded.write(writer);
+    reader = ASN1.getReader(builder.toByteString());
+    deleteDecoded = (ModifyDNResponseProtocolOp)LDAPReader.readProtocolOp(reader);
 
     assertEquals(deleteDecoded.getMatchedDN(), null);
     assertEquals(deleteDecoded.getErrorMessage(), null);
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/ldap/TestModifyRequestProtocolOp.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/ldap/TestModifyRequestProtocolOp.java
index 3e95c1b..08c3ba4 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/ldap/TestModifyRequestProtocolOp.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/ldap/TestModifyRequestProtocolOp.java
@@ -26,13 +26,11 @@
  */
 package org.opends.server.protocols.ldap;
 
-import org.opends.server.protocols.asn1.ASN1OctetString;
-import org.opends.server.protocols.asn1.ASN1Element;
-import org.opends.server.protocols.asn1.ASN1Sequence;
 import static org.opends.server.util.ServerConstants.EOL;
-import org.opends.server.types.LDAPException;
-import org.opends.server.types.ModificationType;
-import org.opends.server.types.RawModification;
+import org.opends.server.types.*;
+import org.opends.server.protocols.asn1.ASN1Writer;
+import org.opends.server.protocols.asn1.ASN1;
+import org.opends.server.protocols.asn1.ASN1Reader;
 import org.testng.annotations.Test;
 import static org.testng.Assert.assertEquals;
 import static org.testng.Assert.assertNotNull;
@@ -63,14 +61,14 @@
   /**
    * The DN for modify requests in this test case.
    */
-  private static final ASN1OctetString dn =
-      new ASN1OctetString("dc=example,dc=com");
+  private static final ByteString dn =
+      ByteString.valueOf("dc=example,dc=com");
 
   /**
    * The alternative DN for add requests in this test case.
    */
-  private static final ASN1OctetString dnAlt =
-      new ASN1OctetString("dc=sun,dc=com");
+  private static final ByteString dnAlt =
+      ByteString.valueOf("dc=sun,dc=com");
 
   /**
    * Generate modifications for use in test cases. Attributes will have names
@@ -204,23 +202,6 @@
   }
 
   /**
-   * Test to make sure that setter methods work.
-   *
-   * @throws Exception If the test failed unexpectedly.
-   */
-  @Test
-  public void testSetMethods() throws Exception
-  {
-    ModifyRequestProtocolOp modifyRequest;
-
-    modifyRequest = new ModifyRequestProtocolOp(dn);
-    assertEquals(modifyRequest.getDN(), dn);
-    modifyRequest.setDN(dnAlt);
-    assertEquals(modifyRequest.getDN(), dnAlt);
-
-  }
-
-  /**
    * Test the decode method when an null element is passed
    *
    * @throws Exception If the test failed unexpectedly.
@@ -228,7 +209,7 @@
   @Test(expectedExceptions = LDAPException.class)
   public void testDecodeNullElement() throws Exception
   {
-    ModifyRequestProtocolOp.decodeModifyRequest(null);
+    LDAPReader.readProtocolOp(null);
   }
 
   /**
@@ -239,9 +220,13 @@
   @Test(expectedExceptions = LDAPException.class)
   public void testDecodeEmptyElement() throws Exception
   {
-    ArrayList<ASN1Element> elements = new ArrayList<ASN1Element>();
-    ModifyRequestProtocolOp.decode(new ASN1Sequence(OP_TYPE_MODIFY_REQUEST,
-                                                    elements));
+    ByteStringBuilder builder = new ByteStringBuilder();
+    ASN1Writer writer = ASN1.getWriter(builder);
+    writer.writeStartSequence(OP_TYPE_MODIFY_REQUEST);
+    writer.writeEndSequence();
+
+    ASN1Reader reader = ASN1.getReader(builder.toByteString());
+    LDAPReader.readProtocolOp(reader);
   }
 
   /**
@@ -252,13 +237,16 @@
   @Test(expectedExceptions = LDAPException.class)
   public void testDecodeInvalidElement() throws Exception
   {
-    ArrayList<ASN1Element> elements = new ArrayList<ASN1Element>(2);
-    ArrayList<ASN1Element> attrElements =
-         new ArrayList<ASN1Element>();
-    elements.add(new ASN1Sequence(attrElements));
-    elements.add(dn);
-    ModifyRequestProtocolOp.decode(new ASN1Sequence(OP_TYPE_MODIFY_REQUEST,
-                                                    elements));
+    ByteStringBuilder builder = new ByteStringBuilder();
+    ASN1Writer writer = ASN1.getWriter(builder);
+    writer.writeStartSequence(OP_TYPE_MODIFY_REQUEST);
+    writer.writeStartSequence();
+    writer.writeEndSequence();
+    writer.writeOctetString(dn);
+    writer.writeEndSequence();
+
+    ASN1Reader reader = ASN1.getReader(builder.toByteString());
+    LDAPReader.readProtocolOp(reader);
   }
 
   /**
@@ -269,13 +257,16 @@
   @Test(expectedExceptions = LDAPException.class)
   public void testDecodeWrongElementType() throws Exception
   {
-    ArrayList<ASN1Element> elements = new ArrayList<ASN1Element>(2);
-    ArrayList<ASN1Element> attrElements =
-         new ArrayList<ASN1Element>();
-    elements.add(dn);
-    elements.add(new ASN1Sequence(attrElements));
-    ModifyRequestProtocolOp.decode(new ASN1Sequence(OP_TYPE_MODIFY_RESPONSE,
-                                                    elements));
+    ByteStringBuilder builder = new ByteStringBuilder();
+    ASN1Writer writer = ASN1.getWriter(builder);
+    writer.writeStartSequence(OP_TYPE_MODIFY_RESPONSE);
+    writer.writeOctetString(dn);
+    writer.writeStartSequence();
+    writer.writeEndSequence();
+    writer.writeEndSequence();
+
+    ASN1Reader reader = ASN1.getReader(builder.toByteString());
+    LDAPReader.readProtocolOp(reader);
   }
 
   /**
@@ -286,14 +277,16 @@
   @Test(expectedExceptions = Exception.class)
   public void testNullEncodeDecode() throws Exception
   {
+    ByteStringBuilder builder = new ByteStringBuilder();
+    ASN1Writer writer = ASN1.getWriter(builder);
     ModifyRequestProtocolOp modifyEncoded;
     ModifyRequestProtocolOp modifyDecoded;
-    ASN1Element element;
 
     modifyEncoded = new ModifyRequestProtocolOp(null, null);
-    element = modifyEncoded.encode();
-    modifyDecoded = (ModifyRequestProtocolOp)ModifyRequestProtocolOp.decode(
-        element);
+    modifyEncoded.write(writer);
+
+    ASN1Reader reader = ASN1.getReader(builder.toByteString());
+    modifyDecoded = (ModifyRequestProtocolOp)LDAPReader.readProtocolOp(reader);
   }
 
   /**
@@ -304,18 +297,19 @@
   @Test
   public void testEncodeDecode() throws Exception
   {
+    ByteStringBuilder builder = new ByteStringBuilder();
+    ASN1Writer writer = ASN1.getWriter(builder);
     ModifyRequestProtocolOp modifyEncoded;
     ModifyRequestProtocolOp modifyDecoded;
-    ASN1Element element;
     ArrayList<RawModification> modifies;
 
 
     //Test case for a full encode decode operation with normal params.
     modifies = generateModifications(10,"test");
     modifyEncoded = new ModifyRequestProtocolOp(dn, modifies);
-    element = modifyEncoded.encode();
-    modifyDecoded = (ModifyRequestProtocolOp)ModifyRequestProtocolOp.decode(
-        element);
+    modifyEncoded.write(writer);
+    ASN1Reader reader = ASN1.getReader(builder.toByteString());
+    modifyDecoded = (ModifyRequestProtocolOp)LDAPReader.readProtocolOp(reader);
 
     assertEquals(modifyEncoded.getType(), OP_TYPE_MODIFY_REQUEST);
     assertEquals(modifyEncoded.getDN(), modifyDecoded.getDN());
@@ -325,9 +319,10 @@
     //Test case for a full encode decode operation with large modifications.
     modifies = generateModifications(100,"test");
     modifyEncoded = new ModifyRequestProtocolOp(dn, modifies);
-    element = modifyEncoded.encode();
-    modifyDecoded = (ModifyRequestProtocolOp)ModifyRequestProtocolOp.decode(
-        element);
+    builder.clear();
+    modifyEncoded.write(writer);
+    reader = ASN1.getReader(builder.toByteString());
+    modifyDecoded = (ModifyRequestProtocolOp)LDAPReader.readProtocolOp(reader);
 
     assertEquals(modifyEncoded.getDN(), modifyDecoded.getDN());
     assertTrue(modificationsEquals(modifyEncoded.getModifications(),
@@ -335,9 +330,10 @@
 
     //Test case for a full encode decode operation with no attributes.
     modifyEncoded = new ModifyRequestProtocolOp(dn, null);
-    element = modifyEncoded.encode();
-    modifyDecoded = (ModifyRequestProtocolOp)ModifyRequestProtocolOp.decode(
-        element);
+    builder.clear();
+    modifyEncoded.write(writer);
+    reader = ASN1.getReader(builder.toByteString());
+    modifyDecoded = (ModifyRequestProtocolOp)LDAPReader.readProtocolOp(reader);
 
     assertEquals(modifyEncoded.getDN(), modifyDecoded.getDN());
     assertTrue(modificationsEquals(modifyEncoded.getModifications(),
@@ -411,9 +407,9 @@
 
     key.append(indentBuf);
     key.append("  DN:  ");
-    dn.toString(key);
-    key.append(EOL);
+    key.append(dn);
 
+    key.append(EOL);
     key.append("  Modifications:");
     key.append(EOL);
 
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/ldap/TestModifyResponseProtocolOp.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/ldap/TestModifyResponseProtocolOp.java
index b98447a..18230e0 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/ldap/TestModifyResponseProtocolOp.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/ldap/TestModifyResponseProtocolOp.java
@@ -26,11 +26,7 @@
  */
 package org.opends.server.protocols.ldap;
 
-import org.opends.server.types.DN;
-import org.opends.server.types.AttributeType;
-import org.opends.server.types.AttributeValue;
-import org.opends.server.types.LDAPException;
-import org.opends.server.types.RDN;
+import org.opends.server.types.*;
 import org.opends.server.core.DirectoryServer;
 import org.opends.server.protocols.asn1.*;
 import static org.opends.server.util.ServerConstants.EOL;
@@ -84,7 +80,7 @@
     AttributeType attribute =
         DirectoryServer.getDefaultAttributeType("testAttribute");
 
-    AttributeValue attributeValue = new AttributeValue(attribute, "testValue");
+    AttributeValue attributeValue = AttributeValues.create(attribute, "testValue");
 
     RDN[] rdns = new RDN[1];
     rdns[0] = RDN.create(attribute, attributeValue);
@@ -154,34 +150,6 @@
   }
 
   /**
-   * Test to make sure that setter methods work.
-   *
-   * @throws Exception If the test failed unexpectedly.
-   */
-  @Test
-  public void testSetMethods() throws Exception
-  {
-    ModifyResponseProtocolOp modifyResponse;
-    modifyResponse = new ModifyResponseProtocolOp(resultCode);
-
-    modifyResponse.setResultCode(resultCode + 1);
-    assertEquals(modifyResponse.getResultCode(), resultCode + 1);
-
-    modifyResponse.setErrorMessage(resultMsg);
-    assertEquals(modifyResponse.getErrorMessage(), resultMsg);
-
-    modifyResponse.setMatchedDN(dn);
-    assertEquals(modifyResponse.getMatchedDN(), dn);
-
-    ArrayList<String> referralURLs = new ArrayList<String>();
-    referralURLs.add("ds1.example.com");
-    referralURLs.add("ds2.example.com");
-    referralURLs.add("ds3.example.com");
-    modifyResponse.setReferralURLs(referralURLs);
-    assertEquals(modifyResponse.getReferralURLs(), referralURLs);
-  }
-
-  /**
    * Test the decode method when an empty element is passed
    *
    * @throws Exception If the test failed unexpectedly.
@@ -189,9 +157,13 @@
   @Test(expectedExceptions = LDAPException.class)
   public void testDecodeEmptyElement() throws Exception
   {
-    ArrayList<ASN1Element> elements = new ArrayList<ASN1Element>();
-    ModifyResponseProtocolOp.decode(new ASN1Sequence(OP_TYPE_MODIFY_RESPONSE,
-                                                     elements));
+    ByteStringBuilder builder = new ByteStringBuilder();
+    ASN1Writer writer = ASN1.getWriter(builder);
+    writer.writeStartSequence(OP_TYPE_MODIFY_RESPONSE);
+    writer.writeEndSequence();
+
+    ASN1Reader reader = ASN1.getReader(builder.toByteString());
+    LDAPReader.readProtocolOp(reader);
   }
 
   /**
@@ -203,12 +175,16 @@
   @Test(expectedExceptions = LDAPException.class)
   public void testDecodeInvalidResultCode() throws Exception
   {
-    ArrayList<ASN1Element> elements = new ArrayList<ASN1Element>(2);
-    elements.add(new ASN1OctetString("Invalid Data"));
-    elements.add(new ASN1Null());
-    elements.add(new ASN1Null());
-    ModifyResponseProtocolOp.decode(new ASN1Sequence(OP_TYPE_MODIFY_RESPONSE,
-                                                    elements));
+    ByteStringBuilder builder = new ByteStringBuilder();
+    ASN1Writer writer = ASN1.getWriter(builder);
+    writer.writeStartSequence(OP_TYPE_MODIFY_RESPONSE);
+    writer.writeOctetString("Invalid Data");
+    writer.writeNull();
+    writer.writeNull();
+    writer.writeEndSequence();
+
+    ASN1Reader reader = ASN1.getReader(builder.toByteString());
+    LDAPReader.readProtocolOp(reader);
   }
 
   /**
@@ -221,12 +197,16 @@
   @Test
   public void testDecodeInvalidDN() throws Exception
   {
-    ArrayList<ASN1Element> elements = new ArrayList<ASN1Element>(2);
-    elements.add(new ASN1Enumerated(resultCode));
-    elements.add(new ASN1Null());
-    elements.add(new ASN1Null());
-    ModifyResponseProtocolOp.decode(new ASN1Sequence(OP_TYPE_MODIFY_RESPONSE,
-                                                    elements));
+    ByteStringBuilder builder = new ByteStringBuilder();
+    ASN1Writer writer = ASN1.getWriter(builder);
+    writer.writeStartSequence(OP_TYPE_MODIFY_RESPONSE);
+    writer.writeInteger(resultCode);
+    writer.writeNull();
+    writer.writeNull();
+    writer.writeEndSequence();
+
+    ASN1Reader reader = ASN1.getReader(builder.toByteString());
+    LDAPReader.readProtocolOp(reader);
   }
 
   /**
@@ -239,12 +219,16 @@
   @Test
   public void testDecodeInvalidResultMsg() throws Exception
   {
-    ArrayList<ASN1Element> elements = new ArrayList<ASN1Element>(2);
-    elements.add(new ASN1Enumerated(resultCode));
-    elements.add(new ASN1OctetString(dn.toString()));
-    elements.add(new ASN1Null());
-    ModifyResponseProtocolOp.decode(new ASN1Sequence(OP_TYPE_MODIFY_RESPONSE,
-                                                    elements));
+    ByteStringBuilder builder = new ByteStringBuilder();
+    ASN1Writer writer = ASN1.getWriter(builder);
+    writer.writeStartSequence(OP_TYPE_MODIFY_RESPONSE);
+    writer.writeInteger(resultCode);
+    writer.writeOctetString(dn.toString());
+    writer.writeNull();
+    writer.writeEndSequence();
+
+    ASN1Reader reader = ASN1.getReader(builder.toByteString());
+    LDAPReader.readProtocolOp(reader);
   }
 
   /**
@@ -257,13 +241,17 @@
   @Test
   public void testDecodeInvalidReferralURLs() throws Exception
   {
-    ArrayList<ASN1Element> elements = new ArrayList<ASN1Element>(2);
-    elements.add(new ASN1Enumerated(resultCode));
-    elements.add(new ASN1OctetString(dn.toString()));
-    elements.add(new ASN1OctetString(String.valueOf(resultMsg)));
-    elements.add(new ASN1Null());
-    ModifyResponseProtocolOp.decode(new ASN1Sequence(OP_TYPE_MODIFY_RESPONSE,
-                                                    elements));
+    ByteStringBuilder builder = new ByteStringBuilder();
+    ASN1Writer writer = ASN1.getWriter(builder);
+    writer.writeStartSequence(OP_TYPE_MODIFY_RESPONSE);
+    writer.writeInteger(resultCode);
+    writer.writeOctetString(dn.toString());
+    writer.writeOctetString(resultMsg.toString());
+    writer.writeNull();
+    writer.writeEndSequence();
+
+    ASN1Reader reader = ASN1.getReader(builder.toByteString());
+    LDAPReader.readProtocolOp(reader);
   }
 
   /**
@@ -274,9 +262,10 @@
   @Test
   public void testEncodeDecode() throws Exception
   {
+    ByteStringBuilder builder = new ByteStringBuilder();
+    ASN1Writer writer = ASN1.getWriter(builder);
     ModifyResponseProtocolOp modifyEncoded;
     ModifyResponseProtocolOp modifyDecoded;
-    ASN1Element element;
 
     ArrayList<String> referralURLs = new ArrayList<String>();
     referralURLs.add("ds1.example.com");
@@ -287,9 +276,9 @@
     //Test case for a full encode decode operation with normal params.
     modifyEncoded = new ModifyResponseProtocolOp(resultCode, resultMsg, dn,
                                                  referralURLs);
-    element = modifyEncoded.encode();
-    modifyDecoded = (ModifyResponseProtocolOp)ModifyResponseProtocolOp.decode(
-        element);
+    modifyEncoded.write(writer);
+    ASN1Reader reader = ASN1.getReader(builder.toByteString());
+    modifyDecoded = (ModifyResponseProtocolOp)LDAPReader.readProtocolOp(reader);
 
     assertEquals(modifyEncoded.getType(), OP_TYPE_MODIFY_RESPONSE);
     assertEquals(modifyEncoded.getMatchedDN().compareTo(
@@ -305,25 +294,28 @@
     //Test case for a full encode decode operation with an empty DN params.
     modifyEncoded = new ModifyResponseProtocolOp(resultCode, resultMsg, DN.nullDN(),
                                                  referralURLs);
-    element = modifyEncoded.encode();
-    modifyDecoded = (ModifyResponseProtocolOp)ModifyResponseProtocolOp.decode(
-        element);
+    builder.clear();
+    modifyEncoded.write(writer);
+    reader = ASN1.getReader(builder.toByteString());
+    modifyDecoded = (ModifyResponseProtocolOp)LDAPReader.readProtocolOp(reader);
     assertEquals(modifyDecoded.getMatchedDN(), null);
 
     //Test case for a full empty referral url param.
     ArrayList<String> emptyReferralURLs = new ArrayList<String>();
     modifyEncoded = new ModifyResponseProtocolOp(resultCode, resultMsg, dn,
                                                  emptyReferralURLs);
-    element = modifyEncoded.encode();
-    modifyDecoded = (ModifyResponseProtocolOp)ModifyResponseProtocolOp.decode(
-        element);
+    builder.clear();
+    modifyEncoded.write(writer);
+    reader = ASN1.getReader(builder.toByteString());
+    modifyDecoded = (ModifyResponseProtocolOp)LDAPReader.readProtocolOp(reader);
     assertTrue(modifyDecoded.getReferralURLs() == null);
 
     //Test case for a full encode decode operation with resultCode param only.
     modifyEncoded = new ModifyResponseProtocolOp(resultCode);
-    element = modifyEncoded.encode();
-    modifyDecoded = (ModifyResponseProtocolOp)ModifyResponseProtocolOp.decode(
-        element);
+    builder.clear();
+    modifyEncoded.write(writer);
+    reader = ASN1.getReader(builder.toByteString());
+    modifyDecoded = (ModifyResponseProtocolOp)LDAPReader.readProtocolOp(reader);
 
     assertEquals(modifyDecoded.getMatchedDN(), null);
     assertEquals(modifyDecoded.getErrorMessage(), null);
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/ldap/TestSearchProtocolOp.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/ldap/TestSearchProtocolOp.java
index c432d9b..ff78795 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/ldap/TestSearchProtocolOp.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/ldap/TestSearchProtocolOp.java
@@ -29,10 +29,9 @@
 package org.opends.server.protocols.ldap;
 
 import org.testng.annotations.Test;
-import org.opends.server.types.DereferencePolicy;
-import org.opends.server.types.LDAPException;
-import org.opends.server.types.SearchScope;
+import org.opends.server.types.*;
 import org.opends.server.protocols.asn1.*;
+import static org.opends.server.protocols.asn1.ASN1Constants.UNIVERSAL_OCTET_STRING_TYPE;
 import static org.opends.server.protocols.ldap.LDAPConstants.*;
 import static org.testng.Assert.*;
 
@@ -45,6 +44,25 @@
  */
 public class TestSearchProtocolOp extends LdapTestCase
 {
+    ByteString baseDN = ByteString.valueOf("dc=example,dc=COM");
+    SearchScope scope = SearchScope.WHOLE_SUBTREE;
+    DereferencePolicy dereferencePolicy = DereferencePolicy.DEREF_IN_SEARCHING;
+    int sizeLimit = Integer.MAX_VALUE;
+    int timeLimit = Integer.MAX_VALUE;
+    boolean typesOnly = true;
+    LDAPFilter filter;
+    String[] attrArray = new String[]
+         {
+              "description", "cn", "cn;optionA"
+         };
+    LinkedHashSet<String> attributes =
+         new LinkedHashSet<String>(Arrays.asList(attrArray));
+
+  public TestSearchProtocolOp() throws Exception
+  {
+    filter = LDAPFilter.decode("(objectClass=*)");
+  }
+
   /**
    * Create a test search request protocol op.
    * @return A test search request protocol op.
@@ -53,20 +71,6 @@
   private SearchRequestProtocolOp buildSearchRequestProtocolOp()
        throws LDAPException
   {
-    ASN1OctetString baseDN = new ASN1OctetString("dc=example,dc=COM");
-    SearchScope scope = SearchScope.WHOLE_SUBTREE;
-    DereferencePolicy dereferencePolicy = DereferencePolicy.DEREF_IN_SEARCHING;
-    int sizeLimit = Integer.MAX_VALUE;
-    int timeLimit = Integer.MAX_VALUE;
-    boolean typesOnly = true;
-    LDAPFilter filter = LDAPFilter.decode("(objectClass=*)");
-    String[] attrArray = new String[]
-         {
-              "description", "cn", "cn;optionA"
-         };
-    LinkedHashSet<String> attributes =
-         new LinkedHashSet<String>(Arrays.asList(attrArray));
-
     return new SearchRequestProtocolOp(baseDN,
                                        scope,
                                        dereferencePolicy,
@@ -89,14 +93,18 @@
   @Test ()
   public void testSearchRequestEncodeDecode() throws Exception
   {
+    ByteStringBuilder builder = new ByteStringBuilder();
+    ASN1Writer writer = ASN1.getWriter(builder);
+
     // Construct a protocol op.
     SearchRequestProtocolOp protocolOp = buildSearchRequestProtocolOp();
 
     // Encode to ASN1.
-    ASN1Element element = protocolOp.encode();
+    protocolOp.write(writer);
 
     // Decode to a new protocol op.
-    ProtocolOp decodedProtocolOp = ProtocolOp.decode(element);
+    ASN1Reader reader = ASN1.getReader(builder.toByteString());
+    ProtocolOp decodedProtocolOp = LDAPReader.readProtocolOp(reader);
 
     // Make sure the protocol op is the correct type.
     assertTrue(decodedProtocolOp instanceof SearchRequestProtocolOp);
@@ -121,106 +129,304 @@
   @Test (expectedExceptions = LDAPException.class)
   public void testInvalidSearchRequestSequence() throws Exception
   {
-    ProtocolOp.decode(new ASN1Integer(OP_TYPE_SEARCH_REQUEST, 0));
+    ByteStringBuilder builder = new ByteStringBuilder();
+    ASN1Writer writer = ASN1.getWriter(builder);
+    writer.writeInteger(OP_TYPE_SEARCH_REQUEST, 0);
+
+    ASN1Reader reader = ASN1.getReader(builder.toByteString());
+    LDAPReader.readProtocolOp(reader);
   }
 
   @Test (expectedExceptions = LDAPException.class)
   public void testInvalidSearchRequestTooManyElements() throws Exception
   {
-    ASN1Element element = buildSearchRequestProtocolOp().encode();
-    ArrayList<ASN1Element> elements = ((ASN1Sequence)element).elements();
-    elements.add(new ASN1Boolean(true));
-    ProtocolOp.decode(new ASN1Sequence(OP_TYPE_SEARCH_REQUEST, elements));
+    ByteStringBuilder builder = new ByteStringBuilder();
+    ASN1Writer writer = ASN1.getWriter(builder);
+    writer.writeStartSequence(OP_TYPE_SEARCH_REQUEST);
+    writer.writeOctetString(baseDN);
+    writer.writeInteger(scope.intValue());
+    writer.writeInteger(dereferencePolicy.intValue());
+    writer.writeInteger(sizeLimit);
+    writer.writeInteger(timeLimit);
+    writer.writeBoolean(typesOnly);
+    filter.write(writer);
+
+    writer.writeStartSequence();
+    for(String attribute : attributes)
+    {
+      writer.writeOctetString(attribute);
+    }
+    writer.writeEndSequence();
+
+    writer.writeBoolean(true);
+    writer.writeEndSequence();
+
+    ASN1Reader reader = ASN1.getReader(builder.toByteString());
+    LDAPReader.readProtocolOp(reader);
   }
 
   @Test (expectedExceptions = LDAPException.class)
   public void testInvalidSearchRequestTooFewElements() throws Exception
   {
-    ASN1Element element = buildSearchRequestProtocolOp().encode();
-    ArrayList<ASN1Element> elements = ((ASN1Sequence)element).elements();
-    elements.remove(0);
-    ProtocolOp.decode(new ASN1Sequence(OP_TYPE_SEARCH_REQUEST, elements));
+    ByteStringBuilder builder = new ByteStringBuilder();
+    ASN1Writer writer = ASN1.getWriter(builder);
+    writer.writeStartSequence(OP_TYPE_SEARCH_REQUEST);
+    writer.writeInteger(scope.intValue());
+    writer.writeInteger(dereferencePolicy.intValue());
+    writer.writeInteger(sizeLimit);
+    writer.writeInteger(timeLimit);
+    writer.writeBoolean(typesOnly);
+    filter.write(writer);
+
+    writer.writeStartSequence();
+    for(String attribute : attributes)
+    {
+      writer.writeOctetString(attribute);
+    }
+    writer.writeEndSequence();
+
+    writer.writeEndSequence();
+
+    ASN1Reader reader = ASN1.getReader(builder.toByteString());
+    LDAPReader.readProtocolOp(reader);
   }
 
   @Test (expectedExceptions = LDAPException.class)
   public void testInvalidSearchRequestScope() throws Exception
   {
-    ASN1Element element = buildSearchRequestProtocolOp().encode();
-    ArrayList<ASN1Element> elements = ((ASN1Sequence)element).elements();
-    elements.set(1, new ASN1Integer(9));
-    ProtocolOp.decode(new ASN1Sequence(OP_TYPE_SEARCH_REQUEST, elements));
+    ByteStringBuilder builder = new ByteStringBuilder();
+    ASN1Writer writer = ASN1.getWriter(builder);
+    writer.writeStartSequence(OP_TYPE_SEARCH_REQUEST);
+    writer.writeOctetString(baseDN);
+    writer.writeInteger(9);
+    writer.writeInteger(dereferencePolicy.intValue());
+    writer.writeInteger(sizeLimit);
+    writer.writeInteger(timeLimit);
+    writer.writeBoolean(typesOnly);
+    filter.write(writer);
+
+    writer.writeStartSequence();
+    for(String attribute : attributes)
+    {
+      writer.writeOctetString(attribute);
+    }
+    writer.writeEndSequence();
+
+    writer.writeEndSequence();
+
+    ASN1Reader reader = ASN1.getReader(builder.toByteString());
+    LDAPReader.readProtocolOp(reader);
   }
 
   @Test (expectedExceptions = LDAPException.class)
   public void testInvalidSearchRequestDerefPolicy() throws Exception
   {
-    ASN1Element element = buildSearchRequestProtocolOp().encode();
-    ArrayList<ASN1Element> elements = ((ASN1Sequence)element).elements();
-    elements.set(2, new ASN1Integer(9));
-    ProtocolOp.decode(new ASN1Sequence(OP_TYPE_SEARCH_REQUEST, elements));
+    ByteStringBuilder builder = new ByteStringBuilder();
+    ASN1Writer writer = ASN1.getWriter(builder);
+    writer.writeStartSequence(OP_TYPE_SEARCH_REQUEST);
+    writer.writeOctetString(baseDN);
+    writer.writeInteger(scope.intValue());
+    writer.writeInteger(9);
+    writer.writeInteger(sizeLimit);
+    writer.writeInteger(timeLimit);
+    writer.writeBoolean(typesOnly);
+    filter.write(writer);
+
+    writer.writeStartSequence();
+    for(String attribute : attributes)
+    {
+      writer.writeOctetString(attribute);
+    }
+    writer.writeEndSequence();
+
+    writer.writeEndSequence();
+
+    ASN1Reader reader = ASN1.getReader(builder.toByteString());
+    LDAPReader.readProtocolOp(reader);
   }
 
   @Test (expectedExceptions = LDAPException.class)
   public void testInvalidSearchRequestElement1() throws Exception
   {
-    ASN1Element element = buildSearchRequestProtocolOp().encode();
-    ArrayList<ASN1Element> elements = ((ASN1Sequence)element).elements();
-    elements.set(1, new ASN1OctetString());
-    ProtocolOp.decode(new ASN1Sequence(OP_TYPE_SEARCH_REQUEST, elements));
+    ByteStringBuilder builder = new ByteStringBuilder();
+    ASN1Writer writer = ASN1.getWriter(builder);
+    writer.writeStartSequence(OP_TYPE_SEARCH_REQUEST);
+    writer.writeOctetString(baseDN);
+    writer.writeNull(UNIVERSAL_OCTET_STRING_TYPE);
+    writer.writeInteger(dereferencePolicy.intValue());
+    writer.writeInteger(sizeLimit);
+    writer.writeInteger(timeLimit);
+    writer.writeBoolean(typesOnly);
+    filter.write(writer);
+
+    writer.writeStartSequence();
+    for(String attribute : attributes)
+    {
+      writer.writeOctetString(attribute);
+    }
+    writer.writeEndSequence();
+
+    writer.writeEndSequence();
+
+    ASN1Reader reader = ASN1.getReader(builder.toByteString());
+    LDAPReader.readProtocolOp(reader);
   }
 
   @Test (expectedExceptions = LDAPException.class)
   public void testInvalidSearchRequestElement2() throws Exception
   {
-    ASN1Element element = buildSearchRequestProtocolOp().encode();
-    ArrayList<ASN1Element> elements = ((ASN1Sequence)element).elements();
-    elements.set(2, new ASN1OctetString());
-    ProtocolOp.decode(new ASN1Sequence(OP_TYPE_SEARCH_REQUEST, elements));
+    ByteStringBuilder builder = new ByteStringBuilder();
+    ASN1Writer writer = ASN1.getWriter(builder);
+    writer.writeStartSequence(OP_TYPE_SEARCH_REQUEST);
+    writer.writeOctetString(baseDN);
+    writer.writeInteger(scope.intValue());
+    writer.writeNull(UNIVERSAL_OCTET_STRING_TYPE);
+    writer.writeInteger(sizeLimit);
+    writer.writeInteger(timeLimit);
+    writer.writeBoolean(typesOnly);
+    filter.write(writer);
+
+    writer.writeStartSequence();
+    for(String attribute : attributes)
+    {
+      writer.writeOctetString(attribute);
+    }
+    writer.writeEndSequence();
+
+    writer.writeEndSequence();
+
+    ASN1Reader reader = ASN1.getReader(builder.toByteString());
+    LDAPReader.readProtocolOp(reader);
   }
 
   @Test (expectedExceptions = LDAPException.class)
   public void testInvalidSearchRequestElement3() throws Exception
   {
-    ASN1Element element = buildSearchRequestProtocolOp().encode();
-    ArrayList<ASN1Element> elements = ((ASN1Sequence)element).elements();
-    elements.set(3, new ASN1OctetString());
-    ProtocolOp.decode(new ASN1Sequence(OP_TYPE_SEARCH_REQUEST, elements));
+    ByteStringBuilder builder = new ByteStringBuilder();
+    ASN1Writer writer = ASN1.getWriter(builder);
+    writer.writeStartSequence(OP_TYPE_SEARCH_REQUEST);
+    writer.writeOctetString(baseDN);
+    writer.writeInteger(scope.intValue());
+    writer.writeInteger(dereferencePolicy.intValue());
+    writer.writeNull(UNIVERSAL_OCTET_STRING_TYPE);
+    writer.writeInteger(timeLimit);
+    writer.writeBoolean(typesOnly);
+    filter.write(writer);
+
+    writer.writeStartSequence();
+    for(String attribute : attributes)
+    {
+      writer.writeOctetString(attribute);
+    }
+    writer.writeEndSequence();
+
+    writer.writeEndSequence();
+
+    ASN1Reader reader = ASN1.getReader(builder.toByteString());
+    LDAPReader.readProtocolOp(reader);
   }
 
   @Test (expectedExceptions = LDAPException.class)
   public void testInvalidSearchRequestElement4() throws Exception
   {
-    ASN1Element element = buildSearchRequestProtocolOp().encode();
-    ArrayList<ASN1Element> elements = ((ASN1Sequence)element).elements();
-    elements.set(4, new ASN1OctetString());
-    ProtocolOp.decode(new ASN1Sequence(OP_TYPE_SEARCH_REQUEST, elements));
+    ByteStringBuilder builder = new ByteStringBuilder();
+    ASN1Writer writer = ASN1.getWriter(builder);
+    writer.writeStartSequence(OP_TYPE_SEARCH_REQUEST);
+    writer.writeOctetString(baseDN);
+    writer.writeInteger(scope.intValue());
+    writer.writeInteger(dereferencePolicy.intValue());
+    writer.writeInteger(sizeLimit);
+    writer.writeNull(UNIVERSAL_OCTET_STRING_TYPE);
+    writer.writeBoolean(typesOnly);
+    filter.write(writer);
+
+    writer.writeStartSequence();
+    for(String attribute : attributes)
+    {
+      writer.writeOctetString(attribute);
+    }
+    writer.writeEndSequence();
+
+    writer.writeEndSequence();
+
+    ASN1Reader reader = ASN1.getReader(builder.toByteString());
+    LDAPReader.readProtocolOp(reader);
   }
 
   @Test (expectedExceptions = LDAPException.class)
   public void testInvalidSearchRequestElement5() throws Exception
   {
-    ASN1Element element = buildSearchRequestProtocolOp().encode();
-    ArrayList<ASN1Element> elements = ((ASN1Sequence)element).elements();
-    elements.set(5, new ASN1OctetString());
-    ProtocolOp.decode(new ASN1Sequence(OP_TYPE_SEARCH_REQUEST, elements));
+    ByteStringBuilder builder = new ByteStringBuilder();
+    ASN1Writer writer = ASN1.getWriter(builder);
+    writer.writeStartSequence(OP_TYPE_SEARCH_REQUEST);
+    writer.writeOctetString(baseDN);
+    writer.writeInteger(scope.intValue());
+    writer.writeInteger(dereferencePolicy.intValue());
+    writer.writeInteger(sizeLimit);
+    writer.writeInteger(timeLimit);
+    writer.writeNull(UNIVERSAL_OCTET_STRING_TYPE);
+    filter.write(writer);
+
+    writer.writeStartSequence();
+    for(String attribute : attributes)
+    {
+      writer.writeOctetString(attribute);
+    }
+    writer.writeEndSequence();
+
+    writer.writeEndSequence();
+
+    ASN1Reader reader = ASN1.getReader(builder.toByteString());
+    LDAPReader.readProtocolOp(reader);
   }
 
   @Test (expectedExceptions = LDAPException.class)
   public void testInvalidSearchRequestElement6() throws Exception
   {
-    ASN1Element element = buildSearchRequestProtocolOp().encode();
-    ArrayList<ASN1Element> elements = ((ASN1Sequence)element).elements();
-    elements.set(6, new ASN1OctetString());
-    ProtocolOp.decode(new ASN1Sequence(OP_TYPE_SEARCH_REQUEST, elements));
+    ByteStringBuilder builder = new ByteStringBuilder();
+    ASN1Writer writer = ASN1.getWriter(builder);
+    writer.writeStartSequence(OP_TYPE_SEARCH_REQUEST);
+    writer.writeOctetString(baseDN);
+    writer.writeInteger(scope.intValue());
+    writer.writeInteger(dereferencePolicy.intValue());
+    writer.writeInteger(sizeLimit);
+    writer.writeInteger(timeLimit);
+    writer.writeBoolean(typesOnly);
+    writer.writeNull(UNIVERSAL_OCTET_STRING_TYPE);
+
+    writer.writeStartSequence();
+    for(String attribute : attributes)
+    {
+      writer.writeOctetString(attribute);
+    }
+    writer.writeEndSequence();
+
+    writer.writeEndSequence();
+
+    ASN1Reader reader = ASN1.getReader(builder.toByteString());
+    LDAPReader.readProtocolOp(reader);
   }
 
   @Test (expectedExceptions = LDAPException.class)
   public void testInvalidSearchRequestElement7() throws Exception
   {
-    ASN1Element element = buildSearchRequestProtocolOp().encode();
-    ArrayList<ASN1Element> elements = ((ASN1Sequence)element).elements();
-    elements.set(7, new ASN1OctetString("cn"));
-    ProtocolOp.decode(new ASN1Sequence(OP_TYPE_SEARCH_REQUEST, elements));
+    ByteStringBuilder builder = new ByteStringBuilder();
+    ASN1Writer writer = ASN1.getWriter(builder);
+    writer.writeStartSequence(OP_TYPE_SEARCH_REQUEST);
+    writer.writeOctetString(baseDN);
+    writer.writeInteger(scope.intValue());
+    writer.writeInteger(dereferencePolicy.intValue());
+    writer.writeInteger(sizeLimit);
+    writer.writeInteger(timeLimit);
+    writer.writeBoolean(typesOnly);
+    filter.write(writer);
+
+    writer.writeInteger(0);
+
+    writer.writeEndSequence();
+
+    ASN1Reader reader = ASN1.getReader(builder.toByteString());
+    LDAPReader.readProtocolOp(reader);
   }
 
 }
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/ldap/TestSearchResultEntryProtocolOp.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/ldap/TestSearchResultEntryProtocolOp.java
index a92d2bb..1f3470b 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/ldap/TestSearchResultEntryProtocolOp.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/ldap/TestSearchResultEntryProtocolOp.java
@@ -28,9 +28,7 @@
 
 package org.opends.server.protocols.ldap;
 
-import org.opends.server.types.Entry;
-import org.opends.server.types.LDAPException;
-import org.opends.server.types.SearchResultEntry;
+import org.opends.server.types.*;
 import org.opends.server.TestCaseUtils;
 import org.opends.server.protocols.asn1.*;
 import static org.opends.server.protocols.ldap.LDAPConstants.
@@ -196,15 +194,19 @@
   @Test(dataProvider = "entries")
   public void testEncodeDecode(Entry entry) throws Exception
   {
+    ByteStringBuilder builder = new ByteStringBuilder();
+    ASN1Writer writer = ASN1.getWriter(builder);
+
     SearchResultEntryProtocolOp protocolOp =
          new SearchResultEntryProtocolOp(new SearchResultEntry(entry));
 
     // Encode to ASN1.
-    ASN1Element element = protocolOp.encode();
+    protocolOp.write(writer);
 
     // Decode to a new protocol op.
+    ASN1Reader reader = ASN1.getReader(builder.toByteString());
     SearchResultEntryProtocolOp decodedProtocolOp =
-         (SearchResultEntryProtocolOp)ProtocolOp.decode(element);
+        (SearchResultEntryProtocolOp)LDAPReader.readProtocolOp(reader);
 
     assertEquals(decodedProtocolOp.getDN(), protocolOp.getDN());
     assertTrue(testEqual(decodedProtocolOp.getAttributes(),
@@ -214,40 +216,66 @@
   @Test (expectedExceptions = LDAPException.class)
   public void testInvalidSequence() throws Exception
   {
-    ProtocolOp.decode(new ASN1Integer(OP_TYPE_SEARCH_RESULT_ENTRY, 0));
+    ByteStringBuilder builder = new ByteStringBuilder();
+    ASN1Writer writer = ASN1.getWriter(builder);
+    writer.writeInteger(OP_TYPE_SEARCH_RESULT_ENTRY, 0);
+
+    ASN1Reader reader = ASN1.getReader(builder.toByteString());
+    LDAPReader.readProtocolOp(reader);
   }
 
   @Test (dataProvider = "entries", expectedExceptions = LDAPException.class)
   public void testTooManyElements(Entry entry) throws Exception
   {
-    SearchResultEntryProtocolOp protocolOp =
-         new SearchResultEntryProtocolOp(new SearchResultEntry(entry));
-    ASN1Element element = protocolOp.encode();
-    ArrayList<ASN1Element> elements = ((ASN1Sequence)element).elements();
-    elements.add(new ASN1Boolean(true));
-    ProtocolOp.decode(new ASN1Sequence(OP_TYPE_SEARCH_RESULT_ENTRY, elements));
+    ByteStringBuilder builder = new ByteStringBuilder();
+    ASN1Writer writer = ASN1.getWriter(builder);
+    writer.writeStartSequence(OP_TYPE_SEARCH_RESULT_ENTRY);
+    writer.writeBoolean(true);
+    writer.writeOctetString(entry.getDN().toString());
+
+    writer.writeStartSequence();
+    for(Attribute attr : entry.getAttributes())
+    {
+      new LDAPAttribute(attr).write(writer);
+    }
+    writer.writeEndSequence();
+    writer.writeEndSequence();
+
+    ASN1Reader reader = ASN1.getReader(builder.toByteString());
+    LDAPReader.readProtocolOp(reader);
   }
 
   @Test (dataProvider = "entries", expectedExceptions = LDAPException.class)
   public void testTooFewElements(Entry entry) throws Exception
   {
-    SearchResultEntryProtocolOp protocolOp =
-         new SearchResultEntryProtocolOp(new SearchResultEntry(entry));
-    ASN1Element element = protocolOp.encode();
-    ArrayList<ASN1Element> elements = ((ASN1Sequence)element).elements();
-    elements.remove(0);
-    ProtocolOp.decode(new ASN1Sequence(OP_TYPE_SEARCH_RESULT_ENTRY, elements));
+    ByteStringBuilder builder = new ByteStringBuilder();
+    ASN1Writer writer = ASN1.getWriter(builder);
+    writer.writeStartSequence(OP_TYPE_SEARCH_RESULT_ENTRY);
+
+    writer.writeStartSequence();
+    for(Attribute attr : entry.getAttributes())
+    {
+      new LDAPAttribute(attr).write(writer);
+    }
+    writer.writeEndSequence();
+    writer.writeEndSequence();
+
+    ASN1Reader reader = ASN1.getReader(builder.toByteString());
+    LDAPReader.readProtocolOp(reader);
   }
 
   @Test (dataProvider = "entries", expectedExceptions = LDAPException.class)
   public void testInvalidElement1(Entry entry) throws Exception
   {
-    SearchResultEntryProtocolOp protocolOp =
-         new SearchResultEntryProtocolOp(new SearchResultEntry(entry));
-    ASN1Element element = protocolOp.encode();
-    ArrayList<ASN1Element> elements = ((ASN1Sequence)element).elements();
-    elements.set(1, new ASN1OctetString("cn"));
-    ProtocolOp.decode(new ASN1Sequence(OP_TYPE_SEARCH_RESULT_ENTRY, elements));
+    ByteStringBuilder builder = new ByteStringBuilder();
+    ASN1Writer writer = ASN1.getWriter(builder);
+    writer.writeStartSequence(OP_TYPE_SEARCH_RESULT_ENTRY);
+    writer.writeOctetString(entry.getDN().toString());
+    writer.writeOctetString("cn");
+    writer.writeEndSequence();
+
+    ASN1Reader reader = ASN1.getReader(builder.toByteString());
+    LDAPReader.readProtocolOp(reader);
   }
 
 }
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/ldap/TestUnbindRequestProtocolOp.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/ldap/TestUnbindRequestProtocolOp.java
index 1ed36a3..c33a78e 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/ldap/TestUnbindRequestProtocolOp.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/ldap/TestUnbindRequestProtocolOp.java
@@ -26,8 +26,10 @@
  */
 package org.opends.server.protocols.ldap;
 
-import org.opends.server.protocols.asn1.ASN1Element;
-import org.opends.server.protocols.ldap.UnbindRequestProtocolOp;
+import org.opends.server.protocols.asn1.ASN1Writer;
+import org.opends.server.protocols.asn1.ASN1;
+import org.opends.server.protocols.asn1.ASN1Reader;
+import org.opends.server.types.ByteStringBuilder;
 import org.testng.annotations.Test;
 import static org.testng.Assert.*;
 
@@ -36,9 +38,12 @@
 
   @Test()
   public void testUnbindEncodeDecodeRequest() throws Exception {
+      ByteStringBuilder builder = new ByteStringBuilder();
+      ASN1Writer writer = ASN1.getWriter(builder);
       UnbindRequestProtocolOp req = new UnbindRequestProtocolOp();
-      ASN1Element reqElem=req.encode();
-      ProtocolOp reqOp= ProtocolOp.decode(reqElem);
+      req.write(writer);
+      ASN1Reader reader = ASN1.getReader(builder.toByteString());
+      ProtocolOp reqOp = LDAPReader.readProtocolOp(reader);
       assertTrue(reqOp.getProtocolOpName() == req.getProtocolOpName());
       assertTrue(reqOp.getType() == req.getType());
   }
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/replication/GenerationIdTest.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/replication/GenerationIdTest.java
index 2bdca58..305edb8 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/replication/GenerationIdTest.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/replication/GenerationIdTest.java
@@ -191,6 +191,7 @@
    * @throws Exception
    *           If the environment could not be set up.
    */
+  @Override
   @BeforeClass
   public void setUp() throws Exception
   {
@@ -529,7 +530,8 @@
           Attribute attr = attrs.get(0);
           if (attr.size() == 1)
           {
-            genId = Long.decode(attr.iterator().next().getStringValue());
+            genId =
+                Long.decode(attr.iterator().next().getValue().toString());
           }
         }
 
@@ -1397,7 +1399,7 @@
             server2ID, 100, getChangelogPort(changelog1ID),
             1000, !emptyOldChanges, generationId);
         debugInfo(testCase + " Expect genId to be set in memory on the replication " +
-        " server side even if not wrote on disk/db since no change occurred.");
+          " server side even if not wrote on disk/db since no change occurred.");
         rgenId = replServer1.getGenerationId(baseDn.toNormalizedString());
         assertEquals(rgenId, generationId);
         broker.stop();
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/replication/ProtocolWindowTest.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/replication/ProtocolWindowTest.java
index 48bf021..440f0bf 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/replication/ProtocolWindowTest.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/replication/ProtocolWindowTest.java
@@ -47,7 +47,6 @@
 import org.opends.server.core.DeleteOperationBasis;
 import org.opends.server.core.DirectoryServer;
 import org.opends.server.core.ModifyOperation;
-import org.opends.server.protocols.asn1.ASN1OctetString;
 import org.opends.server.protocols.internal.InternalClientConnection;
 import org.opends.server.protocols.internal.InternalSearchOperation;
 import org.opends.server.protocols.ldap.LDAPFilter;
@@ -55,19 +54,10 @@
 import org.opends.server.replication.protocol.ReplicationMsg;
 import org.opends.server.replication.server.ReplServerFakeConfiguration;
 import org.opends.server.replication.server.ReplicationServer;
-import org.opends.server.types.DN;
-import org.opends.server.types.Entry;
-import org.opends.server.types.SearchResultEntry;
-import org.opends.server.types.LDAPException;
-import org.opends.server.types.Modification;
-import org.opends.server.types.Operation;
-import org.opends.server.types.OperationType;
-import org.opends.server.types.ResultCode;
-import org.opends.server.types.SearchScope;
 import org.testng.annotations.AfterClass;
 import org.testng.annotations.BeforeClass;
 import org.testng.annotations.Test;
-import org.opends.server.types.Attribute;
+import org.opends.server.types.*;
 
 import static org.opends.server.TestCaseUtils.*;
 import static org.testng.Assert.assertNotNull;
@@ -232,7 +222,7 @@
           throws LDAPException
   {
     InternalSearchOperation op = connection.processSearch(
-        new ASN1OctetString("cn=monitor"),
+        ByteString.valueOf("cn=monitor"),
         SearchScope.WHOLE_SUBTREE, LDAPFilter.decode(
             "(max-waiting-changes=" +  changelog_queue_size + ")"));
     assertEquals(op.getResultCode(), ResultCode.SUCCESS);
@@ -247,7 +237,7 @@
   private boolean checkWindows(int windowSize) throws LDAPException
   {
     InternalSearchOperation op = connection.processSearch(
-        new ASN1OctetString("cn=monitor"),
+        ByteString.valueOf("cn=monitor"),
         SearchScope.WHOLE_SUBTREE,
         LDAPFilter.decode("(max-rcv-window=" + windowSize + ")"));
     assertEquals(op.getResultCode(), ResultCode.SUCCESS);
@@ -263,7 +253,7 @@
   private void searchUpdateSent() throws Exception
   {
     InternalSearchOperation op = connection.processSearch(
-        new ASN1OctetString("cn=monitor"),
+        ByteString.valueOf("cn=monitor"),
         SearchScope.WHOLE_SUBTREE,
         LDAPFilter.decode("(sent-updates=" + WINDOW_SIZE + ")"));
 
@@ -272,7 +262,7 @@
         "Entries#=" + op.getEntriesSent());
 
     op = connection.processSearch(
-        new ASN1OctetString("cn=monitor"),
+        ByteString.valueOf("cn=monitor"),
         SearchScope.WHOLE_SUBTREE,
         LDAPFilter.decode("(missing-changes=" +
             (REPLICATION_QUEUE_SIZE + WINDOW_SIZE) + ")"));
@@ -288,7 +278,7 @@
         Attribute attr = attit.next();
         logError(Message.raw(Category.SYNC, Severity.INFORMATION,
         e.getDN() + "= " + attr.getName() + " " + attr.iterator()
-        .next().getStringValue()));
+        .next().getValue().toString()));
       }
     }
     assertEquals(op.getEntriesSent(), 1, "Entries#=" + op.getEntriesSent());
@@ -301,6 +291,7 @@
    * @throws Exception
    *           If the environment could not be set up.
    */
+  @Override
   @BeforeClass
   public void setUp() throws Exception
   {
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/replication/ReplicationTestCase.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/replication/ReplicationTestCase.java
index 53ef7fc..e5d2c99 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/replication/ReplicationTestCase.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/replication/ReplicationTestCase.java
@@ -67,25 +67,11 @@
 import org.opends.server.replication.protocol.ReplicationMsg;
 import org.opends.server.schema.DirectoryStringSyntax;
 import org.opends.server.schema.IntegerSyntax;
-import org.opends.server.types.Attribute;
-import org.opends.server.types.AttributeType;
-import org.opends.server.types.AttributeValue;
-import org.opends.server.types.Attributes;
-import org.opends.server.types.ByteStringFactory;
-import org.opends.server.types.DN;
-import org.opends.server.types.Entry;
-import org.opends.server.types.LockManager;
-import org.opends.server.types.Modification;
-import org.opends.server.types.ModificationType;
-import org.opends.server.types.ResultCode;
-import org.opends.server.types.SearchFilter;
-import org.opends.server.types.SearchResultEntry;
-import org.opends.server.types.SearchScope;
+import org.opends.server.types.*;
 import org.testng.annotations.AfterClass;
 import org.testng.annotations.BeforeClass;
 import org.testng.annotations.Test;
 import org.opends.server.TestCaseUtils;
-import org.opends.server.protocols.asn1.ASN1OctetString;
 import org.opends.server.replication.plugin.MultimasterReplication;
 
 /**
@@ -591,7 +577,7 @@
     {
       // Search for matching entries in config backend
       InternalSearchOperation op = connection.processSearch(
-        new ASN1OctetString("cn=config"),
+        ByteString.valueOf("cn=config"),
         SearchScope.WHOLE_SUBTREE,
         LDAPFilter.decode(filter));
 
@@ -658,7 +644,7 @@
       if (count++>0)
         Thread.sleep(100);
       op = connection.processSearch(
-                                    ByteStringFactory.create("cn=monitor"),
+          ByteString.valueOf("cn=monitor"),
                                     SearchScope.SINGLE_LEVEL,
                                     LDAPFilter.decode(monitorFilter));
     }
@@ -716,7 +702,7 @@
 
             AttributeType attrType =
               DirectoryServer.getAttributeType(attrTypeStr, true);
-            found = tmpAttr.contains(new AttributeValue(attrType, valueString));
+            found = tmpAttr.contains(AttributeValues.create(attrType, valueString));
           }
         }
 
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/replication/UpdateOperationTest.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/replication/UpdateOperationTest.java
index 0e3fb88..0f367a2 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/replication/UpdateOperationTest.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/replication/UpdateOperationTest.java
@@ -52,7 +52,6 @@
 import org.opends.server.core.ModifyOperationBasis;
 import org.opends.server.extensions.DummyAlertHandler;
 import org.opends.server.plugins.ShortCircuitPlugin;
-import org.opends.server.protocols.asn1.ASN1OctetString;
 import org.opends.server.protocols.internal.InternalClientConnection;
 import org.opends.server.protocols.ldap.LDAPAttribute;
 import org.opends.server.protocols.ldap.LDAPModification;
@@ -68,20 +67,7 @@
 import org.opends.server.replication.protocol.OperationContext;
 import org.opends.server.replication.protocol.ReplicationMsg;
 import org.opends.server.schema.DirectoryStringSyntax;
-import org.opends.server.types.Attribute;
-import org.opends.server.types.AttributeType;
-import org.opends.server.types.AttributeValue;
-import org.opends.server.types.Attributes;
-import org.opends.server.types.DN;
-import org.opends.server.types.Entry;
-import org.opends.server.types.LockManager;
-import org.opends.server.types.Modification;
-import org.opends.server.types.ModificationType;
-import org.opends.server.types.Operation;
-import org.opends.server.types.OperationType;
-import org.opends.server.types.RDN;
-import org.opends.server.types.RawModification;
-import org.opends.server.types.ResultCode;
+import org.opends.server.types.*;
 import org.testng.annotations.BeforeClass;
 import org.testng.annotations.DataProvider;
 import org.testng.annotations.Test;
@@ -521,7 +507,7 @@
     Entry entry = DirectoryServer.getEntry(dn1);
     List<Attribute> attrs = entry.getAttribute(entryuuidType);
     String entryuuid =
-         attrs.get(0).iterator().next().getStringValue();
+         attrs.get(0).iterator().next().getValue().toString();
 
     // A change on a first server.
     ChangeNumber t1 = new ChangeNumber(1, (short) 0, (short) 3);
@@ -556,7 +542,7 @@
     entry = DirectoryServer.getEntry(dn1);
     attrs = entry.getAttribute(attrType);
     String attrValue1 =
-         attrs.get(0).iterator().next().getStringValue();
+         attrs.get(0).iterator().next().getValue().toString();
 
     // the value should be the last (time t2) value added
     assertEquals(attrValue1, "B");
@@ -1557,7 +1543,7 @@
 
           for (AttributeValue val : tmpAttr)
           {
-            found = val.getStringValue();
+            found = val.getValue().toString();
             break;
           }
         }
@@ -1698,14 +1684,14 @@
    */
   private static void setReceiveStatus(String syncConfigDN, boolean enable)
   {
-    ArrayList<ASN1OctetString> valueList = new ArrayList<ASN1OctetString>(1);
+    ArrayList<ByteString> valueList = new ArrayList<ByteString>(1);
     if (enable)
     {
-      valueList.add(new ASN1OctetString("TRUE"));
+      valueList.add(ByteString.valueOf("TRUE"));
     }
     else
     {
-      valueList.add(new ASN1OctetString("FALSE"));
+      valueList.add(ByteString.valueOf("FALSE"));
     }
     LDAPAttribute a = new LDAPAttribute("ds-cfg-receive-status", valueList);
 
@@ -1716,8 +1702,8 @@
 
     InternalClientConnection conn =
          InternalClientConnection.getRootConnection();
-    ASN1OctetString rawEntryDN =
-         new ASN1OctetString(syncConfigDN);
+    ByteString rawEntryDN =
+         ByteString.valueOf(syncConfigDN);
     ModifyOperation internalModify = conn.processModify(rawEntryDN, modList);
 
     ResultCode resultCode = internalModify.getResultCode();
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/replication/plugin/AssuredReplicationPluginTest.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/replication/plugin/AssuredReplicationPluginTest.java
index 7cd3394..0a05838 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/replication/plugin/AssuredReplicationPluginTest.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/replication/plugin/AssuredReplicationPluginTest.java
@@ -71,8 +71,8 @@
 import org.opends.server.replication.protocol.AddMsg;
 import org.opends.server.types.Attribute;
 import org.opends.server.types.AttributeValue;
-import org.opends.server.types.ByteStringFactory;
 import org.testng.annotations.BeforeClass;
+import org.opends.server.types.ByteString;
 import org.opends.server.types.DN;
 import org.opends.server.types.Entry;
 import org.opends.server.types.LockManager;
@@ -105,16 +105,16 @@
    * The port of the replicationServer.
    */
   private int replServerPort;
-  private byte RS_SERVER_ID = (byte) 90;
+  private final byte RS_SERVER_ID = (byte) 90;
   // Sleep time of the RS, before sending an ack
   private static final long NO_TIMEOUT_RS_SLEEP_TIME = 2000;
-  private String testName = this.getClass().getSimpleName();
+  private final String testName = this.getClass().getSimpleName();
 
   // Create to distincts base dn, one for safe data replication, the other one
   // for safe read replication
-  private String SAFE_DATA_DN = "ou=safe-data," + TEST_ROOT_DN_STRING;
-  private String SAFE_READ_DN = "ou=safe-read," + TEST_ROOT_DN_STRING;
-  private String NOT_ASSURED_DN = "ou=not-assured," + TEST_ROOT_DN_STRING;
+  private final String SAFE_DATA_DN = "ou=safe-data," + TEST_ROOT_DN_STRING;
+  private final String SAFE_READ_DN = "ou=safe-read," + TEST_ROOT_DN_STRING;
+  private final String NOT_ASSURED_DN = "ou=not-assured," + TEST_ROOT_DN_STRING;
   private Entry safeDataDomainCfgEntry = null;
   private Entry safeReadDomainCfgEntry = null;
   private Entry notAssuredDomainCfgEntry = null;
@@ -310,14 +310,14 @@
     private ProtocolSession session = null;
 
     // Parameters given at constructor time
-    private int port;
+    private final int port;
     private short serverId = -1;
     boolean isAssured = false; // Default value for config
     AssuredMode assuredMode = AssuredMode.SAFE_DATA_MODE; // Default value for config
     byte safeDataLevel = (byte) 1; // Default value for config
 
     // Predefined config parameters
-    private int degradedStatusThreshold = 5000;
+    private final int degradedStatusThreshold = 5000;
 
     // Parameters set with received server start message
     private String baseDn = null;
@@ -630,7 +630,7 @@
     {
       try
       {
-        // Create add message        
+        // Create add message
         AddMsg addMsg =
           new AddMsg(gen.newChangeNumber(), entry.getDN().toString(), UUID.randomUUID().toString(),
                      parentUid,
@@ -787,7 +787,7 @@
         checkUpdateAssuredParameters(updateMsg);
 
         // let timeout occur
-        
+
         scenarioExecuted = true;
 
       } catch (Exception e)
@@ -1003,7 +1003,7 @@
         TIMEOUT);
       // Wait for connection of domain to RS
       waitForConnectionToRs(testcase, replicationServer);
-      
+
       // Make an LDAP update (add an entry)
       long startTime = System.currentTimeMillis(); // Time the update has been initiated
       String entry = "dn: ou=assured-sr-timeout-entry," + SAFE_READ_DN + "\n" +
@@ -1228,7 +1228,7 @@
       assertEquals(getMonitorAttrValue(baseDn, "assured-sd-timeout-updates"), 0);
       errorsByServer = getErrorsByServers(baseDn, AssuredMode.SAFE_DATA_MODE);
       assertTrue(errorsByServer.isEmpty());
-      
+
     } finally
     {
       endTest();
@@ -1342,7 +1342,7 @@
 
           for (AttributeValue val : tmpAttr)
           {
-            found = val.getStringValue();
+            found = val.toString();
             break;
           }
         }
@@ -1730,7 +1730,7 @@
       assertEquals(getMonitorAttrValue(baseDn, "assured-sd-timeout-updates"), 0);
       errorsByServer = getErrorsByServers(baseDn, AssuredMode.SAFE_DATA_MODE);
       assertTrue(errorsByServer.isEmpty());
-    
+
       // Make a second LDAP update (delete the entry)
       startTime = System.currentTimeMillis(); // Time the update has been initiated
       deleteEntry(entryDn);
@@ -1864,7 +1864,7 @@
       if (count++>0)
         Thread.sleep(100);
       op = connection.processSearch(
-                                    ByteStringFactory.create("cn=monitor"),
+                                    ByteString.valueOf("cn=monitor"),
                                     SearchScope.SINGLE_LEVEL,
                                     LDAPFilter.decode(monitorFilter));
     }
@@ -1904,7 +1904,7 @@
     // Parse and store values
     while (attValIt.hasNext())
     {
-      String srvStr = attValIt.next().getStringValue();
+      String srvStr = attValIt.next().toString();
       StringTokenizer strtok = new StringTokenizer(srvStr, ":");
       String token = strtok.nextToken();
       if (token != null)
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/replication/plugin/AttrInfoTest.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/replication/plugin/AttrInfoTest.java
index 9264fe0..58dd232 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/replication/plugin/AttrInfoTest.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/replication/plugin/AttrInfoTest.java
@@ -36,6 +36,7 @@
 import org.opends.server.types.AttributeType;
 import org.opends.server.types.AttributeValue;
 import org.opends.server.types.Attributes;
+import org.opends.server.types.AttributeValues;
 import org.opends.server.util.TimeThread;
 import org.testng.annotations.DataProvider;
 import org.testng.annotations.Test;
@@ -55,9 +56,9 @@
   {
     AttributeType type = DirectoryServer.getAttributeType("description");
 
-    AttributeValue att1 = new AttributeValue(type, "string");
-    AttributeValue att2 = new AttributeValue(type, "value");
-    AttributeValue att3 = new AttributeValue(type, "again");
+    AttributeValue att1 = AttributeValues.create(type, "string");
+    AttributeValue att2 = AttributeValues.create(type, "value");
+    AttributeValue att3 = AttributeValues.create(type, "again");
 
     ChangeNumber del1 = new ChangeNumber(1, (short) 0, (short) 1);
     ChangeNumber del2 = new ChangeNumber(1, (short) 1, (short) 1);
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/replication/plugin/HistoricalCsnOrderingTest.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/replication/plugin/HistoricalCsnOrderingTest.java
index 4789ca0..62577f9 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/replication/plugin/HistoricalCsnOrderingTest.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/replication/plugin/HistoricalCsnOrderingTest.java
@@ -40,7 +40,6 @@
 import org.opends.server.TestCaseUtils;
 import org.opends.server.core.AddOperationBasis;
 import org.opends.server.core.DirectoryServer;
-import org.opends.server.protocols.asn1.ASN1OctetString;
 import org.opends.server.protocols.internal.InternalClientConnection;
 import org.opends.server.protocols.internal.InternalSearchOperation;
 import org.opends.server.replication.ReplicationTestCase;
@@ -164,8 +163,8 @@
     ChangeNumber del1 = new ChangeNumber(1, (short) 0, (short) 1);
     ChangeNumber del2 = new ChangeNumber(1, (short) 1, (short) 1);
 
-    ByteString v1 = new ASN1OctetString("a"+":"+del1.toString());
-    ByteString v2 = new ASN1OctetString("a"+":"+del2.toString());
+    ByteString v1 = ByteString.valueOf("a"+":"+del1.toString());
+    ByteString v2 = ByteString.valueOf("a"+":"+del2.toString());
 
     int cmp = r.compareValues(v1, v1);
     assertTrue(cmp == 0);
@@ -222,7 +221,7 @@
     assertTrue(attrs1.isEmpty() != true);
 
     String histValue =
-      attrs1.get(0).iterator().next().getStringValue();
+      attrs1.get(0).iterator().next().getValue().toString();
 
     logError(Message.raw(Category.SYNC, Severity.INFORMATION,
         "First historical value:" + histValue));
@@ -244,7 +243,7 @@
 
     for (AttributeValue av : attrs2.get(0)) {
       logError(Message.raw(Category.SYNC, Severity.INFORMATION,
-          "Second historical value:" + av.getStringValue()));
+          "Second historical value:" + av.getValue().toString()));
     }
 
     // Build a change number from the first modification
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/replication/plugin/HistoricalTest.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/replication/plugin/HistoricalTest.java
index 8f0d85f..48954e6 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/replication/plugin/HistoricalTest.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/replication/plugin/HistoricalTest.java
@@ -243,7 +243,7 @@
     Entry entry = DirectoryServer.getEntry(dn1);
     List<Attribute> attrs = entry.getAttribute(entryuuidType);
     String entryuuid =
-         attrs.get(0).iterator().next().getStringValue();
+         attrs.get(0).iterator().next().getValue().toString();
 
     // Add the second test entry.
     TestCaseUtils.addEntry(
@@ -261,7 +261,7 @@
     entry = DirectoryServer.getEntry(dn2);
     attrs = entry.getAttribute(entryuuidType);
     String entryuuid2 =
-         attrs.get(0).iterator().next().getStringValue();
+         attrs.get(0).iterator().next().getValue().toString();
 
     // A change on a first server.
     ChangeNumber t1 = new ChangeNumber(1, (short) 0, (short) 3);
@@ -315,13 +315,13 @@
     entry = DirectoryServer.getEntry(dn1);
     attrs = entry.getAttribute(attrType);
     String attrValue1 =
-         attrs.get(0).iterator().next().getStringValue();
+         attrs.get(0).iterator().next().getValue().toString();
 
     // Read the second entry to see how the conflict was resolved.
     entry = DirectoryServer.getEntry(dn2);
     attrs = entry.getAttribute(attrType);
     String attrValue2 =
-         attrs.get(0).iterator().next().getStringValue();
+         attrs.get(0).iterator().next().getValue().toString();
 
     // The two values should be the first value added.
     assertEquals(attrValue1, "A");
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/replication/plugin/ModifyConflictTest.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/replication/plugin/ModifyConflictTest.java
index b0bf2d4..2818fb5 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/replication/plugin/ModifyConflictTest.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/replication/plugin/ModifyConflictTest.java
@@ -51,17 +51,7 @@
 import org.opends.server.replication.plugin.Historical;
 import org.opends.server.replication.protocol.ModifyContext;
 import org.opends.server.replication.protocol.ReplicationMsg;
-import org.opends.server.types.Attribute;
-import org.opends.server.types.AttributeBuilder;
-import org.opends.server.types.AttributeType;
-import org.opends.server.types.AttributeValue;
-import org.opends.server.types.Attributes;
-import org.opends.server.types.DN;
-import org.opends.server.types.DirectoryException;
-import org.opends.server.types.Entry;
-import org.opends.server.types.Modification;
-import org.opends.server.types.ModificationType;
-import org.opends.server.types.ObjectClass;
+import org.opends.server.types.*;
 import org.opends.server.workflowelement.localbackend.LocalBackendAddOperation;
 import org.opends.server.workflowelement.localbackend.LocalBackendModifyOperation;
 import static org.opends.server.TestCaseUtils.*;
@@ -692,7 +682,7 @@
     assertEquals(mod.getModificationType(), ModificationType.DELETE);
     assertEquals(mod.getAttribute().size(), 1);
     assertTrue(mod.getAttribute().contains(
-        new AttributeValue(descriptionAttrType, "value3")));
+        AttributeValues.create(descriptionAttrType, "value3")));
   }
 
   /**
@@ -741,16 +731,16 @@
     assertEquals(mod.getModificationType(), ModificationType.DELETE);
     assertEquals(mod.getAttribute().size(), 2);
     assertTrue(mod.getAttribute().contains(
-        new AttributeValue(descriptionAttrType, "value3")));
+        AttributeValues.create(descriptionAttrType, "value3")));
     assertTrue(mod.getAttribute().contains(
-        new AttributeValue(descriptionAttrType, "value4")));
+        AttributeValues.create(descriptionAttrType, "value4")));
     Attribute resultEntryAttr = entry.getAttribute(descriptionAttrType).get(0);
     // check that the entry now contains value1 and value2 and no other values.
     assertEquals(resultEntryAttr.size(), 2);
     assertTrue(resultEntryAttr.contains(
-        new AttributeValue(descriptionAttrType, "value1")));
+        AttributeValues.create(descriptionAttrType, "value1")));
     assertTrue(resultEntryAttr.contains(
-        new AttributeValue(descriptionAttrType, "value2")));
+        AttributeValues.create(descriptionAttrType, "value2")));
 
     // simulate a REPLACE of the attribute with values : value1, value2, value3
     // at time t1.
@@ -769,15 +759,15 @@
     assertEquals(mod.getModificationType(), ModificationType.REPLACE);
     assertEquals(mod.getAttribute().size(), 2);
     assertTrue(mod.getAttribute().contains(
-        new AttributeValue(descriptionAttrType, "value1")));
+        AttributeValues.create(descriptionAttrType, "value1")));
     assertTrue(mod.getAttribute().contains(
-        new AttributeValue(descriptionAttrType, "value2")));
+        AttributeValues.create(descriptionAttrType, "value2")));
     // check that the entry now contains value1 and value2 and no other values.
     assertEquals(resultEntryAttr.size(), 2);
     assertTrue(resultEntryAttr.contains(
-        new AttributeValue(descriptionAttrType, "value1")));
+        AttributeValues.create(descriptionAttrType, "value1")));
     assertTrue(resultEntryAttr.contains(
-        new AttributeValue(descriptionAttrType, "value2")));
+        AttributeValues.create(descriptionAttrType, "value2")));
   }
 
   /**
@@ -888,8 +878,8 @@
     List<Attribute> attrs = entry.getAttribute(DESCRIPTION);
     Attribute attr = attrs.get(0);
     assertEquals(2, attr.size());
-    attr.contains(new AttributeValue(attr.getAttributeType(), "value1"));
-    attr.contains(new AttributeValue(attr.getAttributeType(), "value2"));
+    attr.contains(AttributeValues.create(attr.getAttributeType(), "value1"));
+    attr.contains(AttributeValues.create(attr.getAttributeType(), "value2"));
 
 
     // do the same as before but in reverse order
@@ -917,8 +907,8 @@
     attrs = entry.getAttribute(DESCRIPTION);
     attr = attrs.get(0);
     assertEquals(2, attr.size());
-    attr.contains(new AttributeValue(attr.getAttributeType(), "value1"));
-    attr.contains(new AttributeValue(attr.getAttributeType(), "value2"));
+    attr.contains(AttributeValues.create(attr.getAttributeType(), "value1"));
+    attr.contains(AttributeValues.create(attr.getAttributeType(), "value2"));
   }
 
   /**
@@ -1052,7 +1042,7 @@
     Modification newMod = mods.get(0);
     assertTrue(newMod.getModificationType().equals(modType));
     AttributeValue val = newMod.getAttribute().iterator().next();
-    assertEquals(val.getStringValue(), value);
+    assertEquals(val.getValue().toString(), value);
   }
 
   /**
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/replication/plugin/ValueInfoTest.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/replication/plugin/ValueInfoTest.java
index a7fefe7..4861447 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/replication/plugin/ValueInfoTest.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/replication/plugin/ValueInfoTest.java
@@ -32,6 +32,7 @@
 import org.opends.server.replication.plugin.ValueInfo;
 import org.opends.server.types.AttributeType;
 import org.opends.server.types.AttributeValue;
+import org.opends.server.types.AttributeValues;
 import org.opends.server.util.TimeThread;
 import org.testng.annotations.DataProvider;
 import org.testng.annotations.Test;
@@ -50,9 +51,9 @@
   public Object[][] createData() {
     AttributeType type = DirectoryServer.getAttributeType("description");
 
-    AttributeValue att1 = new AttributeValue(type, "string");
-    AttributeValue att2 = new AttributeValue(type, "value");
-    AttributeValue att3 = new AttributeValue(type, "again");
+    AttributeValue att1 = AttributeValues.create(type, "string");
+    AttributeValue att2 = AttributeValues.create(type, "value");
+    AttributeValue att3 = AttributeValues.create(type, "again");
 
     ChangeNumber del1 = new ChangeNumber(1, (short) 0, (short) 1);
     ChangeNumber del2 = new ChangeNumber(1, (short) 1, (short) 1);
@@ -84,7 +85,7 @@
     AttributeType type = DirectoryServer.getAttributeType("description");
     ValueInfo valInfo1 = new ValueInfo(value,CNupdate,CNdelete);
     ValueInfo valInfo2 = new ValueInfo(value,CNupdate,CNupdate);
-    ValueInfo valInfo3 = new ValueInfo(new AttributeValue(type,"Test"),
+    ValueInfo valInfo3 = new ValueInfo(AttributeValues.create(type,"Test"),
         CNupdate,CNupdate);
 
     // Check equals
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/replication/server/ReplicationServerTest.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/replication/server/ReplicationServerTest.java
index c9ba1cb..6a17504 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/replication/server/ReplicationServerTest.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/replication/server/ReplicationServerTest.java
@@ -58,10 +58,10 @@
 import org.opends.server.core.ModifyDNOperationBasis;
 import org.opends.server.loggers.ErrorLogger;
 import org.opends.server.loggers.debug.DebugTracer;
-import org.opends.server.protocols.asn1.ASN1OctetString;
 import org.opends.server.protocols.internal.InternalSearchOperation;
 import org.opends.server.protocols.internal.InternalClientConnection;
 import org.opends.server.protocols.ldap.LDAPFilter;
+import org.opends.server.protocols.ldap.LDAPControl;
 import org.opends.server.replication.ReplicationTestCase;
 import org.opends.server.replication.service.ReplicationBroker;
 import org.opends.server.replication.common.ChangeNumber;
@@ -1430,7 +1430,7 @@
 
        // General search
        InternalSearchOperation op2 = connection.processSearch(
-           new ASN1OctetString("cn=monitor"),
+           ByteString.valueOf("cn=monitor"),
            SearchScope.WHOLE_SUBTREE,
            LDAPFilter.decode("(objectclass=*)"));
        assertEquals(op2.getResultCode(), ResultCode.SUCCESS,
@@ -1475,7 +1475,7 @@
        InternalClientConnection conn =
        InternalClientConnection.getRootConnection();
        LinkedList<Control> requestControls = new LinkedList<Control>();
-       requestControls.add(new Control(OID_INTERNAL_GROUP_MEMBERSHIP_UPDATE,
+       requestControls.add(new LDAPControl(OID_INTERNAL_GROUP_MEMBERSHIP_UPDATE,
                                       false));
        DN baseDN=DN.decode("dc=replicationChanges");
        //Test the group membership control causes search to be skipped.
@@ -1493,7 +1493,7 @@
 
        // General search
        InternalSearchOperation op = connection.processSearch(
-           new ASN1OctetString("dc=oops"),
+           ByteString.valueOf("dc=oops"),
            SearchScope.WHOLE_SUBTREE,
            LDAPFilter.decode("(changetype=*)"));
        assertEquals(op.getResultCode(), ResultCode.NO_SUCH_OBJECT);
@@ -1508,7 +1508,7 @@
 
        // General search
        op = connection.processSearch(
-           new ASN1OctetString("dc=replicationChanges"),
+           ByteString.valueOf("dc=replicationChanges"),
            SearchScope.WHOLE_SUBTREE,
            LDAPFilter.decode("(changetype=*)"));
 
@@ -1529,28 +1529,28 @@
 
        debugInfo("Query / filter based on changetype");
        op = connection.processSearch(
-           new ASN1OctetString("dc=replicationChanges"),
+           ByteString.valueOf("dc=replicationChanges"),
            SearchScope.WHOLE_SUBTREE,
            LDAPFilter.decode("(changetype=add)"));
        assertEquals(op.getResultCode(), ResultCode.SUCCESS);
        assertTrue(op.getSearchEntries().size() == 2);
 
        op = connection.processSearch(
-           new ASN1OctetString("dc=replicationChanges"),
+           ByteString.valueOf("dc=replicationChanges"),
            SearchScope.WHOLE_SUBTREE,
            LDAPFilter.decode("(changetype=modify)"));
        assertEquals(op.getResultCode(), ResultCode.SUCCESS);
        assertTrue(op.getSearchEntries().size() == 1);
 
        op = connection.processSearch(
-           new ASN1OctetString("dc=replicationChanges"),
+           ByteString.valueOf("dc=replicationChanges"),
            SearchScope.WHOLE_SUBTREE,
            LDAPFilter.decode("(changetype=moddn)"));
        assertEquals(op.getResultCode(), ResultCode.SUCCESS);
        assertTrue(op.getSearchEntries().size() == 1);
 
        op = connection.processSearch(
-           new ASN1OctetString("dc=replicationChanges"),
+           ByteString.valueOf("dc=replicationChanges"),
            SearchScope.WHOLE_SUBTREE,
            LDAPFilter.decode("(changetype=delete)"));
        assertEquals(op.getResultCode(), ResultCode.SUCCESS);
@@ -1558,7 +1558,7 @@
 
        debugInfo("Query / filter based on objectclass");
        op = connection.processSearch(
-           new ASN1OctetString("dc=replicationChanges"),
+           ByteString.valueOf("dc=replicationChanges"),
            SearchScope.WHOLE_SUBTREE,
            LDAPFilter.decode("(objectclass=person)"));
        assertEquals(op.getResultCode(), ResultCode.SUCCESS);
@@ -1573,7 +1573,7 @@
         *
         * debugInfo("Query / searchBase");
         * op = connection.processSearch(
-        *    new ASN1OctetString("uid=new person,ou=People,dc=example,dc=com,dc=replicationChanges"),
+        *    ByteString.valueOf("uid=new person,ou=People,dc=example,dc=com,dc=replicationChanges"),
         *    SearchScope.WHOLE_SUBTREE,
         *    LDAPFilter.decode("(changetype=*)"));
         * assertEquals(op.getResultCode(), ResultCode.SUCCESS);
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/schema/ApproximatematchingRule.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/schema/ApproximatematchingRule.java
index 5a3ac9f..ccb396f 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/schema/ApproximatematchingRule.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/schema/ApproximatematchingRule.java
@@ -29,7 +29,6 @@
 import static org.testng.Assert.*;
 
 import org.opends.server.api.ApproximateMatchingRule;
-import org.opends.server.protocols.asn1.ASN1OctetString;
 import org.opends.server.types.ByteString;
 import org.testng.annotations.DataProvider;
 import org.testng.annotations.Test;
@@ -151,9 +150,9 @@
 
     // normalize the 2 provided values
     ByteString normalizedValue1 =
-      ruleInstance.normalizeValue(new ASN1OctetString(value1));
+      ruleInstance.normalizeValue(ByteString.valueOf(value1));
     ByteString normalizedValue2 =
-      ruleInstance.normalizeValue(new ASN1OctetString(value2));
+      ruleInstance.normalizeValue(ByteString.valueOf(value2));
 
     // check that the approximatelyMatch return the expected result.
     Boolean liveResult = ruleInstance.approximatelyMatch(normalizedValue1,
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/schema/AttributeSyntaxTest.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/schema/AttributeSyntaxTest.java
index 75ce04c..0a190ab 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/schema/AttributeSyntaxTest.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/schema/AttributeSyntaxTest.java
@@ -29,7 +29,7 @@
 import static org.testng.Assert.*;
 
 import org.opends.server.api.AttributeSyntax;
-import org.opends.server.protocols.asn1.ASN1OctetString;
+import org.opends.server.types.ByteString;
 import org.opends.messages.MessageBuilder;
 import org.testng.annotations.DataProvider;
 import org.testng.annotations.Test;
@@ -67,7 +67,7 @@
     MessageBuilder reason = new MessageBuilder();
     // test the valueIsAcceptable method
     Boolean liveResult =
-      syntax.valueIsAcceptable(new ASN1OctetString(value), reason);
+      syntax.valueIsAcceptable(ByteString.valueOf(value), reason);
     
     if (liveResult != result)
       fail(syntax + ".valueIsAcceptable gave bad result for " + value + 
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/schema/AttributeTypeSyntaxTest.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/schema/AttributeTypeSyntaxTest.java
index c7cf07c..9f9e23a 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/schema/AttributeTypeSyntaxTest.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/schema/AttributeTypeSyntaxTest.java
@@ -29,12 +29,10 @@
 import org.testng.annotations.DataProvider;
 import org.testng.annotations.Test;
 
-import org.opends.server.api.ApproximateMatchingRule;
 import org.opends.server.api.AttributeSyntax;
 import org.opends.server.core.DirectoryServer;
 import org.opends.server.types.AttributeType;
 import org.opends.server.types.ByteString;
-import org.opends.server.types.ByteStringFactory;
 import org.opends.messages.MessageBuilder;
 
 import static org.testng.Assert.*;
@@ -132,7 +130,7 @@
 
 
     // Create an attribute type definition and verify that it is acceptable.
-    ByteString definition = ByteStringFactory.create(
+    ByteString definition = ByteString.valueOf(
       "( testxapproxtype-oid NAME 'testXApproxType' " +
            "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 " +
            "X-APPROX 'equalLengthApproximateMatch' )");
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/schema/AuthPasswordEqualityMatchingRuleTest.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/schema/AuthPasswordEqualityMatchingRuleTest.java
index 2c71895..37a0542 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/schema/AuthPasswordEqualityMatchingRuleTest.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/schema/AuthPasswordEqualityMatchingRuleTest.java
@@ -33,7 +33,6 @@
 import org.opends.server.config.ConfigEntry;
 import org.opends.server.core.DirectoryServer;
 import org.opends.server.extensions.SaltedMD5PasswordStorageScheme;
-import org.opends.server.protocols.asn1.ASN1OctetString;
 import org.opends.server.types.ByteString;
 import org.opends.server.types.DN;
 import org.testng.annotations.DataProvider;
@@ -72,7 +71,7 @@
 
   private Object[] generateValues(String password) throws Exception
   {
-    ByteString bytePassword = new ASN1OctetString(password);
+    ByteString bytePassword = ByteString.valueOf(password);
     SaltedMD5PasswordStorageScheme scheme = new SaltedMD5PasswordStorageScheme();
 
     ConfigEntry configEntry =
@@ -90,7 +89,7 @@
     ByteString encodedAuthPassword = scheme.encodeAuthPassword(bytePassword);
     StringBuilder[] authPWComponents =
          AuthPasswordSyntax.decodeAuthPassword(
-              encodedAuthPassword.stringValue());
+              encodedAuthPassword.toString());
 
      return new Object[] {
          AUTH_PASSWORD_SCHEME_NAME_SALTED_MD5 + "$"
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/schema/BitStringSyntaxTest.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/schema/BitStringSyntaxTest.java
index 9493f35..999c7cf 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/schema/BitStringSyntaxTest.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/schema/BitStringSyntaxTest.java
@@ -29,11 +29,7 @@
 import static org.testng.Assert.*;
 
 import org.opends.server.api.AttributeSyntax;
-import org.opends.server.config.ConfigEntry;
-import org.opends.server.core.DirectoryServer;
-import org.opends.server.protocols.asn1.ASN1OctetString;
 import org.opends.server.types.ByteString;
-import org.opends.server.types.DN;
 import org.opends.messages.MessageBuilder;
 import org.testng.annotations.DataProvider;
 import org.testng.annotations.Test;
@@ -80,7 +76,7 @@
     BitStringSyntax syntax = new BitStringSyntax();
     syntax.initializeSyntax(null);
 
-    ByteString byteStringValue = new ASN1OctetString(value);
+    ByteString byteStringValue = ByteString.valueOf(value);
 
     MessageBuilder reason = new MessageBuilder();
     Boolean liveResult =
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/schema/CollationMatchingRuleTest.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/schema/CollationMatchingRuleTest.java
index 97cdd7d..ba958db 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/schema/CollationMatchingRuleTest.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/schema/CollationMatchingRuleTest.java
@@ -28,21 +28,22 @@
 
 package org.opends.server.schema;
 
+import static org.testng.Assert.*;
+
 import java.util.List;
 
-
-import org.opends.server.protocols.asn1.ASN1OctetString;
 import org.opends.server.TestCaseUtils;
 import org.opends.server.protocols.internal.InternalClientConnection;
 import org.opends.server.protocols.internal.InternalSearchOperation;
 import org.opends.server.protocols.ldap.LDAPFilter;
 import org.opends.server.tools.LDAPModify;
+import org.opends.server.types.ByteString;
 import org.opends.server.types.DereferencePolicy;
 import org.opends.server.types.ResultCode;
 import org.opends.server.types.SearchResultEntry;
 import org.opends.server.types.SearchScope;
-import org.testng.annotations.*;
-import static org.testng.Assert.*;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
 
 
 /**
@@ -83,7 +84,7 @@
             "departmentNumber:: w4NiYzExMQ==",
             "carLicense:: w6liZTI=",
             "uid: user",
-            "cn:: U8ODbmNoZXo=", 
+            "cn:: U8ODbmNoZXo=",
             "sn:: UXXDqWJlYw==");
     String[] args = new String []
     {
@@ -117,7 +118,7 @@
               InternalClientConnection.nextOperationID(),
               InternalClientConnection.nextMessageID(),
               null,
-              new ASN1OctetString("uid=user,o=test"),
+              ByteString.valueOf("uid=user,o=test"),
               SearchScope.WHOLE_SUBTREE,
               DereferencePolicy.NEVER_DEREF_ALIASES,
               Integer.MAX_VALUE,
@@ -154,7 +155,7 @@
               InternalClientConnection.nextOperationID(),
               InternalClientConnection.nextMessageID(),
               null,
-              new ASN1OctetString("uid=user,o=test"),
+              ByteString.valueOf("uid=user,o=test"),
               SearchScope.WHOLE_SUBTREE,
               DereferencePolicy.NEVER_DEREF_ALIASES,
               Integer.MAX_VALUE,
@@ -190,7 +191,7 @@
               InternalClientConnection.nextOperationID(),
               InternalClientConnection.nextMessageID(),
               null,
-              new ASN1OctetString("uid=user,o=test"),
+              ByteString.valueOf("uid=user,o=test"),
               SearchScope.WHOLE_SUBTREE,
               DereferencePolicy.NEVER_DEREF_ALIASES,
               Integer.MAX_VALUE,
@@ -228,7 +229,7 @@
               InternalClientConnection.nextOperationID(),
               InternalClientConnection.nextMessageID(),
               null,
-              new ASN1OctetString("uid=user,o=test"),
+              ByteString.valueOf("uid=user,o=test"),
               SearchScope.WHOLE_SUBTREE,
               DereferencePolicy.NEVER_DEREF_ALIASES,
               Integer.MAX_VALUE,
@@ -266,7 +267,7 @@
               InternalClientConnection.nextOperationID(),
               InternalClientConnection.nextMessageID(),
               null,
-              new ASN1OctetString("uid=user,o=test"),
+              ByteString.valueOf("uid=user,o=test"),
               SearchScope.WHOLE_SUBTREE,
               DereferencePolicy.NEVER_DEREF_ALIASES,
               Integer.MAX_VALUE,
@@ -304,7 +305,7 @@
               InternalClientConnection.nextOperationID(),
               InternalClientConnection.nextMessageID(),
               null,
-              new ASN1OctetString("uid=user,o=test"),
+              ByteString.valueOf("uid=user,o=test"),
               SearchScope.WHOLE_SUBTREE,
               DereferencePolicy.NEVER_DEREF_ALIASES,
               Integer.MAX_VALUE,
@@ -345,7 +346,7 @@
               InternalClientConnection.nextOperationID(),
               InternalClientConnection.nextMessageID(),
               null,
-              new ASN1OctetString("uid=user,o=test"),
+              ByteString.valueOf("uid=user,o=test"),
               SearchScope.WHOLE_SUBTREE,
               DereferencePolicy.NEVER_DEREF_ALIASES,
               Integer.MAX_VALUE,
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/schema/ConfigurableAttributeSyntaxTest.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/schema/ConfigurableAttributeSyntaxTest.java
index 8ae1102..142f3a5 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/schema/ConfigurableAttributeSyntaxTest.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/schema/ConfigurableAttributeSyntaxTest.java
@@ -37,12 +37,11 @@
 import org.opends.server.admin.server.AdminTestCaseUtils;
 import org.opends.server.admin.std.meta.TelephoneNumberAttributeSyntaxCfgDefn;
 import org.opends.server.admin.std.server.TelephoneNumberAttributeSyntaxCfg;
-import org.opends.server.api.AttributeSyntax;
 import org.opends.server.config.ConfigEntry;
 import org.opends.server.core.DirectoryServer;
-import org.opends.server.protocols.asn1.ASN1OctetString;
 import org.opends.server.types.ConfigChangeResult;
 import org.opends.server.types.ResultCode;
+import org.opends.server.types.ByteString;
 import org.testng.annotations.DataProvider;
 import org.testng.annotations.Test;
 
@@ -128,7 +127,7 @@
 
     // check the syntax of the given value.
     Boolean liveResult = syntax.valueIsAcceptable(
-        new ASN1OctetString(value), new MessageBuilder());
+        ByteString.valueOf(value), new MessageBuilder());
     assertEquals(result, liveResult);
 
     // call the getters to increase code coverage...
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/schema/EqualLengthApproximateMatchingRule.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/schema/EqualLengthApproximateMatchingRule.java
index e32ac69..e9d2ce0 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/schema/EqualLengthApproximateMatchingRule.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/schema/EqualLengthApproximateMatchingRule.java
@@ -28,14 +28,15 @@
 
 
 
+import static org.opends.server.schema.SchemaConstants.*;
+
 import java.util.Collection;
 import java.util.Collections;
-import org.opends.server.api.ApproximateMatchingRule;
-import org.opends.server.types.ByteString;
-import org.opends.server.types.ByteStringFactory;
-import org.opends.server.types.DirectoryException;
 
-import static org.opends.server.schema.SchemaConstants.*;
+import org.opends.server.api.ApproximateMatchingRule;
+import org.opends.server.types.ByteSequence;
+import org.opends.server.types.ByteString;
+import org.opends.server.types.DirectoryException;
 
 
 
@@ -60,6 +61,7 @@
   /**
    * {@inheritDoc}
    */
+  @Override
   public Collection<String> getAllNames()
   {
     return Collections.singleton(getName());
@@ -73,6 +75,7 @@
    * @return  The common name for this matching rule, or <CODE>null</CODE> if
    * it does not have a name.
    */
+  @Override
   public String getName()
   {
     return "equalLengthApproximateMatch";
@@ -85,6 +88,7 @@
    *
    * @return  The OID for this matching rule.
    */
+  @Override
   public String getOID()
   {
     return "1.3.6.1.4.1.26027.1.999.26";
@@ -98,6 +102,7 @@
    * @return  The description for this matching rule, or <CODE>null</CODE> if
    *          there is none.
    */
+  @Override
   public String getDescription()
   {
     return null;
@@ -111,6 +116,7 @@
    *
    * @return  The OID of the syntax with which this matching rule is associated.
    */
+  @Override
   public String getSyntaxOID()
   {
     return SYNTAX_DIRECTORY_STRING_OID;
@@ -129,12 +135,13 @@
    * @throws  DirectoryException  If the provided value is invalid according to
    *                              the associated attribute syntax.
    */
-  public ByteString normalizeValue(ByteString value)
+  @Override
+  public ByteString normalizeValue(ByteSequence value)
          throws DirectoryException
   {
     // Any value is acceptable, so we can just return a copy of the
     // value.
-    return ByteStringFactory.create(value.value());
+    return value.toByteString();
   }
 
 
@@ -149,9 +156,10 @@
    * @return  <CODE>true</CODE> if the provided values are approximately equal,
    *          or <CODE>false</CODE> if not.
    */
-  public boolean approximatelyMatch(ByteString value1, ByteString value2)
+  @Override
+  public boolean approximatelyMatch(ByteSequence value1, ByteSequence value2)
   {
-    return (value1.value().length == value2.value().length);
+    return value1.length() == value2.length();
   }
 }
 
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/schema/EqualityMatchingRuleTest.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/schema/EqualityMatchingRuleTest.java
index a50e128..44b2ff1 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/schema/EqualityMatchingRuleTest.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/schema/EqualityMatchingRuleTest.java
@@ -28,7 +28,6 @@
 
 import org.opends.server.api.EqualityMatchingRule;
 import org.opends.server.core.DirectoryServer;
-import org.opends.server.protocols.asn1.ASN1OctetString;
 import org.opends.server.types.AcceptRejectWarn;
 import org.opends.server.types.ByteString;
 import org.opends.server.types.ConditionResult;
@@ -78,9 +77,9 @@
 
     // normalize the 2 provided values and check that they are equals
     ByteString normalizedValue1 =
-      rule.normalizeValue(new ASN1OctetString(value1));
+      rule.normalizeValue(ByteString.valueOf(value1));
     ByteString normalizedValue2 =
-      rule.normalizeValue(new ASN1OctetString(value2));
+      rule.normalizeValue(ByteString.valueOf(value2));
 
     Boolean liveResult = rule.areEqual(normalizedValue1, normalizedValue2);
     assertEquals(result, liveResult);
@@ -131,7 +130,7 @@
     boolean success = false;
     try
     {
-      rule.normalizeValue(new ASN1OctetString(value));
+      rule.normalizeValue(ByteString.valueOf(value));
     } catch (DirectoryException e) {
       success = true;
     }
@@ -165,9 +164,9 @@
 
     // normalize the 2 provided values and check that they are equals
     ByteString normalizedValue1 =
-      rule.normalizeValue(new ASN1OctetString(value1));
+      rule.normalizeValue(ByteString.valueOf(value1));
     ByteString normalizedValue2 =
-      rule.normalizeValue(new ASN1OctetString(value2));
+      rule.normalizeValue(ByteString.valueOf(value2));
 
     ConditionResult liveResult =
       rule.valuesMatch(normalizedValue1, normalizedValue2);
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/schema/OrderingMatchingRuleTest.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/schema/OrderingMatchingRuleTest.java
index 635b8a2..b78395b 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/schema/OrderingMatchingRuleTest.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/schema/OrderingMatchingRuleTest.java
@@ -30,7 +30,6 @@
 
 import org.opends.server.api.OrderingMatchingRule;
 import org.opends.server.core.DirectoryServer;
-import org.opends.server.protocols.asn1.ASN1OctetString;
 import org.opends.server.types.AcceptRejectWarn;
 import org.opends.server.types.ByteString;
 import org.opends.server.types.DirectoryException;
@@ -66,9 +65,9 @@
     // ruleInstance.initializeMatchingRule(configEntry);
 
     ByteString normalizedValue1 =
-      ruleInstance.normalizeValue(new ASN1OctetString(value1));
+      ruleInstance.normalizeValue(ByteString.valueOf(value1));
     ByteString normalizedValue2 =
-      ruleInstance.normalizeValue(new ASN1OctetString(value2));
+      ruleInstance.normalizeValue(ByteString.valueOf(value2));
     int res = ruleInstance.compareValues(normalizedValue1, normalizedValue2);
     if (result == 0)
     {
@@ -125,7 +124,7 @@
     // normalize the 2 provided values
     try
     {
-      ruleInstance.normalizeValue(new ASN1OctetString(value));
+      ruleInstance.normalizeValue(ByteString.valueOf(value));
     } catch (DirectoryException e) {
       // that's the expected path : the matching rule has detected that
       // the value is incorrect.
@@ -152,7 +151,7 @@
     // normalize the 2 provided values
     try
     {
-      ruleInstance.normalizeValue(new ASN1OctetString(value));
+      ruleInstance.normalizeValue(ByteString.valueOf(value));
     } catch (Exception e)
     {
       fail(ruleInstance + " in warn mode should not reject value " + value + e);
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/schema/SubstringMatchingRuleTest.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/schema/SubstringMatchingRuleTest.java
index 6e41533..1d7dfa0 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/schema/SubstringMatchingRuleTest.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/schema/SubstringMatchingRuleTest.java
@@ -30,8 +30,8 @@
 import java.util.List;
 
 import org.opends.server.api.SubstringMatchingRule;
-import org.opends.server.protocols.asn1.ASN1OctetString;
 import org.opends.server.types.ByteString;
+import org.opends.server.types.ByteSequence;
 import org.testng.annotations.DataProvider;
 import org.testng.annotations.Test;
 
@@ -86,16 +86,17 @@
 
     // normalize the 2 provided values and check that they are equals
     ByteString normalizedValue =
-      rule.normalizeValue(new ASN1OctetString(value));
+      rule.normalizeValue(ByteString.valueOf(value));
 
     StringBuilder printableMiddleSubs = new StringBuilder();
-    List<ByteString> middleList = new ArrayList<ByteString>(middleSubs.length);
+    List<ByteSequence> middleList =
+        new ArrayList<ByteSequence>(middleSubs.length);
     for (int i=0; i<middleSubs.length; i++)
     {
       printableMiddleSubs.append(middleSubs[i]);
       printableMiddleSubs.append(",");
       middleList.add(
-          rule.normalizeSubstring(new ASN1OctetString(middleSubs[i])));
+          rule.normalizeSubstring(ByteString.valueOf(middleSubs[i])));
     }
 
     Boolean liveResult =
@@ -120,10 +121,10 @@
 
     // normalize the 2 provided values and check that they are equals
     ByteString normalizedValue =
-      rule.normalizeValue(new ASN1OctetString(value));
+      rule.normalizeValue(ByteString.valueOf(value));
 
     ByteString normalizedInitial =
-      rule.normalizeValue(new ASN1OctetString(initial));
+      rule.normalizeValue(ByteString.valueOf(initial));
     Boolean liveResult = rule.valueMatchesSubstring(
         normalizedValue, normalizedInitial, null, null);
     if (result != liveResult)
@@ -146,10 +147,10 @@
 
     // normalize the 2 provided values and check that they are equals
     ByteString normalizedValue =
-      rule.normalizeValue(new ASN1OctetString(value));
+      rule.normalizeValue(ByteString.valueOf(value));
 
     ByteString normalizedFinal =
-      rule.normalizeValue(new ASN1OctetString(finalValue));
+      rule.normalizeValue(ByteString.valueOf(finalValue));
     Boolean liveResult = rule.valueMatchesSubstring(
         normalizedValue, null, null, normalizedFinal);
     if (result != liveResult)
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/schema/UserPasswordEqualityMatchingRuleTest.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/schema/UserPasswordEqualityMatchingRuleTest.java
index 7993104..d009ff1 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/schema/UserPasswordEqualityMatchingRuleTest.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/schema/UserPasswordEqualityMatchingRuleTest.java
@@ -33,7 +33,6 @@
 import org.opends.server.config.ConfigEntry;
 import org.opends.server.core.DirectoryServer;
 import org.opends.server.extensions.SaltedMD5PasswordStorageScheme;
-import org.opends.server.protocols.asn1.ASN1OctetString;
 import org.opends.server.types.ByteString;
 import org.opends.server.types.DN;
 import org.testng.annotations.DataProvider;
@@ -71,7 +70,7 @@
 
   private Object[] generateValues(String password) throws Exception
   {
-    ByteString bytePassword = new ASN1OctetString(password);
+    ByteString bytePassword = ByteString.valueOf(password);
     SaltedMD5PasswordStorageScheme scheme = new SaltedMD5PasswordStorageScheme();
 
     ConfigEntry configEntry =
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/tasks/DisconnectClientTaskTestCase.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/tasks/DisconnectClientTaskTestCase.java
index 818aaae..857c2c2 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/tasks/DisconnectClientTaskTestCase.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/tasks/DisconnectClientTaskTestCase.java
@@ -43,6 +43,7 @@
 import org.opends.server.protocols.asn1.*;
 import org.opends.server.protocols.ldap.*;
 import org.opends.server.types.DN;
+import org.opends.server.types.ByteString;
 
 import static org.testng.Assert.*;
 
@@ -82,16 +83,18 @@
   {
     // Establish a connection to the server, bind, and get the connection ID.
     Socket s = new Socket("127.0.0.1", TestCaseUtils.getServerLdapPort());
-    ASN1Reader r = new ASN1Reader(s);
-    ASN1Writer w = new ASN1Writer(s);
+    org.opends.server.tools.LDAPReader r =
+        new org.opends.server.tools.LDAPReader(s);
+    org.opends.server.tools.LDAPWriter w =
+        new org.opends.server.tools.LDAPWriter(s);
 
     BindRequestProtocolOp bindRequest =
-         new BindRequestProtocolOp(new ASN1OctetString("cn=Directory Manager"),
-                                   3, new ASN1OctetString("password"));
+         new BindRequestProtocolOp(ByteString.valueOf("cn=Directory Manager"),
+                                   3, ByteString.valueOf("password"));
     LDAPMessage message = new LDAPMessage(1, bindRequest);
-    w.writeElement(message.encode());
+    w.writeMessage(message);
 
-    message = LDAPMessage.decode(r.readElement().decodeAsSequence());
+    message = r.readMessage();
     BindResponseProtocolOp bindResponse = message.getBindResponseProtocolOp();
     assertEquals(bindResponse.getResultCode(), LDAPResultCode.SUCCESS);
 
@@ -99,9 +102,9 @@
     ExtendedRequestProtocolOp extendedRequest =
          new ExtendedRequestProtocolOp(OID_GET_CONNECTION_ID_EXTOP);
     message = new LDAPMessage(2, extendedRequest);
-    w.writeElement(message.encode());
+    w.writeMessage(message);
 
-    message = LDAPMessage.decode(r.readElement().decodeAsSequence());
+    message = r.readMessage();
     ExtendedResponseProtocolOp extendedResponse =
          message.getExtendedResponseProtocolOp();
     assertEquals(extendedResponse.getResultCode(), LDAPResultCode.SUCCESS);
@@ -133,7 +136,7 @@
 
     // Make sure that we get a notice of disconnection on the initial
     // connection.
-    message = LDAPMessage.decode(r.readElement().decodeAsSequence());
+    message = r.readMessage();
     extendedResponse = message.getExtendedResponseProtocolOp();
     assertEquals(extendedResponse.getOID(),
                  LDAPConstants.OID_NOTICE_OF_DISCONNECTION);
@@ -159,16 +162,18 @@
   {
     // Establish a connection to the server, bind, and get the connection ID.
     Socket s = new Socket("127.0.0.1", TestCaseUtils.getServerLdapPort());
-    ASN1Reader r = new ASN1Reader(s);
-    ASN1Writer w = new ASN1Writer(s);
+    org.opends.server.tools.LDAPReader r =
+        new org.opends.server.tools.LDAPReader(s);
+    org.opends.server.tools.LDAPWriter w =
+        new org.opends.server.tools.LDAPWriter(s);
 
     BindRequestProtocolOp bindRequest =
-         new BindRequestProtocolOp(new ASN1OctetString("cn=Directory Manager"),
-                                   3, new ASN1OctetString("password"));
+         new BindRequestProtocolOp(ByteString.valueOf("cn=Directory Manager"),
+                                   3, ByteString.valueOf("password"));
     LDAPMessage message = new LDAPMessage(1, bindRequest);
-    w.writeElement(message.encode());
+    w.writeMessage(message);
 
-    message = LDAPMessage.decode(r.readElement().decodeAsSequence());
+    message = r.readMessage();
     BindResponseProtocolOp bindResponse = message.getBindResponseProtocolOp();
     assertEquals(bindResponse.getResultCode(), LDAPResultCode.SUCCESS);
 
@@ -176,9 +181,9 @@
     ExtendedRequestProtocolOp extendedRequest =
          new ExtendedRequestProtocolOp(OID_GET_CONNECTION_ID_EXTOP);
     message = new LDAPMessage(2, extendedRequest);
-    w.writeElement(message.encode());
+    w.writeMessage(message);
 
-    message = LDAPMessage.decode(r.readElement().decodeAsSequence());
+    message = r.readMessage();
     ExtendedResponseProtocolOp extendedResponse =
          message.getExtendedResponseProtocolOp();
     assertEquals(extendedResponse.getResultCode(), LDAPResultCode.SUCCESS);
@@ -208,7 +213,7 @@
 
     // Make sure that the client connection has been closed with no notice of
     // disconnection.
-    assertNull(r.readElement());
+    assertNull(r.readMessage());
 
     try
     {
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/tasks/DummyTask.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/tasks/DummyTask.java
index 84f71cd..d5a2c92 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/tasks/DummyTask.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/tasks/DummyTask.java
@@ -82,7 +82,7 @@
         {
           for (AttributeValue v : a)
           {
-            sleepTime = Long.parseLong(v.getStringValue());
+            sleepTime = Long.parseLong(v.getValue().toString());
           }
         }
       }
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/tools/LDAPAuthenticationHandlerTestCase.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/tools/LDAPAuthenticationHandlerTestCase.java
index aebf22d..a0828ef 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/tools/LDAPAuthenticationHandlerTestCase.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/tools/LDAPAuthenticationHandlerTestCase.java
@@ -49,12 +49,9 @@
 import org.opends.server.core.AddOperation;
 import org.opends.server.core.DirectoryServer;
 import org.opends.server.extensions.AnonymousSASLMechanismHandler;
-import org.opends.server.protocols.asn1.ASN1OctetString;
 import org.opends.server.protocols.internal.InternalClientConnection;
 import org.opends.server.protocols.ldap.LDAPControl;
-import org.opends.server.types.Entry;
-import org.opends.server.types.LDAPException;
-import org.opends.server.types.ResultCode;
+import org.opends.server.types.*;
 
 import static org.testng.Assert.*;
 
@@ -179,13 +176,13 @@
     LDAPWriter w = new LDAPWriter(s);
 
     AtomicInteger          messageID        = new AtomicInteger(1);
-    ArrayList<LDAPControl> requestControls  = new ArrayList<LDAPControl>();
-    ArrayList<LDAPControl> responseControls = new ArrayList<LDAPControl>();
+    ArrayList<Control> requestControls  = new ArrayList<Control>();
+    ArrayList<Control> responseControls = new ArrayList<Control>();
 
     LDAPAuthenticationHandler authHandler =
          new LDAPAuthenticationHandler(r, w, "localhost", messageID);
-    authHandler.doSimpleBind(3, new ASN1OctetString("cn=Directory Manager"),
-                             new ASN1OctetString("password"), requestControls,
+    authHandler.doSimpleBind(3, ByteString.valueOf("cn=Directory Manager"),
+                             ByteString.valueOf("password"), requestControls,
                              responseControls);
 
     s.close();
@@ -208,8 +205,8 @@
     LDAPWriter w = new LDAPWriter(s);
 
     AtomicInteger          messageID        = new AtomicInteger(1);
-    ArrayList<LDAPControl> requestControls  = new ArrayList<LDAPControl>();
-    ArrayList<LDAPControl> responseControls = new ArrayList<LDAPControl>();
+    ArrayList<Control> requestControls  = new ArrayList<Control>();
+    ArrayList<Control> responseControls = new ArrayList<Control>();
 
     LDAPAuthenticationHandler authHandler =
          new LDAPAuthenticationHandler(r, w, "localhost", messageID);
@@ -235,12 +232,12 @@
     LDAPWriter w = new LDAPWriter(s);
 
     AtomicInteger          messageID        = new AtomicInteger(1);
-    ArrayList<LDAPControl> requestControls  = new ArrayList<LDAPControl>();
-    ArrayList<LDAPControl> responseControls = new ArrayList<LDAPControl>();
+    ArrayList<Control> requestControls  = new ArrayList<Control>();
+    ArrayList<Control> responseControls = new ArrayList<Control>();
 
     LDAPAuthenticationHandler authHandler =
          new LDAPAuthenticationHandler(r, w, "localhost", messageID);
-    authHandler.doSimpleBind(3, new ASN1OctetString(), new ASN1OctetString(),
+    authHandler.doSimpleBind(3, ByteString.empty(), ByteString.empty(),
                              requestControls, responseControls);
 
     s.close();
@@ -263,16 +260,16 @@
     LDAPWriter w = new LDAPWriter(s);
 
     AtomicInteger          messageID        = new AtomicInteger(1);
-    ArrayList<LDAPControl> requestControls  = new ArrayList<LDAPControl>();
-    ArrayList<LDAPControl> responseControls = new ArrayList<LDAPControl>();
+    ArrayList<Control> requestControls  = new ArrayList<Control>();
+    ArrayList<Control> responseControls = new ArrayList<Control>();
 
     LDAPAuthenticationHandler authHandler =
          new LDAPAuthenticationHandler(r, w, "localhost", messageID);
 
     try
     {
-      authHandler.doSimpleBind(3, new ASN1OctetString("cn=Directory Manager"),
-                               new ASN1OctetString(), requestControls,
+      authHandler.doSimpleBind(3, ByteString.valueOf("cn=Directory Manager"),
+                               ByteString.empty(), requestControls,
                                responseControls);
     }
     finally
@@ -298,16 +295,16 @@
     LDAPWriter w = new LDAPWriter(s);
 
     AtomicInteger          messageID        = new AtomicInteger(1);
-    ArrayList<LDAPControl> requestControls  = new ArrayList<LDAPControl>();
-    ArrayList<LDAPControl> responseControls = new ArrayList<LDAPControl>();
+    ArrayList<Control> requestControls  = new ArrayList<Control>();
+    ArrayList<Control> responseControls = new ArrayList<Control>();
 
     LDAPAuthenticationHandler authHandler =
          new LDAPAuthenticationHandler(r, w, "localhost", messageID);
 
     try
     {
-      authHandler.doSimpleBind(3, new ASN1OctetString("cn=Directory Manager"),
-                               new ASN1OctetString("wrongPassword"),
+      authHandler.doSimpleBind(3, ByteString.valueOf("cn=Directory Manager"),
+                               ByteString.valueOf("wrongPassword"),
                                requestControls, responseControls);
     }
     finally
@@ -333,15 +330,15 @@
     LDAPWriter w = new LDAPWriter(s);
 
     AtomicInteger          messageID        = new AtomicInteger(1);
-    ArrayList<LDAPControl> requestControls  = new ArrayList<LDAPControl>();
-    ArrayList<LDAPControl> responseControls = new ArrayList<LDAPControl>();
+    ArrayList<Control> requestControls  = new ArrayList<Control>();
+    ArrayList<Control> responseControls = new ArrayList<Control>();
 
-    requestControls.add(new LDAPControl(new PasswordPolicyRequestControl()));
+    requestControls.add(new PasswordPolicyRequestControl());
 
     LDAPAuthenticationHandler authHandler =
          new LDAPAuthenticationHandler(r, w, "localhost", messageID);
-    authHandler.doSimpleBind(3, new ASN1OctetString("cn=Directory Manager"),
-                             new ASN1OctetString("password"),
+    authHandler.doSimpleBind(3, ByteString.valueOf("cn=Directory Manager"),
+                             ByteString.valueOf("password"),
                              requestControls, responseControls);
 
     s.close();
@@ -363,8 +360,8 @@
     LDAPWriter w = new LDAPWriter(s);
 
     AtomicInteger          messageID        = new AtomicInteger(1);
-    ArrayList<LDAPControl> requestControls  = new ArrayList<LDAPControl>();
-    ArrayList<LDAPControl> responseControls = new ArrayList<LDAPControl>();
+    ArrayList<Control> requestControls  = new ArrayList<Control>();
+    ArrayList<Control> responseControls = new ArrayList<Control>();
 
     LinkedHashMap<String,List<String>> saslProperties =
          new LinkedHashMap<String,List<String>>();
@@ -399,8 +396,8 @@
     LDAPWriter w = new LDAPWriter(s);
 
     AtomicInteger          messageID        = new AtomicInteger(1);
-    ArrayList<LDAPControl> requestControls  = new ArrayList<LDAPControl>();
-    ArrayList<LDAPControl> responseControls = new ArrayList<LDAPControl>();
+    ArrayList<Control> requestControls  = new ArrayList<Control>();
+    ArrayList<Control> responseControls = new ArrayList<Control>();
 
     LinkedHashMap<String,List<String>> saslProperties =
          new LinkedHashMap<String,List<String>>();
@@ -435,8 +432,8 @@
     LDAPWriter w = new LDAPWriter(s);
 
     AtomicInteger          messageID        = new AtomicInteger(1);
-    ArrayList<LDAPControl> requestControls  = new ArrayList<LDAPControl>();
-    ArrayList<LDAPControl> responseControls = new ArrayList<LDAPControl>();
+    ArrayList<Control> requestControls  = new ArrayList<Control>();
+    ArrayList<Control> responseControls = new ArrayList<Control>();
 
     LinkedHashMap<String,List<String>> saslProperties =
          new LinkedHashMap<String,List<String>>();
@@ -472,8 +469,8 @@
     LDAPWriter w = new LDAPWriter(s);
 
     AtomicInteger          messageID        = new AtomicInteger(1);
-    ArrayList<LDAPControl> requestControls  = new ArrayList<LDAPControl>();
-    ArrayList<LDAPControl> responseControls = new ArrayList<LDAPControl>();
+    ArrayList<Control> requestControls  = new ArrayList<Control>();
+    ArrayList<Control> responseControls = new ArrayList<Control>();
 
     LinkedHashMap<String,List<String>> saslProperties =
          new LinkedHashMap<String,List<String>>();
@@ -486,7 +483,7 @@
 
     try
     {
-      authHandler.doSASLBind(new ASN1OctetString(), new ASN1OctetString(),
+      authHandler.doSASLBind(ByteString.empty(), ByteString.empty(),
                              "ANONYMOUS", saslProperties, requestControls,
                              responseControls);
     }
@@ -516,8 +513,8 @@
     LDAPWriter w = new LDAPWriter(s);
 
     AtomicInteger          messageID        = new AtomicInteger(1);
-    ArrayList<LDAPControl> requestControls  = new ArrayList<LDAPControl>();
-    ArrayList<LDAPControl> responseControls = new ArrayList<LDAPControl>();
+    ArrayList<Control> requestControls  = new ArrayList<Control>();
+    ArrayList<Control> responseControls = new ArrayList<Control>();
 
     LinkedHashMap<String,List<String>> saslProperties =
          new LinkedHashMap<String,List<String>>();
@@ -528,7 +525,7 @@
     LDAPAuthenticationHandler authHandler =
          new LDAPAuthenticationHandler(r, w, "localhost", messageID);
 
-    authHandler.doSASLBind(new ASN1OctetString(), new ASN1OctetString(),
+    authHandler.doSASLBind(ByteString.empty(), ByteString.empty(),
                            "ANONYMOUS", saslProperties, requestControls,
                            responseControls);
     s.close();
@@ -555,8 +552,8 @@
     LDAPWriter w = new LDAPWriter(s);
 
     AtomicInteger          messageID        = new AtomicInteger(1);
-    ArrayList<LDAPControl> requestControls  = new ArrayList<LDAPControl>();
-    ArrayList<LDAPControl> responseControls = new ArrayList<LDAPControl>();
+    ArrayList<Control> requestControls  = new ArrayList<Control>();
+    ArrayList<Control> responseControls = new ArrayList<Control>();
 
     LinkedHashMap<String,List<String>> saslProperties =
          new LinkedHashMap<String,List<String>>();
@@ -564,7 +561,7 @@
     LDAPAuthenticationHandler authHandler =
          new LDAPAuthenticationHandler(r, w, "localhost", messageID);
 
-    authHandler.doSASLBind(new ASN1OctetString(), new ASN1OctetString(),
+    authHandler.doSASLBind(ByteString.empty(), ByteString.empty(),
                            "ANONYMOUS", saslProperties, requestControls,
                            responseControls);
     s.close();
@@ -592,8 +589,8 @@
     LDAPWriter w = new LDAPWriter(s);
 
     AtomicInteger          messageID        = new AtomicInteger(1);
-    ArrayList<LDAPControl> requestControls  = new ArrayList<LDAPControl>();
-    ArrayList<LDAPControl> responseControls = new ArrayList<LDAPControl>();
+    ArrayList<Control> requestControls  = new ArrayList<Control>();
+    ArrayList<Control> responseControls = new ArrayList<Control>();
 
     LinkedHashMap<String,List<String>> saslProperties =
          new LinkedHashMap<String,List<String>>();
@@ -607,7 +604,7 @@
 
     try
     {
-      authHandler.doSASLBind(new ASN1OctetString(), new ASN1OctetString(),
+      authHandler.doSASLBind(ByteString.empty(), ByteString.empty(),
                              "ANONYMOUS", saslProperties, requestControls,
                              responseControls);
     }
@@ -639,8 +636,8 @@
     LDAPWriter w = new LDAPWriter(s);
 
     AtomicInteger          messageID        = new AtomicInteger(1);
-    ArrayList<LDAPControl> requestControls  = new ArrayList<LDAPControl>();
-    ArrayList<LDAPControl> responseControls = new ArrayList<LDAPControl>();
+    ArrayList<Control> requestControls  = new ArrayList<Control>();
+    ArrayList<Control> responseControls = new ArrayList<Control>();
 
     LinkedHashMap<String,List<String>> saslProperties =
          new LinkedHashMap<String,List<String>>();
@@ -653,7 +650,7 @@
 
     try
     {
-      authHandler.doSASLBind(new ASN1OctetString(), new ASN1OctetString(),
+      authHandler.doSASLBind(ByteString.empty(), ByteString.empty(),
                              "ANONYMOUS", saslProperties, requestControls,
                              responseControls);
     }
@@ -685,10 +682,10 @@
     LDAPWriter w = new LDAPWriter(s);
 
     AtomicInteger          messageID        = new AtomicInteger(1);
-    ArrayList<LDAPControl> requestControls  = new ArrayList<LDAPControl>();
-    ArrayList<LDAPControl> responseControls = new ArrayList<LDAPControl>();
+    ArrayList<Control> requestControls  = new ArrayList<Control>();
+    ArrayList<Control> responseControls = new ArrayList<Control>();
 
-    requestControls.add(new LDAPControl(new PasswordPolicyRequestControl()));
+    requestControls.add(new PasswordPolicyRequestControl());
 
     LinkedHashMap<String,List<String>> saslProperties =
          new LinkedHashMap<String,List<String>>();
@@ -699,7 +696,7 @@
     LDAPAuthenticationHandler authHandler =
          new LDAPAuthenticationHandler(r, w, "localhost", messageID);
 
-    authHandler.doSASLBind(new ASN1OctetString(), new ASN1OctetString(),
+    authHandler.doSASLBind(ByteString.empty(), ByteString.empty(),
                            "ANONYMOUS", saslProperties, requestControls,
                            responseControls);
     s.close();
@@ -752,8 +749,8 @@
     LDAPWriter w = new LDAPWriter(s);
 
     AtomicInteger          messageID        = new AtomicInteger(1);
-    ArrayList<LDAPControl> requestControls  = new ArrayList<LDAPControl>();
-    ArrayList<LDAPControl> responseControls = new ArrayList<LDAPControl>();
+    ArrayList<Control> requestControls  = new ArrayList<Control>();
+    ArrayList<Control> responseControls = new ArrayList<Control>();
 
     LinkedHashMap<String,List<String>> saslProperties =
          new LinkedHashMap<String,List<String>>();
@@ -766,8 +763,8 @@
 
     try
     {
-      authHandler.doSASLBind(new ASN1OctetString(),
-                             new ASN1OctetString("password"),
+      authHandler.doSASLBind(ByteString.empty(),
+                             ByteString.valueOf("password"),
                              "CRAM-MD5", saslProperties, requestControls,
                              responseControls);
     }
@@ -819,8 +816,8 @@
     LDAPWriter w = new LDAPWriter(s);
 
     AtomicInteger          messageID        = new AtomicInteger(1);
-    ArrayList<LDAPControl> requestControls  = new ArrayList<LDAPControl>();
-    ArrayList<LDAPControl> responseControls = new ArrayList<LDAPControl>();
+    ArrayList<Control> requestControls  = new ArrayList<Control>();
+    ArrayList<Control> responseControls = new ArrayList<Control>();
 
     LinkedHashMap<String,List<String>> saslProperties =
          new LinkedHashMap<String,List<String>>();
@@ -831,8 +828,8 @@
     LDAPAuthenticationHandler authHandler =
          new LDAPAuthenticationHandler(r, w, "localhost", messageID);
 
-    authHandler.doSASLBind(new ASN1OctetString(),
-                           new ASN1OctetString("password"),
+    authHandler.doSASLBind(ByteString.empty(),
+                           ByteString.valueOf("password"),
                            "CRAM-MD5", saslProperties, requestControls,
                            responseControls);
     s.close();
@@ -857,8 +854,8 @@
     LDAPWriter w = new LDAPWriter(s);
 
     AtomicInteger          messageID        = new AtomicInteger(1);
-    ArrayList<LDAPControl> requestControls  = new ArrayList<LDAPControl>();
-    ArrayList<LDAPControl> responseControls = new ArrayList<LDAPControl>();
+    ArrayList<Control> requestControls  = new ArrayList<Control>();
+    ArrayList<Control> responseControls = new ArrayList<Control>();
 
     LinkedHashMap<String,List<String>> saslProperties =
          new LinkedHashMap<String,List<String>>();
@@ -871,8 +868,8 @@
 
     try
     {
-      authHandler.doSASLBind(new ASN1OctetString(),
-                             new ASN1OctetString("password"),
+      authHandler.doSASLBind(ByteString.empty(),
+                             ByteString.valueOf("password"),
                              "CRAM-MD5", saslProperties, requestControls,
                              responseControls);
     }
@@ -901,8 +898,8 @@
     LDAPWriter w = new LDAPWriter(s);
 
     AtomicInteger          messageID        = new AtomicInteger(1);
-    ArrayList<LDAPControl> requestControls  = new ArrayList<LDAPControl>();
-    ArrayList<LDAPControl> responseControls = new ArrayList<LDAPControl>();
+    ArrayList<Control> requestControls  = new ArrayList<Control>();
+    ArrayList<Control> responseControls = new ArrayList<Control>();
 
     LinkedHashMap<String,List<String>> saslProperties =
          new LinkedHashMap<String,List<String>>();
@@ -915,8 +912,8 @@
 
     try
     {
-      authHandler.doSASLBind(new ASN1OctetString(),
-                             new ASN1OctetString("password"),
+      authHandler.doSASLBind(ByteString.empty(),
+                             ByteString.valueOf("password"),
                              "CRAM-MD5", saslProperties, requestControls,
                              responseControls);
     }
@@ -967,8 +964,8 @@
     LDAPWriter w = new LDAPWriter(s);
 
     AtomicInteger          messageID        = new AtomicInteger(1);
-    ArrayList<LDAPControl> requestControls  = new ArrayList<LDAPControl>();
-    ArrayList<LDAPControl> responseControls = new ArrayList<LDAPControl>();
+    ArrayList<Control> requestControls  = new ArrayList<Control>();
+    ArrayList<Control> responseControls = new ArrayList<Control>();
 
     LinkedHashMap<String,List<String>> saslProperties =
          new LinkedHashMap<String,List<String>>();
@@ -981,8 +978,8 @@
 
     try
     {
-      authHandler.doSASLBind(new ASN1OctetString(),
-                             new ASN1OctetString("invalidPassword"),
+      authHandler.doSASLBind(ByteString.empty(),
+                             ByteString.valueOf("invalidPassword"),
                              "CRAM-MD5", saslProperties, requestControls,
                              responseControls);
     }
@@ -1031,8 +1028,8 @@
     LDAPWriter w = new LDAPWriter(s);
 
     AtomicInteger          messageID        = new AtomicInteger(1);
-    ArrayList<LDAPControl> requestControls  = new ArrayList<LDAPControl>();
-    ArrayList<LDAPControl> responseControls = new ArrayList<LDAPControl>();
+    ArrayList<Control> requestControls  = new ArrayList<Control>();
+    ArrayList<Control> responseControls = new ArrayList<Control>();
 
     LinkedHashMap<String,List<String>> saslProperties =
          new LinkedHashMap<String,List<String>>();
@@ -1045,8 +1042,8 @@
 
     try
     {
-      authHandler.doSASLBind(new ASN1OctetString(),
-                             new ASN1OctetString("password"),
+      authHandler.doSASLBind(ByteString.empty(),
+                             ByteString.valueOf("password"),
                              "CRAM-MD5", saslProperties, requestControls,
                              responseControls);
     }
@@ -1073,8 +1070,8 @@
     LDAPWriter w = new LDAPWriter(s);
 
     AtomicInteger          messageID        = new AtomicInteger(1);
-    ArrayList<LDAPControl> requestControls  = new ArrayList<LDAPControl>();
-    ArrayList<LDAPControl> responseControls = new ArrayList<LDAPControl>();
+    ArrayList<Control> requestControls  = new ArrayList<Control>();
+    ArrayList<Control> responseControls = new ArrayList<Control>();
 
     LinkedHashMap<String,List<String>> saslProperties = null;
 
@@ -1083,8 +1080,8 @@
 
     try
     {
-      authHandler.doSASLBind(new ASN1OctetString(),
-                             new ASN1OctetString("password"),
+      authHandler.doSASLBind(ByteString.empty(),
+                             ByteString.valueOf("password"),
                              "CRAM-MD5", saslProperties, requestControls,
                              responseControls);
     }
@@ -1111,8 +1108,8 @@
     LDAPWriter w = new LDAPWriter(s);
 
     AtomicInteger          messageID        = new AtomicInteger(1);
-    ArrayList<LDAPControl> requestControls  = new ArrayList<LDAPControl>();
-    ArrayList<LDAPControl> responseControls = new ArrayList<LDAPControl>();
+    ArrayList<Control> requestControls  = new ArrayList<Control>();
+    ArrayList<Control> responseControls = new ArrayList<Control>();
 
     LinkedHashMap<String,List<String>> saslProperties =
          new LinkedHashMap<String,List<String>>();
@@ -1122,8 +1119,8 @@
 
     try
     {
-      authHandler.doSASLBind(new ASN1OctetString(),
-                             new ASN1OctetString("password"),
+      authHandler.doSASLBind(ByteString.empty(),
+                             ByteString.valueOf("password"),
                              "CRAM-MD5", saslProperties, requestControls,
                              responseControls);
     }
@@ -1152,8 +1149,8 @@
     LDAPWriter w = new LDAPWriter(s);
 
     AtomicInteger          messageID        = new AtomicInteger(1);
-    ArrayList<LDAPControl> requestControls  = new ArrayList<LDAPControl>();
-    ArrayList<LDAPControl> responseControls = new ArrayList<LDAPControl>();
+    ArrayList<Control> requestControls  = new ArrayList<Control>();
+    ArrayList<Control> responseControls = new ArrayList<Control>();
 
     LinkedHashMap<String,List<String>> saslProperties =
          new LinkedHashMap<String,List<String>>();
@@ -1167,8 +1164,8 @@
 
     try
     {
-      authHandler.doSASLBind(new ASN1OctetString(),
-                             new ASN1OctetString("password"),
+      authHandler.doSASLBind(ByteString.empty(),
+                             ByteString.valueOf("password"),
                              "CRAM-MD5", saslProperties, requestControls,
                              responseControls);
     }
@@ -1197,8 +1194,8 @@
     LDAPWriter w = new LDAPWriter(s);
 
     AtomicInteger          messageID        = new AtomicInteger(1);
-    ArrayList<LDAPControl> requestControls  = new ArrayList<LDAPControl>();
-    ArrayList<LDAPControl> responseControls = new ArrayList<LDAPControl>();
+    ArrayList<Control> requestControls  = new ArrayList<Control>();
+    ArrayList<Control> responseControls = new ArrayList<Control>();
 
     LinkedHashMap<String,List<String>> saslProperties =
          new LinkedHashMap<String,List<String>>();
@@ -1215,8 +1212,8 @@
 
     try
     {
-      authHandler.doSASLBind(new ASN1OctetString(),
-                             new ASN1OctetString("password"),
+      authHandler.doSASLBind(ByteString.empty(),
+                             ByteString.valueOf("password"),
                              "CRAM-MD5", saslProperties, requestControls,
                              responseControls);
     }
@@ -1268,10 +1265,10 @@
     LDAPWriter w = new LDAPWriter(s);
 
     AtomicInteger          messageID        = new AtomicInteger(1);
-    ArrayList<LDAPControl> requestControls  = new ArrayList<LDAPControl>();
-    ArrayList<LDAPControl> responseControls = new ArrayList<LDAPControl>();
+    ArrayList<Control> requestControls  = new ArrayList<Control>();
+    ArrayList<Control> responseControls = new ArrayList<Control>();
 
-    requestControls.add(new LDAPControl(new PasswordPolicyRequestControl()));
+    requestControls.add(new PasswordPolicyRequestControl());
 
     LinkedHashMap<String,List<String>> saslProperties =
          new LinkedHashMap<String,List<String>>();
@@ -1282,8 +1279,8 @@
     LDAPAuthenticationHandler authHandler =
          new LDAPAuthenticationHandler(r, w, "localhost", messageID);
 
-    authHandler.doSASLBind(new ASN1OctetString(),
-                           new ASN1OctetString("password"),
+    authHandler.doSASLBind(ByteString.empty(),
+                           ByteString.valueOf("password"),
                            "CRAM-MD5", saslProperties, requestControls,
                            responseControls);
     s.close();
@@ -1335,8 +1332,8 @@
     LDAPWriter w = new LDAPWriter(s);
 
     AtomicInteger          messageID        = new AtomicInteger(1);
-    ArrayList<LDAPControl> requestControls  = new ArrayList<LDAPControl>();
-    ArrayList<LDAPControl> responseControls = new ArrayList<LDAPControl>();
+    ArrayList<Control> requestControls  = new ArrayList<Control>();
+    ArrayList<Control> responseControls = new ArrayList<Control>();
 
     LinkedHashMap<String,List<String>> saslProperties =
          new LinkedHashMap<String,List<String>>();
@@ -1353,8 +1350,8 @@
 
     try
     {
-      authHandler.doSASLBind(new ASN1OctetString(),
-                             new ASN1OctetString("password"),
+      authHandler.doSASLBind(ByteString.empty(),
+                             ByteString.valueOf("password"),
                              "DIGEST-MD5", saslProperties, requestControls,
                              responseControls);
     }
@@ -1407,8 +1404,8 @@
     LDAPWriter w = new LDAPWriter(s);
 
     AtomicInteger          messageID        = new AtomicInteger(1);
-    ArrayList<LDAPControl> requestControls  = new ArrayList<LDAPControl>();
-    ArrayList<LDAPControl> responseControls = new ArrayList<LDAPControl>();
+    ArrayList<Control> requestControls  = new ArrayList<Control>();
+    ArrayList<Control> responseControls = new ArrayList<Control>();
 
     LinkedHashMap<String,List<String>> saslProperties =
          new LinkedHashMap<String,List<String>>();
@@ -1420,8 +1417,8 @@
 
     LDAPAuthenticationHandler authHandler =
          new LDAPAuthenticationHandler(r, w, this.hostname, messageID);
-    authHandler.doSASLBind(new ASN1OctetString(),
-                           new ASN1OctetString("password"),
+    authHandler.doSASLBind(ByteString.empty(),
+                           ByteString.valueOf("password"),
                            "DIGEST-MD5", saslProperties, requestControls,
                            responseControls);
 
@@ -1469,8 +1466,8 @@
     LDAPWriter w = new LDAPWriter(s);
 
     AtomicInteger          messageID        = new AtomicInteger(1);
-    ArrayList<LDAPControl> requestControls  = new ArrayList<LDAPControl>();
-    ArrayList<LDAPControl> responseControls = new ArrayList<LDAPControl>();
+    ArrayList<Control> requestControls  = new ArrayList<Control>();
+    ArrayList<Control> responseControls = new ArrayList<Control>();
 
     LinkedHashMap<String,List<String>> saslProperties =
          new LinkedHashMap<String,List<String>>();
@@ -1479,11 +1476,11 @@
     saslProperties.put("authid", propList);
 
     propList = new ArrayList<String>();
- 
+
     LDAPAuthenticationHandler authHandler =
          new LDAPAuthenticationHandler(r, w, this.hostname, messageID);
-    authHandler.doSASLBind(new ASN1OctetString(),
-                           new ASN1OctetString("password"),
+    authHandler.doSASLBind(ByteString.empty(),
+                           ByteString.valueOf("password"),
                            "DIGEST-MD5", saslProperties, requestControls,
                            responseControls);
 
@@ -1507,8 +1504,8 @@
     LDAPWriter w = new LDAPWriter(s);
 
     AtomicInteger          messageID        = new AtomicInteger(1);
-    ArrayList<LDAPControl> requestControls  = new ArrayList<LDAPControl>();
-    ArrayList<LDAPControl> responseControls = new ArrayList<LDAPControl>();
+    ArrayList<Control> requestControls  = new ArrayList<Control>();
+    ArrayList<Control> responseControls = new ArrayList<Control>();
 
     LinkedHashMap<String,List<String>> saslProperties = null;
 
@@ -1517,8 +1514,8 @@
 
     try
     {
-      authHandler.doSASLBind(new ASN1OctetString(),
-                             new ASN1OctetString("password"),
+      authHandler.doSASLBind(ByteString.empty(),
+                             ByteString.valueOf("password"),
                              "DIGEST-MD5", saslProperties, requestControls,
                              responseControls);
     }
@@ -1545,8 +1542,8 @@
     LDAPWriter w = new LDAPWriter(s);
 
     AtomicInteger          messageID        = new AtomicInteger(1);
-    ArrayList<LDAPControl> requestControls  = new ArrayList<LDAPControl>();
-    ArrayList<LDAPControl> responseControls = new ArrayList<LDAPControl>();
+    ArrayList<Control> requestControls  = new ArrayList<Control>();
+    ArrayList<Control> responseControls = new ArrayList<Control>();
 
     LinkedHashMap<String,List<String>> saslProperties =
          new LinkedHashMap<String,List<String>>();
@@ -1556,8 +1553,8 @@
 
     try
     {
-      authHandler.doSASLBind(new ASN1OctetString(),
-                             new ASN1OctetString("password"),
+      authHandler.doSASLBind(ByteString.empty(),
+                             ByteString.valueOf("password"),
                              "DIGEST-MD5", saslProperties, requestControls,
                              responseControls);
     }
@@ -1584,8 +1581,8 @@
     LDAPWriter w = new LDAPWriter(s);
 
     AtomicInteger          messageID        = new AtomicInteger(1);
-    ArrayList<LDAPControl> requestControls  = new ArrayList<LDAPControl>();
-    ArrayList<LDAPControl> responseControls = new ArrayList<LDAPControl>();
+    ArrayList<Control> requestControls  = new ArrayList<Control>();
+    ArrayList<Control> responseControls = new ArrayList<Control>();
 
     LinkedHashMap<String,List<String>> saslProperties =
          new LinkedHashMap<String,List<String>>();
@@ -1598,8 +1595,8 @@
 
     try
     {
-      authHandler.doSASLBind(new ASN1OctetString(),
-                             new ASN1OctetString("password"),
+      authHandler.doSASLBind(ByteString.empty(),
+                             ByteString.valueOf("password"),
                              "DIGEST-MD5", saslProperties, requestControls,
                              responseControls);
     }
@@ -1626,8 +1623,8 @@
     LDAPWriter w = new LDAPWriter(s);
 
     AtomicInteger          messageID        = new AtomicInteger(1);
-    ArrayList<LDAPControl> requestControls  = new ArrayList<LDAPControl>();
-    ArrayList<LDAPControl> responseControls = new ArrayList<LDAPControl>();
+    ArrayList<Control> requestControls  = new ArrayList<Control>();
+    ArrayList<Control> responseControls = new ArrayList<Control>();
 
     LinkedHashMap<String,List<String>> saslProperties =
          new LinkedHashMap<String,List<String>>();
@@ -1641,8 +1638,8 @@
 
     try
     {
-      authHandler.doSASLBind(new ASN1OctetString(),
-                             new ASN1OctetString("password"),
+      authHandler.doSASLBind(ByteString.empty(),
+                             ByteString.valueOf("password"),
                              "DIGEST-MD5", saslProperties, requestControls,
                              responseControls);
     }
@@ -1669,8 +1666,8 @@
     LDAPWriter w = new LDAPWriter(s);
 
     AtomicInteger          messageID        = new AtomicInteger(1);
-    ArrayList<LDAPControl> requestControls  = new ArrayList<LDAPControl>();
-    ArrayList<LDAPControl> responseControls = new ArrayList<LDAPControl>();
+    ArrayList<Control> requestControls  = new ArrayList<Control>();
+    ArrayList<Control> responseControls = new ArrayList<Control>();
 
     LinkedHashMap<String,List<String>> saslProperties =
          new LinkedHashMap<String,List<String>>();
@@ -1683,8 +1680,8 @@
 
     try
     {
-      authHandler.doSASLBind(new ASN1OctetString(),
-                             new ASN1OctetString("password"),
+      authHandler.doSASLBind(ByteString.empty(),
+                             ByteString.valueOf("password"),
                              "DIGEST-MD5", saslProperties, requestControls,
                              responseControls);
     }
@@ -1711,8 +1708,8 @@
     LDAPWriter w = new LDAPWriter(s);
 
     AtomicInteger          messageID        = new AtomicInteger(1);
-    ArrayList<LDAPControl> requestControls  = new ArrayList<LDAPControl>();
-    ArrayList<LDAPControl> responseControls = new ArrayList<LDAPControl>();
+    ArrayList<Control> requestControls  = new ArrayList<Control>();
+    ArrayList<Control> responseControls = new ArrayList<Control>();
 
     LinkedHashMap<String,List<String>> saslProperties =
          new LinkedHashMap<String,List<String>>();
@@ -1731,8 +1728,8 @@
 
     try
     {
-      authHandler.doSASLBind(new ASN1OctetString(),
-                             new ASN1OctetString("password"),
+      authHandler.doSASLBind(ByteString.empty(),
+                             ByteString.valueOf("password"),
                              "DIGEST-MD5", saslProperties, requestControls,
                              responseControls);
     }
@@ -1783,8 +1780,8 @@
     LDAPWriter w = new LDAPWriter(s);
 
     AtomicInteger          messageID        = new AtomicInteger(1);
-    ArrayList<LDAPControl> requestControls  = new ArrayList<LDAPControl>();
-    ArrayList<LDAPControl> responseControls = new ArrayList<LDAPControl>();
+    ArrayList<Control> requestControls  = new ArrayList<Control>();
+    ArrayList<Control> responseControls = new ArrayList<Control>();
 
     LinkedHashMap<String,List<String>> saslProperties =
          new LinkedHashMap<String,List<String>>();
@@ -1799,8 +1796,8 @@
 
     LDAPAuthenticationHandler authHandler =
          new LDAPAuthenticationHandler(r, w, this.hostname, messageID);
-    authHandler.doSASLBind(new ASN1OctetString(),
-                           new ASN1OctetString("password"),
+    authHandler.doSASLBind(ByteString.empty(),
+                           ByteString.valueOf("password"),
                            "DIGEST-MD5", saslProperties, requestControls,
                            responseControls);
 
@@ -1825,8 +1822,8 @@
     LDAPWriter w = new LDAPWriter(s);
 
     AtomicInteger          messageID        = new AtomicInteger(1);
-    ArrayList<LDAPControl> requestControls  = new ArrayList<LDAPControl>();
-    ArrayList<LDAPControl> responseControls = new ArrayList<LDAPControl>();
+    ArrayList<Control> requestControls  = new ArrayList<Control>();
+    ArrayList<Control> responseControls = new ArrayList<Control>();
 
     LinkedHashMap<String,List<String>> saslProperties =
          new LinkedHashMap<String,List<String>>();
@@ -1848,8 +1845,8 @@
 
     try
     {
-      authHandler.doSASLBind(new ASN1OctetString(),
-                             new ASN1OctetString("password"),
+      authHandler.doSASLBind(ByteString.empty(),
+                             ByteString.valueOf("password"),
                              "DIGEST-MD5", saslProperties, requestControls,
                              responseControls);
     }
@@ -1877,8 +1874,8 @@
     LDAPWriter w = new LDAPWriter(s);
 
     AtomicInteger          messageID        = new AtomicInteger(1);
-    ArrayList<LDAPControl> requestControls  = new ArrayList<LDAPControl>();
-    ArrayList<LDAPControl> responseControls = new ArrayList<LDAPControl>();
+    ArrayList<Control> requestControls  = new ArrayList<Control>();
+    ArrayList<Control> responseControls = new ArrayList<Control>();
 
     LinkedHashMap<String,List<String>> saslProperties =
          new LinkedHashMap<String,List<String>>();
@@ -1900,8 +1897,8 @@
 
     try
     {
-      authHandler.doSASLBind(new ASN1OctetString(),
-                             new ASN1OctetString("password"),
+      authHandler.doSASLBind(ByteString.empty(),
+                             ByteString.valueOf("password"),
                              "DIGEST-MD5", saslProperties, requestControls,
                              responseControls);
     }
@@ -1928,8 +1925,8 @@
     LDAPWriter w = new LDAPWriter(s);
 
     AtomicInteger          messageID        = new AtomicInteger(1);
-    ArrayList<LDAPControl> requestControls  = new ArrayList<LDAPControl>();
-    ArrayList<LDAPControl> responseControls = new ArrayList<LDAPControl>();
+    ArrayList<Control> requestControls  = new ArrayList<Control>();
+    ArrayList<Control> responseControls = new ArrayList<Control>();
 
     LinkedHashMap<String,List<String>> saslProperties =
          new LinkedHashMap<String,List<String>>();
@@ -1951,8 +1948,8 @@
 
     try
     {
-      authHandler.doSASLBind(new ASN1OctetString(),
-                             new ASN1OctetString("password"),
+      authHandler.doSASLBind(ByteString.empty(),
+                             ByteString.valueOf("password"),
                              "DIGEST-MD5", saslProperties, requestControls,
                              responseControls);
     }
@@ -1979,8 +1976,8 @@
     LDAPWriter w = new LDAPWriter(s);
 
     AtomicInteger          messageID        = new AtomicInteger(1);
-    ArrayList<LDAPControl> requestControls  = new ArrayList<LDAPControl>();
-    ArrayList<LDAPControl> responseControls = new ArrayList<LDAPControl>();
+    ArrayList<Control> requestControls  = new ArrayList<Control>();
+    ArrayList<Control> responseControls = new ArrayList<Control>();
 
     LinkedHashMap<String,List<String>> saslProperties =
          new LinkedHashMap<String,List<String>>();
@@ -2004,8 +2001,8 @@
 
     try
     {
-      authHandler.doSASLBind(new ASN1OctetString(),
-                             new ASN1OctetString("password"),
+      authHandler.doSASLBind(ByteString.empty(),
+                             ByteString.valueOf("password"),
                              "DIGEST-MD5", saslProperties, requestControls,
                              responseControls);
     }
@@ -2032,8 +2029,8 @@
     LDAPWriter w = new LDAPWriter(s);
 
     AtomicInteger          messageID        = new AtomicInteger(1);
-    ArrayList<LDAPControl> requestControls  = new ArrayList<LDAPControl>();
-    ArrayList<LDAPControl> responseControls = new ArrayList<LDAPControl>();
+    ArrayList<Control> requestControls  = new ArrayList<Control>();
+    ArrayList<Control> responseControls = new ArrayList<Control>();
 
     LinkedHashMap<String,List<String>> saslProperties =
          new LinkedHashMap<String,List<String>>();
@@ -2056,8 +2053,8 @@
 
     try
     {
-      authHandler.doSASLBind(new ASN1OctetString(),
-                             new ASN1OctetString("password"),
+      authHandler.doSASLBind(ByteString.empty(),
+                             ByteString.valueOf("password"),
                              "DIGEST-MD5", saslProperties, requestControls,
                              responseControls);
     }
@@ -2084,8 +2081,8 @@
     LDAPWriter w = new LDAPWriter(s);
 
     AtomicInteger          messageID        = new AtomicInteger(1);
-    ArrayList<LDAPControl> requestControls  = new ArrayList<LDAPControl>();
-    ArrayList<LDAPControl> responseControls = new ArrayList<LDAPControl>();
+    ArrayList<Control> requestControls  = new ArrayList<Control>();
+    ArrayList<Control> responseControls = new ArrayList<Control>();
 
     LinkedHashMap<String,List<String>> saslProperties =
          new LinkedHashMap<String,List<String>>();
@@ -2108,8 +2105,8 @@
 
     try
     {
-      authHandler.doSASLBind(new ASN1OctetString(),
-                             new ASN1OctetString("password"),
+      authHandler.doSASLBind(ByteString.empty(),
+                             ByteString.valueOf("password"),
                              "DIGEST-MD5", saslProperties, requestControls,
                              responseControls);
     }
@@ -2136,8 +2133,8 @@
     LDAPWriter w = new LDAPWriter(s);
 
     AtomicInteger          messageID        = new AtomicInteger(1);
-    ArrayList<LDAPControl> requestControls  = new ArrayList<LDAPControl>();
-    ArrayList<LDAPControl> responseControls = new ArrayList<LDAPControl>();
+    ArrayList<Control> requestControls  = new ArrayList<Control>();
+    ArrayList<Control> responseControls = new ArrayList<Control>();
 
     LinkedHashMap<String,List<String>> saslProperties =
          new LinkedHashMap<String,List<String>>();
@@ -2155,8 +2152,8 @@
 
     try
     {
-      authHandler.doSASLBind(new ASN1OctetString(),
-                             new ASN1OctetString("password"),
+      authHandler.doSASLBind(ByteString.empty(),
+                             ByteString.valueOf("password"),
                              "DIGEST-MD5", saslProperties, requestControls,
                              responseControls);
     }
@@ -2185,8 +2182,8 @@
     LDAPWriter w = new LDAPWriter(s);
 
     AtomicInteger          messageID        = new AtomicInteger(1);
-    ArrayList<LDAPControl> requestControls  = new ArrayList<LDAPControl>();
-    ArrayList<LDAPControl> responseControls = new ArrayList<LDAPControl>();
+    ArrayList<Control> requestControls  = new ArrayList<Control>();
+    ArrayList<Control> responseControls = new ArrayList<Control>();
 
     LinkedHashMap<String,List<String>> saslProperties =
          new LinkedHashMap<String,List<String>>();
@@ -2204,8 +2201,8 @@
 
     try
     {
-      authHandler.doSASLBind(new ASN1OctetString(),
-                             new ASN1OctetString("password"),
+      authHandler.doSASLBind(ByteString.empty(),
+                             ByteString.valueOf("password"),
                              "DIGEST-MD5", saslProperties, requestControls,
                              responseControls);
     }
@@ -2256,8 +2253,8 @@
     LDAPWriter w = new LDAPWriter(s);
 
     AtomicInteger          messageID        = new AtomicInteger(1);
-    ArrayList<LDAPControl> requestControls  = new ArrayList<LDAPControl>();
-    ArrayList<LDAPControl> responseControls = new ArrayList<LDAPControl>();
+    ArrayList<Control> requestControls  = new ArrayList<Control>();
+    ArrayList<Control> responseControls = new ArrayList<Control>();
 
     LinkedHashMap<String,List<String>> saslProperties =
          new LinkedHashMap<String,List<String>>();
@@ -2275,8 +2272,8 @@
 
     try
     {
-      authHandler.doSASLBind(new ASN1OctetString(),
-                             new ASN1OctetString("wrongPassword"),
+      authHandler.doSASLBind(ByteString.empty(),
+                             ByteString.valueOf("wrongPassword"),
                              "DIGEST-MD5", saslProperties, requestControls,
                              responseControls);
     }
@@ -2325,8 +2322,8 @@
     LDAPWriter w = new LDAPWriter(s);
 
     AtomicInteger          messageID        = new AtomicInteger(1);
-    ArrayList<LDAPControl> requestControls  = new ArrayList<LDAPControl>();
-    ArrayList<LDAPControl> responseControls = new ArrayList<LDAPControl>();
+    ArrayList<Control> requestControls  = new ArrayList<Control>();
+    ArrayList<Control> responseControls = new ArrayList<Control>();
 
     LinkedHashMap<String,List<String>> saslProperties =
          new LinkedHashMap<String,List<String>>();
@@ -2344,8 +2341,8 @@
 
     try
     {
-      authHandler.doSASLBind(new ASN1OctetString(),
-                             new ASN1OctetString("password"),
+      authHandler.doSASLBind(ByteString.empty(),
+                             ByteString.valueOf("password"),
                              "DIGEST-MD5", saslProperties, requestControls,
                              responseControls);
     }
@@ -2397,10 +2394,10 @@
     LDAPWriter w = new LDAPWriter(s);
 
     AtomicInteger          messageID        = new AtomicInteger(1);
-    ArrayList<LDAPControl> requestControls  = new ArrayList<LDAPControl>();
-    ArrayList<LDAPControl> responseControls = new ArrayList<LDAPControl>();
+    ArrayList<Control> requestControls  = new ArrayList<Control>();
+    ArrayList<Control> responseControls = new ArrayList<Control>();
 
-    requestControls.add(new LDAPControl(new PasswordPolicyRequestControl()));
+    requestControls.add(new PasswordPolicyRequestControl());
 
     LinkedHashMap<String,List<String>> saslProperties =
          new LinkedHashMap<String,List<String>>();
@@ -2412,8 +2409,8 @@
 
     LDAPAuthenticationHandler authHandler =
          new LDAPAuthenticationHandler(r, w, this.hostname, messageID);
-    authHandler.doSASLBind(new ASN1OctetString(),
-                           new ASN1OctetString("password"),
+    authHandler.doSASLBind(ByteString.empty(),
+                           ByteString.valueOf("password"),
                            "DIGEST-MD5", saslProperties, requestControls,
                            responseControls);
 
@@ -2475,8 +2472,8 @@
     LDAPWriter w = new LDAPWriter(s);
 
     AtomicInteger          messageID        = new AtomicInteger(1);
-    ArrayList<LDAPControl> requestControls  = new ArrayList<LDAPControl>();
-    ArrayList<LDAPControl> responseControls = new ArrayList<LDAPControl>();
+    ArrayList<Control> requestControls  = new ArrayList<Control>();
+    ArrayList<Control> responseControls = new ArrayList<Control>();
 
     LinkedHashMap<String,List<String>> saslProperties =
          new LinkedHashMap<String,List<String>>();
@@ -2486,7 +2483,7 @@
 
     try
     {
-      authHandler.doSASLBind(new ASN1OctetString(), null, "EXTERNAL",
+      authHandler.doSASLBind(ByteString.empty(), null, "EXTERNAL",
                              saslProperties, requestControls, responseControls);
     }
     finally
@@ -2546,15 +2543,15 @@
     LDAPWriter w = new LDAPWriter(s);
 
     AtomicInteger          messageID        = new AtomicInteger(1);
-    ArrayList<LDAPControl> requestControls  = new ArrayList<LDAPControl>();
-    ArrayList<LDAPControl> responseControls = new ArrayList<LDAPControl>();
+    ArrayList<Control> requestControls  = new ArrayList<Control>();
+    ArrayList<Control> responseControls = new ArrayList<Control>();
 
     LinkedHashMap<String,List<String>> saslProperties =
          new LinkedHashMap<String,List<String>>();
 
     LDAPAuthenticationHandler authHandler =
          new LDAPAuthenticationHandler(r, w, "localhost", messageID);
-    authHandler.doSASLBind(new ASN1OctetString(), null, "EXTERNAL",
+    authHandler.doSASLBind(ByteString.empty(), null, "EXTERNAL",
                            saslProperties, requestControls, responseControls);
 
     s.close();
@@ -2615,8 +2612,8 @@
     LDAPWriter w = new LDAPWriter(s);
 
     AtomicInteger          messageID        = new AtomicInteger(1);
-    ArrayList<LDAPControl> requestControls  = new ArrayList<LDAPControl>();
-    ArrayList<LDAPControl> responseControls = new ArrayList<LDAPControl>();
+    ArrayList<Control> requestControls  = new ArrayList<Control>();
+    ArrayList<Control> responseControls = new ArrayList<Control>();
 
     LinkedHashMap<String,List<String>> saslProperties =
          new LinkedHashMap<String,List<String>>();
@@ -2629,7 +2626,7 @@
 
     try
     {
-      authHandler.doSASLBind(new ASN1OctetString(), null, "EXTERNAL",
+      authHandler.doSASLBind(ByteString.empty(), null, "EXTERNAL",
                              saslProperties, requestControls, responseControls);
     }
     finally
@@ -2690,17 +2687,17 @@
     LDAPWriter w = new LDAPWriter(s);
 
     AtomicInteger          messageID        = new AtomicInteger(1);
-    ArrayList<LDAPControl> requestControls  = new ArrayList<LDAPControl>();
-    ArrayList<LDAPControl> responseControls = new ArrayList<LDAPControl>();
+    ArrayList<Control> requestControls  = new ArrayList<Control>();
+    ArrayList<Control> responseControls = new ArrayList<Control>();
 
-    requestControls.add(new LDAPControl(new PasswordPolicyRequestControl()));
+    requestControls.add(new PasswordPolicyRequestControl());
 
     LinkedHashMap<String,List<String>> saslProperties =
          new LinkedHashMap<String,List<String>>();
 
     LDAPAuthenticationHandler authHandler =
          new LDAPAuthenticationHandler(r, w, "localhost", messageID);
-    authHandler.doSASLBind(new ASN1OctetString(), null, "EXTERNAL",
+    authHandler.doSASLBind(ByteString.empty(), null, "EXTERNAL",
                            saslProperties, requestControls, responseControls);
 
     s.close();
@@ -2723,8 +2720,8 @@
     LDAPWriter w = new LDAPWriter(s);
 
     AtomicInteger          messageID        = new AtomicInteger(1);
-    ArrayList<LDAPControl> requestControls  = new ArrayList<LDAPControl>();
-    ArrayList<LDAPControl> responseControls = new ArrayList<LDAPControl>();
+    ArrayList<Control> requestControls  = new ArrayList<Control>();
+    ArrayList<Control> responseControls = new ArrayList<Control>();
 
     LinkedHashMap<String,List<String>> saslProperties = null;
 
@@ -2733,7 +2730,7 @@
 
     try
     {
-      authHandler.doSASLBind(new ASN1OctetString(), new ASN1OctetString(),
+      authHandler.doSASLBind(ByteString.empty(), ByteString.empty(),
                              "GSSAPI", saslProperties, requestControls,
                              responseControls);
     }
@@ -2760,8 +2757,8 @@
     LDAPWriter w = new LDAPWriter(s);
 
     AtomicInteger          messageID        = new AtomicInteger(1);
-    ArrayList<LDAPControl> requestControls  = new ArrayList<LDAPControl>();
-    ArrayList<LDAPControl> responseControls = new ArrayList<LDAPControl>();
+    ArrayList<Control> requestControls  = new ArrayList<Control>();
+    ArrayList<Control> responseControls = new ArrayList<Control>();
 
     LinkedHashMap<String,List<String>> saslProperties =
          new LinkedHashMap<String,List<String>>();
@@ -2771,7 +2768,7 @@
 
     try
     {
-      authHandler.doSASLBind(new ASN1OctetString(), new ASN1OctetString(),
+      authHandler.doSASLBind(ByteString.empty(), ByteString.empty(),
                              "GSSAPI", saslProperties, requestControls,
                              responseControls);
     }
@@ -2798,8 +2795,8 @@
     LDAPWriter w = new LDAPWriter(s);
 
     AtomicInteger          messageID        = new AtomicInteger(1);
-    ArrayList<LDAPControl> requestControls  = new ArrayList<LDAPControl>();
-    ArrayList<LDAPControl> responseControls = new ArrayList<LDAPControl>();
+    ArrayList<Control> requestControls  = new ArrayList<Control>();
+    ArrayList<Control> responseControls = new ArrayList<Control>();
 
     LinkedHashMap<String,List<String>> saslProperties =
          new LinkedHashMap<String,List<String>>();
@@ -2813,7 +2810,7 @@
 
     try
     {
-      authHandler.doSASLBind(new ASN1OctetString(), new ASN1OctetString(),
+      authHandler.doSASLBind(ByteString.empty(), ByteString.empty(),
                              "GSSAPI", saslProperties, requestControls,
                              responseControls);
     }
@@ -2840,8 +2837,8 @@
     LDAPWriter w = new LDAPWriter(s);
 
     AtomicInteger          messageID        = new AtomicInteger(1);
-    ArrayList<LDAPControl> requestControls  = new ArrayList<LDAPControl>();
-    ArrayList<LDAPControl> responseControls = new ArrayList<LDAPControl>();
+    ArrayList<Control> requestControls  = new ArrayList<Control>();
+    ArrayList<Control> responseControls = new ArrayList<Control>();
 
     LinkedHashMap<String,List<String>> saslProperties =
          new LinkedHashMap<String,List<String>>();
@@ -2856,7 +2853,7 @@
 
     try
     {
-      authHandler.doSASLBind(new ASN1OctetString(), new ASN1OctetString(),
+      authHandler.doSASLBind(ByteString.empty(), ByteString.empty(),
                              "GSSAPI", saslProperties, requestControls,
                              responseControls);
     }
@@ -2883,8 +2880,8 @@
     LDAPWriter w = new LDAPWriter(s);
 
     AtomicInteger          messageID        = new AtomicInteger(1);
-    ArrayList<LDAPControl> requestControls  = new ArrayList<LDAPControl>();
-    ArrayList<LDAPControl> responseControls = new ArrayList<LDAPControl>();
+    ArrayList<Control> requestControls  = new ArrayList<Control>();
+    ArrayList<Control> responseControls = new ArrayList<Control>();
 
     LinkedHashMap<String,List<String>> saslProperties =
          new LinkedHashMap<String,List<String>>();
@@ -2903,7 +2900,7 @@
 
     try
     {
-      authHandler.doSASLBind(new ASN1OctetString(), new ASN1OctetString(),
+      authHandler.doSASLBind(ByteString.empty(), ByteString.empty(),
                              "GSSAPI", saslProperties, requestControls,
                              responseControls);
     }
@@ -2930,8 +2927,8 @@
     LDAPWriter w = new LDAPWriter(s);
 
     AtomicInteger          messageID        = new AtomicInteger(1);
-    ArrayList<LDAPControl> requestControls  = new ArrayList<LDAPControl>();
-    ArrayList<LDAPControl> responseControls = new ArrayList<LDAPControl>();
+    ArrayList<Control> requestControls  = new ArrayList<Control>();
+    ArrayList<Control> responseControls = new ArrayList<Control>();
 
     LinkedHashMap<String,List<String>> saslProperties =
          new LinkedHashMap<String,List<String>>();
@@ -2950,7 +2947,7 @@
 
     try
     {
-      authHandler.doSASLBind(new ASN1OctetString(), new ASN1OctetString(),
+      authHandler.doSASLBind(ByteString.empty(), ByteString.empty(),
                              "GSSAPI", saslProperties, requestControls,
                              responseControls);
     }
@@ -2977,8 +2974,8 @@
     LDAPWriter w = new LDAPWriter(s);
 
     AtomicInteger          messageID        = new AtomicInteger(1);
-    ArrayList<LDAPControl> requestControls  = new ArrayList<LDAPControl>();
-    ArrayList<LDAPControl> responseControls = new ArrayList<LDAPControl>();
+    ArrayList<Control> requestControls  = new ArrayList<Control>();
+    ArrayList<Control> responseControls = new ArrayList<Control>();
 
     LinkedHashMap<String,List<String>> saslProperties =
          new LinkedHashMap<String,List<String>>();
@@ -2998,7 +2995,7 @@
 
     try
     {
-      authHandler.doSASLBind(new ASN1OctetString(), new ASN1OctetString(),
+      authHandler.doSASLBind(ByteString.empty(), ByteString.empty(),
                              "GSSAPI", saslProperties, requestControls,
                              responseControls);
     }
@@ -3026,8 +3023,8 @@
     LDAPWriter w = new LDAPWriter(s);
 
     AtomicInteger          messageID        = new AtomicInteger(1);
-    ArrayList<LDAPControl> requestControls  = new ArrayList<LDAPControl>();
-    ArrayList<LDAPControl> responseControls = new ArrayList<LDAPControl>();
+    ArrayList<Control> requestControls  = new ArrayList<Control>();
+    ArrayList<Control> responseControls = new ArrayList<Control>();
 
     LinkedHashMap<String,List<String>> saslProperties =
          new LinkedHashMap<String,List<String>>();
@@ -3045,7 +3042,7 @@
 
     try
     {
-      authHandler.doSASLBind(new ASN1OctetString(), new ASN1OctetString(),
+      authHandler.doSASLBind(ByteString.empty(), ByteString.empty(),
                              "GSSAPI", saslProperties, requestControls,
                              responseControls);
     }
@@ -3073,8 +3070,8 @@
     LDAPWriter w = new LDAPWriter(s);
 
     AtomicInteger          messageID        = new AtomicInteger(1);
-    ArrayList<LDAPControl> requestControls  = new ArrayList<LDAPControl>();
-    ArrayList<LDAPControl> responseControls = new ArrayList<LDAPControl>();
+    ArrayList<Control> requestControls  = new ArrayList<Control>();
+    ArrayList<Control> responseControls = new ArrayList<Control>();
 
     LinkedHashMap<String,List<String>> saslProperties =
          new LinkedHashMap<String,List<String>>();
@@ -3092,7 +3089,7 @@
 
     try
     {
-      authHandler.doSASLBind(new ASN1OctetString(), new ASN1OctetString(),
+      authHandler.doSASLBind(ByteString.empty(), ByteString.empty(),
                              "GSSAPI", saslProperties, requestControls,
                              responseControls);
     }
@@ -3119,8 +3116,8 @@
     LDAPWriter w = new LDAPWriter(s);
 
     AtomicInteger          messageID        = new AtomicInteger(1);
-    ArrayList<LDAPControl> requestControls  = new ArrayList<LDAPControl>();
-    ArrayList<LDAPControl> responseControls = new ArrayList<LDAPControl>();
+    ArrayList<Control> requestControls  = new ArrayList<Control>();
+    ArrayList<Control> responseControls = new ArrayList<Control>();
 
     LinkedHashMap<String,List<String>> saslProperties =
          new LinkedHashMap<String,List<String>>();
@@ -3138,7 +3135,7 @@
 
     try
     {
-      authHandler.doSASLBind(new ASN1OctetString(), new ASN1OctetString(),
+      authHandler.doSASLBind(ByteString.empty(), ByteString.empty(),
                              "GSSAPI", saslProperties, requestControls,
                              responseControls);
     }
@@ -3165,8 +3162,8 @@
     LDAPWriter w = new LDAPWriter(s);
 
     AtomicInteger          messageID        = new AtomicInteger(1);
-    ArrayList<LDAPControl> requestControls  = new ArrayList<LDAPControl>();
-    ArrayList<LDAPControl> responseControls = new ArrayList<LDAPControl>();
+    ArrayList<Control> requestControls  = new ArrayList<Control>();
+    ArrayList<Control> responseControls = new ArrayList<Control>();
 
     LinkedHashMap<String,List<String>> saslProperties =
          new LinkedHashMap<String,List<String>>();
@@ -3185,7 +3182,7 @@
 
     try
     {
-      authHandler.doSASLBind(new ASN1OctetString(), new ASN1OctetString(),
+      authHandler.doSASLBind(ByteString.empty(), ByteString.empty(),
                              "GSSAPI", saslProperties, requestControls,
                              responseControls);
     }
@@ -3212,8 +3209,8 @@
     LDAPWriter w = new LDAPWriter(s);
 
     AtomicInteger          messageID        = new AtomicInteger(1);
-    ArrayList<LDAPControl> requestControls  = new ArrayList<LDAPControl>();
-    ArrayList<LDAPControl> responseControls = new ArrayList<LDAPControl>();
+    ArrayList<Control> requestControls  = new ArrayList<Control>();
+    ArrayList<Control> responseControls = new ArrayList<Control>();
 
     LinkedHashMap<String,List<String>> saslProperties =
          new LinkedHashMap<String,List<String>>();
@@ -3231,7 +3228,7 @@
 
     try
     {
-      authHandler.doSASLBind(new ASN1OctetString(), new ASN1OctetString(),
+      authHandler.doSASLBind(ByteString.empty(), ByteString.empty(),
                              "GSSAPI", saslProperties, requestControls,
                              responseControls);
     }
@@ -3258,8 +3255,8 @@
     LDAPWriter w = new LDAPWriter(s);
 
     AtomicInteger          messageID        = new AtomicInteger(1);
-    ArrayList<LDAPControl> requestControls  = new ArrayList<LDAPControl>();
-    ArrayList<LDAPControl> responseControls = new ArrayList<LDAPControl>();
+    ArrayList<Control> requestControls  = new ArrayList<Control>();
+    ArrayList<Control> responseControls = new ArrayList<Control>();
 
     LinkedHashMap<String,List<String>> saslProperties =
          new LinkedHashMap<String,List<String>>();
@@ -3273,7 +3270,7 @@
 
     try
     {
-      authHandler.doSASLBind(new ASN1OctetString(), new ASN1OctetString(),
+      authHandler.doSASLBind(ByteString.empty(), ByteString.empty(),
                              "GSSAPI", saslProperties, requestControls,
                              responseControls);
     }
@@ -3327,8 +3324,8 @@
     LDAPWriter w = new LDAPWriter(s);
 
     AtomicInteger          messageID        = new AtomicInteger(1);
-    ArrayList<LDAPControl> requestControls  = new ArrayList<LDAPControl>();
-    ArrayList<LDAPControl> responseControls = new ArrayList<LDAPControl>();
+    ArrayList<Control> requestControls  = new ArrayList<Control>();
+    ArrayList<Control> responseControls = new ArrayList<Control>();
 
     LinkedHashMap<String,List<String>> saslProperties =
          new LinkedHashMap<String,List<String>>();
@@ -3341,8 +3338,8 @@
 
     try
     {
-      authHandler.doSASLBind(new ASN1OctetString(),
-                             new ASN1OctetString("password"), "PLAIN",
+      authHandler.doSASLBind(ByteString.empty(),
+                             ByteString.valueOf("password"), "PLAIN",
                              saslProperties, requestControls, responseControls);
     }
     finally
@@ -3392,8 +3389,8 @@
     LDAPWriter w = new LDAPWriter(s);
 
     AtomicInteger          messageID        = new AtomicInteger(1);
-    ArrayList<LDAPControl> requestControls  = new ArrayList<LDAPControl>();
-    ArrayList<LDAPControl> responseControls = new ArrayList<LDAPControl>();
+    ArrayList<Control> requestControls  = new ArrayList<Control>();
+    ArrayList<Control> responseControls = new ArrayList<Control>();
 
     LinkedHashMap<String,List<String>> saslProperties =
          new LinkedHashMap<String,List<String>>();
@@ -3403,8 +3400,8 @@
 
     LDAPAuthenticationHandler authHandler =
          new LDAPAuthenticationHandler(r, w, "localhost", messageID);
-    authHandler.doSASLBind(new ASN1OctetString(),
-                           new ASN1OctetString("password"), "PLAIN",
+    authHandler.doSASLBind(ByteString.empty(),
+                           ByteString.valueOf("password"), "PLAIN",
                            saslProperties, requestControls, responseControls);
 
     s.close();
@@ -3427,8 +3424,8 @@
     LDAPWriter w = new LDAPWriter(s);
 
     AtomicInteger          messageID        = new AtomicInteger(1);
-    ArrayList<LDAPControl> requestControls  = new ArrayList<LDAPControl>();
-    ArrayList<LDAPControl> responseControls = new ArrayList<LDAPControl>();
+    ArrayList<Control> requestControls  = new ArrayList<Control>();
+    ArrayList<Control> responseControls = new ArrayList<Control>();
 
     LinkedHashMap<String,List<String>> saslProperties = null;
 
@@ -3437,8 +3434,8 @@
 
     try
     {
-      authHandler.doSASLBind(new ASN1OctetString(),
-                             new ASN1OctetString("password"), "PLAIN",
+      authHandler.doSASLBind(ByteString.empty(),
+                             ByteString.valueOf("password"), "PLAIN",
                              saslProperties, requestControls, responseControls);
     }
     finally
@@ -3464,8 +3461,8 @@
     LDAPWriter w = new LDAPWriter(s);
 
     AtomicInteger          messageID        = new AtomicInteger(1);
-    ArrayList<LDAPControl> requestControls  = new ArrayList<LDAPControl>();
-    ArrayList<LDAPControl> responseControls = new ArrayList<LDAPControl>();
+    ArrayList<Control> requestControls  = new ArrayList<Control>();
+    ArrayList<Control> responseControls = new ArrayList<Control>();
 
     LinkedHashMap<String,List<String>> saslProperties =
          new LinkedHashMap<String,List<String>>();
@@ -3475,8 +3472,8 @@
 
     try
     {
-      authHandler.doSASLBind(new ASN1OctetString(),
-                             new ASN1OctetString("password"), "PLAIN",
+      authHandler.doSASLBind(ByteString.empty(),
+                             ByteString.valueOf("password"), "PLAIN",
                              saslProperties, requestControls, responseControls);
     }
     finally
@@ -3502,8 +3499,8 @@
     LDAPWriter w = new LDAPWriter(s);
 
     AtomicInteger          messageID        = new AtomicInteger(1);
-    ArrayList<LDAPControl> requestControls  = new ArrayList<LDAPControl>();
-    ArrayList<LDAPControl> responseControls = new ArrayList<LDAPControl>();
+    ArrayList<Control> requestControls  = new ArrayList<Control>();
+    ArrayList<Control> responseControls = new ArrayList<Control>();
 
     LinkedHashMap<String,List<String>> saslProperties =
          new LinkedHashMap<String,List<String>>();
@@ -3518,8 +3515,8 @@
 
     try
     {
-      authHandler.doSASLBind(new ASN1OctetString(),
-                             new ASN1OctetString("password"), "PLAIN",
+      authHandler.doSASLBind(ByteString.empty(),
+                             ByteString.valueOf("password"), "PLAIN",
                              saslProperties, requestControls, responseControls);
     }
     finally
@@ -3545,8 +3542,8 @@
     LDAPWriter w = new LDAPWriter(s);
 
     AtomicInteger          messageID        = new AtomicInteger(1);
-    ArrayList<LDAPControl> requestControls  = new ArrayList<LDAPControl>();
-    ArrayList<LDAPControl> responseControls = new ArrayList<LDAPControl>();
+    ArrayList<Control> requestControls  = new ArrayList<Control>();
+    ArrayList<Control> responseControls = new ArrayList<Control>();
 
     LinkedHashMap<String,List<String>> saslProperties =
          new LinkedHashMap<String,List<String>>();
@@ -3560,8 +3557,8 @@
 
     try
     {
-      authHandler.doSASLBind(new ASN1OctetString(),
-                             new ASN1OctetString("password"), "PLAIN",
+      authHandler.doSASLBind(ByteString.empty(),
+                             ByteString.valueOf("password"), "PLAIN",
                              saslProperties, requestControls, responseControls);
     }
     finally
@@ -3587,8 +3584,8 @@
     LDAPWriter w = new LDAPWriter(s);
 
     AtomicInteger          messageID        = new AtomicInteger(1);
-    ArrayList<LDAPControl> requestControls  = new ArrayList<LDAPControl>();
-    ArrayList<LDAPControl> responseControls = new ArrayList<LDAPControl>();
+    ArrayList<Control> requestControls  = new ArrayList<Control>();
+    ArrayList<Control> responseControls = new ArrayList<Control>();
 
     LinkedHashMap<String,List<String>> saslProperties =
          new LinkedHashMap<String,List<String>>();
@@ -3607,8 +3604,8 @@
 
     try
     {
-      authHandler.doSASLBind(new ASN1OctetString(),
-                             new ASN1OctetString("password"), "PLAIN",
+      authHandler.doSASLBind(ByteString.empty(),
+                             ByteString.valueOf("password"), "PLAIN",
                              saslProperties, requestControls, responseControls);
     }
     finally
@@ -3634,8 +3631,8 @@
     LDAPWriter w = new LDAPWriter(s);
 
     AtomicInteger          messageID        = new AtomicInteger(1);
-    ArrayList<LDAPControl> requestControls  = new ArrayList<LDAPControl>();
-    ArrayList<LDAPControl> responseControls = new ArrayList<LDAPControl>();
+    ArrayList<Control> requestControls  = new ArrayList<Control>();
+    ArrayList<Control> responseControls = new ArrayList<Control>();
 
     LinkedHashMap<String,List<String>> saslProperties =
          new LinkedHashMap<String,List<String>>();
@@ -3653,8 +3650,8 @@
 
     try
     {
-      authHandler.doSASLBind(new ASN1OctetString(),
-                             new ASN1OctetString("password"), "PLAIN",
+      authHandler.doSASLBind(ByteString.empty(),
+                             ByteString.valueOf("password"), "PLAIN",
                              saslProperties, requestControls, responseControls);
     }
     finally
@@ -3680,8 +3677,8 @@
     LDAPWriter w = new LDAPWriter(s);
 
     AtomicInteger          messageID        = new AtomicInteger(1);
-    ArrayList<LDAPControl> requestControls  = new ArrayList<LDAPControl>();
-    ArrayList<LDAPControl> responseControls = new ArrayList<LDAPControl>();
+    ArrayList<Control> requestControls  = new ArrayList<Control>();
+    ArrayList<Control> responseControls = new ArrayList<Control>();
 
     LinkedHashMap<String,List<String>> saslProperties =
          new LinkedHashMap<String,List<String>>();
@@ -3695,8 +3692,8 @@
 
     try
     {
-      authHandler.doSASLBind(new ASN1OctetString(),
-                             new ASN1OctetString("password"), "PLAIN",
+      authHandler.doSASLBind(ByteString.empty(),
+                             ByteString.valueOf("password"), "PLAIN",
                              saslProperties, requestControls, responseControls);
     }
     finally
@@ -3725,8 +3722,8 @@
     LDAPWriter w = new LDAPWriter(s);
 
     AtomicInteger          messageID        = new AtomicInteger(1);
-    ArrayList<LDAPControl> requestControls  = new ArrayList<LDAPControl>();
-    ArrayList<LDAPControl> responseControls = new ArrayList<LDAPControl>();
+    ArrayList<Control> requestControls  = new ArrayList<Control>();
+    ArrayList<Control> responseControls = new ArrayList<Control>();
 
     LinkedHashMap<String,List<String>> saslProperties =
          new LinkedHashMap<String,List<String>>();
@@ -3736,8 +3733,8 @@
 
     LDAPAuthenticationHandler authHandler =
          new LDAPAuthenticationHandler(r, w, "localhost", messageID);
-    authHandler.doSASLBind(new ASN1OctetString(),
-                           new ASN1OctetString("password"), "PLAIN",
+    authHandler.doSASLBind(ByteString.empty(),
+                           ByteString.valueOf("password"), "PLAIN",
                            saslProperties, requestControls, responseControls);
 
     s.close();
@@ -3782,8 +3779,8 @@
     LDAPWriter w = new LDAPWriter(s);
 
     AtomicInteger          messageID        = new AtomicInteger(1);
-    ArrayList<LDAPControl> requestControls  = new ArrayList<LDAPControl>();
-    ArrayList<LDAPControl> responseControls = new ArrayList<LDAPControl>();
+    ArrayList<Control> requestControls  = new ArrayList<Control>();
+    ArrayList<Control> responseControls = new ArrayList<Control>();
 
     LinkedHashMap<String,List<String>> saslProperties =
          new LinkedHashMap<String,List<String>>();
@@ -3793,8 +3790,8 @@
 
     LDAPAuthenticationHandler authHandler =
          new LDAPAuthenticationHandler(r, w, "localhost", messageID);
-    authHandler.doSASLBind(new ASN1OctetString(),
-                           new ASN1OctetString("wrongPassword"), "PLAIN",
+    authHandler.doSASLBind(ByteString.empty(),
+                           ByteString.valueOf("wrongPassword"), "PLAIN",
                            saslProperties, requestControls, responseControls);
 
     s.close();
@@ -3840,10 +3837,10 @@
     LDAPWriter w = new LDAPWriter(s);
 
     AtomicInteger          messageID        = new AtomicInteger(1);
-    ArrayList<LDAPControl> requestControls  = new ArrayList<LDAPControl>();
-    ArrayList<LDAPControl> responseControls = new ArrayList<LDAPControl>();
+    ArrayList<Control> requestControls  = new ArrayList<Control>();
+    ArrayList<Control> responseControls = new ArrayList<Control>();
 
-    requestControls.add(new LDAPControl(new PasswordPolicyRequestControl()));
+    requestControls.add(new PasswordPolicyRequestControl());
 
     LinkedHashMap<String,List<String>> saslProperties =
          new LinkedHashMap<String,List<String>>();
@@ -3853,8 +3850,8 @@
 
     LDAPAuthenticationHandler authHandler =
          new LDAPAuthenticationHandler(r, w, "localhost", messageID);
-    authHandler.doSASLBind(new ASN1OctetString(),
-                           new ASN1OctetString("password"), "PLAIN",
+    authHandler.doSASLBind(ByteString.empty(),
+                           ByteString.valueOf("password"), "PLAIN",
                            saslProperties, requestControls, responseControls);
 
     s.close();
@@ -3901,12 +3898,12 @@
     LDAPWriter w = new LDAPWriter(s);
 
     AtomicInteger          messageID        = new AtomicInteger(1);
-    ArrayList<LDAPControl> requestControls  = new ArrayList<LDAPControl>();
-    ArrayList<LDAPControl> responseControls = new ArrayList<LDAPControl>();
+    ArrayList<Control> requestControls  = new ArrayList<Control>();
+    ArrayList<Control> responseControls = new ArrayList<Control>();
 
     LDAPAuthenticationHandler authHandler =
          new LDAPAuthenticationHandler(r, w, "localhost", messageID);
-    authHandler.doSimpleBind(3, new ASN1OctetString(), new ASN1OctetString(),
+    authHandler.doSimpleBind(3, ByteString.empty(), ByteString.empty(),
                              requestControls, responseControls);
     assertNull(authHandler.requestAuthorizationIdentity());
 
@@ -3930,13 +3927,13 @@
     LDAPWriter w = new LDAPWriter(s);
 
     AtomicInteger          messageID        = new AtomicInteger(1);
-    ArrayList<LDAPControl> requestControls  = new ArrayList<LDAPControl>();
-    ArrayList<LDAPControl> responseControls = new ArrayList<LDAPControl>();
+    ArrayList<Control> requestControls  = new ArrayList<Control>();
+    ArrayList<Control> responseControls = new ArrayList<Control>();
 
     LDAPAuthenticationHandler authHandler =
          new LDAPAuthenticationHandler(r, w, "localhost", messageID);
-    authHandler.doSimpleBind(3, new ASN1OctetString("cn=Directory Manager"),
-                             new ASN1OctetString("password"), requestControls,
+    authHandler.doSimpleBind(3, ByteString.valueOf("cn=Directory Manager"),
+                             ByteString.valueOf("password"), requestControls,
                              responseControls);
     assertNotNull(authHandler.requestAuthorizationIdentity());
 
@@ -3982,13 +3979,13 @@
     LDAPWriter w = new LDAPWriter(s);
 
     AtomicInteger          messageID        = new AtomicInteger(1);
-    ArrayList<LDAPControl> requestControls  = new ArrayList<LDAPControl>();
-    ArrayList<LDAPControl> responseControls = new ArrayList<LDAPControl>();
+    ArrayList<Control> requestControls  = new ArrayList<Control>();
+    ArrayList<Control> responseControls = new ArrayList<Control>();
 
     LDAPAuthenticationHandler authHandler =
          new LDAPAuthenticationHandler(r, w, "localhost", messageID);
-    authHandler.doSimpleBind(3, new ASN1OctetString("uid=test.user,o=test"),
-                             new ASN1OctetString("password"), requestControls,
+    authHandler.doSimpleBind(3, ByteString.valueOf("uid=test.user,o=test"),
+                             ByteString.valueOf("password"), requestControls,
                              responseControls);
     assertNotNull(authHandler.requestAuthorizationIdentity());
 
@@ -4015,8 +4012,8 @@
     LDAPWriter w = new LDAPWriter(s);
 
     AtomicInteger          messageID        = new AtomicInteger(1);
-    ArrayList<LDAPControl> requestControls  = new ArrayList<LDAPControl>();
-    ArrayList<LDAPControl> responseControls = new ArrayList<LDAPControl>();
+    ArrayList<Control> requestControls  = new ArrayList<Control>();
+    ArrayList<Control> responseControls = new ArrayList<Control>();
 
     LinkedHashMap<String,List<String>> saslProperties =
          new LinkedHashMap<String,List<String>>();
@@ -4027,7 +4024,7 @@
     LDAPAuthenticationHandler authHandler =
          new LDAPAuthenticationHandler(r, w, "localhost", messageID);
 
-    authHandler.doSASLBind(new ASN1OctetString(), new ASN1OctetString(),
+    authHandler.doSASLBind(ByteString.empty(), ByteString.empty(),
                            "ANONYMOUS", saslProperties, requestControls,
                            responseControls);
     assertNull(authHandler.requestAuthorizationIdentity());
@@ -4077,8 +4074,8 @@
     LDAPWriter w = new LDAPWriter(s);
 
     AtomicInteger          messageID        = new AtomicInteger(1);
-    ArrayList<LDAPControl> requestControls  = new ArrayList<LDAPControl>();
-    ArrayList<LDAPControl> responseControls = new ArrayList<LDAPControl>();
+    ArrayList<Control> requestControls  = new ArrayList<Control>();
+    ArrayList<Control> responseControls = new ArrayList<Control>();
 
     LinkedHashMap<String,List<String>> saslProperties =
          new LinkedHashMap<String,List<String>>();
@@ -4089,8 +4086,8 @@
     LDAPAuthenticationHandler authHandler =
          new LDAPAuthenticationHandler(r, w, "localhost", messageID);
 
-    authHandler.doSASLBind(new ASN1OctetString(),
-                           new ASN1OctetString("password"),
+    authHandler.doSASLBind(ByteString.empty(),
+                           ByteString.valueOf("password"),
                            "CRAM-MD5", saslProperties, requestControls,
                            responseControls);
     assertNotNull(authHandler.requestAuthorizationIdentity());
@@ -4139,8 +4136,8 @@
     LDAPWriter w = new LDAPWriter(s);
 
     AtomicInteger          messageID        = new AtomicInteger(1);
-    ArrayList<LDAPControl> requestControls  = new ArrayList<LDAPControl>();
-    ArrayList<LDAPControl> responseControls = new ArrayList<LDAPControl>();
+    ArrayList<Control> requestControls  = new ArrayList<Control>();
+    ArrayList<Control> responseControls = new ArrayList<Control>();
 
     LinkedHashMap<String,List<String>> saslProperties =
          new LinkedHashMap<String,List<String>>();
@@ -4152,8 +4149,8 @@
 
     LDAPAuthenticationHandler authHandler =
          new LDAPAuthenticationHandler(r, w, this.hostname, messageID);
-    authHandler.doSASLBind(new ASN1OctetString(),
-                           new ASN1OctetString("password"),
+    authHandler.doSASLBind(ByteString.empty(),
+                           ByteString.valueOf("password"),
                            "DIGEST-MD5", saslProperties, requestControls,
                            responseControls);
     assertNotNull(authHandler.requestAuthorizationIdentity());
@@ -4211,15 +4208,15 @@
     LDAPWriter w = new LDAPWriter(s);
 
     AtomicInteger          messageID        = new AtomicInteger(1);
-    ArrayList<LDAPControl> requestControls  = new ArrayList<LDAPControl>();
-    ArrayList<LDAPControl> responseControls = new ArrayList<LDAPControl>();
+    ArrayList<Control> requestControls  = new ArrayList<Control>();
+    ArrayList<Control> responseControls = new ArrayList<Control>();
 
     LinkedHashMap<String,List<String>> saslProperties =
          new LinkedHashMap<String,List<String>>();
 
     LDAPAuthenticationHandler authHandler =
          new LDAPAuthenticationHandler(r, w, "localhost", messageID);
-    authHandler.doSASLBind(new ASN1OctetString(), null, "EXTERNAL",
+    authHandler.doSASLBind(ByteString.empty(), null, "EXTERNAL",
                            saslProperties, requestControls, responseControls);
     assertNotNull(authHandler.requestAuthorizationIdentity());
 
@@ -4265,8 +4262,8 @@
     LDAPWriter w = new LDAPWriter(s);
 
     AtomicInteger          messageID        = new AtomicInteger(1);
-    ArrayList<LDAPControl> requestControls  = new ArrayList<LDAPControl>();
-    ArrayList<LDAPControl> responseControls = new ArrayList<LDAPControl>();
+    ArrayList<Control> requestControls  = new ArrayList<Control>();
+    ArrayList<Control> responseControls = new ArrayList<Control>();
 
     LinkedHashMap<String,List<String>> saslProperties =
          new LinkedHashMap<String,List<String>>();
@@ -4276,8 +4273,8 @@
 
     LDAPAuthenticationHandler authHandler =
          new LDAPAuthenticationHandler(r, w, "localhost", messageID);
-    authHandler.doSASLBind(new ASN1OctetString(),
-                           new ASN1OctetString("password"), "PLAIN",
+    authHandler.doSASLBind(ByteString.empty(),
+                           ByteString.valueOf("password"), "PLAIN",
                            saslProperties, requestControls, responseControls);
     assertNotNull(authHandler.requestAuthorizationIdentity());
 
@@ -4291,6 +4288,6 @@
          this.hostname = "localhost";
       }
   }
-  
+
 }
 
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/types/AttributeBuilderTest.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/types/AttributeBuilderTest.java
index c0c7606..e53f664 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/types/AttributeBuilderTest.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/types/AttributeBuilderTest.java
@@ -160,7 +160,7 @@
             noOptions,
             new String[]
             {
-              cnValue.getStringValue()
+              cnValue.getValue().toString()
             }
         },
         {
@@ -171,7 +171,7 @@
             noOptions,
             new String[]
             {
-              cnValue.getStringValue()
+              cnValue.getValue().toString()
             }
         },
         {
@@ -182,7 +182,7 @@
             noOptions,
             new String[]
             {
-              cnValue.getStringValue()
+              cnValue.getValue().toString()
             }
         },
         {
@@ -193,7 +193,7 @@
             noOptions,
             new String[]
             {
-              cnValue.getStringValue()
+              cnValue.getValue().toString()
             }
         },
         {
@@ -204,7 +204,7 @@
             noOptions,
             new String[]
             {
-              cnValue.getStringValue()
+              cnValue.getValue().toString()
             }
         },
         {
@@ -215,7 +215,7 @@
             noOptions,
             new String[]
             {
-              cnValue.getStringValue()
+              cnValue.getValue().toString()
             }
         },
         {
@@ -605,7 +605,7 @@
     cnType = DirectoryServer.getAttributeType("cn");
     Assert.assertNotNull(cnType);
 
-    cnValue = new AttributeValue(cnType, "john doe");
+    cnValue = AttributeValues.create(cnType, "john doe");
   }
 
 
@@ -632,8 +632,8 @@
 
     Attribute a = builder.toAttribute();
     Assert.assertEquals(a.size(), 2);
-    Assert.assertTrue(a.contains(new AttributeValue(cnType, "value1")));
-    Assert.assertTrue(a.contains(new AttributeValue(cnType, "value2")));
+    Assert.assertTrue(a.contains(AttributeValues.create(cnType, "value1")));
+    Assert.assertTrue(a.contains(AttributeValues.create(cnType, "value2")));
   }
 
 
@@ -650,21 +650,21 @@
     AttributeBuilder builder = new AttributeBuilder(cnType);
 
     // Note duplicate values.
-    Assert.assertTrue(builder.addAll(Arrays.asList(new AttributeValue(cnType,
-        "value1"), new AttributeValue(cnType, "value1"), new AttributeValue(
+    Assert.assertTrue(builder.addAll(Arrays.asList(AttributeValues.create(cnType,
+        "value1"), AttributeValues.create(cnType, "value1"), AttributeValues.create(
         cnType, "value2"))));
     Assert.assertEquals(builder.size(), 2);
 
     // Add same values.
-    Assert.assertFalse(builder.addAll(Arrays.asList(new AttributeValue(cnType,
-        "value1"), new AttributeValue(cnType, "value1"), new AttributeValue(
+    Assert.assertFalse(builder.addAll(Arrays.asList(AttributeValues.create(cnType,
+        "value1"), AttributeValues.create(cnType, "value1"), AttributeValues.create(
         cnType, "value2"))));
     Assert.assertEquals(builder.size(), 2);
 
     Attribute a = builder.toAttribute();
     Assert.assertEquals(a.size(), 2);
-    Assert.assertTrue(a.contains(new AttributeValue(cnType, "value1")));
-    Assert.assertTrue(a.contains(new AttributeValue(cnType, "value2")));
+    Assert.assertTrue(a.contains(AttributeValues.create(cnType, "value1")));
+    Assert.assertTrue(a.contains(AttributeValues.create(cnType, "value2")));
   }
 
 
@@ -686,13 +686,13 @@
     Assert.assertFalse(builder.add(cnValue));
     Assert.assertEquals(builder.size(), 1);
 
-    Assert.assertTrue(builder.add(new AttributeValue(cnType, "jane doe")));
+    Assert.assertTrue(builder.add(AttributeValues.create(cnType, "jane doe")));
     Assert.assertEquals(builder.size(), 2);
 
     Attribute a = builder.toAttribute();
     Assert.assertEquals(a.size(), 2);
     Assert.assertTrue(a.contains(cnValue));
-    Assert.assertTrue(a.contains(new AttributeValue(cnType, "jane doe")));
+    Assert.assertTrue(a.contains(AttributeValues.create(cnType, "jane doe")));
   }
 
 
@@ -719,8 +719,8 @@
 
     Attribute a = builder.toAttribute();
     Assert.assertEquals(a.size(), 2);
-    Assert.assertTrue(a.contains(new AttributeValue(cnType, "value1")));
-    Assert.assertTrue(a.contains(new AttributeValue(cnType, "value2")));
+    Assert.assertTrue(a.contains(AttributeValues.create(cnType, "value1")));
+    Assert.assertTrue(a.contains(AttributeValues.create(cnType, "value2")));
   }
 
 
@@ -761,9 +761,9 @@
 
     builder.addAll(createAttribute(cnType, "cn", noOptions, twoValues));
 
-    Assert.assertTrue(builder.contains(new AttributeValue(cnType, "value1")));
-    Assert.assertTrue(builder.contains(new AttributeValue(cnType, "value2")));
-    Assert.assertFalse(builder.contains(new AttributeValue(cnType, "value3")));
+    Assert.assertTrue(builder.contains(AttributeValues.create(cnType, "value1")));
+    Assert.assertTrue(builder.contains(AttributeValues.create(cnType, "value2")));
+    Assert.assertFalse(builder.contains(AttributeValues.create(cnType, "value3")));
   }
 
 
@@ -781,9 +781,9 @@
 
     builder.addAll(createAttribute(cnType, "cn", noOptions, twoValues));
 
-    AttributeValue av1 = new AttributeValue(cnType, "value1");
-    AttributeValue av2 = new AttributeValue(cnType, "value2");
-    AttributeValue av3 = new AttributeValue(cnType, "value3");
+    AttributeValue av1 = AttributeValues.create(cnType, "value1");
+    AttributeValue av2 = AttributeValues.create(cnType, "value2");
+    AttributeValue av3 = AttributeValues.create(cnType, "value3");
 
     Assert.assertTrue(builder.containsAll(Collections
         .<AttributeValue> emptySet()));
@@ -905,7 +905,7 @@
 
     builder.add("value1");
     Assert.assertTrue(builder.iterator().hasNext());
-    Assert.assertEquals(builder.iterator().next(), new AttributeValue(cnType,
+    Assert.assertEquals(builder.iterator().next(), AttributeValues.create(cnType,
         "value1"));
   }
 
@@ -945,7 +945,7 @@
 
     Attribute a = builder.toAttribute();
     Assert.assertEquals(a.size(), 1);
-    Assert.assertTrue(a.contains(new AttributeValue(cnType, "value3")));
+    Assert.assertTrue(a.contains(AttributeValues.create(cnType, "value3")));
   }
 
 
@@ -964,13 +964,13 @@
     builder.addAll(createAttribute(cnType, "cn", noOptions, threeValues));
 
     // Remove existing values.
-    Assert.assertTrue(builder.removeAll(Arrays.asList(new AttributeValue(
-        cnType, "value1"), new AttributeValue(cnType, "value2"))));
+    Assert.assertTrue(builder.removeAll(Arrays.asList(AttributeValues.create(
+        cnType, "value1"), AttributeValues.create(cnType, "value2"))));
     Assert.assertEquals(builder.size(), 1);
 
     // Remove removed values.
-    Assert.assertFalse(builder.removeAll(Arrays.asList(new AttributeValue(
-        cnType, "value1"), new AttributeValue(cnType, "value2"))));
+    Assert.assertFalse(builder.removeAll(Arrays.asList(AttributeValues.create(
+        cnType, "value1"), AttributeValues.create(cnType, "value2"))));
     Assert.assertEquals(builder.size(), 1);
 
     // Remove nothing.
@@ -980,12 +980,12 @@
 
     // Remove non existent value.
     Assert.assertFalse(builder.removeAll(Collections
-        .singleton(new AttributeValue(cnType, "value4"))));
+        .singleton(AttributeValues.create(cnType, "value4"))));
     Assert.assertEquals(builder.size(), 1);
 
     Attribute a = builder.toAttribute();
     Assert.assertEquals(a.size(), 1);
-    Assert.assertTrue(a.contains(new AttributeValue(cnType, "value3")));
+    Assert.assertTrue(a.contains(AttributeValues.create(cnType, "value3")));
   }
 
 
@@ -1003,21 +1003,21 @@
 
     builder.addAll(createAttribute(cnType, "cn", noOptions, threeValues));
 
-    Assert.assertTrue(builder.remove(new AttributeValue(cnType, "value1")));
+    Assert.assertTrue(builder.remove(AttributeValues.create(cnType, "value1")));
     Assert.assertEquals(builder.size(), 2);
 
     // Already removed.
-    Assert.assertFalse(builder.remove(new AttributeValue(cnType, "value1")));
+    Assert.assertFalse(builder.remove(AttributeValues.create(cnType, "value1")));
     Assert.assertEquals(builder.size(), 2);
 
     // Non existent.
-    Assert.assertFalse(builder.remove(new AttributeValue(cnType, "value4")));
+    Assert.assertFalse(builder.remove(AttributeValues.create(cnType, "value4")));
     Assert.assertEquals(builder.size(), 2);
 
     Attribute a = builder.toAttribute();
     Assert.assertEquals(a.size(), 2);
-    Assert.assertTrue(a.contains(new AttributeValue(cnType, "value2")));
-    Assert.assertTrue(a.contains(new AttributeValue(cnType, "value3")));
+    Assert.assertTrue(a.contains(AttributeValues.create(cnType, "value2")));
+    Assert.assertTrue(a.contains(AttributeValues.create(cnType, "value3")));
   }
 
 
@@ -1048,8 +1048,8 @@
 
     Attribute a = builder.toAttribute();
     Assert.assertEquals(a.size(), 2);
-    Assert.assertTrue(a.contains(new AttributeValue(cnType, "value2")));
-    Assert.assertTrue(a.contains(new AttributeValue(cnType, "value3")));
+    Assert.assertTrue(a.contains(AttributeValues.create(cnType, "value2")));
+    Assert.assertTrue(a.contains(AttributeValues.create(cnType, "value3")));
   }
 
 
@@ -1071,8 +1071,8 @@
 
     Attribute a = builder.toAttribute();
     Assert.assertEquals(a.size(), 2);
-    Assert.assertTrue(a.contains(new AttributeValue(cnType, "value2")));
-    Assert.assertTrue(a.contains(new AttributeValue(cnType, "value4")));
+    Assert.assertTrue(a.contains(AttributeValues.create(cnType, "value2")));
+    Assert.assertTrue(a.contains(AttributeValues.create(cnType, "value4")));
   }
 
 
@@ -1090,15 +1090,15 @@
     builder.addAll(createAttribute(cnType, "cn", noOptions, threeValues));
 
     // Note duplicate values.
-    builder.replaceAll(Arrays.asList(new AttributeValue(cnType, "value2"),
-        new AttributeValue(cnType, "value2"), new AttributeValue(cnType,
+    builder.replaceAll(Arrays.asList(AttributeValues.create(cnType, "value2"),
+        AttributeValues.create(cnType, "value2"), AttributeValues.create(cnType,
             "value4")));
     Assert.assertEquals(builder.size(), 2);
 
     Attribute a = builder.toAttribute();
     Assert.assertEquals(a.size(), 2);
-    Assert.assertTrue(a.contains(new AttributeValue(cnType, "value2")));
-    Assert.assertTrue(a.contains(new AttributeValue(cnType, "value4")));
+    Assert.assertTrue(a.contains(AttributeValues.create(cnType, "value2")));
+    Assert.assertTrue(a.contains(AttributeValues.create(cnType, "value4")));
   }
 
 
@@ -1115,12 +1115,12 @@
     AttributeBuilder builder = new AttributeBuilder(cnType);
     builder.addAll(createAttribute(cnType, "cn", noOptions, threeValues));
 
-    builder.replace(new AttributeValue(cnType, "value4"));
+    builder.replace(AttributeValues.create(cnType, "value4"));
     Assert.assertEquals(builder.size(), 1);
 
     Attribute a = builder.toAttribute();
     Assert.assertEquals(a.size(), 1);
-    Assert.assertTrue(a.contains(new AttributeValue(cnType, "value4")));
+    Assert.assertTrue(a.contains(AttributeValues.create(cnType, "value4")));
   }
 
 
@@ -1142,7 +1142,7 @@
 
     Attribute a = builder.toAttribute();
     Assert.assertEquals(a.size(), 1);
-    Assert.assertTrue(a.contains(new AttributeValue(cnType, "value4")));
+    Assert.assertTrue(a.contains(AttributeValues.create(cnType, "value4")));
   }
 
 
@@ -1310,14 +1310,14 @@
     // Check contains().
     for (String value : values)
     {
-      Assert.assertTrue(a.contains(new AttributeValue(type, value)));
+      Assert.assertTrue(a.contains(AttributeValues.create(type, value)));
 
       // Assumes internal normalization to lower-case.
       Assert.assertTrue(a
-          .contains(new AttributeValue(type, value.toUpperCase())));
+          .contains(AttributeValues.create(type, value.toUpperCase())));
     }
 
-    Assert.assertFalse(a.contains(new AttributeValue(type, "xxxx")));
+    Assert.assertFalse(a.contains(AttributeValues.create(type, "xxxx")));
   }
 
 
@@ -1349,7 +1349,7 @@
     Set<AttributeValue> expectedValues = new HashSet<AttributeValue>();
     for (String value : values)
     {
-      expectedValues.add(new AttributeValue(type, value));
+      expectedValues.add(AttributeValues.create(type, value));
     }
 
     Assert.assertTrue(a.containsAll(Collections.<AttributeValue> emptySet()));
@@ -1363,14 +1363,14 @@
     }
 
     Set<AttributeValue> bigSet = new HashSet<AttributeValue>(expectedValues);
-    bigSet.add(new AttributeValue(type, "xxxx"));
+    bigSet.add(AttributeValues.create(type, "xxxx"));
     Assert.assertFalse(a.containsAll(bigSet));
 
     expectedValues.clear();
     for (String value : values)
     {
       // Assumes internal normalization to lower-case.
-      expectedValues.add(new AttributeValue(type, value.toUpperCase()));
+      expectedValues.add(AttributeValues.create(type, value.toUpperCase()));
     }
     Assert.assertTrue(a.containsAll(expectedValues));
   }
@@ -1813,7 +1813,7 @@
         Assert.assertTrue(i.hasNext());
 
         AttributeValue v = i.next();
-        Assert.assertEquals(v, new AttributeValue(type, value));
+        Assert.assertEquals(v, AttributeValues.create(type, value));
 
         try
         {
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/types/ByteSequenceReaderTest.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/types/ByteSequenceReaderTest.java
new file mode 100644
index 0000000..dda7356
--- /dev/null
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/types/ByteSequenceReaderTest.java
@@ -0,0 +1,402 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License").  You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE
+ * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
+ * add the following below this CDDL HEADER, 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.server.types;
+
+import org.testng.annotations.Test;
+import org.testng.annotations.DataProvider;
+import org.testng.Assert;
+
+import java.util.Arrays;
+
+/**
+ * Test class for ByteSequenceReader
+ */
+public class ByteSequenceReaderTest extends TypesTestCase
+{
+    private static final byte[] eightBytes =
+      new byte[]{ (byte) 0x01, (byte) 0x02, (byte) 0x03, (byte) 0x04,
+          (byte) 0x05, (byte) 0x06, (byte) 0x07, (byte) 0x08 };
+
+  @DataProvider(name = "readerProvider")
+  public Object[][] byteSequenceReaderProvider()
+  {
+    return new Object[][] {
+        { ByteString.wrap(eightBytes).asReader(), eightBytes },
+        { new ByteStringBuilder().append(eightBytes).asReader(), eightBytes },
+        { new ByteStringBuilder().append(eightBytes).
+            subSequence(0, 8).asReader(), eightBytes }
+    };
+  }
+
+  @Test(dataProvider = "readerProvider",
+      expectedExceptions = IndexOutOfBoundsException.class)
+  public void testGet(ByteSequenceReader reader, byte[] ba)
+  {
+    reader.rewind();
+    for(int i = 0; i < ba.length; i++)
+    {
+      Assert.assertEquals(reader.get(), ba[i]);
+    }
+
+    // The next get should result in IOB exception.
+    reader.get();
+  }
+
+  @Test(dataProvider = "readerProvider",
+      expectedExceptions = IndexOutOfBoundsException.class)
+  public void testBulkGet(ByteSequenceReader reader, byte[] ba)
+  {
+    reader.rewind();
+    int remaining = ba.length;
+
+    while(remaining > 0)
+    {
+      int length = remaining / 2;
+      if(length == 0)
+      {
+        length = remaining % 2;
+      }
+
+      byte[] readArray = new byte[length];
+      reader.get(readArray);
+      byte[] subArray = new byte[length];
+      System.arraycopy(ba, ba.length - remaining, subArray, 0, length);
+      Assert.assertTrue(Arrays.equals(readArray, subArray));
+
+      remaining -= length;
+    }
+
+    // Any more gets should result in IOB exception.
+    reader.get(new byte[1]);
+  }
+
+  @Test(dataProvider = "readerProvider")
+  public void testBulkGetWithOffset(ByteSequenceReader reader, byte[] ba)
+  {
+    reader.rewind();
+    int remaining = ba.length;
+    byte[] readArray = new byte[ba.length];
+
+    while(remaining > 0)
+    {
+      int length = remaining / 2;
+      if(length == 0)
+      {
+        length = remaining % 2;
+      }
+
+      reader.get(readArray, ba.length - remaining, length);
+
+      remaining -= length;
+    }
+
+    Assert.assertTrue(Arrays.equals(readArray, ba));
+  }
+
+  @Test(dataProvider = "readerProvider",
+      expectedExceptions = IndexOutOfBoundsException.class)
+  public void testNegativeOffsetBulkGet(ByteSequenceReader reader, byte[] ba)
+  {
+    reader.rewind();
+    byte[] array = new byte[ba.length];
+    reader.get(array, -1, ba.length);
+  }
+
+  @Test(dataProvider = "readerProvider",
+      expectedExceptions = IndexOutOfBoundsException.class)
+  public void testNegativeLengthBulkGet(ByteSequenceReader reader, byte[] ba)
+  {
+    reader.rewind();
+    byte[] array = new byte[ba.length];
+    reader.get(array, 0, -1);
+  }
+
+  @Test(dataProvider = "readerProvider",
+      expectedExceptions = IndexOutOfBoundsException.class)
+  public void testBadOffLenBulkGet(ByteSequenceReader reader, byte[] ba)
+  {
+    reader.rewind();
+    byte[] array = new byte[ba.length];
+    reader.get(array, 3, ba.length);
+  }
+
+  @Test(expectedExceptions = IndexOutOfBoundsException.class)
+  public void testGetBERLength()
+  {
+    ByteSequenceReader reader = ByteString.wrap(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,
+
+        (byte) 0x84, (byte) 0x10, (byte) 0x00
+    }).asReader();
+
+    int[] expectedLength = new int[]{
+        0x00000000, 0x00000001, 0x0000000F, 0x00000010,
+        0x0000007F,
+
+        0x000000FF,
+
+        0x00000100, 0x00000FFF, 0x00001000, 0x0000FFFF,
+
+        0x00010000, 0x000FFFFF, 0x00100000, 0x00FFFFFF,
+
+        0x01000000, 0x0FFFFFFF, 0x10000000, 0xFFFFFFFF
+    };
+
+    for(int i = 0; i < expectedLength.length; i++)
+    {
+      Assert.assertEquals(reader.getBERLength(), expectedLength[i]);
+    }
+
+    // Last one is incomplete and should throw error
+    reader.getBERLength();
+  }
+
+  @Test(expectedExceptions = IndexOutOfBoundsException.class)
+  public void testOversizedGetBERLength()
+  {
+    ByteSequenceReader reader = ByteString.wrap(new byte[]{
+        (byte) 0x85, (byte) 0x10, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+        (byte) 0x00 }).asReader();
+
+    // Shouldn't be able to reader over a 4 byte length.
+    reader.getBERLength();
+  }
+
+ @Test(expectedExceptions = IndexOutOfBoundsException.class)
+  public void testUndersizedGetBERLength()
+  {
+    ByteSequenceReader reader = ByteString.wrap(new byte[0]).asReader();
+
+    // Shouldn't be able to reader over a 4 byte length.
+    reader.getBERLength();
+  }
+
+  @Test(dataProvider = "readerProvider",
+      expectedExceptions = IndexOutOfBoundsException.class)
+  public void testGetByteSequence(ByteSequenceReader reader, byte[] ba)
+  {
+    reader.rewind();
+    int remaining = ba.length;
+
+    while(remaining > 0)
+    {
+      int length = remaining / 2;
+      if(length == 0)
+      {
+        length = remaining % 2;
+      }
+
+      ByteSequence readSequence = reader.getByteSequence(length);
+      byte[] subArray = new byte[length];
+      System.arraycopy(ba, ba.length - remaining, subArray, 0, length);
+      Assert.assertTrue(Arrays.equals(readSequence.toByteArray(), subArray));
+
+      remaining -= length;
+    }
+
+    // Any more gets should result in IOB exception.
+    reader.getByteSequence(1);
+  }
+
+  @Test(dataProvider = "readerProvider",
+      expectedExceptions = IndexOutOfBoundsException.class)
+  public void testGetByteString(ByteSequenceReader reader, byte[] ba)
+  {
+    reader.rewind();
+    int remaining = ba.length;
+
+    while(remaining > 0)
+    {
+      int length = remaining / 2;
+      if(length == 0)
+      {
+        length = remaining % 2;
+      }
+
+      ByteString readSequence = reader.getByteString(length);
+      byte[] subArray = new byte[length];
+      System.arraycopy(ba, ba.length - remaining, subArray, 0, length);
+      Assert.assertTrue(Arrays.equals(readSequence.toByteArray(), subArray));
+
+      remaining -= length;
+    }
+
+    // Any more gets should result in IOB exception.
+    reader.getByteString(1);
+  }
+
+  @Test(expectedExceptions = IndexOutOfBoundsException.class)
+  public void testGetShort()
+  {
+    ByteSequenceReader reader = ByteString.wrap(new byte[]{
+        (byte) 0x80, (byte) 0x00, (byte) 0x7F, (byte) 0xFF, (byte) 0xFF
+    }).asReader();
+
+    Assert.assertEquals(reader.getShort(), Short.MIN_VALUE);
+    Assert.assertEquals(reader.getShort(), Short.MAX_VALUE);
+
+    // Any more gets should result in IOB exception.
+    reader.getShort();
+  }
+
+  @Test(expectedExceptions = IndexOutOfBoundsException.class)
+  public void testGetInt()
+  {
+    ByteSequenceReader reader = ByteString.wrap(new byte[]{
+        (byte) 0x80, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x7F,
+        (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF }).asReader();
+
+    Assert.assertEquals(reader.getInt(), Integer.MIN_VALUE);
+    Assert.assertEquals(reader.getInt(), Integer.MAX_VALUE);
+
+    // Any more gets should result in IOB exception.
+    reader.getInt();
+  }
+
+  @Test(expectedExceptions = IndexOutOfBoundsException.class)
+  public void testGetLong()
+  {
+    ByteSequenceReader reader = ByteString.wrap(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, (byte) 0xFF }).asReader();
+
+    Assert.assertEquals(reader.getLong(), Long.MIN_VALUE);
+    Assert.assertEquals(reader.getLong(), Long.MAX_VALUE);
+
+    // Any more gets should result in IOB exception.
+    reader.getLong();
+  }
+
+  @Test(dataProvider = "readerProvider",
+      expectedExceptions = IndexOutOfBoundsException.class)
+  public void testGetString(ByteSequenceReader reader, byte[] ba)
+  {
+    reader.rewind();
+    int remaining = ba.length;
+
+    while(remaining > 0)
+    {
+      int length = remaining / 2;
+      if(length == 0)
+      {
+        length = remaining % 2;
+      }
+
+      String readString = reader.getString(length);
+      String subString = new String(ba, ba.length - remaining, length);
+      Assert.assertTrue(readString.equals(subString));
+
+      remaining -= length;
+    }
+
+    // Any more gets should result in IOB exception.
+    reader.getString(1);
+  }
+
+  @Test(dataProvider = "readerProvider",
+      expectedExceptions = IndexOutOfBoundsException.class)
+  public void testSetPosition(ByteSequenceReader reader, byte[] ba)
+  {
+    reader.rewind();
+
+    for(int i = 0; i < ba.length; i++)
+    {
+      reader.position(i);
+      String readString = reader.getString(ba.length - i);
+      String subString = new String(ba, i, ba.length - i);
+      Assert.assertTrue(readString.equals(subString));
+    }
+
+    // Setting an invalid position should result in IOB exception.
+    reader.position(ba.length+1);
+  }
+
+  @Test(dataProvider = "readerProvider")
+  public void testRemaining(ByteSequenceReader reader, byte[] ba)
+  {
+    reader.rewind();
+
+    for(int i = 0; i < ba.length; i++)
+    {
+      reader.position(i);
+      Assert.assertEquals(reader.remaining(), ba.length - i);
+    }
+  }
+
+  @Test(dataProvider = "readerProvider")
+  public void testRewind(ByteSequenceReader reader, byte[] ba)
+  {
+    reader.position(ba.length - 1);
+    reader.rewind();
+    Assert.assertEquals(reader.position(), 0);
+  }
+
+  @Test(dataProvider = "readerProvider",
+      expectedExceptions = IndexOutOfBoundsException.class)
+  public void testSkip(ByteSequenceReader reader, byte[] ba)
+  {
+    reader.rewind();
+    int remaining = ba.length;
+
+    while(remaining > 0)
+    {
+      int length = remaining / 2;
+      if(length == 0)
+      {
+        length = remaining % 2;
+      }
+
+      reader.skip(length);
+      remaining -= length;
+
+      Assert.assertEquals(reader.position(), ba.length - remaining);
+    }
+
+    // Any more skips should result in IOB exception.
+    reader.skip(1);
+  }
+}
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/types/ByteSequenceTest.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/types/ByteSequenceTest.java
new file mode 100644
index 0000000..d870674
--- /dev/null
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/types/ByteSequenceTest.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 2009 Sun Microsystems, Inc.
+ */
+
+package org.opends.server.types;
+
+import org.testng.annotations.Test;
+import org.testng.annotations.DataProvider;
+import org.testng.Assert;
+
+import java.util.Arrays;
+import java.io.ByteArrayOutputStream;
+import java.io.UnsupportedEncodingException;
+
+/**
+ * Abstract test case for the ByteSequence interface.
+ */
+public abstract class ByteSequenceTest extends TypesTestCase
+{
+  /**
+   * 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();
+  }
+
+  protected abstract Object[][] byteSequenceProvider() throws Exception;
+
+  @Test(dataProvider = "byteSequenceProvider")
+  public void testByteAt(ByteSequence bs, 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(ByteSequence bs, byte[] ba)
+  {
+    bs.byteAt(ba.length);
+  }
+
+  @Test(dataProvider = "byteSequenceProvider",
+      expectedExceptions = IndexOutOfBoundsException.class)
+  public void testByteAtBadIndex2(ByteSequence bs, byte[] ba)
+  {
+    bs.byteAt(-1);
+  }
+
+  @Test(dataProvider = "byteSequenceProvider")
+  public void testCopyTo(ByteSequence bs, byte[] ba)
+  {
+    byte[] newBa = new byte[ba.length];
+    bs.copyTo(newBa);
+    Assert.assertTrue(Arrays.equals(newBa, ba));
+  }
+
+  @Test(dataProvider = "byteSequenceProvider")
+  public void testCopyToWithOffset(ByteSequence bs, byte[] ba)
+  {
+    for(int i = 0; i < ba.length * 2; i++)
+    {
+      byte[] newBa = new byte[ba.length * 2];
+      bs.copyTo(newBa, i);
+
+      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",
+      expectedExceptions = IndexOutOfBoundsException.class)
+  public void testCopyToWithBadOffset(ByteSequence bs, byte[] ba)
+  {
+    bs.copyTo(new byte[0], -1);
+  }
+
+  @Test(dataProvider = "byteSequenceProvider")
+  public void testCopyToByteSequenceBuilder(ByteSequence bs, byte[] ba)
+  {
+    ByteStringBuilder builder = new ByteStringBuilder();
+    bs.copyTo(builder);
+    Assert.assertTrue(Arrays.equals(builder.toByteArray(), ba));
+  }
+
+  @Test(dataProvider = "byteSequenceProvider")
+  public void testCopyToOutputStream(ByteSequence bs, byte[] ba) throws Exception
+  {
+    ByteArrayOutputStream stream = new ByteArrayOutputStream();
+    bs.copyTo(stream);
+    Assert.assertTrue(Arrays.equals(stream.toByteArray(), ba));
+  }
+
+  @Test(dataProvider = "byteSequenceProvider")
+  public void testEquals(ByteSequence bs, byte[] ba) throws Exception
+  {
+    Assert.assertTrue(bs.equals(ByteString.wrap(ba)));
+  }
+
+  @Test(dataProvider = "byteSequenceProvider")
+  public void testLength(ByteSequence bs, byte[] ba) throws Exception
+  {
+    Assert.assertEquals(bs.length(), ba.length);
+  }
+
+  @Test(dataProvider = "byteSequenceProvider")
+  public void testSubSequence(ByteSequence bs, 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(ByteSequence bs, byte[] ba)
+  {
+    bs.subSequence(-1, bs.length());
+  }
+
+  @Test(dataProvider = "byteSequenceProvider",
+      expectedExceptions = IndexOutOfBoundsException.class)
+  public void testSubSequenceBadStartEnd2(ByteSequence bs, byte[] ba)
+  {
+    bs.subSequence(0, bs.length()+1);
+  }
+
+  @Test(dataProvider = "byteSequenceProvider",
+      expectedExceptions = IndexOutOfBoundsException.class)
+  public void testSubSequenceBadStartEnd3(ByteSequence bs, byte[] ba)
+  {
+    bs.subSequence(-1, bs.length()+1);
+  }
+
+  @Test(dataProvider = "byteSequenceProvider")
+  public void testToByteArray(ByteSequence bs, byte[] ba)
+  {
+    Assert.assertTrue(Arrays.equals(bs.toByteArray(), ba));
+  }
+
+  @Test(dataProvider = "byteSequenceProvider")
+  public void testToByteSequence(ByteSequence bs, byte[] ba)
+  {
+    Assert.assertTrue(Arrays.equals(bs.toByteString().toByteArray(), ba));
+  }
+
+  @Test(dataProvider = "byteSequenceProvider")
+  public void testToString(ByteSequence bs, byte[] ba)
+  {
+    String str;
+    try
+    {
+      str = new String(ba, "UTF-8");
+    }
+    catch(UnsupportedEncodingException uee)
+    {
+      str = new String(ba);
+    }
+
+    Assert.assertTrue(bs.toString().equals(str));
+  }
+
+}
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/types/ByteStringBuilderTest.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/types/ByteStringBuilderTest.java
new file mode 100644
index 0000000..7248867
--- /dev/null
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/types/ByteStringBuilderTest.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 2009 Sun Microsystems, Inc.
+ */
+
+package org.opends.server.types;
+
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+import org.testng.Assert;
+
+import java.nio.ByteBuffer;
+import java.io.InputStream;
+import java.io.ByteArrayInputStream;
+import java.util.Arrays;
+
+/**
+ * Test case for ByteStringBuilder.
+ */
+public class ByteStringBuilderTest extends ByteSequenceTest
+{
+  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.
+   */
+  @DataProvider(name = "byteSequenceProvider")
+  public Object[][] byteSequenceProvider() throws Exception {
+    Object[][] builders = byteStringBuilderProvider();
+    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;
+  }
+
+  @DataProvider(name = "builderProvider")
+  private Object[][] byteStringBuilderProvider() throws Exception
+  {
+    ByteBuffer testBuffer = ByteBuffer.wrap(eightBytes);
+    ByteString testByteString = ByteString.wrap(eightBytes);
+    ByteSequenceReader testByteReader = testByteString.asReader();
+    InputStream testStream = new ByteArrayInputStream(eightBytes);
+    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}},
+
+    };
+  }
+
+  @Test(expectedExceptions = IllegalArgumentException.class)
+  public void testInvalidCapacity()
+  {
+    new ByteStringBuilder(-1);
+  }
+
+  @Test(dataProvider = "builderProvider",
+      expectedExceptions = IndexOutOfBoundsException.class)
+  public void testClear(ByteStringBuilder bs, byte[] ba)
+  {
+    bs.clear();
+    Assert.assertEquals(bs.length(), 0);
+    bs.byteAt(0);
+  }
+
+  @Test
+  public void testEnsureAdditionalCapacity()
+  {
+    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(ByteStringBuilder bs, byte[] ba)
+  {
+    byte[] trimmedArray = new byte[bs.length()];
+    System.arraycopy(bs.getBackingArray(), 0, trimmedArray, 0, bs.length());
+    Assert.assertTrue(Arrays.equals(trimmedArray, ba));
+  }
+
+  @Test
+  public void testTrimToSize()
+  {
+    ByteStringBuilder bsb = new ByteStringBuilder();
+    bsb.append(eightBytes);
+    Assert.assertTrue(bsb.getBackingArray().length > 8);
+    bsb.trimToSize();
+    Assert.assertEquals(bsb.getBackingArray().length, 8);
+  }
+
+  @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(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 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
+  {
+    ByteArrayInputStream stream = new ByteArrayInputStream(new byte[5]);
+    new ByteStringBuilder().append(stream, -1);
+  }
+
+  @Test
+  public void testAppendInputStream() throws Exception
+  {
+    ByteStringBuilder bsb = new ByteStringBuilder();
+    ByteArrayInputStream stream = new ByteArrayInputStream(new byte[5]);
+    Assert.assertEquals(bsb.append(stream, 10), 5);
+  }
+}
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/types/ByteStringTest.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/types/ByteStringTest.java
new file mode 100644
index 0000000..466611b
--- /dev/null
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/types/ByteStringTest.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.server.types;
+
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+import org.testng.Assert;
+
+import java.util.Arrays;
+import java.io.ByteArrayOutputStream;
+
+/**
+ * This class defines a set of tests for the
+ * org.opends.server.types.ByteString class.
+ */
+public class ByteStringTest extends ByteSequenceTest
+{
+  @DataProvider(name = "byteStringIntegerProvier")
+  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 = "byteStringLongProvier")
+  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 }
+        };
+  }
+
+  /**
+   * ByteString data provider.
+   *
+   * @return The array of ByteStrings and the bytes it should contain.
+   */
+  @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] },
+    };
+  }
+ 
+  @Test(dataProvider = "byteStringIntegerProvider")
+  public void testToInteger(ByteString bs, int i)
+  {
+    Assert.assertEquals(bs.toInt(), i);
+  }
+
+  @Test(dataProvider = "byteStringLongProvider")
+  public void testToLong(ByteString bs, long l)
+  {
+    Assert.assertEquals(bs.toLong(), l);
+  }
+
+  @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();
+  }
+
+  @Test(expectedExceptions = IndexOutOfBoundsException.class)
+  public void testInvalidWrapLength()
+  {
+    ByteString.wrap(new byte[]{(byte)0x00, (byte)0x01, (byte)0x02,
+        (byte)0x03}, 2, 8);
+  }
+}
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/types/PrivilegeTestCase.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/types/PrivilegeTestCase.java
index e174069..626d7c3 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/types/PrivilegeTestCase.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/types/PrivilegeTestCase.java
@@ -60,7 +60,6 @@
 import org.opends.server.core.ModifyOperation;
 import org.opends.server.core.ModifyOperationBasis;
 import org.opends.server.core.SchemaConfigManager;
-import org.opends.server.protocols.asn1.ASN1OctetString;
 import org.opends.server.protocols.internal.InternalClientConnection;
 import org.opends.server.protocols.internal.InternalSearchOperation;
 import org.opends.server.tools.LDAPModify;
@@ -475,7 +474,7 @@
     CompareOperation compareOperation =
          conn.processCompare(DN.decode("cn=config"),
                              DirectoryServer.getAttributeType("cn"),
-                             ByteStringFactory.create("config"));
+             ByteString.valueOf("config"));
     if (hasPrivilege)
     {
       assertEquals(compareOperation.getResultCode(), ResultCode.COMPARE_TRUE);
@@ -1343,7 +1342,7 @@
          new CompareOperationBasis(conn, conn.nextOperationID(),
                               conn.nextMessageID(), controls, targetDN,
                               DirectoryServer.getAttributeType("cn", true),
-                              ByteStringFactory.create("PWReset Target"));
+             ByteString.valueOf("PWReset Target"));
     compareOperation.run();
 
     if (hasProxyPrivilege)
@@ -1415,7 +1414,7 @@
 
     ArrayList<Control> controls = new ArrayList<Control>(1);
     controls.add(new ProxiedAuthV2Control(
-                          new ASN1OctetString("dn:cn=PWReset Target,o=test")));
+        ByteString.valueOf("dn:cn=PWReset Target,o=test")));
 
 
     // Try to add the entry.  If this fails with the proxy control, then add it
@@ -1540,7 +1539,7 @@
     DN targetDN = DN.decode("cn=PWReset Target,o=test");
     ArrayList<Control> controls = new ArrayList<Control>(1);
     controls.add(new ProxiedAuthV2Control(
-                          new ASN1OctetString("dn:" + targetDN.toString())));
+        ByteString.valueOf("dn:" + targetDN.toString())));
 
 
     // Test a compare operation against the PWReset Target user.
@@ -1548,7 +1547,7 @@
          new CompareOperationBasis(conn, conn.nextOperationID(),
                               conn.nextMessageID(), controls, targetDN,
                               DirectoryServer.getAttributeType("cn", true),
-                              ByteStringFactory.create("PWReset Target"));
+             ByteString.valueOf("PWReset Target"));
     compareOperation.run();
 
     if (hasProxyPrivilege)
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/types/SearchFilterTests.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/types/SearchFilterTests.java
index db85dcc..504d38f 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/types/SearchFilterTests.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/types/SearchFilterTests.java
@@ -28,7 +28,6 @@
 
 import org.opends.server.DirectoryServerTestCase;
 import org.opends.server.TestCaseUtils;
-import org.opends.server.protocols.asn1.ASN1OctetString;
 import org.opends.server.util.StaticUtils;
 import org.opends.server.types.DirectoryException;
 import org.opends.server.core.DirectoryServer;
@@ -639,7 +638,7 @@
 
     description.filterType = filterType;
     description.attributeType = DirectoryServer.getAttributeType(attributeType);
-    description.assertionValue = new AttributeValue(description.attributeType, attributeValue);
+    description.assertionValue = AttributeValues.create(description.attributeType, attributeValue);
 
     if (filterType == FilterType.EQUALITY) {
       description.searchFilter = SearchFilter.createEqualityFilter(description.attributeType,
@@ -717,13 +716,13 @@
     description.filterType = FilterType.SUBSTRING;
     description.attributeType = DirectoryServer.getAttributeType(attributeType);
 
-    description.subInitialElement = new ASN1OctetString(subInitial);
+    description.subInitialElement = ByteString.valueOf(subInitial);
     description.subAnyElements = new ArrayList<ByteString>();
     for (int i = 0; (subAny != null) && (i < subAny.size()); i++) {
       String s = subAny.get(i);
-      description.subAnyElements.add(new ASN1OctetString(s));
+      description.subAnyElements.add(ByteString.valueOf(s));
     }
-    description.subFinalElement = new ASN1OctetString(subFinal);
+    description.subFinalElement = ByteString.valueOf(subFinal);
 
     description.searchFilter = SearchFilter.createSubstringFilter(description.attributeType,
             description.subInitialElement,
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/types/TestAttributeType.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/types/TestAttributeType.java
index bb22057..c847daa 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/types/TestAttributeType.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/types/TestAttributeType.java
@@ -40,7 +40,6 @@
 import org.opends.server.api.OrderingMatchingRule;
 import org.opends.server.api.SubstringMatchingRule;
 import org.opends.server.core.DirectoryServer;
-import org.opends.server.protocols.asn1.ASN1OctetString;
 import org.opends.server.util.ServerConstants;
 import org.testng.Assert;
 import org.testng.annotations.DataProvider;
@@ -682,87 +681,6 @@
 
 
   /**
-   * Create test data for testing the
-   * {@link AttributeType#generateHashCode(AttributeValue)} method.
-   *
-   * @return Returns the array of test data.
-   */
-  @DataProvider(name = "generateHashCodeTestData")
-  public Object[][] createGenerateHashCodeTestData() {
-    return new Object[][] { { "one", "one", true },
-        { "one", "ONE", true }, { "one", "  oNe  ", true },
-        { "one two", " one  two  ", true },
-        { "one two", "onetwo", false }, { "one", "two", false } };
-  }
-
-
-
-  /**
-   * Check that the
-   * {@link AttributeType#generateHashCode(AttributeValue)} method
-   * works as expected.
-   *
-   * @param value1
-   *          The first test value.
-   * @param value2
-   *          The second test value.
-   * @param result
-   *          The expected result.
-   * @throws Exception
-   *           If the test failed unexpectedly.
-   */
-  @Test(dataProvider = "generateHashCodeTestData")
-  public void testGenerateHashCodeTestData(String value1,
-      String value2, boolean result) throws Exception {
-    AttributeTypeBuilder builder = new AttributeTypeBuilder("test",
-        "1.2.3");
-    builder.setSyntax(DirectoryServer.getDefaultStringSyntax());
-    AttributeType type = builder.getInstance();
-
-    AttributeValue av1 = new AttributeValue(type, value1);
-    AttributeValue av2 = new AttributeValue(type, value2);
-
-    int h1 = type.generateHashCode(av1);
-    int h2 = type.generateHashCode(av2);
-
-    Assert.assertEquals(h1 == h2, result);
-  }
-
-
-
-  /**
-   * Check that the {@link AttributeType#normalize(ByteString)} method
-   * works as expected.
-   *
-   * @param value1
-   *          The first test value.
-   * @param value2
-   *          The second test value.
-   * @param result
-   *          The expected result.
-   * @throws Exception
-   *           If the test failed unexpectedly.
-   */
-  @Test(dataProvider = "generateHashCodeTestData")
-  public void testNormalize(String value1, String value2,
-      boolean result) throws Exception {
-    AttributeTypeBuilder builder = new AttributeTypeBuilder("test",
-        "1.2.3");
-    builder.setSyntax(DirectoryServer.getDefaultStringSyntax());
-    AttributeType type = builder.getInstance();
-
-    ByteString b1 = new ASN1OctetString(value1);
-    ByteString b2 = new ASN1OctetString(value2);
-
-    ByteString r1 = type.normalize(b1);
-    ByteString r2 = type.normalize(b2);
-
-    Assert.assertEquals(r1.equals(r2), result);
-  }
-
-
-
-  /**
    * Check that the {@link AttributeType#isCollective()} method.
    *
    * @throws Exception
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/types/TestAttributeValue.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/types/TestAttributeValue.java
new file mode 100644
index 0000000..35f338f
--- /dev/null
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/types/TestAttributeValue.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 2006-2009 Sun Microsystems, Inc.
+ */
+package org.opends.server.types;
+
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+import org.testng.Assert;
+import org.opends.server.core.DirectoryServer;
+
+/**
+ * Test case for AttributeValues
+ */
+public class TestAttributeValue extends TypesTestCase
+{
+  /**
+   * Create test data for testing the
+   * {@link AttributeValue#hashCode()} method.
+   *
+   * @return Returns the array of test data.
+   */
+  @DataProvider(name = "generateHashCodeTestData")
+  public Object[][] createHashCodeTestData() {
+    return new Object[][] { { "one", "one", true },
+        { "one", "ONE", true }, { "one", "  oNe  ", true },
+        { "one two", " one  two  ", true },
+        { "one two", "onetwo", false }, { "one", "two", false } };
+  }
+
+
+
+  /**
+   * Check that the
+   * {@link AttributeValue#hashCode()} method
+   * works as expected.
+   *
+   * @param value1
+   *          The first test value.
+   * @param value2
+   *          The second test value.
+   * @param result
+   *          The expected result.
+   * @throws Exception
+   *           If the test failed unexpectedly.
+   */
+  @Test(dataProvider = "generateHashCodeTestData")
+  public void testHashCodeTestData(String value1,
+      String value2, boolean result) throws Exception {
+    AttributeType type = DirectoryServer.getDefaultAttributeType("test");
+
+    AttributeValue av1 = AttributeValues.create(type, value1);
+    AttributeValue av2 = AttributeValues.create(type, value2);
+
+    int h1 = av1.hashCode();
+    int h2 = av2.hashCode();
+
+    Assert.assertEquals(h1 == h2, result);
+  }
+
+
+
+  /**
+   * Check that the {@link AttributeValue#getNormalizedValue()} method
+   * works as expected.
+   *
+   * @param value1
+   *          The first test value.
+   * @param value2
+   *          The second test value.
+   * @param result
+   *          The expected result.
+   * @throws Exception
+   *           If the test failed unexpectedly.
+   */
+  @Test(dataProvider = "generateHashCodeTestData")
+  public void testGetNormalizedValue(String value1, String value2,
+      boolean result) throws Exception {
+    AttributeType type = DirectoryServer.getDefaultAttributeType("test");
+
+    AttributeValue av1 = AttributeValues.create(type, value1);
+    AttributeValue av2 = AttributeValues.create(type, value2);
+
+    ByteString r1 = av1.getNormalizedValue();
+    ByteString r2 = av2.getNormalizedValue();
+
+    Assert.assertEquals(r1.equals(r2), result);
+  }
+}
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/types/TestDN.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/types/TestDN.java
index 0dc69c3..2f5e8dd 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/types/TestDN.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/types/TestDN.java
@@ -33,8 +33,8 @@
 import static org.testng.Assert.*;
 
 import org.opends.server.TestCaseUtils;
+import org.opends.server.util.StaticUtils;
 import org.opends.server.core.DirectoryServer;
-import org.opends.server.protocols.asn1.ASN1OctetString;
 import org.testng.annotations.DataProvider;
 import org.testng.annotations.Test;
 import org.testng.annotations.BeforeClass;
@@ -316,7 +316,7 @@
   @Test(dataProvider = "testDNs")
   public void testDecodeOctetString(String rawDN, String normDN,
       String stringDN) throws Exception {
-    ASN1OctetString octetString = new ASN1OctetString(rawDN);
+    ByteString octetString = ByteString.valueOf(rawDN);
 
     DN dn = DN.decode(octetString);
     assertEquals(dn.toNormalizedString(), normDN);
@@ -394,7 +394,7 @@
    */
   @Test(dataProvider = "illegalDNs", expectedExceptions = DirectoryException.class)
   public void testIllegalOctetStringDNs(String dn) throws Exception {
-    ASN1OctetString octetString = new ASN1OctetString(dn);
+    ByteString octetString = ByteString.valueOf(dn);
 
     try {
       DN.decode(octetString);
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/types/TestEntry.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/types/TestEntry.java
index 4b061db..a02d6a0 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/types/TestEntry.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/types/TestEntry.java
@@ -35,11 +35,11 @@
 import java.util.List;
 
 import org.opends.server.TestCaseUtils;
+import org.opends.server.util.StaticUtils;
 import org.opends.messages.MessageBuilder;
 import org.opends.server.api.SubtreeSpecificationSet;
 import org.opends.server.core.DirectoryServer;
 import org.opends.server.core.RFC3672SubtreeSpecification;
-import org.opends.server.protocols.asn1.ASN1OctetString;
 import org.opends.server.schema.AttributeTypeSyntax;
 import org.opends.server.schema.BooleanSyntax;
 import org.opends.server.schema.IntegerSyntax;
@@ -272,7 +272,8 @@
         + "SYNTAX 1.3.6.1.4.1.1466.115.121.1.45 )";
 
     AttributeType type = AttributeTypeSyntax.decodeAttributeType(
-        new ASN1OctetString(string), DirectoryServer.getSchema(), false);
+        ByteString.valueOf(string),
+        DirectoryServer.getSchema(), false);
 
     // Test values.
     String[] values = new String[] { "{ }",
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/types/TestRDN.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/types/TestRDN.java
index 550407f..03e7feb 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/types/TestRDN.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/types/TestRDN.java
@@ -38,7 +38,6 @@
 
 import org.opends.server.TestCaseUtils;
 import org.opends.server.core.DirectoryServer;
-import org.opends.server.protocols.asn1.ASN1OctetString;
 import org.testng.annotations.BeforeClass;
 import org.testng.annotations.DataProvider;
 import org.testng.annotations.Test;
@@ -88,9 +87,9 @@
             .getDefaultIntegerSyntax());
     DirectoryServer.getSchema().registerAttributeType(dummy, true);
 
-    AV_DC_ORG = new AttributeValue(AT_DC, "org");
-    AV_DC_OPENDS = new AttributeValue(AT_DC, "opends");
-    AV_CN = new AttributeValue(AT_DC, "hello world");
+    AV_DC_ORG = AttributeValues.create(AT_DC, "org");
+    AV_DC_OPENDS = AttributeValues.create(AT_DC, "opends");
+    AV_CN = AttributeValues.create(AT_DC, "hello world");
   }
 
 
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/types/VirtualAttributeTestCase.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/types/VirtualAttributeTestCase.java
index 7c75fe8..f80c70b 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/types/VirtualAttributeTestCase.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/types/VirtualAttributeTestCase.java
@@ -120,21 +120,21 @@
          throws Exception
   {
     assertEquals(virtualAttribute.size(), 1);
-    assertTrue(virtualAttribute.contains(new AttributeValue(entryDNType, "o=test")));
+    assertTrue(virtualAttribute.contains(AttributeValues.create(entryDNType, "o=test")));
 
     assertTrue(!virtualAttribute.isEmpty());
 
-    assertTrue(virtualAttribute.contains(new AttributeValue(entryDNType,
+    assertTrue(virtualAttribute.contains(AttributeValues.create(entryDNType,
                                                             "o=test")));
-    assertFalse(virtualAttribute.contains(new AttributeValue(entryDNType,
+    assertFalse(virtualAttribute.contains(AttributeValues.create(entryDNType,
                                                              "o=not test")));
 
     LinkedHashSet<AttributeValue> testValues =
          new LinkedHashSet<AttributeValue>();
-    testValues.add(new AttributeValue(entryDNType, "o=test"));
+    testValues.add(AttributeValues.create(entryDNType, "o=test"));
     assertTrue(virtualAttribute.containsAll(testValues));
 
-    testValues.add(new AttributeValue(entryDNType, "o=not test"));
+    testValues.add(AttributeValues.create(entryDNType, "o=not test"));
     assertFalse(virtualAttribute.containsAll(testValues));
   }
 
@@ -150,11 +150,11 @@
          throws Exception
   {
     assertEquals(virtualAttribute.matchesSubstring(
-                      ByteStringFactory.create("o="), null,
-                      ByteStringFactory.create("test")),
+        ByteString.valueOf("o="), null,
+        ByteString.valueOf("test")),
                  ConditionResult.UNDEFINED);
 
-    AttributeValue assertionValue = new AttributeValue(entryDNType, "o=test");
+    AttributeValue assertionValue = AttributeValues.create(entryDNType, "o=test");
     assertEquals(virtualAttribute.greaterThanOrEqualTo(assertionValue),
                  ConditionResult.UNDEFINED);
     assertEquals(virtualAttribute.lessThanOrEqualTo(assertionValue),
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/util/TestLDIFReader.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/util/TestLDIFReader.java
index f281150..6d69921 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/util/TestLDIFReader.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/util/TestLDIFReader.java
@@ -37,19 +37,7 @@
 import org.opends.server.TestCaseUtils;
 import org.opends.messages.Message;
 import org.opends.server.core.DirectoryServer;
-import org.opends.server.types.Attribute;
-import org.opends.server.types.AttributeBuilder;
-import org.opends.server.types.AttributeType;
-import org.opends.server.types.AttributeValue;
-import org.opends.server.types.Attributes;
-import org.opends.server.types.DN;
-import org.opends.server.types.Entry;
-import org.opends.server.types.LDIFImportConfig;
-import org.opends.server.types.Modification;
-import org.opends.server.types.ModificationType;
-import org.opends.server.types.ObjectClass;
-import org.opends.server.types.RawModification;
-import org.opends.server.types.RDN;
+import org.opends.server.types.*;
 import org.testng.Assert;
 import org.testng.annotations.AfterClass;
 import org.testng.annotations.BeforeClass;
@@ -337,9 +325,9 @@
           .decode("cn=john, dc=foo, dc=com"));
       Assert.assertTrue(entry.hasObjectClass(OC_TOP));
       Assert.assertTrue(entry.hasObjectClass(OC_PERSON));
-      Assert.assertTrue(entry.hasValue(AT_CN, null, new AttributeValue(
+      Assert.assertTrue(entry.hasValue(AT_CN, null, AttributeValues.create(
           AT_CN, "john")));
-      Assert.assertTrue(entry.hasValue(AT_SN, null, new AttributeValue(
+      Assert.assertTrue(entry.hasValue(AT_SN, null, AttributeValues.create(
           AT_SN, "smith")));
 
       Assert.assertNull(reader.readEntry());
@@ -372,7 +360,7 @@
       Entry entry = reader.readEntry();
       Assert.assertNotNull(entry);
 
-      Assert.assertTrue(entry.hasValue(AT_DESCR, null, new AttributeValue(
+      Assert.assertTrue(entry.hasValue(AT_DESCR, null, AttributeValues.create(
           AT_DESCR, "once upon a time in the west")));
     } finally {
       reader.close();
@@ -398,7 +386,7 @@
       Entry entry = reader.readEntry();
       Assert.assertNotNull(entry);
 
-      Assert.assertTrue(entry.hasValue(AT_DESCR, null, new AttributeValue(
+      Assert.assertTrue(entry.hasValue(AT_DESCR, null, AttributeValues.create(
           AT_DESCR, "once upon a time in the west")));
     } finally {
       reader.close();
@@ -431,9 +419,9 @@
           .decode("cn=anne, dc=foo, dc=com"));
       Assert.assertTrue(entry.hasObjectClass(OC_TOP));
       Assert.assertTrue(entry.hasObjectClass(OC_PERSON));
-      Assert.assertTrue(entry.hasValue(AT_CN, null, new AttributeValue(
+      Assert.assertTrue(entry.hasValue(AT_CN, null, AttributeValues.create(
           AT_CN, "anne")));
-      Assert.assertTrue(entry.hasValue(AT_SN, null, new AttributeValue(
+      Assert.assertTrue(entry.hasValue(AT_SN, null, AttributeValues.create(
           AT_SN, "other")));
 
       Assert.assertNull(reader.readEntry());
@@ -479,9 +467,9 @@
 
       List<Attribute> attrs = new ArrayList<Attribute>();
       AttributeBuilder builder = new AttributeBuilder(AT_OC, "objectclass");
-      builder.add(new AttributeValue(AT_OC, "top"));
-      builder.add(new AttributeValue(AT_OC, "person"));
-      builder.add(new AttributeValue(AT_OC, "organizationalPerson"));
+      builder.add(AttributeValues.create(AT_OC, "top"));
+      builder.add(AttributeValues.create(AT_OC, "person"));
+      builder.add(AttributeValues.create(AT_OC, "organizationalPerson"));
 
       attrs.add(builder.toAttribute());
       attrs.add(Attributes.create("cn", "Fiona Jensen"));
@@ -557,8 +545,8 @@
       Assert.assertEquals(mod.getModificationType(),
           ModificationType.REPLACE);
       builder = new AttributeBuilder(AT_TELN, "telephonenumber");
-      builder.add(new AttributeValue(AT_TELN, "+1 408 555 1234"));
-      builder.add(new AttributeValue(AT_TELN, "+1 408 555 5678"));
+      builder.add(AttributeValues.create(AT_TELN, "+1 408 555 1234"));
+      builder.add(AttributeValues.create(AT_TELN, "+1 408 555 5678"));
       Assert.assertEquals(mod.getAttribute(), builder.toAttribute());
 
       Assert.assertTrue(i.hasNext());
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/util/TestStaticUtils.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/util/TestStaticUtils.java
index a087762..0d73baa 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/util/TestStaticUtils.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/util/TestStaticUtils.java
@@ -45,6 +45,8 @@
 import java.util.List;
 
 import org.opends.server.TestCaseUtils;
+import org.opends.server.types.ByteString;
+import org.opends.server.types.ByteSequence;
 import org.testng.Assert;
 import org.testng.annotations.BeforeClass;
 import org.testng.annotations.DataProvider;
@@ -618,7 +620,7 @@
   }
 
   /**
-   * Tests the {@link StaticUtils#needsBase64Encoding(byte[])} method.
+   * Tests the {@link StaticUtils#needsBase64Encoding(ByteSequence)} method.
    *
    * @param s
    *          The test string.
@@ -630,7 +632,7 @@
   @Test(dataProvider = "needsBase64EncodingTestData")
   public void testNeedsBase64EncodingBytes(String s, boolean result)
       throws Exception {
-    byte[] bytes = s != null ? s.getBytes("UTF-8") : null;
+    ByteString bytes = s != null ? ByteString.valueOf(s) : null;
     Assert.assertEquals(StaticUtils.needsBase64Encoding(bytes), result);
   }
 
@@ -1021,7 +1023,7 @@
 
   /**
    * Tests the
-   * {@link StaticUtils#toLowerCase(byte[], StringBuilder, boolean)}
+   * {@link StaticUtils#toLowerCase(ByteSequence, StringBuilder, boolean)}
    * method.
    *
    * @param input
@@ -1036,7 +1038,7 @@
   @Test(dataProvider = "stringCaseConversionTestData")
   public void testToLowerCaseBytes(String input, String lower, String upper)
       throws Exception {
-    byte[] bytes = input != null ? input.getBytes("UTF-8") : null;
+    ByteString bytes = input != null ? ByteString.valueOf(input) : null;
     StringBuilder buffer = new StringBuilder();
     StaticUtils.toLowerCase(bytes, buffer, false);
     Assert.assertEquals(buffer.toString(), input != null ? lower : "");

--
Gitblit v1.10.0