mirror of https://github.com/OpenIdentityPlatform/OpenDJ.git

matthew_swift
30.27.2009 1203131b06ceafa01b0e2a54eedb9a86525ec73e
Initial import of SDK source from data provider branch.
362 files added
114483 ■■■■■ changed files
opendj-sdk/sdk/src/org/opends/sdk/AbstractAttribute.java 512 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/AbstractConnection.java 315 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/AbstractConnectionFactory.java 125 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/AbstractEntry.java 421 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/AbstractFilterVisitor.java 233 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/Assertion.java 53 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/AsynchronousConnection.java 495 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/Attribute.java 563 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/AttributeDescription.java 1496 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/AuthenticatedConnectionFactory.java 702 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/Change.java 126 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/ConditionResult.java 295 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/Connection.java 1084 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/ConnectionEventListener.java 109 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/ConnectionFactory.java 95 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/ConnectionFuture.java 150 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/ConnectionResultHandler.java 81 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/DN.java 763 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/DecodeException.java 154 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/DereferenceAliasesPolicy.java 223 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/Entry.java 603 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/ErrorResultException.java 103 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/ErrorResultIOException.java 75 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/Filter.java 1978 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/FilterVisitor.java 238 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/LinkedAttribute.java 1063 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/Matcher.java 871 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/ModificationType.java 212 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/RDN.java 899 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/ResultCode.java 764 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/ResultFuture.java 153 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/ResultHandler.java 81 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/RootDSE.java 463 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/SearchResultHandler.java 82 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/SearchScope.java 207 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/SortedEntry.java 295 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/SynchronousConnection.java 261 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/Types.java 985 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/asn1/ASN1.java 221 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/asn1/ASN1ByteSequenceReader.java 563 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/asn1/ASN1Constants.java 167 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/asn1/ASN1InputStreamReader.java 789 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/asn1/ASN1OutputStreamWriter.java 560 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/asn1/ASN1Reader.java 448 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/asn1/ASN1Writer.java 401 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/asn1/AbstractASN1Reader.java 210 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/asn1/AbstractASN1Writer.java 157 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/controls/AccountUsabilityControl.java 691 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/controls/AssertionControl.java 201 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/controls/AuthorizationIdentityControl.java 295 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/controls/Control.java 80 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/controls/ControlDecoder.java 72 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/controls/EntryChangeNotificationControl.java 396 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/controls/GenericControl.java 157 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/controls/GetEffectiveRightsRequestControl.java 271 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/controls/MatchedValuesControl.java 351 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/controls/PagedResultsControl.java 258 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/controls/PasswordExpiredControl.java 137 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/controls/PasswordExpiringControl.java 175 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/controls/PasswordPolicyControl.java 412 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/controls/PasswordPolicyErrorType.java 128 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/controls/PasswordPolicyWarningType.java 107 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/controls/PersistentSearchChangeType.java 108 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/controls/PersistentSearchControl.java 328 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/controls/PostReadControl.java 447 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/controls/PreReadControl.java 447 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/controls/ProxiedAuthV1Control.java 212 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/controls/ProxiedAuthV2Control.java 216 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/controls/ServerSideSortControl.java 549 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/controls/SortKey.java 144 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/controls/SortResult.java 113 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/controls/SubtreeDeleteControl.java 112 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/controls/VLVControl.java 654 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/controls/VLVResult.java 113 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/controls/VLVTarget.java 191 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/extensions/CancelRequest.java 171 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/extensions/ExtendedOperation.java 34 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/extensions/GetConnectionIDRequest.java 140 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/extensions/GetConnectionIDResult.java 122 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/extensions/GetSymmetricKeyRequest.java 231 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/extensions/PasswordModifyRequest.java 278 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/extensions/PasswordModifyResult.java 119 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/extensions/PasswordPolicyStateExtendedOperation.java 1077 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/extensions/StartTLSRequest.java 120 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/extensions/WhoAmIRequest.java 110 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/extensions/WhoAmIResult.java 113 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/ldap/ASN1StreamReader.java 838 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/ldap/ASN1StreamWriter.java 675 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/ldap/AbstractLDAPMessageHandler.java 258 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/ldap/AbstractLDAPTransport.java 244 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/ldap/AbstractResultFutureImpl.java 259 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/ldap/BindResultFutureImpl.java 98 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/ldap/CompareResultFutureImpl.java 80 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/ldap/ExtendedResultFutureImpl.java 90 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/ldap/LDAPConnection.java 1676 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/ldap/LDAPConnectionFactory.java 129 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/ldap/LDAPConnectionFactoryImpl.java 636 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/ldap/LDAPConnectionOptions.java 210 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/ldap/LDAPConstants.java 332 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/ldap/LDAPDecoder.java 1922 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/ldap/LDAPEncoder.java 723 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/ldap/LDAPMessageHandler.java 190 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/ldap/LDAPUtils.java 738 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/ldap/ResolvedSchema.java 65 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/ldap/ResultFutureImpl.java 80 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/ldap/SASLFilter.java 350 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/ldap/SASLStreamReader.java 118 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/ldap/SASLStreamWriter.java 87 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/ldap/SearchResultFutureImpl.java 127 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/ldap/UnexpectedRequestException.java 71 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/ldap/UnexpectedResponseException.java 71 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/ldap/UnsupportedMessageException.java 81 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/ldif/AbstractLDIFReader.java 891 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/ldif/AbstractLDIFStream.java 174 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/ldif/AbstractLDIFWriter.java 545 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/ldif/ChangeRecord.java 71 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/ldif/ChangeRecordReader.java 86 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/ldif/ChangeRecordVisitor.java 110 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/ldif/ChangeRecordVisitorWriter.java 106 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/ldif/ChangeRecordWriter.java 185 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/ldif/ConnectionChangeRecordWriter.java 323 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/ldif/ConnectionEntryWriter.java 156 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/ldif/EntryReader.java 85 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/ldif/EntryWriter.java 110 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/ldif/LDIFChangeRecordReader.java 719 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/ldif/LDIFChangeRecordWriter.java 478 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/ldif/LDIFEntryReader.java 432 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/ldif/LDIFEntryWriter.java 360 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/ldif/package-info.java 46 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/package-info.java 87 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/requests/AbandonRequest.java 147 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/requests/AbandonRequestImpl.java 95 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/requests/AbstractBindRequest.java 73 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/requests/AbstractExtendedRequest.java 117 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/requests/AbstractRequestImpl.java 170 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/requests/AbstractUnmodifiableRequestImpl.java 138 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/requests/AddRequest.java 341 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/requests/AddRequestImpl.java 387 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/requests/BindRequest.java 137 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/requests/CompareRequest.java 288 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/requests/CompareRequestImpl.java 229 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/requests/DeleteRequest.java 190 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/requests/DeleteRequestImpl.java 133 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/requests/ExtendedRequest.java 165 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/requests/GenericBindRequest.java 243 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/requests/GenericBindRequestImpl.java 182 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/requests/GenericExtendedRequest.java 188 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/requests/GenericExtendedRequestImpl.java 192 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/requests/ModifyDNRequest.java 334 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/requests/ModifyDNRequestImpl.java 244 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/requests/ModifyRequest.java 280 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/requests/ModifyRequestImpl.java 226 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/requests/Request.java 124 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/requests/Requests.java 699 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/requests/SearchRequest.java 527 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/requests/SearchRequestImpl.java 416 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/requests/SimpleBindRequest.java 254 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/requests/SimpleBindRequestImpl.java 174 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/requests/UnbindRequest.java 119 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/requests/UnbindRequestImpl.java 67 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/responses/AbstractExtendedResult.java 113 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/responses/AbstractIntermediateResponse.java 98 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/responses/AbstractResponseImpl.java 170 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/responses/AbstractResultImpl.java 245 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/responses/AbstractUnmodifiableResponseImpl.java 137 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/responses/AbstractUnmodifiableResultImpl.java 167 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/responses/BindResult.java 208 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/responses/BindResultImpl.java 126 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/responses/CompareResult.java 166 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/responses/CompareResultImpl.java 97 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/responses/ExtendedResult.java 172 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/responses/GenericExtendedResult.java 198 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/responses/GenericExtendedResultImpl.java 144 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/responses/GenericIntermediateResponse.java 137 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/responses/GenericIntermediateResponseImpl.java 133 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/responses/IntermediateResponse.java 116 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/responses/Response.java 124 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/responses/Responses.java 278 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/responses/Result.java 279 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/responses/ResultImpl.java 86 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/responses/SearchResultEntry.java 230 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/responses/SearchResultEntryImpl.java 377 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/responses/SearchResultReference.java 151 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/responses/SearchResultReferenceImpl.java 145 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/sasl/AbstractSASLContext.java 248 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/sasl/AnonymousSASLBindRequest.java 161 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/sasl/CRAMMD5SASLBindRequest.java 275 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/sasl/DigestMD5SASLBindRequest.java 436 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/sasl/ExternalSASLBindRequest.java 190 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/sasl/GSSAPISASLBindRequest.java 304 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/sasl/GenericSASLBindRequest.java 175 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/sasl/NameCallbackHandler.java 42 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/sasl/PasswordCallbackHandler.java 42 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/sasl/PlainSASLBindRequest.java 320 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/sasl/SASLBindRequest.java 66 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/sasl/SASLContext.java 77 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/sasl/TextInputCallbackHandler.java 42 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/schema/AbstractMatchingRuleImpl.java 132 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/schema/AbstractOrderingMatchingRuleImpl.java 104 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/schema/AbstractSubstringMatchingRuleImpl.java 270 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/schema/AbstractSyntaxImpl.java 77 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/schema/AttributeType.java 908 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/schema/AttributeTypeSyntaxImpl.java 277 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/schema/AttributeUsage.java 112 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/schema/AuthPasswordExactEqualityMatchingRuleImpl.java 62 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/schema/AuthPasswordSyntaxImpl.java 340 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/schema/BinarySyntaxImpl.java 98 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/schema/BitStringEqualityMatchingRuleImpl.java 89 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/schema/BitStringSyntaxImpl.java 127 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/schema/BooleanEqualityMatchingRuleImpl.java 64 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/schema/BooleanSyntaxImpl.java 105 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/schema/CaseExactEqualityMatchingRuleImpl.java 83 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/schema/CaseExactIA5EqualityMatchingRuleImpl.java 98 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/schema/CaseExactIA5SubstringMatchingRuleImpl.java 117 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/schema/CaseExactOrderingMatchingRuleImpl.java 83 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/schema/CaseExactSubstringMatchingRuleImpl.java 100 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/schema/CaseIgnoreEqualityMatchingRuleImpl.java 83 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/schema/CaseIgnoreIA5EqualityMatchingRuleImpl.java 98 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/schema/CaseIgnoreIA5SubstringMatchingRuleImpl.java 115 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/schema/CaseIgnoreListEqualityMatchingRuleImpl.java 96 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/schema/CaseIgnoreListSubstringMatchingRuleImpl.java 140 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/schema/CaseIgnoreOrderingMatchingRuleImpl.java 83 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/schema/CaseIgnoreSubstringMatchingRuleImpl.java 101 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/schema/CertificateListSyntaxImpl.java 108 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/schema/CertificatePairSyntaxImpl.java 107 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/schema/CertificateSyntaxImpl.java 107 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/schema/ConflictingSchemaElementException.java 58 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/schema/CoreSchema.java 2666 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/schema/CoreSchemaImpl.java 1146 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/schema/CountryStringSyntaxImpl.java 136 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/schema/DITContentRule.java 623 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/schema/DITContentRuleSyntaxImpl.java 203 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/schema/DITStructureRule.java 342 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/schema/DITStructureRuleSyntaxImpl.java 205 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/schema/DeliveryMethodSyntaxImpl.java 172 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/schema/DirectoryStringFirstComponentEqualityMatchingRuleImpl.java 140 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/schema/DirectoryStringSyntaxImpl.java 125 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/schema/DistinguishedNameEqualityMatchingRuleImpl.java 213 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/schema/DistinguishedNameSyntaxImpl.java 95 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/schema/DoubleMetaphoneApproximateMatchingRuleImpl.java 1117 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/schema/EnhancedGuideSyntaxImpl.java 184 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/schema/EnumOrderingMatchingRule.java 73 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/schema/EnumSyntaxImpl.java 200 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/schema/EqualLengthApproximateMatchingRuleImpl.java 71 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/schema/FacsimileNumberSyntaxImpl.java 240 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/schema/FaxSyntaxImpl.java 100 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/schema/GeneralizedTimeEqualityMatchingRuleImpl.java 50 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/schema/GeneralizedTimeOrderingMatchingRuleImpl.java 50 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/schema/GeneralizedTimeSyntaxImpl.java 1463 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/schema/GenerateCoreSchema.java 415 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/schema/GuideSyntaxImpl.java 430 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/schema/IA5StringSyntaxImpl.java 131 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/schema/IntegerEqualityMatchingRuleImpl.java 66 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/schema/IntegerFirstComponentEqualityMatchingRuleImpl.java 131 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/schema/IntegerOrderingMatchingRuleImpl.java 66 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/schema/IntegerSyntaxImpl.java 228 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/schema/JPEGSyntaxImpl.java 99 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/schema/KeywordEqualityMatchingRuleImpl.java 184 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/schema/LDAPSyntaxDescriptionSyntaxImpl.java 236 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/schema/MatchingRule.java 457 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/schema/MatchingRuleImpl.java 160 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/schema/MatchingRuleSyntaxImpl.java 215 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/schema/MatchingRuleUse.java 371 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/schema/MatchingRuleUseSyntaxImpl.java 217 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/schema/NameAndOptionalUIDSyntaxImpl.java 152 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/schema/NameForm.java 452 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/schema/NameFormSyntaxImpl.java 223 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/schema/NumericStringEqualityMatchingRuleImpl.java 60 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/schema/NumericStringOrderingMatchingRuleImpl.java 59 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/schema/NumericStringSubstringMatchingRuleImpl.java 59 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/schema/NumericStringSyntaxImpl.java 137 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/schema/OIDSyntaxImpl.java 108 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/schema/ObjectClass.java 810 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/schema/ObjectClassSyntaxImpl.java 214 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/schema/ObjectClassType.java 82 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/schema/ObjectIdentifierEqualityMatchingRuleImpl.java 188 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/schema/ObjectIdentifierFirstComponentEqualityMatchingRuleImpl.java 110 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/schema/OctetStringEqualityMatchingRuleImpl.java 49 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/schema/OctetStringOrderingMatchingRuleImpl.java 49 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/schema/OctetStringSubstringMatchingRuleImpl.java 49 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/schema/OctetStringSyntaxImpl.java 99 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/schema/OtherMailboxSyntaxImpl.java 177 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/schema/PostalAddressSyntaxImpl.java 101 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/schema/PresentationAddressEqualityMatchingRuleImpl.java 85 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/schema/PresentationAddressSyntaxImpl.java 113 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/schema/PrintableStringSyntaxImpl.java 250 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/schema/ProtocolInformationEqualityMatchingRuleImpl.java 85 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/schema/ProtocolInformationSyntaxImpl.java 113 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/schema/RegexSyntaxImpl.java 127 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/schema/Schema.java 2531 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/schema/SchemaBuilder.java 3007 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/schema/SchemaCompatOptions.java 164 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/schema/SchemaConstants.java 1623 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/schema/SchemaElement.java 185 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/schema/SchemaException.java 89 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/schema/SchemaLocal.java 130 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/schema/SchemaNotFoundException.java 93 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/schema/SchemaUtils.java 883 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/schema/SubstringAssertionSyntaxImpl.java 150 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/schema/SupportedAlgorithmSyntaxImpl.java 108 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/schema/Syntax.java 439 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/schema/SyntaxImpl.java 144 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/schema/TelephoneNumberEqualityMatchingRuleImpl.java 67 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/schema/TelephoneNumberSubstringMatchingRuleImpl.java 67 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/schema/TelephoneNumberSyntaxImpl.java 203 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/schema/TeletexTerminalIdentifierSyntaxImpl.java 271 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/schema/TelexNumberSyntaxImpl.java 230 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/schema/UTCTimeSyntaxImpl.java 767 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/schema/UUIDEqualityMatchingRuleImpl.java 135 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/schema/UUIDOrderingMatchingRuleImpl.java 135 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/schema/UUIDSyntaxImpl.java 150 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/schema/UniqueMemberEqualityMatchingRuleImpl.java 50 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/schema/UnknownSchemaElementException.java 56 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/schema/UserPasswordExactEqualityMatchingRuleImpl.java 78 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/schema/UserPasswordSyntaxImpl.java 202 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/schema/WordEqualityMatchingRuleImpl.java 184 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/tools/Argument.java 808 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/tools/ArgumentException.java 96 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/tools/ArgumentGroup.java 209 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/tools/ArgumentParser.java 2007 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/tools/ArgumentParserConnectionFactory.java 940 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/tools/BooleanArgument.java 125 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/tools/DataSource.java 481 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/tools/FileBasedArgument.java 283 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/tools/IntegerArgument.java 547 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/tools/LDAPCompare.java 674 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/tools/LDAPModify.java 801 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/tools/LDAPPasswordModify.java 475 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/tools/LDAPSearch.java 1241 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/tools/ModRate.java 431 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/tools/MultiChoiceArgument.java 273 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/tools/MultiColumnPrinter.java 519 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/tools/PerformanceRunner.java 943 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/tools/SearchRate.java 519 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/tools/StringArgument.java 150 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/tools/Utils.java 476 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/util/ASCIICharProp.java 372 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/util/Base64.java 388 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/util/ByteSequence.java 348 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/util/ByteSequenceOutputStream.java 113 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/util/ByteSequenceReader.java 510 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/util/ByteString.java 681 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/util/ByteStringBuilder.java 1108 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/util/Function.java 58 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/util/Functions.java 345 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/util/Iterables.java 397 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/util/Iterators.java 549 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/util/LocalizableException.java 48 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/util/LocalizedIllegalArgumentException.java 101 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/util/Platform.java 650 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/util/Predicate.java 57 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/util/SSLUtils.java 47 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/util/SizeLimitInputStream.java 182 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/util/StaticUtils.java 1998 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/util/StringPrepProfile.java 696 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/util/SubstringReader.java 84 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/util/Validator.java 215 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/util/ssl/DistrustAllTrustManager.java 66 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/util/ssl/HostnameMismatchCertificateException.java 67 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/util/ssl/PromptingTrustManager.java 412 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/util/ssl/TrustAllTrustManager.java 64 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/util/ssl/TrustStoreTrustManager.java 285 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/AbstractAttribute.java
New file
@@ -0,0 +1,512 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Copyright 2009 Sun Microsystems, Inc.
 */
package org.opends.sdk;
import java.util.*;
import org.opends.sdk.schema.AttributeType;
import org.opends.sdk.schema.MatchingRule;
import org.opends.sdk.util.ByteString;
import org.opends.sdk.util.Function;
import org.opends.sdk.util.Validator;
/**
 * This class provides a skeletal implementation of the {@code
 * Attribute} interface, to minimize the effort required to implement
 * this interface.
 */
public abstract class AbstractAttribute extends AbstractSet<ByteString>
    implements Attribute
{
  /**
   * Returns {@code true} if {@code object} is an attribute which is
   * equal to {@code attribute}. Two attributes are considered equal if
   * their attribute descriptions are equal, they both have the same
   * number of attribute values, and every attribute value contained in
   * the first attribute is also contained in the second attribute.
   *
   * @param attribute
   *          The attribute to be tested for equality.
   * @param object
   *          The object to be tested for equality with the attribute.
   * @return {@code true} if {@code object} is an attribute which is
   *         equal to {@code attribute}, or {@code false} if not.
   */
  static boolean equals(Attribute attribute, Object object)
  {
    if (attribute == object)
    {
      return true;
    }
    if (!(object instanceof Attribute))
    {
      return false;
    }
    Attribute other = (Attribute) object;
    if (!attribute.getAttributeDescription().equals(
        other.getAttributeDescription()))
    {
      return false;
    }
    // Attribute description is the same, compare values.
    if (attribute.size() != other.size())
    {
      return false;
    }
    return attribute.containsAll(other);
  }
  /**
   * Returns the hash code for {@code attribute}. It will be calculated
   * as the sum of the hash codes of the attribute description and all
   * of the attribute values.
   *
   * @param attribute
   *          The attribute whose hash code should be calculated.
   * @return The hash code for {@code attribute}.
   */
  static int hashCode(Attribute attribute)
  {
    int hashCode = attribute.getAttributeDescription().hashCode();
    for (ByteString value : attribute)
    {
      hashCode += normalizeValue(attribute, value).hashCode();
    }
    return hashCode;
  }
  /**
   * Returns the normalized form of {@code value} normalized using
   * {@code attribute}'s equality matching rule.
   *
   * @param attribute
   *          The attribute whose equality matching rule should be used
   *          for normalization.
   * @param value
   *          The attribute value to be normalized.
   * @return The normalized form of {@code value} normalized using
   *         {@code attribute}'s equality matching rule.
   */
  static ByteString normalizeValue(Attribute attribute, ByteString value)
  {
    AttributeDescription attributeDescription = attribute
        .getAttributeDescription();
    AttributeType attributeType = attributeDescription
        .getAttributeType();
    MatchingRule matchingRule = attributeType.getEqualityMatchingRule();
    try
    {
      return matchingRule.normalizeAttributeValue(value);
    }
    catch (Exception e)
    {
      // Fall back to provided value.
      return value;
    }
  }
  /**
   * Returns a string representation of {@code attribute}.
   *
   * @param attribute
   *          The attribute whose string representation should be
   *          returned.
   * @return The string representation of {@code attribute}.
   */
  static String toString(Attribute attribute)
  {
    StringBuilder builder = new StringBuilder();
    builder.append("Attribute(");
    builder.append(attribute.getAttributeDescriptionAsString());
    builder.append(", {");
    boolean firstValue = true;
    for (ByteString value : attribute)
    {
      if (!firstValue)
      {
        builder.append(", ");
      }
      builder.append(value);
      firstValue = false;
    }
    builder.append("})");
    return builder.toString();
  }
  /**
   * Sole constructor.
   */
  protected AbstractAttribute()
  {
    // No implementation required.
  }
  /**
   * {@inheritDoc}
   */
  public abstract boolean add(ByteString value)
      throws UnsupportedOperationException, NullPointerException;
  /**
   * {@inheritDoc}
   */
  public boolean add(Object firstValue, Object... remainingValues)
      throws UnsupportedOperationException, NullPointerException
  {
    Validator.ensureNotNull(firstValue);
    boolean modified = add(ByteString.valueOf(firstValue));
    if (remainingValues != null)
    {
      for (Object value : remainingValues)
      {
        modified |= add(ByteString.valueOf(value));
      }
    }
    return modified;
  }
  /**
   * {@inheritDoc}
   */
  public boolean addAll(Collection<? extends ByteString> values)
      throws UnsupportedOperationException, NullPointerException
  {
    return addAll(values, null);
  }
  /**
   * {@inheritDoc}
   */
  public boolean addAll(Collection<? extends ByteString> values,
      Collection<? super ByteString> duplicateValues)
      throws UnsupportedOperationException, NullPointerException
  {
    boolean modified = false;
    for (ByteString value : values)
    {
      if (add(value))
      {
        modified = true;
      }
      else if (duplicateValues != null)
      {
        duplicateValues.add(value);
      }
    }
    return modified;
  }
  /**
   * {@inheritDoc}
   */
  public abstract boolean contains(Object value)
      throws NullPointerException;
  /**
   * {@inheritDoc}
   */
  public boolean containsAll(Collection<?> values)
      throws NullPointerException
  {
    for (Object value : values)
    {
      if (!contains(value))
      {
        return false;
      }
    }
    return true;
  }
  /**
   * {@inheritDoc}
   */
  public boolean equals(Object object)
  {
    return equals(this, object);
  }
  /**
   * {@inheritDoc}
   */
  public ByteString firstValue() throws NoSuchElementException
  {
    return iterator().next();
  }
  /**
   * {@inheritDoc}
   */
  public <T> T firstValueAsObject(
      Function<? super ByteString, T, Void> type)
      throws NoSuchElementException
  {
    return type.apply(firstValue(), null);
  }
  /**
   * {@inheritDoc}
   */
  public <T, P> T firstValueAsObject(
      Function<? super ByteString, T, P> type, P p)
      throws NoSuchElementException
  {
    return type.apply(firstValue(), p);
  }
  /**
   * {@inheritDoc}
   */
  public String firstValueAsString() throws NoSuchElementException
  {
    return firstValue().toString();
  }
  /**
   * {@inheritDoc}
   */
  public abstract AttributeDescription getAttributeDescription();
  /**
   * {@inheritDoc}
   */
  public String getAttributeDescriptionAsString()
  {
    return getAttributeDescription().toString();
  }
  /**
   * {@inheritDoc}
   */
  public int hashCode()
  {
    return hashCode(this);
  }
  /**
   * {@inheritDoc}
   */
  public abstract Iterator<ByteString> iterator();
  /**
   * {@inheritDoc}
   */
  public abstract boolean remove(Object value)
      throws UnsupportedOperationException, NullPointerException;
  /**
   * {@inheritDoc}
   */
  public boolean removeAll(Collection<?> values)
      throws UnsupportedOperationException, NullPointerException
  {
    return removeAll(values, null);
  }
  /**
   * {@inheritDoc}
   */
  public <T> boolean removeAll(Collection<T> values,
      Collection<? super T> missingValues)
      throws UnsupportedOperationException, NullPointerException
  {
    boolean modified = false;
    for (T value : values)
    {
      if (remove(value))
      {
        modified = true;
      }
      else if (missingValues != null)
      {
        missingValues.add(value);
      }
    }
    return modified;
  }
  /**
   * {@inheritDoc}
   */
  public boolean retainAll(Collection<?> values)
      throws UnsupportedOperationException, NullPointerException
  {
    return retainAll(values, null);
  }
  /**
   * {@inheritDoc}
   */
  public <T> boolean retainAll(Collection<T> values,
      Collection<? super T> missingValues)
      throws UnsupportedOperationException, NullPointerException
  {
    if (values.isEmpty())
    {
      if (isEmpty())
      {
        return false;
      }
      else
      {
        clear();
        return true;
      }
    }
    if (isEmpty())
    {
      if (missingValues != null)
      {
        for (T value : values)
        {
          missingValues.add(value);
        }
      }
      return false;
    }
    Map<ByteString, T> valuesToRetain = new HashMap<ByteString, T>(
        values.size());
    for (T value : values)
    {
      valuesToRetain.put(
          normalizeValue(this, ByteString.valueOf(value)), value);
    }
    boolean modified = false;
    Iterator<ByteString> iterator = iterator();
    while (iterator.hasNext())
    {
      ByteString value = iterator.next();
      ByteString normalizedValue = normalizeValue(this, value);
      if (valuesToRetain.remove(normalizedValue) == null)
      {
        modified = true;
        iterator.remove();
      }
    }
    if (missingValues != null)
    {
      missingValues.addAll(valuesToRetain.values());
    }
    return modified;
  }
  /**
   * {@inheritDoc}
   */
  public abstract int size();
  /**
   * {@inheritDoc}
   */
  public ByteString[] toArray()
  {
    return toArray(new ByteString[size()]);
  }
  /**
   * {@inheritDoc}
   */
  public String toString()
  {
    return toString(this);
  }
}
opendj-sdk/sdk/src/org/opends/sdk/AbstractConnection.java
New file
@@ -0,0 +1,315 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Copyright 2009 Sun Microsystems, Inc.
 */
package org.opends.sdk;
import static org.opends.messages.ProtocolMessages.*;
import java.util.Collection;
import java.util.LinkedList;
import java.util.List;
import org.opends.sdk.requests.Requests;
import org.opends.sdk.requests.SearchRequest;
import org.opends.sdk.responses.*;
import org.opends.sdk.util.ByteString;
import org.opends.sdk.util.LocalizedIllegalArgumentException;
import org.opends.sdk.util.Validator;
/**
 * This class provides a skeletal implementation of the {@code
 * Connection} interface, to minimize the effort required to implement
 * this interface.
 */
public abstract class AbstractConnection implements Connection
{
  /**
   * Creates a new abstract connection.
   */
  protected AbstractConnection()
  {
    // No implementation required.
  }
  private static final class SingleEntryHandler implements
      SearchResultHandler<Void>
  {
    // FIXME: does this need to be thread safe?
    private SearchResultEntry firstEntry = null;
    private SearchResultReference firstReference = null;
    private int entryCount = 0;
    public void handleReference(Void p, SearchResultReference reference)
    {
      if (firstReference == null)
      {
        firstReference = reference;
      }
    }
    public void handleEntry(Void p, SearchResultEntry entry)
    {
      if (firstEntry == null)
      {
        firstEntry = entry;
      }
      entryCount++;
    }
  }
  public Result add(Entry entry) throws ErrorResultException,
      InterruptedException, UnsupportedOperationException,
      IllegalStateException, NullPointerException
  {
    return add(Requests.newAddRequest(entry));
  }
  public Result add(String... ldifLines) throws ErrorResultException,
      InterruptedException, UnsupportedOperationException,
      LocalizedIllegalArgumentException, IllegalStateException,
      NullPointerException
  {
    return add(Requests.newAddRequest(ldifLines));
  }
  public BindResult bind(String name, String password)
      throws ErrorResultException, InterruptedException,
      LocalizedIllegalArgumentException, UnsupportedOperationException,
      IllegalStateException, NullPointerException
  {
    return bind(Requests.newSimpleBindRequest(name, password));
  }
  public CompareResult compare(String name,
      String attributeDescription, String assertionValue)
      throws ErrorResultException, InterruptedException,
      LocalizedIllegalArgumentException, UnsupportedOperationException,
      IllegalStateException, NullPointerException
  {
    return compare(Requests.newCompareRequest(name,
        attributeDescription, assertionValue));
  }
  public Result delete(String name) throws ErrorResultException,
      InterruptedException, LocalizedIllegalArgumentException,
      UnsupportedOperationException, IllegalStateException,
      NullPointerException
  {
    return delete(Requests.newDeleteRequest(name));
  }
  public GenericExtendedResult extendedRequest(String requestName,
      ByteString requestValue) throws ErrorResultException,
      InterruptedException, UnsupportedOperationException,
      IllegalStateException, NullPointerException
  {
    return extendedRequest(Requests.newGenericExtendedRequest(
        requestName, requestValue));
  }
  public Result modify(String... ldifLines)
      throws ErrorResultException, InterruptedException,
      UnsupportedOperationException, LocalizedIllegalArgumentException,
      IllegalStateException, NullPointerException
  {
    return modify(Requests.newModifyRequest(ldifLines));
  }
  public Result modifyDN(String name, String newRDN)
      throws ErrorResultException, InterruptedException,
      LocalizedIllegalArgumentException, UnsupportedOperationException,
      IllegalStateException, NullPointerException
  {
    return modifyDN(Requests.newModifyDNRequest(name, newRDN));
  }
  public Result search(SearchRequest request,
      final Collection<? super SearchResultEntry> entries,
      final Collection<? super SearchResultReference> references)
      throws ErrorResultException, InterruptedException,
      UnsupportedOperationException, IllegalStateException,
      NullPointerException
  {
    Validator.ensureNotNull(request, entries);
    // FIXME: does this need to be thread safe?
    SearchResultHandler<Void> handler = new SearchResultHandler<Void>()
    {
      public void handleReference(Void p,
          SearchResultReference reference)
      {
        if (references != null)
        {
          references.add(reference);
        }
      }
      public void handleEntry(Void p, SearchResultEntry entry)
      {
        entries.add(entry);
      }
    };
    return search(request, handler, null);
  }
  /**
   * {@inheritDoc}
   */
  public Result search(SearchRequest request,
      Collection<? super SearchResultEntry> entries)
      throws ErrorResultException, InterruptedException,
      UnsupportedOperationException, IllegalStateException,
      NullPointerException
  {
    return search(request, entries, null);
  }
  public List<SearchResultEntry> search(String baseObject,
      SearchScope scope, String filter, String... attributeDescriptions)
      throws ErrorResultException, InterruptedException,
      LocalizedIllegalArgumentException, UnsupportedOperationException,
      IllegalStateException, NullPointerException
  {
    List<SearchResultEntry> entries = new LinkedList<SearchResultEntry>();
    SearchRequest request = Requests.newSearchRequest(baseObject,
        scope, filter, attributeDescriptions);
    search(request, entries);
    return entries;
  }
  public SearchResultEntry searchSingleEntry(SearchRequest request)
      throws ErrorResultException, InterruptedException,
      UnsupportedOperationException, IllegalStateException,
      NullPointerException
  {
    SingleEntryHandler handler = new SingleEntryHandler();
    search(request, handler, null);
    if (handler.entryCount > 1)
    {
      // Got more entries than expected.
      Result result = Responses.newResult(
          ResultCode.CLIENT_SIDE_LOCAL_ERROR).setDiagnosticMessage(
          ERR_UNEXPECTED_SEARCH_RESULT_ENTRIES.get(handler.entryCount)
              .toString());
      throw new ErrorResultException(result);
    }
    else if (handler.firstReference != null)
    {
      // Got an unexpected search result reference.
      Result result = Responses.newResult(
          ResultCode.CLIENT_SIDE_LOCAL_ERROR).setDiagnosticMessage(
          ERR_UNEXPECTED_SEARCH_RESULT_REFERENCES.get(
              handler.firstReference.getURIs().iterator().next())
              .toString());
      throw new ErrorResultException(result);
    }
    else
    {
      return handler.firstEntry;
    }
  }
  public SearchResultEntry searchSingleEntry(String baseObject,
      SearchScope scope, String filter, String... attributeDescriptions)
      throws ErrorResultException, InterruptedException,
      LocalizedIllegalArgumentException, UnsupportedOperationException,
      IllegalStateException, NullPointerException
  {
    SearchRequest request = Requests.newSearchRequest(baseObject,
        scope, filter, attributeDescriptions);
    return searchSingleEntry(request);
  }
  public SearchResultEntry readEntry(String baseObject,
      String... attributeDescriptions) throws ErrorResultException,
      InterruptedException, LocalizedIllegalArgumentException,
      UnsupportedOperationException, IllegalStateException,
      NullPointerException
  {
    return readEntry(DN.valueOf(baseObject));
  }
  public SearchResultEntry readEntry(DN baseObject,
      String... attributeDescriptions) throws ErrorResultException,
      InterruptedException, UnsupportedOperationException,
      IllegalStateException, NullPointerException
  {
    SearchRequest request = Requests.newSearchRequest(baseObject,
        SearchScope.BASE_OBJECT, Filter.getObjectClassPresentFilter(),
        attributeDescriptions);
    return searchSingleEntry(request);
  }
}
opendj-sdk/sdk/src/org/opends/sdk/AbstractConnectionFactory.java
New file
@@ -0,0 +1,125 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Copyright 2009 Sun Microsystems, Inc.
 */
package org.opends.sdk;
import org.opends.sdk.responses.Responses;
import org.opends.sdk.responses.Result;
/**
 * This class provides a skeletal implementation of the {@code
 * ConnectionFactory} interface, to minimize the effort required to
 * implement this interface.
 *
 * @param <C>
 *          The type of asynchronous connection returned by this
 *          connection factory.
 */
public abstract class AbstractConnectionFactory<C extends AsynchronousConnection>
    implements ConnectionFactory<C>
{
  /**
   * Creates a new abstract connection factory.
   */
  protected AbstractConnectionFactory()
  {
    // Nothing to do.
  }
  /**
   * {@inheritDoc}
   */
  public abstract <P> ConnectionFuture<? extends C> getAsynchronousConnection(
      ConnectionResultHandler<? super C, P> handler, P p);
  /**
   * {@inheritDoc}
   * <p>
   * The default implementation is to convert the asynchronous
   * connection returned from {@code
   * blockingGetAsynchronousConnection()} to a synchronous connection
   * using a {@link SynchronousConnection} as per the following code:
   *
   * <pre>
   * return new SynchronousConnection(blockingGetAsynchronousConnection());
   * </pre>
   *
   * Implementations should override this method if they wish to return
   * a different type of synchronous connection.
   *
   * @return A connection to the Directory Server associated with this
   *         connection factory.
   * @throws ErrorResultException
   *           If the connection request failed for some reason.
   */
  public Connection getConnection() throws ErrorResultException
  {
    return new SynchronousConnection(
        blockingGetAsynchronousConnection());
  }
  /**
   * Invokes {@code getAsynchronousConnection}, blocking until the
   * asynchronous connection is obtained or the attempt fails.
   *
   * @return An asynchronous connection obtained using {@code
   *         getAsynchronousConnection}.
   * @throws ErrorResultException
   *           If the connection request failed for some reason.
   */
  protected final C blockingGetAsynchronousConnection()
      throws ErrorResultException
  {
    ConnectionFuture<? extends C> future =
        getAsynchronousConnection(null, null);
    try
    {
      return future.get();
    }
    catch (InterruptedException e)
    {
      // Cancel the request if possible.
      future.cancel(false);
      Result result =
          Responses.newResult(ResultCode.CLIENT_SIDE_LOCAL_ERROR)
              .setCause(e)
              .setDiagnosticMessage(e.getLocalizedMessage());
      throw new ErrorResultException(result);
    }
  }
}
opendj-sdk/sdk/src/org/opends/sdk/AbstractEntry.java
New file
@@ -0,0 +1,421 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Copyright 2009 Sun Microsystems, Inc.
 */
package org.opends.sdk;
import org.opends.sdk.schema.ObjectClass;
import org.opends.sdk.util.*;
/**
 * This class provides a skeletal implementation of the {@code Entry}
 * interface, to minimize the effort required to implement this
 * interface.
 */
public abstract class AbstractEntry implements Entry
{
  // Function used for getObjectClasses
  private static final Function<ByteString, String, Void> BYTE_STRING_TO_STRING_FUNCTION = new Function<ByteString, String, Void>()
  {
    public String apply(ByteString value, Void p)
    {
      return value.toString();
    }
  };
  // Predicate used for findAttributes.
  private static final Predicate<Attribute, AttributeDescription> FIND_ATTRIBUTES_PREDICATE = new Predicate<Attribute, AttributeDescription>()
  {
    public boolean matches(Attribute value, AttributeDescription p)
    {
      return value.getAttributeDescription().isSubTypeOf(p);
    }
  };
  /**
   * Returns {@code true} if {@code object} is an entry which is equal
   * to {@code entry}. Two entry are considered equal if their
   * distinguished names are equal, they both have the same number of
   * attributes, and every attribute contained in the first entry is
   * also contained in the second entry.
   *
   * @param entry
   *          The entry to be tested for equality.
   * @param object
   *          The object to be tested for equality with the entry.
   * @return {@code true} if {@code object} is an entry which is equal
   *         to {@code entry}, or {@code false} if not.
   */
  static boolean equals(Entry entry, Object object)
  {
    if (entry == object)
    {
      return true;
    }
    if (!(object instanceof Entry))
    {
      return false;
    }
    Entry other = (Entry) object;
    if (!entry.getName().equals(other.getName()))
    {
      return false;
    }
    // Distinguished name is the same, compare attributes.
    if (entry.getAttributeCount() != other.getAttributeCount())
    {
      return false;
    }
    for (Attribute attribute : entry.getAttributes())
    {
      Attribute otherAttribute = other.getAttribute(attribute
          .getAttributeDescription());
      if (!attribute.equals(otherAttribute))
      {
        return false;
      }
    }
    return true;
  }
  /**
   * Returns the hash code for {@code entry}. It will be calculated as
   * the sum of the hash codes of the distinguished name and all of the
   * attributes.
   *
   * @param entry
   *          The entry whose hash code should be calculated.
   * @return The hash code for {@code entry}.
   */
  static int hashCode(Entry entry)
  {
    int hashCode = entry.getName().hashCode();
    for (Attribute attribute : entry.getAttributes())
    {
      hashCode += attribute.hashCode();
    }
    return hashCode;
  }
  /**
   * Returns a string representation of {@code entry}.
   *
   * @param entry
   *          The entry whose string representation should be returned.
   * @return The string representation of {@code entry}.
   */
  static String toString(Entry entry)
  {
    StringBuilder builder = new StringBuilder();
    builder.append("Entry(");
    builder.append(entry.getName());
    builder.append(", {");
    boolean firstValue = true;
    for (Attribute attribute : entry.getAttributes())
    {
      if (!firstValue)
      {
        builder.append(", ");
      }
      builder.append(attribute);
      firstValue = false;
    }
    builder.append("})");
    return builder.toString();
  }
  /**
   * Sole constructor.
   */
  protected AbstractEntry()
  {
    // No implementation required.
  }
  /**
   * {@inheritDoc}
   */
  public boolean addAttribute(Attribute attribute)
      throws UnsupportedOperationException, NullPointerException
  {
    return addAttribute(attribute, null);
  }
  /**
   * {@inheritDoc}
   */
  public Entry addAttribute(String attributeDescription,
      Object... values) throws LocalizedIllegalArgumentException,
      UnsupportedOperationException, NullPointerException
  {
    addAttribute(new LinkedAttribute(attributeDescription, values), null);
    return this;
  }
  /**
   * {@inheritDoc}
   */
  public boolean containsAttribute(String attributeDescription)
      throws LocalizedIllegalArgumentException, NullPointerException
  {
    return containsAttribute(AttributeDescription
        .valueOf(attributeDescription));
  }
  /**
   * {@inheritDoc}
   */
  public boolean containsObjectClass(ObjectClass objectClass)
      throws NullPointerException
  {
    return containsObjectClass(objectClass.getOID());
  }
  /**
   * {@inheritDoc}
   */
  public boolean containsObjectClass(String objectClass)
      throws NullPointerException
  {
    Validator.ensureNotNull(objectClass);
    Attribute attribute = getAttribute(AttributeDescription
        .objectClass());
    return attribute != null ? attribute.contains(objectClass) : false;
  }
  /**
   * {@inheritDoc}
   */
  public boolean equals(Object object)
  {
    return equals(this, object);
  }
  /**
   * {@inheritDoc}
   */
  public Iterable<Attribute> findAttributes(
      AttributeDescription attributeDescription)
      throws NullPointerException
  {
    Validator.ensureNotNull(attributeDescription);
    return Iterables.filter(getAttributes(), FIND_ATTRIBUTES_PREDICATE,
        attributeDescription);
  }
  /**
   * {@inheritDoc}
   */
  public Iterable<Attribute> findAttributes(String attributeDescription)
      throws LocalizedIllegalArgumentException, NullPointerException
  {
    return findAttributes(AttributeDescription
        .valueOf(attributeDescription));
  }
  /**
   * {@inheritDoc}
   */
  public Attribute getAttribute(String attributeDescription)
      throws LocalizedIllegalArgumentException, NullPointerException
  {
    return getAttribute(AttributeDescription
        .valueOf(attributeDescription));
  }
  /**
   * {@inheritDoc}
   */
  public Iterable<String> getObjectClasses()
  {
    Attribute attribute = getAttribute(AttributeDescription
        .objectClass());
    if (attribute == null)
    {
      return Iterables.empty();
    }
    else
    {
      return Iterables.transform(attribute,
          BYTE_STRING_TO_STRING_FUNCTION);
    }
  }
  /**
   * {@inheritDoc}
   */
  public int hashCode()
  {
    return hashCode(this);
  }
  /**
   * {@inheritDoc}
   */
  public boolean removeAttribute(
      AttributeDescription attributeDescription)
      throws UnsupportedOperationException, NullPointerException
  {
    return removeAttribute(Types.emptyAttribute(attributeDescription),
        null);
  }
  /**
   * {@inheritDoc}
   */
  public Entry removeAttribute(String attributeDescription)
      throws LocalizedIllegalArgumentException,
      UnsupportedOperationException, NullPointerException
  {
    removeAttribute(new LinkedAttribute(attributeDescription), null);
    return this;
  }
  /**
   * {@inheritDoc}
   */
  public Entry removeAttribute(String attributeDescription,
      Object... values) throws LocalizedIllegalArgumentException,
      UnsupportedOperationException, NullPointerException
  {
    removeAttribute(new LinkedAttribute(attributeDescription, values),
        null);
    return this;
  }
  /**
   * {@inheritDoc}
   */
  public boolean replaceAttribute(Attribute attribute)
      throws UnsupportedOperationException, NullPointerException
  {
    if (attribute.isEmpty())
    {
      return removeAttribute(attribute.getAttributeDescription());
    }
    else
    {
      removeAttribute(attribute.getAttributeDescription());
      addAttribute(attribute);
      return true;
    }
  }
  /**
   * {@inheritDoc}
   */
  public Entry replaceAttribute(String attributeDescription,
      Object... values) throws LocalizedIllegalArgumentException,
      UnsupportedOperationException, NullPointerException
  {
    replaceAttribute(new LinkedAttribute(attributeDescription, values));
    return this;
  }
  /**
   * {@inheritDoc}
   */
  public Entry setName(String dn)
      throws LocalizedIllegalArgumentException,
      UnsupportedOperationException, NullPointerException
  {
    return setName(DN.valueOf(dn));
  }
  /**
   * {@inheritDoc}
   */
  public String toString()
  {
    return toString(this);
  }
}
opendj-sdk/sdk/src/org/opends/sdk/AbstractFilterVisitor.java
New file
@@ -0,0 +1,233 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Copyright 2009 Sun Microsystems, Inc.
 */
package org.opends.sdk;
import java.util.List;
import org.opends.sdk.util.ByteSequence;
/**
 * An abstract filter visitor whose default implementation for all
 * {@code Visitor} methods is to invoke
 * {@link #visitDefaultFilter(Object)}.
 * <p>
 * Implementations can override the methods on a case by case behavior.
 *
 * @param <R>
 *          The return type of this visitor's methods. Use
 *          {@link java.lang.Void} for visitors that do not need to
 *          return results.
 * @param <P>
 *          The type of the additional parameter to this visitor's
 *          methods. Use {@link java.lang.Void} for visitors that do not
 *          need an additional parameter.
 */
public abstract class AbstractFilterVisitor<R, P> implements
    FilterVisitor<R, P>
{
  /**
   * Default constructor.
   */
  protected AbstractFilterVisitor()
  {
    // Nothing to do.
  }
  /**
   * {@inheritDoc}
   * <p>
   * The default implementation is to call
   * {@link #visitDefaultFilter(Object)}.
   */
  public R visitAndFilter(P p, List<Filter> subFilters)
  {
    return visitDefaultFilter(p);
  }
  /**
   * {@inheritDoc}
   * <p>
   * The default implementation is to call
   * {@link #visitDefaultFilter(Object)}.
   */
  public R visitApproxMatchFilter(P p, String attributeDescription,
      ByteSequence assertionValue)
  {
    return visitDefaultFilter(p);
  }
  /**
   * Visits any filters which are not explicitly handled by other
   * visitor methods.
   * <p>
   * The default implementation of this method is to return {@code null}.
   *
   * @param p
   *          A visitor specified parameter.
   * @return A visitor specified result.
   */
  public R visitDefaultFilter(P p)
  {
    return null;
  }
  /**
   * {@inheritDoc}
   * <p>
   * The default implementation is to call
   * {@link #visitDefaultFilter(Object)}.
   */
  public R visitEqualityMatchFilter(P p, String attributeDescription,
      ByteSequence assertionValue)
  {
    return visitDefaultFilter(p);
  }
  /**
   * {@inheritDoc}
   * <p>
   * The default implementation is to call
   * {@link #visitDefaultFilter(Object)}.
   */
  public R visitExtensibleMatchFilter(P p, String matchingRule,
      String attributeDescription, ByteSequence assertionValue,
      boolean dnAttributes)
  {
    return visitDefaultFilter(p);
  }
  /**
   * {@inheritDoc}
   * <p>
   * The default implementation is to call
   * {@link #visitDefaultFilter(Object)}.
   */
  public R visitGreaterOrEqualFilter(P p, String attributeDescription,
      ByteSequence assertionValue)
  {
    return visitDefaultFilter(p);
  }
  /**
   * {@inheritDoc}
   * <p>
   * The default implementation is to call
   * {@link #visitDefaultFilter(Object)}.
   */
  public R visitLessOrEqualFilter(P p, String attributeDescription,
      ByteSequence assertionValue)
  {
    return visitDefaultFilter(p);
  }
  /**
   * {@inheritDoc}
   * <p>
   * The default implementation is to call
   * {@link #visitDefaultFilter(Object)}.
   */
  public R visitNotFilter(P p, Filter subFilter)
  {
    return visitDefaultFilter(p);
  }
  /**
   * {@inheritDoc}
   * <p>
   * The default implementation is to call
   * {@link #visitDefaultFilter(Object)}.
   */
  public R visitOrFilter(P p, List<Filter> subFilters)
  {
    return visitDefaultFilter(p);
  }
  /**
   * {@inheritDoc}
   * <p>
   * The default implementation is to call
   * {@link #visitDefaultFilter(Object)}.
   */
  public R visitPresentFilter(P p, String attributeDescription)
  {
    return visitDefaultFilter(p);
  }
  /**
   * {@inheritDoc}
   * <p>
   * The default implementation is to call
   * {@link #visitDefaultFilter(Object)}.
   */
  public R visitSubstringsFilter(P p, String attributeDescription,
      ByteSequence initialSubstring, List<ByteSequence> anySubstrings,
      ByteSequence finalSubstring)
  {
    return visitDefaultFilter(p);
  }
  /**
   * {@inheritDoc}
   * <p>
   * The default implementation is to call
   * {@link #visitDefaultFilter(Object)}.
   */
  public R visitUnrecognizedFilter(P p, byte filterTag,
      ByteSequence filterBytes)
  {
    return visitDefaultFilter(p);
  }
}
opendj-sdk/sdk/src/org/opends/sdk/Assertion.java
New file
@@ -0,0 +1,53 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Copyright 2009 Sun Microsystems, Inc.
 */
package org.opends.sdk;
import org.opends.sdk.util.ByteSequence;
/**
 * A compiled attribute value assertion.
 */
public interface Assertion
{
  /**
   * Indicates whether the provided attribute value should be considered
   * a match for this assertion value according to the matching rule.
   *
   * @param attributeValue
   *          The attribute value.
   * @return {@code TRUE} if the attribute value should be considered a
   *         match for the provided assertion value, {@code FALSE} if it
   *         does not match, or {@code UNDEFINED} if the result is
   *         undefined.
   */
  public abstract ConditionResult matches(ByteSequence attributeValue);
}
opendj-sdk/sdk/src/org/opends/sdk/AsynchronousConnection.java
New file
@@ -0,0 +1,495 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Copyright 2009 Sun Microsystems, Inc.
 */
package org.opends.sdk;
import java.io.Closeable;
import org.opends.sdk.requests.*;
import org.opends.sdk.responses.*;
/**
 * An asynchronous connection with a Directory Server over which read
 * and update operations may be performed. See RFC 4511 for the LDAPv3
 * protocol specification and more information about the types of
 * operations defined in LDAP.
 * <p>
 * <h3>Operation processing</h3>
 * <p>
 * All operations are performed asynchronously and return a
 * {@link ResultFuture} or sub-type thereof which can be used for
 * retrieving the result using the {@link ResultFuture#get} method.
 * Operation failures, for whatever reason, are signalled by the
 * {@link ResultFuture#get()} method throwing an
 * {@link ErrorResultException}.
 * <p>
 * Synchronous operations are easily simulated by immediately getting
 * the result:
 *
 * <pre>
 * Connection connection = ...;
 * AddRequest request = ...;
 * // Will block until operation completes, and
 * // throws exception on failure.
 * connection.add(request).get();
 * </pre>
 *
 * Operations can be performed in parallel while taking advantage of the
 * simplicity of a synchronous application design:
 *
 * <pre>
 * Connection connection1 = ...;
 * Connection connection2 = ...;
 * AddRequest request = ...;
 * // Add the entry to the first server (don't block).
 * ResultFuture future1 = connection1.add(request);
 * // Add the entry to the second server (in parallel).
 * ResultFuture future2 = connection2.add(request);
 * // Total time = is O(1) instead of O(n).
 * future1.get();
 * future2.get();
 * </pre>
 *
 * More complex client applications can take advantage of a fully
 * asynchronous event driven design using {@link ResultHandler}s:
 *
 * <pre>
 * Connection connection = ...;
 * SearchRequest request = ...;
 * // Process results in the search result handler
 * // in a separate thread.
 * SearchResponseHandler handle = ...;
 * connection.search(request, handler);
 * </pre>
 * <p>
 * <h3>Closing connections</h3>
 * <p>
 * Applications must ensure that a connection is closed by calling
 * {@link #close()} even if a fatal error occurs on the connection. Once
 * a connection has been closed by the client application, any attempts
 * to continue to use the connection will result in an
 * {@link IllegalStateException} being thrown. Note that, if a fatal
 * error is encountered on the connection, then the application can
 * continue to use the connection. In this case all requests subsequent
 * to the failure will fail with an appropriate
 * {@link ErrorResultException} when their result is retrieved.
 * <p>
 * <h3>Event notification</h3>
 * <p>
 * Applications can choose to be notified when a connection is closed by
 * the application, receives an unsolicited notification, or experiences
 * a fatal error by registering a {@link ConnectionEventListener} with
 * the connection using the {@link #addConnectionEventListener} method.
 * <p>
 * <h3>TO DO</h3>
 * <p>
 * <ul>
 * <li>do we need isClosed() and isValid()?
 * <li>do we need connection event notification of client close? JDBC
 * and JCA have this functionality in their pooled (managed) connection
 * APIs. We need some form of event notification at the app level for
 * unsolicited notifications.
 * <li>method for performing update operation (e.g. LDIF change
 * records).
 * <li>should unsupported methods throw UnsupportedOperationException or
 * throw an ErrorResultException using an UnwillingToPerform result code
 * (or something similar)?
 * <li>Implementations should indicate whether or not they are thread
 * safe and support concurrent requests.
 * </ul>
 *
 * @see <a href="http://tools.ietf.org/html/rfc4511">RFC 4511 -
 *      Lightweight Directory Access Protocol (LDAP): The Protocol </a>
 */
public interface AsynchronousConnection extends Closeable
{
  /**
   * Abandons the unfinished operation identified in the provided
   * abandon request.
   * <p>
   * <b>Note:</b> a more convenient approach to abandoning unfinished
   * operations is provided via the {@link ResultFuture#cancel(boolean)}
   * method.
   *
   * @param request
   *          The request identifying the operation to be abandoned.
   * @throws UnsupportedOperationException
   *           If this connection does not support abandon operations.
   * @throws IllegalStateException
   *           If this connection has already been closed, i.e. if
   *           {@code isClosed() == true}.
   * @throws NullPointerException
   *           If {@code request} was {@code null}.
   */
  void abandon(AbandonRequest request)
      throws UnsupportedOperationException, IllegalStateException,
      NullPointerException;
  /**
   * Adds an entry to the Directory Server using the provided add
   * request.
   *
   * @param <P>
   *          The type of the additional parameter to the handler's
   *          methods.
   * @param request
   *          The add request.
   * @param handler
   *          A result handler which can be used to asynchronously
   *          process the operation result when it is received, may be
   *          {@code null}.
   * @param p
   *          Optional additional handler parameter.
   * @return A future representing the result of the operation.
   * @throws UnsupportedOperationException
   *           If this connection does not support add operations.
   * @throws IllegalStateException
   *           If this connection has already been closed, i.e. if
   *           {@code isClosed() == true}.
   * @throws NullPointerException
   *           If {@code request} was {@code null}.
   */
  <P> ResultFuture<Result> add(AddRequest request,
      ResultHandler<Result, P> handler, P p)
      throws UnsupportedOperationException, IllegalStateException,
      NullPointerException;
  /**
   * Authenticates to the Directory Server using the provided bind
   * request.
   *
   * @param <P>
   *          The type of the additional parameter to the handler's
   *          methods.
   * @param request
   *          The bind request.
   * @param handler
   *          A result handler which can be used to asynchronously
   *          process the operation result when it is received, may be
   *          {@code null}.
   * @param p
   *          Optional additional handler parameter.
   * @return A future representing the result of the operation.
   * @throws UnsupportedOperationException
   *           If this connection does not support bind operations.
   * @throws IllegalStateException
   *           If this connection has already been closed, i.e. if
   *           {@code isClosed() == true}.
   * @throws NullPointerException
   *           If {@code request} was {@code null}.
   */
  <P> ResultFuture<BindResult> bind(BindRequest request,
      ResultHandler<? super BindResult, P> handler, P p)
      throws UnsupportedOperationException, IllegalStateException,
      NullPointerException;
  /**
   * Releases any resources associated with this connection. For
   * physical connections to a Directory Server this will mean that an
   * unbind request is sent and the underlying socket is closed.
   * <p>
   * Other connection implementations may behave differently, and may
   * choose not to send an unbind request if its use is inappropriate
   * (for example a pooled connection will be released and returned to
   * its connection pool without ever issuing an unbind request).
   * <p>
   * This method is semantically equivalent to the following code:
   *
   * <pre>
   * UnbindRequest request = Requests.newUnbindRequest();
   * connection.close(request);
   * </pre>
   *
   * Calling {@code close} on a connection that is already closed has no
   * effect.
   */
  void close();
  /**
   * Releases any resources associated with this connection. For
   * physical connections to a Directory Server this will mean that the
   * provided unbind request is sent and the underlying socket is
   * closed.
   * <p>
   * Other connection implementations may behave differently, and may
   * choose to ignore the provided unbind request if its use is
   * inappropriate (for example a pooled connection will be released and
   * returned to its connection pool without ever issuing an unbind
   * request).
   * <p>
   * Calling {@code close} on a connection that is already closed has no
   * effect.
   *
   * @param request
   *          The unbind request to use in the case where a physical
   *          connection is closed.
   * @throws NullPointerException
   *           If {@code request} was {@code null}.
   */
  void close(UnbindRequest request) throws NullPointerException;
  /**
   * Compares an entry in the Directory Server using the provided
   * compare request.
   *
   * @param <P>
   *          The type of the additional parameter to the handler's
   *          methods.
   * @param request
   *          The compare request.
   * @param handler
   *          A result handler which can be used to asynchronously
   *          process the operation result when it is received, may be
   *          {@code null}.
   * @param p
   *          Optional additional handler parameter.
   * @return A future representing the result of the operation.
   * @throws UnsupportedOperationException
   *           If this connection does not support compare operations.
   * @throws IllegalStateException
   *           If this connection has already been closed, i.e. if
   *           {@code isClosed() == true}.
   * @throws NullPointerException
   *           If {@code request} was {@code null}.
   */
  <P> ResultFuture<CompareResult> compare(CompareRequest request,
      ResultHandler<? super CompareResult, P> handler, P p)
      throws UnsupportedOperationException, IllegalStateException,
      NullPointerException;
  /**
   * Deletes an entry from the Directory Server using the provided
   * delete request.
   *
   * @param <P>
   *          The type of the additional parameter to the handler's
   *          methods.
   * @param request
   *          The delete request.
   * @param handler
   *          A result handler which can be used to asynchronously
   *          process the operation result when it is received, may be
   *          {@code null}.
   * @param p
   *          Optional additional handler parameter.
   * @return A future representing the result of the operation.
   * @throws UnsupportedOperationException
   *           If this connection does not support delete operations.
   * @throws IllegalStateException
   *           If this connection has already been closed, i.e. if
   *           {@code isClosed() == true}.
   * @throws NullPointerException
   *           If {@code request} was {@code null}.
   */
  <P> ResultFuture<Result> delete(DeleteRequest request,
      ResultHandler<Result, P> handler, P p)
      throws UnsupportedOperationException, IllegalStateException,
      NullPointerException;
  /**
   * Requests that the Directory Server performs the provided extended
   * request.
   *
   * @param <R>
   *          The type of result returned by the extended request.
   * @param <P>
   *          The type of the additional parameter to the handler's
   *          methods.
   * @param request
   *          The extended request.
   * @param handler
   *          A result handler which can be used to asynchronously
   *          process the operation result when it is received, may be
   *          {@code null}.
   * @param p
   *          Optional additional handler parameter.
   * @return A future representing the result of the operation.
   * @throws UnsupportedOperationException
   *           If this connection does not support extended operations.
   * @throws IllegalStateException
   *           If this connection has already been closed, i.e. if
   *           {@code isClosed() == true}.
   * @throws NullPointerException
   *           If {@code request} was {@code null}.
   */
  <R extends Result, P> ResultFuture<R> extendedRequest(
      ExtendedRequest<R> request, ResultHandler<? super R, P> handler,
      P p) throws UnsupportedOperationException, IllegalStateException,
      NullPointerException;
  /**
   * Modifies an entry in the Directory Server using the provided modify
   * request.
   *
   * @param <P>
   *          The type of the additional parameter to the handler's
   *          methods.
   * @param request
   *          The modify request.
   * @param handler
   *          A result handler which can be used to asynchronously
   *          process the operation result when it is received, may be
   *          {@code null}.
   * @param p
   *          Optional additional handler parameter.
   * @return A future representing the result of the operation.
   * @throws UnsupportedOperationException
   *           If this connection does not support modify operations.
   * @throws IllegalStateException
   *           If this connection has already been closed, i.e. if
   *           {@code isClosed() == true}.
   * @throws NullPointerException
   *           If {@code request} was {@code null}.
   */
  <P> ResultFuture<Result> modify(ModifyRequest request,
      ResultHandler<Result, P> handler, P p)
      throws UnsupportedOperationException, IllegalStateException,
      NullPointerException;
  /**
   * Renames an entry in the Directory Server using the provided modify
   * DN request.
   *
   * @param <P>
   *          The type of the additional parameter to the handler's
   *          methods.
   * @param request
   *          The modify DN request.
   * @param handler
   *          A result handler which can be used to asynchronously
   *          process the operation result when it is received, may be
   *          {@code null}.
   * @param p
   *          Optional additional handler parameter.
   * @return A future representing the result of the operation.
   * @throws UnsupportedOperationException
   *           If this connection does not support modify DN operations.
   * @throws IllegalStateException
   *           If this connection has already been closed, i.e. if
   *           {@code isClosed() == true}.
   * @throws NullPointerException
   *           If {@code request} was {@code null}.
   */
  <P> ResultFuture<Result> modifyDN(ModifyDNRequest request,
      ResultHandler<Result, P> handler, P p)
      throws UnsupportedOperationException, IllegalStateException,
      NullPointerException;
  /**
   * Searches the Directory Server using the provided search request.
   *
   * @param <P>
   *          The type of the additional parameter to the handler's
   *          methods.
   * @param request
   *          The search request.
   * @param resultHandler
   *          A result handler which can be used to asynchronously
   *          process the operation result when it is received, may be
   *          {@code null}.
   * @param searchResulthandler
   *          A search result handler which can be used to
   *          asynchronously process the search result entries and
   *          references as they are received, may be {@code null}.
   * @param p
   *          Optional additional handler parameter.
   * @return A future representing the result of the operation.
   * @throws UnsupportedOperationException
   *           If this connection does not support search operations.
   * @throws IllegalStateException
   *           If this connection has already been closed, i.e. if
   *           {@code isClosed() == true}.
   * @throws NullPointerException
   *           If {@code request} was {@code null}.
   */
  <P> ResultFuture<Result> search(SearchRequest request,
      ResultHandler<Result, P> resultHandler,
      SearchResultHandler<P> searchResulthandler, P p)
      throws UnsupportedOperationException, IllegalStateException,
      NullPointerException;
  /**
   * Registers the provided connection event listener so that it will be
   * notified when this connection is closed by the application,
   * receives an unsolicited notification, or experiences a fatal error.
   *
   * @param listener
   *          The listener which wants to be notified when events occur
   *          on this connection.
   * @throws IllegalStateException
   *           If this connection has already been closed, i.e. if
   *           {@code isClosed() == true}.
   * @throws NullPointerException
   *           If the {@code listener} was {@code null}.
   */
  void addConnectionEventListener(ConnectionEventListener listener)
      throws IllegalStateException, NullPointerException;
  /**
   * Removes the provided connection event listener from this connection
   * so that it will no longer be notified when this connection is
   * closed by the application, receives an unsolicited notification, or
   * experiences a fatal error.
   *
   * @param listener
   *          The listener which no longer wants to be notified when
   *          events occur on this connection.
   * @throws NullPointerException
   *           If the {@code listener} was {@code null}.
   */
  void removeConnectionEventListener(ConnectionEventListener listener)
      throws NullPointerException;
}
opendj-sdk/sdk/src/org/opends/sdk/Attribute.java
New file
@@ -0,0 +1,563 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Copyright 2009 Sun Microsystems, Inc.
 */
package org.opends.sdk;
import java.util.Collection;
import java.util.Iterator;
import java.util.NoSuchElementException;
import java.util.Set;
import org.opends.sdk.util.ByteString;
import org.opends.sdk.util.Function;
/**
 * An attribute, comprising of an attribute description and zero or more
 * attribute values.
 * <p>
 * Any methods which perform comparisons between attribute values use
 * the equality matching rule associated with the attribute description.
 * <p>
 * Any methods which accept {@code Object} based attribute values
 * convert the attribute values to instances of {@code ByteString} as
 * follows:
 *
 * <pre>
 * Object object = ...;
 * ByteString value = null;
 * if (object instanceof ByteSequence)
 * {
 *   value = ((ByteSequence)object).toByteString();
 * }
 * else
 * {
 *   value = ByteString.valueOf(object.toString());
 * }
 * </pre>
 * <p>
 * TODO: matching against attribute value assertions.
 */
public interface Attribute extends Set<ByteString>
{
  /**
   * Adds {@code value} to this attribute if it is not already present
   * (optional operation). If this attribute already contains {@code
   * value}, the call leaves the attribute unchanged and returns {@code
   * false}.
   *
   * @param value
   *          The attribute value to be added to this attribute.
   * @return {@code true} if this attribute changed as a result of this
   *         call.
   * @throws UnsupportedOperationException
   *           If this attribute does not support addition of attribute
   *           values.
   * @throws NullPointerException
   *           If {@code value} was {@code null}.
   */
  boolean add(ByteString value) throws UnsupportedOperationException,
      NullPointerException;
  /**
   * Adds all of the provided attribute values to this attribute if they
   * are not already present (optional operation).
   * <p>
   * Any attribute values which are not instances of {@code ByteString}
   * will be converted using the {@link ByteString#valueOf(Object)}
   * method.
   *
   * @param firstValue
   *          The first attribute value to be added to this attribute.
   * @param remainingValues
   *          The remaining attribute values to be added to this
   *          attribute.
   * @return {@code true} if this attribute changed as a result of this
   *         call.
   * @throws UnsupportedOperationException
   *           If this attribute does not support addition of attribute
   *           values.
   * @throws NullPointerException
   *           If {@code firstValue} was {@code null}.
   */
  boolean add(Object firstValue, Object... remainingValues)
      throws UnsupportedOperationException, NullPointerException;
  /**
   * Adds all of the attribute values contained in {@code values} to
   * this attribute if they are not already present (optional
   * operation).
   * <p>
   * An invocation of this method is equivalent to:
   *
   * <pre>
   * attribute.addAll(values, null);
   * </pre>
   *
   * @param values
   *          The attribute values to be added to this attribute.
   * @return {@code true} if this attribute changed as a result of this
   *         call.
   * @throws UnsupportedOperationException
   *           If this attribute does not support addition of attribute
   *           values.
   * @throws NullPointerException
   *           If {@code values} was {@code null}.
   */
  boolean addAll(Collection<? extends ByteString> values)
      throws UnsupportedOperationException, NullPointerException;
  /**
   * Adds all of the attribute values contained in {@code values} to
   * this attribute if they are not already present (optional
   * operation). Any attribute values which are already present will be
   * added to {@code duplicateValues} if specified.
   *
   * @param values
   *          The attribute values to be added to this attribute.
   * @param duplicateValues
   *          A collection into which duplicate values will be added, or
   *          {@code null} if duplicate values should not be saved.
   * @return {@code true} if this attribute changed as a result of this
   *         call.
   * @throws UnsupportedOperationException
   *           If this attribute does not support addition of attribute
   *           values.
   * @throws NullPointerException
   *           If {@code values} was {@code null}.
   */
  boolean addAll(Collection<? extends ByteString> values,
      Collection<? super ByteString> duplicateValues)
      throws UnsupportedOperationException, NullPointerException;
  /**
   * Removes all of the attribute values from this attribute (optional
   * operation). This attribute will be empty after this call returns.
   */
  void clear() throws UnsupportedOperationException;
  /**
   * Returns {@code true} if this attribute contains {@code value}.
   * <p>
   * If {@code value} is not an instance of {@code ByteString} then it
   * will be converted using the {@link ByteString#valueOf(Object)}
   * method.
   *
   * @param value
   *          The attribute value whose presence in this attribute is to
   *          be tested.
   * @return {@code true} if this attribute contains {@code value}, or
   *         {@code false} if not.
   * @throws NullPointerException
   *           If {@code value} was {@code null}.
   */
  boolean contains(Object value) throws NullPointerException;
  /**
   * Returns {@code true} if this attribute contains all of the
   * attribute values contained in {@code values}.
   * <p>
   * Any attribute values which are not instances of {@code ByteString}
   * will be converted using the {@link ByteString#valueOf(Object)}
   * method.
   *
   * @param values
   *          The attribute values whose presence in this attribute is
   *          to be tested.
   * @return {@code true} if this attribute contains all of the
   *         attribute values contained in {@code values}, or {@code
   *         false} if not.
   * @throws NullPointerException
   *           If {@code values} was {@code null}.
   */
  boolean containsAll(Collection<?> values) throws NullPointerException;
  /**
   * Returns {@code true} if {@code object} is an attribute which is
   * equal to this attribute. Two attributes are considered equal if
   * their attribute descriptions are equal, they both have the same
   * number of attribute values, and every attribute value contained in
   * the first attribute is also contained in the second attribute.
   *
   * @param object
   *          The object to be tested for equality with this attribute.
   * @return {@code true} if {@code object} is an attribute which is
   *         equal to this attribute, or {@code false} if not.
   */
  boolean equals(Object object);
  /**
   * Returns the first attribute value in this attribute.
   *
   * @return The first attribute value in this attribute.
   * @throws NoSuchElementException
   *           If this attribute is empty.
   */
  ByteString firstValue() throws NoSuchElementException;
  /**
   * Returns the first attribute value in this attribute converted to a
   * object of type {@code T} using the function {@code type}. Any
   * run-time exceptions thrown during the conversion will be passed
   * back to the caller (e.g. {@code IllegalArgumentException}).
   *
   * @param <T>
   *          The type of object to decode the first value as.
   * @param type
   *          The function to use for decoding the first attribute value
   *          as a type {@code T}.
   * @return The first attribute value in this attribute.
   * @throws NoSuchElementException
   *           If this attribute is empty.
   * @throws NullPointerException
   *           If {@code type} was {@code null}.
   */
  <T> T firstValueAsObject(Function<? super ByteString, T, Void> type)
      throws NoSuchElementException;
  /**
   * Returns the first attribute value in this attribute converted to a
   * object of type {@code T} using the function {@code type} and
   * passing parameter {@code p}. Any run-time exceptions thrown during
   * the conversion will be passed back to the caller (e.g. {@code
   * IllegalArgumentException}).
   *
   * @param <T>
   *          The type of object to decode the first value as.
   * @param <P>
   *          The type of the additional parameter to {@code type}'s
   *          {@code apply} method. Use {@link java.lang.Void} for
   *          functions that do not need an additional parameter.
   * @param type
   *          The function to use for decoding the first attribute value
   *          as a type {@code T}.
   * @param p
   *          The parameter to pass to {@code type}.
   * @return The first attribute value in this attribute.
   * @throws NoSuchElementException
   *           If this attribute is empty.
   * @throws NullPointerException
   *           If {@code type} was {@code null}.
   */
  <T, P> T firstValueAsObject(Function<? super ByteString, T, P> type,
      P p) throws NoSuchElementException;
  /**
   * Returns the first attribute value in this attribute decoded as a
   * UTF-8 string.
   *
   * @return The first attribute value in this attribute decoded as a
   *         UTF-8 string.
   * @throws NoSuchElementException
   *           If this attribute is empty.
   */
  String firstValueAsString() throws NoSuchElementException;
  /**
   * Returns the attribute description of this attribute, which includes
   * its attribute type and any options.
   *
   * @return The attribute description.
   */
  AttributeDescription getAttributeDescription();
  /**
   * Returns the string representation of the attribute description of
   * this attribute, which includes its attribute type and any options.
   *
   * @return The string representation of the attribute description.
   */
  String getAttributeDescriptionAsString();
  /**
   * Returns the hash code for this attribute. It will be calculated as
   * the sum of the hash codes of the attribute description and all of
   * the attribute values.
   *
   * @return The hash code for this attribute.
   */
  int hashCode();
  /**
   * Returns {@code true} if this attribute contains no attribute
   * values.
   *
   * @return {@code true} if this attribute contains no attribute
   *         values.
   */
  boolean isEmpty();
  /**
   * Returns an iterator over the attribute values in this attribute.
   * The attribute values are returned in no particular order, unless
   * the implementation of this attribute provides such a guarantee.
   *
   * @return An iterator over the attribute values in this attribute.
   */
  Iterator<ByteString> iterator();
  /**
   * Removes {@code value} from this attribute if it is present
   * (optional operation). If this attribute does not contain {@code
   * value}, the call leaves the attribute unchanged and returns {@code
   * false}.
   * <p>
   * If {@code value} is not an instance of {@code ByteString} then it
   * will be converted using the {@link ByteString#valueOf(Object)}
   * method.
   *
   * @param value
   *          The attribute value to be removed from this attribute.
   * @return {@code true} if this attribute changed as a result of this
   *         call.
   * @throws UnsupportedOperationException
   *           If this attribute does not support removal of attribute
   *           values.
   * @throws NullPointerException
   *           If {@code value} was {@code null}.
   */
  boolean remove(Object value) throws UnsupportedOperationException,
      NullPointerException;
  /**
   * Removes all of the attribute values contained in {@code values}
   * from this attribute if they are present (optional operation).
   * <p>
   * Any attribute values which are not instances of {@code ByteString}
   * will be converted using the {@link ByteString#valueOf(Object)}
   * method.
   * <p>
   * An invocation of this method is equivalent to:
   *
   * <pre>
   * attribute.removeAll(values, null);
   * </pre>
   *
   * @param values
   *          The attribute values to be removed from this attribute.
   * @return {@code true} if this attribute changed as a result of this
   *         call.
   * @throws UnsupportedOperationException
   *           If this attribute does not support removal of attribute
   *           values.
   * @throws NullPointerException
   *           If {@code values} was {@code null}.
   */
  boolean removeAll(Collection<?> values)
      throws UnsupportedOperationException, NullPointerException;
  /**
   * Removes all of the attribute values contained in {@code values}
   * from this attribute if they are present (optional operation). Any
   * attribute values which are not already present will be added to
   * {@code missingValues} if specified.
   * <p>
   * Any attribute values which are not instances of {@code ByteString}
   * will be converted using the {@link ByteString#valueOf(Object)}
   * method.
   *
   * @param <T>
   *          The type of the attribute value objects being removed.
   * @param values
   *          The attribute values to be removed from this attribute.
   * @param missingValues
   *          A collection into which missing values will be added, or
   *          {@code null} if missing values should not be saved.
   * @return {@code true} if this attribute changed as a result of this
   *         call.
   * @throws UnsupportedOperationException
   *           If this attribute does not support removal of attribute
   *           values.
   * @throws NullPointerException
   *           If {@code values} was {@code null}.
   */
  <T> boolean removeAll(Collection<T> values,
      Collection<? super T> missingValues)
      throws UnsupportedOperationException, NullPointerException;
  /**
   * Retains only the attribute values in this attribute which are
   * contained in {@code values} (optional operation).
   * <p>
   * Any attribute values which are not instances of {@code ByteString}
   * will be converted using the {@link ByteString#valueOf(Object)}
   * method.
   * <p>
   * An invocation of this method is equivalent to:
   *
   * <pre>
   * attribute.retainAll(values, null);
   * </pre>
   *
   * @param values
   *          The attribute values to be retained in this attribute.
   * @return {@code true} if this attribute changed as a result of this
   *         call.
   * @throws UnsupportedOperationException
   *           If this attribute does not support removal of attribute
   *           values.
   * @throws NullPointerException
   *           If {@code values} was {@code null}.
   */
  boolean retainAll(Collection<?> values)
      throws UnsupportedOperationException, NullPointerException;
  /**
   * Retains only the attribute values in this attribute which are
   * contained in {@code values} (optional operation). Any attribute
   * values which are not already present will be added to {@code
   * missingValues} if specified.
   * <p>
   * Any attribute values which are not instances of {@code ByteString}
   * will be converted using the {@link ByteString#valueOf(Object)}
   * method.
   *
   * @param <T>
   *          The type of the attribute value objects being retained.
   * @param values
   *          The attribute values to be retained in this attribute.
   * @param missingValues
   *          A collection into which missing values will be added, or
   *          {@code null} if missing values should not be saved.
   * @return {@code true} if this attribute changed as a result of this
   *         call.
   * @throws UnsupportedOperationException
   *           If this attribute does not support removal of attribute
   *           values.
   * @throws NullPointerException
   *           If {@code values} was {@code null}.
   */
  <T> boolean retainAll(Collection<T> values,
      Collection<? super T> missingValues)
      throws UnsupportedOperationException, NullPointerException;
  /**
   * Returns the number of attribute values in this attribute.
   *
   * @return The number of attribute values in this attribute.
   */
  int size();
  /**
   * Returns an array containing all of the attribute values contained
   * in this attribute.
   * <p>
   * If this attribute makes any guarantees as to what order its
   * attribute values are returned by its iterator, this method must
   * return the attribute values in the same order.
   * <p>
   * The returned array will be "safe" in that no references to it are
   * maintained by this attribute. The caller is thus free to modify the
   * returned array.
   */
  ByteString[] toArray();
  /**
   * Returns an array containing all of the attribute values in this
   * attribute; the runtime type of the returned array is that of the
   * specified array.
   * <p>
   * If the set fits in the specified array, it is returned therein.
   * Otherwise, a new array is allocated with the runtime type of the
   * specified array and the size of this attribute. If this attribute
   * fits in the specified array with room to spare (i.e., the array has
   * more elements than this attribute), the elements in the array
   * immediately following the end of the set is set to {@code null}.
   * <p>
   * If this attribute makes any guarantees as to what order its
   * attribute values are returned by its iterator, this method must
   * return the attribute values in the same order.
   *
   * @throws ArrayStoreException
   *           If the runtime type of {@code array} is not a supertype
   *           of {@code ByteString}.
   * @throws NullPointerException
   *           If {@code array} was {@code null}.
   */
  <T> T[] toArray(T[] array) throws ArrayStoreException,
      NullPointerException;
  /**
   * Returns a string representation of this attribute.
   *
   * @return The string representation of this attribute.
   */
  String toString();
}
opendj-sdk/sdk/src/org/opends/sdk/AttributeDescription.java
New file
@@ -0,0 +1,1496 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Copyright 2009 Sun Microsystems, Inc.
 */
package org.opends.sdk;
import static org.opends.messages.SchemaMessages.*;
import static org.opends.sdk.util.StaticUtils.*;
import java.util.*;
import org.opends.messages.Message;
import org.opends.sdk.schema.AttributeType;
import org.opends.sdk.schema.Schema;
import org.opends.sdk.schema.UnknownSchemaElementException;
import org.opends.sdk.util.ASCIICharProp;
import org.opends.sdk.util.Iterators;
import org.opends.sdk.util.LocalizedIllegalArgumentException;
import org.opends.sdk.util.Validator;
/**
 * An attribute description as defined in RFC 4512 section 2.5.
 * Attribute descriptions are used to identify an attribute in an entry
 * and are composed of an attribute type and a set of zero or more
 * attribute options.
 *
 * @see <a href="http://tools.ietf.org/html/rfc4512#section-2.5">RFC
 *      4512 - Lightweight Directory Access Protocol (LDAP): Directory
 *      Information Models </a>
 */
public final class AttributeDescription implements
    Comparable<AttributeDescription>
{
  private static abstract class Impl implements Iterable<String>
  {
    protected Impl()
    {
      // Nothing to do.
    }
    public abstract int compareTo(Impl other);
    public abstract boolean containsOption(String normalizedOption);
    public abstract boolean equals(Impl other);
    public abstract String firstNormalizedOption();
    @Override
    public abstract int hashCode();
    public abstract boolean hasOptions();
    public abstract boolean isSubTypeOf(Impl other);
    public abstract boolean isSuperTypeOf(Impl other);
    public abstract int size();
  }
  private static final class MultiOptionImpl extends Impl
  {
    private final String[] normalizedOptions;
    private final String[] options;
    private MultiOptionImpl(String[] options, String[] normalizedOptions)
    {
      if (normalizedOptions.length < 2)
      {
        throw new AssertionError();
      }
      this.options = options;
      this.normalizedOptions = normalizedOptions;
    }
    @Override
    public int compareTo(Impl other)
    {
      final int thisSize = normalizedOptions.length;
      final int otherSize = other.size();
      if (thisSize < otherSize)
      {
        return -1;
      }
      else if (thisSize > otherSize)
      {
        return 1;
      }
      else
      {
        // Same number of options.
        final MultiOptionImpl otherImpl = (MultiOptionImpl) other;
        for (int i = 0; i < thisSize; i++)
        {
          final String o1 = normalizedOptions[i];
          final String o2 = otherImpl.normalizedOptions[i];
          final int result = o1.compareTo(o2);
          if (result != 0)
          {
            return result;
          }
        }
        // All options the same.
        return 0;
      }
    }
    @Override
    public boolean containsOption(String normalizedOption)
    {
      final int sz = normalizedOptions.length;
      for (int i = 0; i < sz; i++)
      {
        if (normalizedOptions[i].equals(normalizedOption))
        {
          return true;
        }
      }
      return false;
    }
    @Override
    public boolean equals(Impl other)
    {
      if (other instanceof MultiOptionImpl)
      {
        final MultiOptionImpl tmp = (MultiOptionImpl) other;
        return Arrays.equals(normalizedOptions, tmp.normalizedOptions);
      }
      else
      {
        return false;
      }
    }
    @Override
    public String firstNormalizedOption()
    {
      return normalizedOptions[0];
    }
    @Override
    public int hashCode()
    {
      return Arrays.hashCode(normalizedOptions);
    }
    @Override
    public boolean hasOptions()
    {
      return true;
    }
    @Override
    public boolean isSubTypeOf(Impl other)
    {
      // Must contain a super-set of other's options.
      if (other == ZERO_OPTION_IMPL)
      {
        return true;
      }
      else if (other.size() == 1)
      {
        return containsOption(other.firstNormalizedOption());
      }
      else if (other.size() > size())
      {
        return false;
      }
      else
      {
        // Check this contains other's options.
        //
        // This could be optimized more if required, but it's probably
        // not worth it.
        final MultiOptionImpl tmp = (MultiOptionImpl) other;
        for (final String normalizedOption : tmp.normalizedOptions)
        {
          if (!containsOption(normalizedOption))
          {
            return false;
          }
        }
        return true;
      }
    }
    @Override
    public boolean isSuperTypeOf(Impl other)
    {
      // Must contain a sub-set of other's options.
      for (final String normalizedOption : normalizedOptions)
      {
        if (!other.containsOption(normalizedOption))
        {
          return false;
        }
      }
      return true;
    }
    public Iterator<String> iterator()
    {
      return Iterators.arrayIterator(options);
    }
    @Override
    public int size()
    {
      return normalizedOptions.length;
    }
  }
  private static final class SingleOptionImpl extends Impl
  {
    private final String normalizedOption;
    private final String option;
    private SingleOptionImpl(String option, String normalizedOption)
    {
      this.option = option;
      this.normalizedOption = normalizedOption;
    }
    @Override
    public int compareTo(Impl other)
    {
      if (other == ZERO_OPTION_IMPL)
      {
        // If other has zero options then this sorts after.
        return 1;
      }
      else if (other.size() == 1)
      {
        // Same number of options, so compare.
        return normalizedOption
            .compareTo(other.firstNormalizedOption());
      }
      else
      {
        // Other has more options, so comes after.
        return -1;
      }
    }
    @Override
    public boolean containsOption(String normalizedOption)
    {
      return this.normalizedOption.equals(normalizedOption);
    }
    @Override
    public boolean equals(Impl other)
    {
      return other.size() == 1
          && other.containsOption(normalizedOption);
    }
    @Override
    public String firstNormalizedOption()
    {
      return normalizedOption;
    }
    @Override
    public int hashCode()
    {
      return normalizedOption.hashCode();
    }
    @Override
    public boolean hasOptions()
    {
      return true;
    }
    @Override
    public boolean isSubTypeOf(Impl other)
    {
      // Other must have no options or the same option.
      if (other == ZERO_OPTION_IMPL)
      {
        return true;
      }
      else
      {
        return equals(other);
      }
    }
    @Override
    public boolean isSuperTypeOf(Impl other)
    {
      // Other must have this option.
      return other.containsOption(normalizedOption);
    }
    public Iterator<String> iterator()
    {
      return Iterators.singleton(option);
    }
    @Override
    public int size()
    {
      return 1;
    }
  }
  private static final class ZeroOptionImpl extends Impl
  {
    private ZeroOptionImpl()
    {
      // Nothing to do.
    }
    @Override
    public int compareTo(Impl other)
    {
      // If other has options then this sorts before.
      return this == other ? 0 : -1;
    }
    @Override
    public boolean containsOption(String normalizedOption)
    {
      return false;
    }
    @Override
    public boolean equals(Impl other)
    {
      return this == other;
    }
    @Override
    public String firstNormalizedOption()
    {
      // No first option.
      return null;
    }
    @Override
    public int hashCode()
    {
      // Use attribute type hash code.
      return 0;
    }
    @Override
    public boolean hasOptions()
    {
      return false;
    }
    @Override
    public boolean isSubTypeOf(Impl other)
    {
      // Can only be a sub-type if other has no options.
      return this == other;
    }
    @Override
    public boolean isSuperTypeOf(Impl other)
    {
      // Will always be a super-type.
      return true;
    }
    public Iterator<String> iterator()
    {
      return Iterators.empty();
    }
    @Override
    public int size()
    {
      return 0;
    }
  }
  private static final ThreadLocal<WeakHashMap<Schema, Map<String, AttributeDescription>>> CACHE = new ThreadLocal<WeakHashMap<Schema, Map<String, AttributeDescription>>>()
  {
    /**
     * {@inheritDoc}
     */
    @Override
    protected WeakHashMap<Schema, Map<String, AttributeDescription>> initialValue()
    {
      return new WeakHashMap<Schema, Map<String, AttributeDescription>>();
    }
  };
  // Object class attribute description.
  private static final ZeroOptionImpl ZERO_OPTION_IMPL = new ZeroOptionImpl();
  private static final AttributeDescription OBJECT_CLASS;
  static
  {
    final AttributeType attributeType = Schema.getCoreSchema()
        .getAttributeType("2.5.4.0");
    OBJECT_CLASS = new AttributeDescription(attributeType
        .getNameOrOID(), attributeType, ZERO_OPTION_IMPL);
  }
  // This is the size of the per-thread per-schema attribute description
  // cache. We should be conservative here in case there are many
  // threads.
  private static final int ATTRIBUTE_DESCRIPTION_CACHE_SIZE = 512;
  /**
   * Creates an attribute description having the same attribute type and
   * options as the provided attribute description and, in addition, the
   * provided list of options.
   *
   * @param attributeDescription
   *          The attribute description.
   * @param options
   *          The attribute options.
   * @return The new attribute description containing {@code options}.
   * @throws NullPointerException
   *           If {@code attributeDescription} or {@code options} was
   *           {@code null}.
   */
  public static AttributeDescription create(
      AttributeDescription attributeDescription, String... options)
      throws NullPointerException
  {
    Validator.ensureNotNull(attributeDescription, options);
    // This should not be called very often, so don't optimize.
    AttributeDescription newAttributeDescription = attributeDescription;
    for (final String option : options)
    {
      newAttributeDescription = create(newAttributeDescription, option);
    }
    return newAttributeDescription;
  }
  /**
   * Creates an attribute description having the same attribute type and
   * options as the provided attribute description and, in addition, the
   * provided new option.
   *
   * @param attributeDescription
   *          The attribute description.
   * @param option
   *          The attribute option.
   * @return The new attribute description containing {@code option}.
   * @throws NullPointerException
   *           If {@code attributeDescription} or {@code option} was
   *           {@code null}.
   */
  public static AttributeDescription create(
      AttributeDescription attributeDescription, String option)
      throws NullPointerException
  {
    Validator.ensureNotNull(attributeDescription, option);
    final String normalizedOption = toLowerCase(option);
    if (attributeDescription.pimpl.containsOption(normalizedOption))
    {
      return attributeDescription;
    }
    final String oldAttributeDescription = attributeDescription.attributeDescription;
    final StringBuilder builder = new StringBuilder(
        oldAttributeDescription.length() + option.length() + 1);
    builder.append(oldAttributeDescription);
    builder.append(';');
    builder.append(option);
    final String newAttributeDescription = builder.toString();
    final Impl impl = attributeDescription.pimpl;
    if (impl instanceof ZeroOptionImpl)
    {
      return new AttributeDescription(newAttributeDescription,
          attributeDescription.attributeType, new SingleOptionImpl(
              option, normalizedOption));
    }
    else if (impl instanceof SingleOptionImpl)
    {
      final SingleOptionImpl simpl = (SingleOptionImpl) impl;
      final String[] newOptions = new String[2];
      newOptions[0] = simpl.option;
      newOptions[1] = option;
      final String[] newNormalizedOptions = new String[2];
      if (normalizedOption.compareTo(simpl.normalizedOption) < 0)
      {
        newNormalizedOptions[0] = normalizedOption;
        newNormalizedOptions[1] = simpl.normalizedOption;
      }
      return new AttributeDescription(newAttributeDescription,
          attributeDescription.attributeType, new MultiOptionImpl(
              newOptions, newNormalizedOptions));
    }
    else
    {
      final MultiOptionImpl mimpl = (MultiOptionImpl) impl;
      final int sz1 = mimpl.options.length;
      final String[] newOptions = new String[sz1 + 1];
      for (int i = 0; i < sz1; i++)
      {
        newOptions[i] = mimpl.options[i];
      }
      newOptions[sz1] = option;
      final int sz2 = mimpl.normalizedOptions.length;
      final String[] newNormalizedOptions = new String[sz2 + 1];
      boolean inserted = false;
      for (int i = 0; i < sz2; i++)
      {
        if (!inserted)
        {
          final String s = mimpl.normalizedOptions[i];
          if (normalizedOption.compareTo(s) < 0)
          {
            newNormalizedOptions[i] = normalizedOption;
            newNormalizedOptions[i + 1] = s;
            inserted = true;
          }
          else
          {
            newNormalizedOptions[i] = s;
          }
        }
        else
        {
          newNormalizedOptions[i + 1] = mimpl.normalizedOptions[i];
        }
      }
      if (!inserted)
      {
        newNormalizedOptions[sz2] = normalizedOption;
      }
      return new AttributeDescription(newAttributeDescription,
          attributeDescription.attributeType, new MultiOptionImpl(
              newOptions, newNormalizedOptions));
    }
  }
  /**
   * Creates an attribute description having the provided attribute type
   * and no options.
   *
   * @param attributeType
   *          The attribute type.
   * @return The attribute description.
   * @throws NullPointerException
   *           If {@code attributeType} was {@code null}.
   */
  public static AttributeDescription create(AttributeType attributeType)
      throws NullPointerException
  {
    Validator.ensureNotNull(attributeType);
    // Use object identity in case attribute type does not come from
    // core schema.
    if (attributeType == OBJECT_CLASS.getAttributeType())
    {
      return OBJECT_CLASS;
    }
    else
    {
      return new AttributeDescription(attributeType.getNameOrOID(),
          attributeType, ZERO_OPTION_IMPL);
    }
  }
  /**
   * Creates an attribute description having the provided attribute type
   * and single option.
   *
   * @param attributeType
   *          The attribute type.
   * @param option
   *          The attribute option.
   * @return The attribute description.
   * @throws NullPointerException
   *           If {@code attributeType} or {@code option} was {@code
   *           null}.
   */
  public static AttributeDescription create(
      AttributeType attributeType, String option)
      throws NullPointerException
  {
    Validator.ensureNotNull(attributeType, option);
    final String oid = attributeType.getNameOrOID();
    final StringBuilder builder = new StringBuilder(oid.length()
        + option.length() + 1);
    builder.append(oid);
    builder.append(';');
    builder.append(option);
    final String attributeDescription = builder.toString();
    final String normalizedOption = toLowerCase(option);
    return new AttributeDescription(attributeDescription,
        attributeType, new SingleOptionImpl(option, normalizedOption));
  }
  /**
   * Creates an attribute description having the provided attribute type
   * and options.
   *
   * @param attributeType
   *          The attribute type.
   * @param options
   *          The attribute options.
   * @return The attribute description.
   * @throws NullPointerException
   *           If {@code attributeType} or {@code options} was {@code
   *           null}.
   */
  public static AttributeDescription create(
      AttributeType attributeType, String... options)
      throws NullPointerException
  {
    Validator.ensureNotNull(attributeType, options);
    switch (options.length)
    {
    case 0:
      return create(attributeType);
    case 1:
      return create(attributeType, options[0]);
    default:
      final String[] optionsList = new String[options.length];
      final String[] normalizedOptions = new String[options.length];
      final String oid = attributeType.getNameOrOID();
      final StringBuilder builder = new StringBuilder(oid.length()
          + options[0].length() + options[1].length() + 2);
      builder.append(oid);
      int i = 0;
      for (final String option : options)
      {
        builder.append(';');
        builder.append(option);
        optionsList[i] = option;
        final String normalizedOption = toLowerCase(option);
        normalizedOptions[i++] = normalizedOption;
      }
      Arrays.sort(normalizedOptions);
      final String attributeDescription = builder.toString();
      return new AttributeDescription(attributeDescription,
          attributeType, new MultiOptionImpl(optionsList,
              normalizedOptions));
    }
  }
  /**
   * Returns an attribute description representing the object class
   * attribute type with no options.
   *
   * @return The object class attribute description.
   */
  public static AttributeDescription objectClass()
  {
    return OBJECT_CLASS;
  }
  /**
   * Parses the provided LDAP string representation of an attribute
   * description using the default schema.
   *
   * @param attributeDescription
   *          The LDAP string representation of an attribute
   *          description.
   * @return The parsed attribute description.
   * @throws LocalizedIllegalArgumentException
   *           If {@code attributeDescription} is not a valid LDAP
   *           string representation of an attribute description.
   * @throws NullPointerException
   *           If {@code attributeDescription} was {@code null}.
   */
  public static AttributeDescription valueOf(String attributeDescription)
      throws LocalizedIllegalArgumentException, NullPointerException
  {
    return valueOf(attributeDescription, Schema.getDefaultSchema());
  }
  /**
   * Parses the provided LDAP string representation of an attribute
   * description using the provided schema.
   *
   * @param attributeDescription
   *          The LDAP string representation of an attribute
   *          description.
   * @param schema
   *          The schema to use when parsing the attribute description.
   * @return The parsed attribute description.
   * @throws LocalizedIllegalArgumentException
   *           If {@code attributeDescription} is not a valid LDAP
   *           string representation of an attribute description.
   * @throws NullPointerException
   *           If {@code attributeDescription} or {@code schema} was
   *           {@code null}.
   */
  @SuppressWarnings("serial")
  public static AttributeDescription valueOf(
      String attributeDescription, Schema schema)
      throws LocalizedIllegalArgumentException, NullPointerException
  {
    Validator.ensureNotNull(attributeDescription, schema);
    // First look up the attribute description in the cache.
    final WeakHashMap<Schema, Map<String, AttributeDescription>> threadLocalMap = CACHE
        .get();
    Map<String, AttributeDescription> schemaLocalMap = threadLocalMap
        .get(schema);
    AttributeDescription ad = null;
    if (schemaLocalMap == null)
    {
      schemaLocalMap = new LinkedHashMap<String, AttributeDescription>(
          ATTRIBUTE_DESCRIPTION_CACHE_SIZE, 0.75f, true)
      {
        @Override
        protected boolean removeEldestEntry(
            Map.Entry<String, AttributeDescription> eldest)
        {
          return size() > ATTRIBUTE_DESCRIPTION_CACHE_SIZE;
        }
      };
      threadLocalMap.put(schema, schemaLocalMap);
    }
    else
    {
      ad = schemaLocalMap.get(attributeDescription);
    }
    // Cache miss: decode and cache.
    if (ad == null)
    {
      ad = valueOf0(attributeDescription, schema);
      schemaLocalMap.put(attributeDescription, ad);
    }
    return ad;
  }
  private static int skipTrailingWhiteSpace(
      String attributeDescription, int i, int length)
      throws LocalizedIllegalArgumentException
  {
    char c;
    while (i < length)
    {
      c = attributeDescription.charAt(i);
      if (c != ' ')
      {
        final Message message = ERR_ATTRIBUTE_DESCRIPTION_INTERNAL_WHITESPACE
            .get(attributeDescription);
        throw new LocalizedIllegalArgumentException(message);
      }
      i++;
    }
    return i;
  }
  // Uncached valueOf implementation.
  private static AttributeDescription valueOf0(
      String attributeDescription, Schema schema)
      throws LocalizedIllegalArgumentException
  {
    int i = 0;
    final int length = attributeDescription.length();
    char c = 0;
    // Skip leading white space.
    while (i < length)
    {
      c = attributeDescription.charAt(i);
      if (c != ' ')
      {
        break;
      }
      i++;
    }
    // If we're already at the end then the attribute description only
    // contained whitespace.
    if (i == length)
    {
      final Message message = ERR_ATTRIBUTE_DESCRIPTION_EMPTY
          .get(attributeDescription);
      throw new LocalizedIllegalArgumentException(message);
    }
    // Validate the first non-whitespace character.
    ASCIICharProp cp = ASCIICharProp.valueOf(c);
    if (cp == null)
    {
      final Message message = ERR_ATTRIBUTE_DESCRIPTION_ILLEGAL_CHARACTER
          .get(attributeDescription, c, i);
      throw new LocalizedIllegalArgumentException(message);
    }
    // Mark the attribute type start position.
    final int attributeTypeStart = i;
    if (cp.isLetter())
    {
      // Non-numeric OID: letter + zero or more keychars.
      i++;
      while (i < length)
      {
        c = attributeDescription.charAt(i);
        if (c == ';' || c == ' ')
        {
          break;
        }
        cp = ASCIICharProp.valueOf(c);
        if (!cp.isKeyChar())
        {
          final Message message = ERR_ATTRIBUTE_DESCRIPTION_ILLEGAL_CHARACTER
              .get(attributeDescription, c, i);
          throw new LocalizedIllegalArgumentException(message);
        }
        i++;
      }
      // (charAt(i) == ';' || c == ' ' || i == length)
    }
    else if (cp.isDigit())
    {
      // Numeric OID: decimal digit + zero or more dots or decimals.
      i++;
      while (i < length)
      {
        c = attributeDescription.charAt(i);
        if (c == ';' || c == ' ')
        {
          break;
        }
        cp = ASCIICharProp.valueOf(c);
        if (c != '.' && !cp.isDigit())
        {
          final Message message = ERR_ATTRIBUTE_DESCRIPTION_ILLEGAL_CHARACTER
              .get(attributeDescription, c, i);
          throw new LocalizedIllegalArgumentException(message);
        }
        i++;
      }
      // (charAt(i) == ';' || charAt(i) == ' ' || i == length)
    }
    else
    {
      final Message message = ERR_ATTRIBUTE_DESCRIPTION_ILLEGAL_CHARACTER
          .get(attributeDescription, c, i);
      throw new LocalizedIllegalArgumentException(message);
    }
    // Skip trailing white space.
    final int attributeTypeEnd = i;
    if (c == ' ')
    {
      i = skipTrailingWhiteSpace(attributeDescription, i + 1, length);
    }
    // Determine the portion of the string containing the attribute type
    // name.
    String oid;
    if (attributeTypeStart == 0 && attributeTypeEnd == length)
    {
      oid = attributeDescription;
    }
    else
    {
      oid = attributeDescription.substring(attributeTypeStart,
          attributeTypeEnd);
    }
    if (oid.length() == 0)
    {
      final Message message = ERR_ATTRIBUTE_DESCRIPTION_NO_TYPE
          .get(attributeDescription);
      throw new LocalizedIllegalArgumentException(message);
    }
    // Get the attribute type from the schema.
    AttributeType attributeType;
    try
    {
      attributeType = schema.getAttributeType(oid);
    }
    catch (final UnknownSchemaElementException e)
    {
      final Message message = ERR_ATTRIBUTE_DESCRIPTION_TYPE_NOT_FOUND
          .get(attributeDescription, e.getMessageObject());
      throw new LocalizedIllegalArgumentException(message);
    }
    // If we're already at the end of the attribute description then it
    // does not contain any options.
    if (i == length)
    {
      // Use object identity in case attribute type does not come from
      // core schema.
      if (attributeType == OBJECT_CLASS.getAttributeType()
          && attributeDescription.equals(OBJECT_CLASS.toString()))
      {
        return OBJECT_CLASS;
      }
      else
      {
        return new AttributeDescription(attributeDescription,
            attributeType, ZERO_OPTION_IMPL);
      }
    }
    // At this point 'i' must point at a semi-colon.
    i++;
    StringBuilder builder = null;
    int optionStart = i;
    while (i < length)
    {
      c = attributeDescription.charAt(i);
      if (c == ' ' || c == ';')
      {
        break;
      }
      cp = ASCIICharProp.valueOf(c);
      if (!cp.isKeyChar())
      {
        final Message message = ERR_ATTRIBUTE_DESCRIPTION_ILLEGAL_CHARACTER
            .get(attributeDescription, c, i);
        throw new LocalizedIllegalArgumentException(message);
      }
      if (builder == null)
      {
        if (cp.isUpperCase())
        {
          // Need to normalize the option.
          builder = new StringBuilder(length - optionStart);
          builder.append(attributeDescription, optionStart, i);
          builder.append(cp.toLowerCase());
        }
      }
      else
      {
        builder.append(cp.toLowerCase());
      }
      i++;
    }
    String option = attributeDescription.substring(optionStart, i);
    String normalizedOption;
    if (builder != null)
    {
      normalizedOption = builder.toString();
    }
    else
    {
      normalizedOption = option;
    }
    if (option.length() == 0)
    {
      final Message message = ERR_ATTRIBUTE_DESCRIPTION_EMPTY_OPTION
          .get(attributeDescription);
      throw new LocalizedIllegalArgumentException(message);
    }
    // Skip trailing white space.
    if (c == ' ')
    {
      i = skipTrailingWhiteSpace(attributeDescription, i + 1, length);
    }
    // If we're already at the end of the attribute description then it
    // only contains a single option.
    if (i == length)
    {
      return new AttributeDescription(attributeDescription,
          attributeType, new SingleOptionImpl(option, normalizedOption));
    }
    // Multiple options need sorting and duplicates removed - we could
    // optimize a bit further here for 2 option attribute descriptions.
    final List<String> options = new LinkedList<String>();
    options.add(option);
    final SortedSet<String> normalizedOptions = new TreeSet<String>();
    normalizedOptions.add(normalizedOption);
    while (i < length)
    {
      // At this point 'i' must point at a semi-colon.
      i++;
      builder = null;
      optionStart = i;
      while (i < length)
      {
        c = attributeDescription.charAt(i);
        if (c == ' ' || c == ';')
        {
          break;
        }
        cp = ASCIICharProp.valueOf(c);
        if (!cp.isKeyChar())
        {
          final Message message = ERR_ATTRIBUTE_DESCRIPTION_ILLEGAL_CHARACTER
              .get(attributeDescription, c, i);
          throw new LocalizedIllegalArgumentException(message);
        }
        if (builder == null)
        {
          if (cp.isUpperCase())
          {
            // Need to normalize the option.
            builder = new StringBuilder(length - optionStart);
            builder.append(attributeDescription, optionStart, i);
            builder.append(cp.toLowerCase());
          }
        }
        else
        {
          builder.append(cp.toLowerCase());
        }
        i++;
      }
      option = attributeDescription.substring(optionStart, i);
      if (builder != null)
      {
        normalizedOption = builder.toString();
      }
      else
      {
        normalizedOption = option;
      }
      if (option.length() == 0)
      {
        final Message message = ERR_ATTRIBUTE_DESCRIPTION_EMPTY_OPTION
            .get(attributeDescription);
        throw new LocalizedIllegalArgumentException(message);
      }
      // Skip trailing white space.
      if (c == ' ')
      {
        i = skipTrailingWhiteSpace(attributeDescription, i + 1, length);
      }
      options.add(option);
      normalizedOptions.add(normalizedOption);
    }
    return new AttributeDescription(attributeDescription,
        attributeType, new MultiOptionImpl(options
            .toArray(new String[options.size()]), normalizedOptions
            .toArray(new String[normalizedOptions.size()])));
  }
  private final String attributeDescription;
  private final AttributeType attributeType;
  private final Impl pimpl;
  // Private constructor.
  private AttributeDescription(String attributeDescription,
      AttributeType attributeType, Impl pimpl)
  {
    this.attributeDescription = attributeDescription;
    this.attributeType = attributeType;
    this.pimpl = pimpl;
  }
  /**
   * Compares this attribute description to the provided attribute
   * description. The attribute types are compared first and then, if
   * equal, the options are normalized, sorted, and compared.
   *
   * @param other
   *          The attribute description to be compared.
   * @return A negative integer, zero, or a positive integer as this
   *         attribute description is less than, equal to, or greater
   *         than the specified attribute description.
   * @throws NullPointerException
   *           If {@code name} was {@code null}.
   */
  public int compareTo(AttributeDescription other)
      throws NullPointerException
  {
    final int result = attributeType.compareTo(other.attributeType);
    if (result != 0)
    {
      return result;
    }
    else
    {
      // Attribute type is the same, so compare options.
      return pimpl.compareTo(other.pimpl);
    }
  }
  /**
   * Indicates whether or not this attribute description contains the
   * provided option.
   *
   * @param option
   *          The option for which to make the determination.
   * @return {@code true} if this attribute description has the provided
   *         option, or {@code false} if not.
   * @throws NullPointerException
   *           If {@code option} was {@code null}.
   */
  public boolean containsOption(String option)
      throws NullPointerException
  {
    final String normalizedOption = toLowerCase(option);
    return pimpl.containsOption(normalizedOption);
  }
  /**
   * Indicates whether the provided object is an attribute description
   * which is equal to this attribute description. It will be considered
   * equal if the attribute type and normalized sorted list of options
   * are identical.
   *
   * @param o
   *          The object for which to make the determination.
   * @return {@code true} if the provided object is an attribute
   *         description that is equal to this attribute description, or
   *         {@code false} if not.
   */
  @Override
  public boolean equals(Object o)
  {
    if (this == o)
    {
      return true;
    }
    if (!(o instanceof AttributeDescription))
    {
      return false;
    }
    final AttributeDescription other = (AttributeDescription) o;
    if (!attributeType.equals(other.attributeType))
    {
      return false;
    }
    // Attribute type is the same, compare options.
    return pimpl.equals(other.pimpl);
  }
  /**
   * Returns the attribute type associated with this attribute
   * description.
   *
   * @return The attribute type associated with this attribute
   *         description.
   */
  public AttributeType getAttributeType()
  {
    return attributeType;
  }
  /**
   * Returns an {@code Iterable} containing the options contained in
   * this attribute description. Attempts to remove options using an
   * iterator's {@code remove()} method are not permitted and will
   * result in an {@code UnsupportedOperationException} being thrown.
   *
   * @return An {@code Iterable} containing the options.
   */
  public Iterable<String> getOptions()
  {
    return pimpl;
  }
  /**
   * Returns the hash code for this attribute description. It will be
   * calculated as the sum of the hash codes of the attribute type and
   * normalized sorted list of options.
   *
   * @return The hash code for this attribute description.
   */
  @Override
  public int hashCode()
  {
    // FIXME: should we cache this?
    return attributeType.hashCode() * 31 + pimpl.hashCode();
  }
  /**
   * Indicates whether or not this attribute description has any
   * options.
   *
   * @return {@code true} if this attribute description has any options,
   *         or {@code false} if not.
   */
  public boolean hasOptions()
  {
    return pimpl.hasOptions();
  }
  /**
   * Indicates whether or not this attribute description is the {@code
   * objectClass} attribute description with no options.
   *
   * @return {@code true} if this attribute description is the {@code
   *         objectClass} attribute description with no options, or
   *         {@code false} if not.
   */
  public boolean isObjectClass()
  {
    return attributeType.isObjectClass() && !hasOptions();
  }
  /**
   * Indicates whether or not this attribute description is a sub-type
   * of the provided attribute description as defined in RFC 4512
   * section 2.5. Specifically, this method will return {@code true} if
   * and only if the following conditions are both {@code true}:
   * <ul>
   * <li>This attribute description has an attribute type which is equal
   * to, or is a sub-type of, the attribute type in the provided
   * attribute description.
   * <li>This attribute description contains all of the options
   * contained in the provided attribute description.
   * </ul>
   * Note that this method will return {@code true} if this attribute
   * description is equal to the provided attribute description.
   *
   * @param other
   *          The attribute description for which to make the
   *          determination.
   * @return {@code true} if this attribute description is a sub-type of
   *         the provided attribute description, or {@code false} if
   *         not.
   * @throws NullPointerException
   *           If {@code name} was {@code null}.
   */
  public boolean isSubTypeOf(AttributeDescription other)
      throws NullPointerException
  {
    if (!attributeType.isSubTypeOf(other.attributeType))
    {
      return false;
    }
    else
    {
      return pimpl.isSubTypeOf(other.pimpl);
    }
  }
  /**
   * Indicates whether or not this attribute description is a super-type
   * of the provided attribute description as defined in RFC 4512
   * section 2.5. Specifically, this method will return {@code true} if
   * and only if the following conditions are both {@code true}:
   * <ul>
   * <li>This attribute description has an attribute type which is equal
   * to, or is a super-type of, the attribute type in the provided
   * attribute description.
   * <li>This attribute description contains a sub-set of the options
   * contained in the provided attribute description.
   * </ul>
   * Note that this method will return {@code true} if this attribute
   * description is equal to the provided attribute description.
   *
   * @param other
   *          The attribute description for which to make the
   *          determination.
   * @return {@code true} if this attribute description is a super-type
   *         of the provided attribute description, or {@code false} if
   *         not.
   * @throws NullPointerException
   *           If {@code name} was {@code null}.
   */
  public boolean isSuperTypeOf(AttributeDescription other)
      throws NullPointerException
  {
    if (!other.attributeType.isSubTypeOf(attributeType))
    {
      return false;
    }
    else
    {
      return pimpl.isSuperTypeOf(other.pimpl);
    }
  }
  /**
   * Returns the string representation of this attribute description as
   * defined in RFC4512 section 2.5.
   *
   * @return The string representation of this attribute description.
   */
  @Override
  public String toString()
  {
    return attributeDescription;
  }
}
opendj-sdk/sdk/src/org/opends/sdk/AuthenticatedConnectionFactory.java
New file
@@ -0,0 +1,702 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Copyright 2009 Sun Microsystems, Inc.
 */
package org.opends.sdk;
import java.util.concurrent.CancellationException;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import org.opends.sdk.requests.*;
import org.opends.sdk.responses.BindResult;
import org.opends.sdk.responses.CompareResult;
import org.opends.sdk.responses.Result;
import org.opends.sdk.util.Validator;
/**
 * An authenticated connection factory can be used to create
 * pre-authenticated connections to a Directory Server.
 * <p>
 * The connections returned by an authenticated connection factory
 * support all operations with the exception of Bind requests. Attempts
 * to perform a Bind will result in an {@code
 * UnsupportedOperationException}.
 * <p>
 * In addition, the returned connections support retrieval of the
 * {@code BindResult} returned from the initial Bind request, or last
 * rebind.
 * <p>
 * Support for connection re-authentication is provided through the
 * {@link #setRebindAllowed} method which, if set to {@code true},
 * causes subsequent connections created using the factory to support
 * the {@code rebind} method.
 * <p>
 * If the Bind request fails for some reason (e.g. invalid credentials),
 * then the connection attempt will fail and an {@code
 * ErrorResultException} will be thrown.
 */
public final class AuthenticatedConnectionFactory
    implements
    ConnectionFactory<AuthenticatedConnectionFactory.AuthenticatedAsynchronousConnection>
{
  // We implement the factory using the pimpl idiom in order have
  // cleaner Javadoc which does not expose implementation methods from
  // AbstractConnectionFactory.
  private static final class Impl
      extends
      AbstractConnectionFactory<AuthenticatedConnectionFactory.AuthenticatedAsynchronousConnection>
      implements
      ConnectionFactory<AuthenticatedConnectionFactory.AuthenticatedAsynchronousConnection>
  {
    private final BindRequest request;
    private final ConnectionFactory<?> parentFactory;
    private boolean allowRebinds = false;
    private Impl(ConnectionFactory<?> factory, BindRequest request)
        throws NullPointerException
    {
      Validator.ensureNotNull(factory, request);
      this.parentFactory = factory;
      // FIXME: should do a defensive copy.
      this.request = request;
    }
    /**
     * {@inheritDoc}
     */
    public <P> ConnectionFuture<AuthenticatedAsynchronousConnection> getAsynchronousConnection(
        ConnectionResultHandler<? super AuthenticatedAsynchronousConnection, P> handler,
        P p)
    {
      ConnectionFutureImpl<P> future = new ConnectionFutureImpl<P>(
          allowRebinds ? request : null, handler, p);
      future.connectFuture = parentFactory.getAsynchronousConnection(
          future, null);
      return future;
    }
    /**
     * {@inheritDoc}
     */
    public AuthenticatedConnection getConnection()
        throws ErrorResultException
    {
      return new AuthenticatedConnection(
          blockingGetAsynchronousConnection());
    }
  }
  private final Impl impl;
  /**
   * An authenticated synchronous connection supports all operations
   * except Bind operations.
   */
  public static final class AuthenticatedConnection extends
      SynchronousConnection
  {
    private final AuthenticatedAsynchronousConnection connection;
    private AuthenticatedConnection(
        AuthenticatedAsynchronousConnection connection)
    {
      super(connection);
      this.connection = connection;
    }
    /**
     * Bind operations are not supported by pre-authenticated
     * connections. This method will always throw {@code
     * UnsupportedOperationException}.
     */
    public BindResult bind(BindRequest request)
        throws UnsupportedOperationException
    {
      throw new UnsupportedOperationException();
    }
    /**
     * Bind operations are not supported by pre-authenticated
     * connections. This method will always throw {@code
     * UnsupportedOperationException}.
     */
    public BindResult bind(String name, String password)
        throws UnsupportedOperationException
    {
      throw new UnsupportedOperationException();
    }
    /**
     * Re-authenticates to the Directory Server using the bind request
     * associated with this connection. If re-authentication fails for
     * some reason then this connection will be automatically closed.
     *
     * @return The result of the operation.
     * @throws ErrorResultException
     *           If the result code indicates that the request failed
     *           for some reason.
     * @throws InterruptedException
     *           If the current thread was interrupted while waiting.
     * @throws UnsupportedOperationException
     *           If this connection does not support rebind operations.
     * @throws IllegalStateException
     *           If this connection has already been closed, i.e. if
     *           {@code isClosed() == true}.
     */
    public BindResult rebind() throws ErrorResultException,
        InterruptedException, UnsupportedOperationException,
        IllegalStateException
    {
      if (connection.request == null)
      {
        throw new UnsupportedOperationException();
      }
      return super.bind(connection.request);
    }
    /**
     * Returns an unmodifiable view of the Bind result which was
     * returned from the server after authentication.
     *
     * @return The Bind result which was returned from the server after
     *         authentication.
     */
    public BindResult getAuthenticatedBindResult()
    {
      return connection.getAuthenticatedBindResult();
    }
  }
  /**
   * An authenticated asynchronous connection supports all operations
   * except Bind operations.
   */
  public static final class AuthenticatedAsynchronousConnection
      implements AsynchronousConnection
  {
    private final BindRequest request;
    private volatile BindResult result;
    private final AsynchronousConnection connection;
    private AuthenticatedAsynchronousConnection(
        AsynchronousConnection connection, BindRequest request,
        BindResult result)
    {
      this.connection = connection;
      this.request = request;
      this.result = result;
    }
    /**
     * Returns an unmodifiable view of the Bind result which was
     * returned from the server after authentication.
     *
     * @return The Bind result which was returned from the server after
     *         authentication.
     */
    public BindResult getAuthenticatedBindResult()
    {
      return result;
    }
    public void abandon(AbandonRequest request)
        throws UnsupportedOperationException, IllegalStateException,
        NullPointerException
    {
      connection.abandon(request);
    }
    public <P> ResultFuture<Result> add(AddRequest request,
        ResultHandler<Result, P> handler, P p)
        throws UnsupportedOperationException, IllegalStateException,
        NullPointerException
    {
      return connection.add(request, handler, p);
    }
    public void addConnectionEventListener(
        ConnectionEventListener listener) throws IllegalStateException,
        NullPointerException
    {
      connection.addConnectionEventListener(listener);
    }
    /**
     * Bind operations are not supported by pre-authenticated
     * connections. This method will always throw {@code
     * UnsupportedOperationException}.
     */
    public <P> ResultFuture<BindResult> bind(BindRequest request,
        ResultHandler<? super BindResult, P> handler, P p)
        throws UnsupportedOperationException, IllegalStateException,
        NullPointerException
    {
      throw new UnsupportedOperationException();
    }
    public void close()
    {
      connection.close();
    }
    public void close(UnbindRequest request)
        throws NullPointerException
    {
      connection.close(request);
    }
    public <P> ResultFuture<CompareResult> compare(
        CompareRequest request,
        ResultHandler<? super CompareResult, P> handler, P p)
        throws UnsupportedOperationException, IllegalStateException,
        NullPointerException
    {
      return connection.compare(request, handler, p);
    }
    public <P> ResultFuture<Result> delete(DeleteRequest request,
        ResultHandler<Result, P> handler, P p)
        throws UnsupportedOperationException, IllegalStateException,
        NullPointerException
    {
      return connection.delete(request, handler, p);
    }
    public <R extends Result, P> ResultFuture<R> extendedRequest(
        ExtendedRequest<R> request,
        ResultHandler<? super R, P> handler, P p)
        throws UnsupportedOperationException, IllegalStateException,
        NullPointerException
    {
      return connection.extendedRequest(request, handler, p);
    }
    public <P> ResultFuture<Result> modify(ModifyRequest request,
        ResultHandler<Result, P> handler, P p)
        throws UnsupportedOperationException, IllegalStateException,
        NullPointerException
    {
      return connection.modify(request, handler, p);
    }
    public <P> ResultFuture<Result> modifyDN(ModifyDNRequest request,
        ResultHandler<Result, P> handler, P p)
        throws UnsupportedOperationException, IllegalStateException,
        NullPointerException
    {
      return connection.modifyDN(request, handler, p);
    }
    /**
     * Re-authenticates to the Directory Server using the bind request
     * associated with this connection. If re-authentication fails for
     * some reason then this connection will be automatically closed.
     *
     * @param <P>
     *          The type of the additional parameter to the handler's
     *          methods.
     * @param handler
     *          A result handler which can be used to asynchronously
     *          process the operation result when it is received, may be
     *          {@code null}.
     * @param p
     *          Optional additional handler parameter.
     * @return A future representing the result of the operation.
     * @throws UnsupportedOperationException
     *           If this connection does not support rebind operations.
     * @throws IllegalStateException
     *           If this connection has already been closed, i.e. if
     *           {@code isClosed() == true}.
     */
    public <P> ResultFuture<BindResult> rebind(
        ResultHandler<? super BindResult, P> handler, P p)
        throws UnsupportedOperationException, IllegalStateException
    {
      if (request == null)
      {
        throw new UnsupportedOperationException();
      }
      // Wrap the client handler so that we can update the connection
      // state.
      final ResultHandler<? super BindResult, P> clientHandler = handler;
      final P clientParameter = p;
      ResultHandler<BindResult, Void> handlerWrapper = new ResultHandler<BindResult, Void>()
      {
        public void handleErrorResult(Void p, ErrorResultException error)
        {
          // This connection is now unauthenticated so prevent
          // further use.
          connection.close();
          if (clientHandler != null)
          {
            clientHandler.handleErrorResult(clientParameter, error);
          }
        }
        public void handleResult(Void p, BindResult result)
        {
          // Save the result.
          AuthenticatedAsynchronousConnection.this.result = result;
          if (clientHandler != null)
          {
            clientHandler.handleResult(clientParameter, result);
          }
        }
      };
      return connection.bind(request, handlerWrapper, null);
    }
    public void removeConnectionEventListener(
        ConnectionEventListener listener) throws NullPointerException
    {
      connection.removeConnectionEventListener(listener);
    }
    public <P> ResultFuture<Result> search(SearchRequest request,
        ResultHandler<Result, P> resultHandler,
        SearchResultHandler<P> searchResulthandler, P p)
        throws UnsupportedOperationException, IllegalStateException,
        NullPointerException
    {
      return connection.search(request, resultHandler,
          searchResulthandler, p);
    }
  }
  /**
   * Creates a new authenticated connection factory which will obtain
   * connections using the provided connection factory and immediately
   * perform the provided Bind request.
   *
   * @param factory
   *          The connection factory to use for connecting to the
   *          Directory Server.
   * @param request
   *          The Bind request to use for authentication.
   * @throws NullPointerException
   *           If {@code factory} or {@code request} was {@code null}.
   */
  public AuthenticatedConnectionFactory(ConnectionFactory<?> factory,
      BindRequest request) throws NullPointerException
  {
    impl = new Impl(factory, request);
  }
  private static final class ConnectionFutureImpl<P> implements
      ConnectionFuture<AuthenticatedAsynchronousConnection>,
      ConnectionResultHandler<AsynchronousConnection, Void>,
      ResultHandler<BindResult, Void>
  {
    private volatile AuthenticatedAsynchronousConnection authenticatedConnection;
    private volatile AsynchronousConnection connection;
    private volatile ErrorResultException exception;
    private volatile ConnectionFuture<?> connectFuture;
    private volatile ResultFuture<BindResult> bindFuture;
    private final CountDownLatch latch = new CountDownLatch(1);
    private final ConnectionResultHandler<? super AuthenticatedAsynchronousConnection, P> handler;
    private final P p;
    private boolean cancelled;
    private final BindRequest request;
    private ConnectionFutureImpl(
        BindRequest request,
        ConnectionResultHandler<? super AuthenticatedAsynchronousConnection, P> handler,
        P p)
    {
      this.request = request;
      this.handler = handler;
      this.p = p;
    }
    public boolean cancel(boolean mayInterruptIfRunning)
    {
      cancelled = connectFuture.cancel(mayInterruptIfRunning)
          || bindFuture != null
          && bindFuture.cancel(mayInterruptIfRunning);
      if (cancelled)
      {
        latch.countDown();
      }
      return cancelled;
    }
    public AuthenticatedAsynchronousConnection get()
        throws InterruptedException, ErrorResultException
    {
      latch.await();
      if (cancelled)
      {
        throw new CancellationException();
      }
      if (exception != null)
      {
        throw exception;
      }
      return authenticatedConnection;
    }
    public AuthenticatedAsynchronousConnection get(long timeout,
        TimeUnit unit) throws InterruptedException, TimeoutException,
        ErrorResultException
    {
      latch.await(timeout, unit);
      if (cancelled)
      {
        throw new CancellationException();
      }
      if (exception != null)
      {
        throw exception;
      }
      return authenticatedConnection;
    }
    public boolean isCancelled()
    {
      return cancelled;
    }
    public boolean isDone()
    {
      return latch.getCount() == 0;
    }
    public void handleConnection(Void v,
        AsynchronousConnection connection)
    {
      this.connection = connection;
      this.bindFuture = this.connection.bind(request, this, null);
    }
    public void handleConnectionError(Void v, ErrorResultException error)
    {
      exception = error;
      latch.countDown();
    }
    public void handleResult(Void v, BindResult result)
    {
      // FIXME: should make the result unmodifiable.
      authenticatedConnection = new AuthenticatedAsynchronousConnection(
          connection, request, result);
      latch.countDown();
      if (handler != null)
      {
        handler.handleConnection(p, authenticatedConnection);
      }
    }
    public void handleErrorResult(Void v, ErrorResultException error)
    {
      // Ensure that the connection is closed.
      try
      {
        connection.close();
      }
      catch (Exception e)
      {
        // Ignore.
      }
      exception = error;
      latch.countDown();
      if (handler != null)
      {
        handler.handleConnectionError(p, exception);
      }
    }
  }
  /**
   * Specifies whether or not rebind requests are to be supported by
   * connections created by this authenticated connection factory.
   * <p>
   * Rebind requests are invoked using the connection's {@code rebind}
   * method which will throw an {@code UnsupportedOperationException} if
   * rebinds are not supported (the default).
   *
   * @param allowRebinds
   *          {@code true} if the {@code rebind} operation is to be
   *          supported, otherwise {@code false}.
   * @return A reference to this connection factory.
   */
  public AuthenticatedConnectionFactory setRebindAllowed(
      boolean allowRebinds)
  {
    impl.allowRebinds = allowRebinds;
    return this;
  }
  /**
   * Indicates whether or not rebind requests are to be supported by
   * connections created by this authenticated connection factory.
   * <p>
   * Rebind requests are invoked using the connection's {@code rebind}
   * method which will throw an {@code UnsupportedOperationException} if
   * rebinds are not supported (the default).
   *
   * @return allowRebinds {@code true} if the {@code rebind} operation
   *         is to be supported, otherwise {@code false}.
   */
  public boolean isRebindAllowed()
  {
    return impl.allowRebinds;
  }
  public <P> ConnectionFuture<AuthenticatedAsynchronousConnection> getAsynchronousConnection(
      ConnectionResultHandler<? super AuthenticatedAsynchronousConnection, P> handler,
      P p)
  {
    return impl.getAsynchronousConnection(handler, p);
  }
  public AuthenticatedConnection getConnection()
      throws ErrorResultException
  {
    return impl.getConnection();
  }
}
opendj-sdk/sdk/src/org/opends/sdk/Change.java
New file
@@ -0,0 +1,126 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Copyright 2009 Sun Microsystems, Inc.
 */
package org.opends.sdk;
import org.opends.sdk.util.ByteString;
import org.opends.sdk.util.Validator;
/**
 * A modification to be performed on an entry during a Modify operation.
 * <p>
 * TODO: other constructors.
 */
public final class Change
{
  private final ModificationType modificationType;
  private final Attribute attribute;
  /**
   * Creates a new modification having the provided modification type
   * and attribute values to be updated. Note that while the returned
   * {@code Change} is immutable, the underlying attribute may not be.
   * The following code ensures that the returned {@code Change} is
   * fully immutable:
   *
   * <pre>
   * Change change =
   *     new Change(modificationType, Types.unmodifiableAttribute(attribute));
   * </pre>
   *
   * @param modificationType
   *          The type of change to be performed.
   * @param attribute
   *          The the attribute containing the values to be modified.
   */
  public Change(ModificationType modificationType, Attribute attribute)
  {
    Validator.ensureNotNull(modificationType, attribute);
    this.modificationType = modificationType;
    this.attribute = attribute;
  }
  /**
   * Returns the type of change to be performed.
   *
   * @return The type of change to be performed.
   */
  public ModificationType getModificationType()
  {
    return modificationType;
  }
  /**
   * Returns the attribute containing the values to be modified.
   *
   * @return The the attribute containing the values to be modified.
   */
  public Attribute getAttribute()
  {
    return attribute;
  }
  /**
   * {@inheritDoc}
   */
  public String toString()
  {
    StringBuilder builder = new StringBuilder();
    builder.append("Change(modificationType=");
    builder.append(modificationType);
    builder.append(", attributeDescription=");
    builder.append(attribute.getAttributeDescriptionAsString());
    builder.append(", attributeValues={");
    boolean firstValue = true;
    for (ByteString value : attribute)
    {
      if (!firstValue)
      {
        builder.append(", ");
      }
      builder.append(value);
      firstValue = false;
    }
    builder.append("})");
    return builder.toString();
  }
}
opendj-sdk/sdk/src/org/opends/sdk/ConditionResult.java
New file
@@ -0,0 +1,295 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Copyright 2009 Sun Microsystems, Inc.
 */
package org.opends.sdk;
/**
 * The result of a tri-state logical expression. Condition results are
 * used to represent the result of a conditional evaluation that can
 * yield three possible values: {@code FALSE} (i.e. "no"), {@code TRUE}
 * (i.e. "yes"), or {@code UNDEFINED} (i.e. "maybe"). A result of
 * {@code UNDEFINED} indicates that further investigation may be
 * required.
 */
public enum ConditionResult
{
  /**
   * Indicates that the condition evaluated to {@code false}.
   */
  FALSE("false"),
  /**
   * Indicates that the condition could not be evaluated and its result
   * is undefined.
   */
  UNDEFINED("undefined"),
  /**
   * Indicates that the condition evaluated to {@code true}.
   */
  TRUE("true");
  // Boolean -> ConditionResult map.
  private static final boolean[] booleanMap = { false, false, true };
  // AND truth table.
  private static final ConditionResult[][] logicalAND =
      { { FALSE, FALSE, FALSE }, { FALSE, UNDEFINED, UNDEFINED },
          { FALSE, UNDEFINED, TRUE }, };
  // NOT truth table.
  private static final ConditionResult[] logicalNOT =
      { TRUE, UNDEFINED, FALSE };
  // OR truth table.
  private static final ConditionResult[][] logicalOR =
      { { FALSE, UNDEFINED, TRUE }, { UNDEFINED, UNDEFINED, TRUE },
          { TRUE, TRUE, TRUE }, };
  /**
   * Returns the logical AND of zero condition results, which is always
   * {@code TRUE}.
   *
   * @return The logical OR of zero condition results, which is always
   *         {@code TRUE}.
   */
  public static ConditionResult and()
  {
    return TRUE;
  }
  /**
   * Returns the logical AND of the provided condition result, which is
   * always {@code r}.
   *
   * @param r
   *          The condition result.
   * @return The logical AND of the provided condition result, which is
   *         always {@code r}.
   */
  public static ConditionResult and(ConditionResult r)
  {
    return r;
  }
  /**
   * Returns the logical AND of the provided condition results, which is
   * {@code TRUE} if all of the provided condition results are {@code
   * TRUE}, {@code FALSE} if at least one of them is {@code FALSE}, and
   * {@code UNDEFINED} otherwise. Note that {@code TRUE} is returned if
   * the provided list of results is empty.
   *
   * @param results
   *          The condition results to be compared.
   * @return The logical AND of the provided condition results.
   */
  public static ConditionResult and(ConditionResult... results)
  {
    ConditionResult finalResult = TRUE;
    for (ConditionResult result : results)
    {
      finalResult = and(finalResult, result);
      if (finalResult == FALSE)
        break;
    }
    return finalResult;
  }
  /**
   * Returns the logical AND of the provided condition results, which is
   * {@code TRUE} if both of the provided condition results are {@code
   * TRUE}, {@code FALSE} if at least one of them is {@code FALSE} , and
   * {@code UNDEFINED} otherwise.
   *
   * @param r1
   *          The first condition result to be compared.
   * @param r2
   *          The second condition result to be compared.
   * @return The logical AND of the provided condition results.
   */
  public static ConditionResult and(ConditionResult r1,
      ConditionResult r2)
  {
    return logicalAND[r1.ordinal()][r2.ordinal()];
  }
  /**
   * Returns the logical NOT of the provided condition result, which is
   * {@code TRUE} if the provided condition result is {@code FALSE},
   * {@code TRUE} if it is {@code FALSE}, and {@code UNDEFINED}
   * otherwise.
   *
   * @param r
   *          The condition result to invert.
   * @return The logical NOT of the provided condition result.
   */
  public static ConditionResult not(ConditionResult r)
  {
    return logicalNOT[r.ordinal()];
  }
  /**
   * Returns the logical OR of zero condition results, which is always
   * {@code FALSE}.
   *
   * @return The logical OR of zero condition results, which is always
   *         {@code FALSE}.
   */
  public static ConditionResult or()
  {
    return FALSE;
  }
  /**
   * Returns the logical OR of the provided condition result, which is
   * always {@code r}.
   *
   * @param r
   *          The condition result.
   * @return The logical OR of the provided condition result, which is
   *         always {@code r}.
   */
  public static ConditionResult or(ConditionResult r)
  {
    return r;
  }
  /**
   * Returns the logical OR of the provided condition results, which is
   * {@code FALSE} if all of the provided condition results are {@code
   * FALSE}, {@code TRUE} if at least one of them is {@code TRUE}, and
   * {@code UNDEFINED} otherwise. Note that {@code FALSE} is returned if
   * the provided list of results is empty.
   *
   * @param results
   *          The condition results to be compared.
   * @return The logical OR of the provided condition results.
   */
  public static ConditionResult or(ConditionResult... results)
  {
    ConditionResult finalResult = FALSE;
    for (ConditionResult result : results)
    {
      finalResult = and(finalResult, result);
      if (finalResult == TRUE)
        break;
    }
    return finalResult;
  }
  /**
   * Returns the logical OR of the provided condition results, which is
   * {@code FALSE} if both of the provided condition results are {@code
   * FALSE}, {@code TRUE} if at least one of them is {@code TRUE} , and
   * {@code UNDEFINED} otherwise.
   *
   * @param r1
   *          The first condition result to be compared.
   * @param r2
   *          The second condition result to be compared.
   * @return The logical OR of the provided condition results.
   */
  public static ConditionResult or(ConditionResult r1,
      ConditionResult r2)
  {
    return logicalOR[r1.ordinal()][r2.ordinal()];
  }
  /**
   * Returns the condition result which is equivalent to the provided
   * boolean value.
   *
   * @param b
   *          The boolean value.
   * @return {@code TRUE} if {@code b} was {@code true}, otherwise
   *         {@code FALSE}.
   */
  public static ConditionResult valueOf(boolean b)
  {
    return b ? TRUE : FALSE;
  }
  // The human-readable name for this result.
  private final String resultName;
  // Prevent instantiation.
  private ConditionResult(String resultName)
  {
    this.resultName = resultName;
  }
  /**
   * Converts this condition result to a boolean value. {@code FALSE}
   * and {@code UNDEFINED} are both converted to {@code false}, and
   * {@code TRUE} is converted to {@code true}.
   *
   * @return The boolean equivalent of this condition result.
   */
  public boolean toBoolean()
  {
    return booleanMap[ordinal()];
  }
  /**
   * Returns the string representation of this condition result.
   *
   * @return The string representation of his condition result.
   */
  @Override
  public String toString()
  {
    return resultName;
  }
}
opendj-sdk/sdk/src/org/opends/sdk/Connection.java
New file
@@ -0,0 +1,1084 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Copyright 2009 Sun Microsystems, Inc.
 */
package org.opends.sdk;
import java.io.Closeable;
import java.util.Collection;
import java.util.List;
import org.opends.sdk.requests.*;
import org.opends.sdk.responses.*;
import org.opends.sdk.util.ByteString;
import org.opends.sdk.util.LocalizedIllegalArgumentException;
/**
 * A synchronous connection with a Directory Server over which read and
 * update operations may be performed. See RFC 4511 for the LDAPv3
 * protocol specification and more information about the types of
 * operations defined in LDAP.
 * <p>
 * <h3>Operation processing</h3>
 * <p>
 * All operations are performed synchronously and return an appropriate
 * {@link Result} representing the final status of the operation.
 * Operation failures, for whatever reason, are signalled using an
 * {@link ErrorResultException}.
 * <p>
 * <h3>Closing connections</h3>
 * <p>
 * Applications must ensure that a connection is closed by calling
 * {@link #close()} even if a fatal error occurs on the connection. Once
 * a connection has been closed by the client application, any attempts
 * to continue to use the connection will result in an
 * {@link IllegalStateException} being thrown. Note that, if a fatal
 * error is encountered on the connection, then the application can
 * continue to use the connection. In this case all requests subsequent
 * to the failure will fail with an appropriate
 * {@link ErrorResultException} when their result is retrieved.
 * <p>
 * <h3>Event notification</h3>
 * <p>
 * Applications can choose to be notified when a connection is closed by
 * the application, receives an unsolicited notification, or experiences
 * a fatal error by registering a {@link ConnectionEventListener} with
 * the connection using the {@link #addConnectionEventListener} method.
 * <p>
 * <h3>TO DO</h3>
 * <p>
 * <ul>
 * <li>do we need isClosed() and isValid()?
 * <li>do we need connection event notification of client close? JDBC
 * and JCA have this functionality in their pooled (managed) connection
 * APIs. We need some form of event notification at the app level for
 * unsolicited notifications.
 * <li>method for performing update operation (e.g. LDIF change
 * records).
 * <li>should unsupported methods throw UnsupportedOperationException or
 * throw an ErrorResultException using an UnwillingToPerform result code
 * (or something similar)?
 * <li>Handler version of search.
 * <li>Finish off Search APIs to support blocking queues and
 * collections.
 * <li>searchSingleEntry Javadoc needs finishing. Code sample is
 * incorrect. How about references? What exceptions are thrown?
 * </ul>
 *
 * @see <a href="http://tools.ietf.org/html/rfc4511">RFC 4511 -
 *      Lightweight Directory Access Protocol (LDAP): The Protocol </a>
 */
public interface Connection extends Closeable
{
  /**
   * Adds an entry to the Directory Server using the provided add
   * request.
   *
   * @param request
   *          The add request.
   * @return The result of the operation.
   * @throws ErrorResultException
   *           If the result code indicates that the request failed for
   *           some reason.
   * @throws InterruptedException
   *           If the current thread was interrupted while waiting.
   * @throws UnsupportedOperationException
   *           If this connection does not support add operations.
   * @throws IllegalStateException
   *           If this connection has already been closed, i.e. if
   *           {@code isClosed() == true}.
   * @throws NullPointerException
   *           If {@code request} was {@code null}.
   */
  Result add(AddRequest request) throws ErrorResultException,
      InterruptedException, UnsupportedOperationException,
      IllegalStateException, NullPointerException;
  /**
   * Adds an entry to the Directory Server using the provided lines of
   * LDIF.
   * <p>
   * This method is equivalent to the following code:
   *
   * <pre>
   * AddRequest request = new AddRequest(ldifLines);
   * connection.add(request);
   * </pre>
   *
   * @param ldifLines
   *          Lines of LDIF containing the an LDIF add change record or
   *          an LDIF entry record.
   * @return The result of the operation.
   * @throws ErrorResultException
   *           If the result code indicates that the request failed for
   *           some reason.
   * @throws InterruptedException
   *           If the current thread was interrupted while waiting.
   * @throws UnsupportedOperationException
   *           If this connection does not support add operations.
   * @throws LocalizedIllegalArgumentException
   *           If {@code ldifLines} was empty, or contained invalid
   *           LDIF, or could not be decoded using the default schema.
   * @throws IllegalStateException
   *           If this connection has already been closed, i.e. if
   *           {@code isClosed() == true}.
   * @throws NullPointerException
   *           If {@code ldifLines} was {@code null} .
   */
  Result add(String... ldifLines) throws ErrorResultException,
      InterruptedException, UnsupportedOperationException,
      LocalizedIllegalArgumentException, IllegalStateException,
      NullPointerException;
  /**
   * Adds the provided entry to the Directory Server.
   * <p>
   * This method is equivalent to the following code:
   *
   * <pre>
   * AddRequest request = new AddRequest(entry);
   * connection.add(request);
   * </pre>
   *
   * @param entry
   *          The entry to be added.
   * @return The result of the operation.
   * @throws ErrorResultException
   *           If the result code indicates that the request failed for
   *           some reason.
   * @throws InterruptedException
   *           If the current thread was interrupted while waiting.
   * @throws UnsupportedOperationException
   *           If this connection does not support add operations.
   * @throws IllegalStateException
   *           If this connection has already been closed, i.e. if
   *           {@code isClosed() == true}.
   * @throws NullPointerException
   *           If {@code entry} was {@code null} .
   */
  Result add(Entry entry) throws ErrorResultException,
      InterruptedException, UnsupportedOperationException,
      IllegalStateException, NullPointerException;
  /**
   * Authenticates to the Directory Server using the provided bind
   * request.
   *
   * @param request
   *          The bind request.
   * @return The result of the operation.
   * @throws ErrorResultException
   *           If the result code indicates that the request failed for
   *           some reason.
   * @throws InterruptedException
   *           If the current thread was interrupted while waiting.
   * @throws UnsupportedOperationException
   *           If this connection does not support bind operations.
   * @throws IllegalStateException
   *           If this connection has already been closed, i.e. if
   *           {@code isClosed() == true}.
   * @throws NullPointerException
   *           If {@code request} was {@code null}.
   */
  BindResult bind(BindRequest request) throws ErrorResultException,
      InterruptedException, UnsupportedOperationException,
      IllegalStateException, NullPointerException;
  /**
   * Authenticates to the Directory Server using simple authentication
   * and the provided user name and password.
   * <p>
   * This method is equivalent to the following code:
   *
   * <pre>
   * BindRequest request = new SimpleBindRequest(name, password);
   * connection.bind(request);
   * </pre>
   *
   * @param name
   *          The distinguished name of the Directory object that the
   *          client wishes to bind as, which may be empty.
   * @param password
   *          The password of the Directory object that the client
   *          wishes to bind as, which may be empty.
   * @return The result of the operation.
   * @throws ErrorResultException
   *           If the result code indicates that the request failed for
   *           some reason.
   * @throws InterruptedException
   *           If the current thread was interrupted while waiting.
   * @throws LocalizedIllegalArgumentException
   *           If {@code name} could not be decoded using the default
   *           schema.
   * @throws UnsupportedOperationException
   *           If this connection does not support bind operations.
   * @throws IllegalStateException
   *           If this connection has already been closed, i.e. if
   *           {@code isClosed() == true}.
   * @throws NullPointerException
   *           If {@code name} or {@code password} was {@code null}.
   */
  BindResult bind(String name, String password)
      throws ErrorResultException, InterruptedException,
      LocalizedIllegalArgumentException, UnsupportedOperationException,
      IllegalStateException, NullPointerException;
  /**
   * Releases any resources associated with this connection. For
   * physical connections to a Directory Server this will mean that an
   * unbind request is sent and the underlying socket is closed.
   * <p>
   * Other connection implementations may behave differently, and may
   * choose not to send an unbind request if its use is inappropriate
   * (for example a pooled connection will be released and returned to
   * its connection pool without ever issuing an unbind request).
   * <p>
   * This method is equivalent to the following code:
   *
   * <pre>
   * UnbindRequest request = new UnbindRequest();
   * connection.close(request);
   * </pre>
   *
   * Calling {@code close} on a connection that is already closed has no
   * effect.
   */
  void close();
  /**
   * Releases any resources associated with this connection. For
   * physical connections to a Directory Server this will mean that the
   * provided unbind request is sent and the underlying socket is
   * closed.
   * <p>
   * Other connection implementations may behave differently, and may
   * choose to ignore the provided unbind request if its use is
   * inappropriate (for example a pooled connection will be released and
   * returned to its connection pool without ever issuing an unbind
   * request).
   * <p>
   * Calling {@code close} on a connection that is already closed has no
   * effect.
   *
   * @param request
   *          The unbind request to use in the case where a physical
   *          connection is closed.
   * @throws NullPointerException
   *           If {@code request} was {@code null}.
   */
  void close(UnbindRequest request) throws NullPointerException;
  /**
   * Compares an entry in the Directory Server using the provided
   * compare request.
   *
   * @param request
   *          The compare request.
   * @return The result of the operation.
   * @throws ErrorResultException
   *           If the result code indicates that the request failed for
   *           some reason.
   * @throws InterruptedException
   *           If the current thread was interrupted while waiting.
   * @throws UnsupportedOperationException
   *           If this connection does not support compare operations.
   * @throws IllegalStateException
   *           If this connection has already been closed, i.e. if
   *           {@code isClosed() == true}.
   * @throws NullPointerException
   *           If {@code request} was {@code null}.
   */
  CompareResult compare(CompareRequest request)
      throws ErrorResultException, InterruptedException,
      UnsupportedOperationException, IllegalStateException,
      NullPointerException;
  /**
   * Compares the named entry in the Directory Server against the
   * provided attribute value assertion.
   * <p>
   * This method is equivalent to the following code:
   *
   * <pre>
   * CompareRequest request = new CompareRequest(name, attributeDescription,
   *     assertionValue);
   * connection.compare(request);
   * </pre>
   *
   * @param name
   *          The distinguished name of the entry to be compared.
   * @param attributeDescription
   *          The name of the attribute to be compared.
   * @param assertionValue
   *          The assertion value to be compared.
   * @return The result of the operation.
   * @throws ErrorResultException
   *           If the result code indicates that the request failed for
   *           some reason.
   * @throws InterruptedException
   *           If the current thread was interrupted while waiting.
   * @throws LocalizedIllegalArgumentException
   *           If {@code name} or {@code AttributeDescription} could not
   *           be decoded using the default schema.
   * @throws UnsupportedOperationException
   *           If this connection does not support compare operations.
   * @throws IllegalStateException
   *           If this connection has already been closed, i.e. if
   *           {@code isClosed() == true}.
   * @throws NullPointerException
   *           If {@code name}, {@code attributeDescription}, or {@code
   *           assertionValue} was {@code null}.
   */
  CompareResult compare(String name, String attributeDescription,
      String assertionValue) throws ErrorResultException,
      InterruptedException, LocalizedIllegalArgumentException,
      UnsupportedOperationException, IllegalStateException,
      NullPointerException;
  /**
   * Deletes an entry from the Directory Server using the provided
   * delete request.
   *
   * @param request
   *          The delete request.
   * @return The result of the operation.
   * @throws ErrorResultException
   *           If the result code indicates that the request failed for
   *           some reason.
   * @throws InterruptedException
   *           If the current thread was interrupted while waiting.
   * @throws UnsupportedOperationException
   *           If this connection does not support delete operations.
   * @throws IllegalStateException
   *           If this connection has already been closed, i.e. if
   *           {@code isClosed() == true}.
   * @throws NullPointerException
   *           If {@code request} was {@code null}.
   */
  Result delete(DeleteRequest request) throws ErrorResultException,
      InterruptedException, UnsupportedOperationException,
      IllegalStateException, NullPointerException;
  /**
   * Deletes the named entry from the Directory Server.
   * <p>
   * This method is equivalent to the following code:
   *
   * <pre>
   * DeleteRequest request = new DeleteRequest(name);
   * connection.delete(request);
   * </pre>
   *
   * @param name
   *          The distinguished name of the entry to be deleted.
   * @return The result of the operation.
   * @throws ErrorResultException
   *           If the result code indicates that the request failed for
   *           some reason.
   * @throws InterruptedException
   *           If the current thread was interrupted while waiting.
   * @throws LocalizedIllegalArgumentException
   *           If {@code name} could not be decoded using the default
   *           schema.
   * @throws UnsupportedOperationException
   *           If this connection does not support delete operations.
   * @throws IllegalStateException
   *           If this connection has already been closed, i.e. if
   *           {@code isClosed() == true}.
   * @throws NullPointerException
   *           If {@code name} was {@code null}.
   */
  Result delete(String name) throws ErrorResultException,
      InterruptedException, LocalizedIllegalArgumentException,
      UnsupportedOperationException, IllegalStateException,
      NullPointerException;
  /**
   * Requests that the Directory Server performs the provided extended
   * request.
   *
   * @param <R>
   *          The type of result returned by the extended request.
   * @param request
   *          The extended request.
   * @return The result of the operation.
   * @throws ErrorResultException
   *           If the result code indicates that the request failed for
   *           some reason.
   * @throws InterruptedException
   *           If the current thread was interrupted while waiting.
   * @throws UnsupportedOperationException
   *           If this connection does not support extended operations.
   * @throws IllegalStateException
   *           If this connection has already been closed, i.e. if
   *           {@code isClosed() == true}.
   * @throws NullPointerException
   *           If {@code request} was {@code null}.
   */
  <R extends Result> R extendedRequest(ExtendedRequest<R> request)
      throws ErrorResultException, InterruptedException,
      UnsupportedOperationException, IllegalStateException,
      NullPointerException;
  /**
   * Requests that the Directory Server performs the provided extended
   * request.
   * <p>
   * This method is equivalent to the following code:
   *
   * <pre>
   * GenericExtendedRequest request = new GenericExtendedRequest(
   *     requestName, requestValue);
   * connection.extendedRequest(request);
   * </pre>
   *
   * @param requestName
   *          The dotted-decimal representation of the unique OID
   *          corresponding to the extended request.
   * @param requestValue
   *          The content of the extended request in a form defined by
   *          the extended operation, or {@code null} if there is no
   *          content.
   * @return The result of the operation.
   * @throws ErrorResultException
   *           If the result code indicates that the request failed for
   *           some reason.
   * @throws InterruptedException
   *           If the current thread was interrupted while waiting.
   * @throws UnsupportedOperationException
   *           If this connection does not support extended operations.
   * @throws IllegalStateException
   *           If this connection has already been closed, i.e. if
   *           {@code isClosed() == true}.
   * @throws NullPointerException
   *           If {@code requestName} was {@code null}.
   */
  GenericExtendedResult extendedRequest(String requestName,
      ByteString requestValue) throws ErrorResultException,
      InterruptedException, UnsupportedOperationException,
      IllegalStateException, NullPointerException;
  // /**
  // * Indicates whether or not this connection has been explicitly
  // closed
  // * by calling {@code close}. This method will not return {@code
  // true}
  // * if a fatal error has occurred on the connection unless {@code
  // * close} has been called.
  // *
  // * @return {@code true} if this connection has been explicitly
  // closed
  // * by calling {@code close}, or {@code false} otherwise.
  // */
  // boolean isClosed();
  //
  //
  //
  // /**
  // * Indicates whether or not this connection is valid. A connection
  // is
  // * not valid if the method {@code close} has been called on it or if
  // * certain fatal errors have occurred. This method is guaranteed to
  // * return {@code false} only when it is called after the method
  // * {@code close} has been called.
  // * <p>
  // * Implementations may choose to send a no-op request to the
  // * underlying Directory Server in order to determine if the
  // underlying
  // * connection is still valid.
  // *
  // * @return {@code true} if this connection is valid, or {@code
  // false}
  // * otherwise.
  // * @throws InterruptedException
  // * If the current thread was interrupted while waiting.
  // */
  // boolean isValid() throws InterruptedException;
  //
  //
  //
  // /**
  // * Indicates whether or not this connection is valid. A connection
  // is
  // * not valid if the method {@code close} has been called on it or if
  // * certain fatal errors have occurred. This method is guaranteed to
  // * return {@code false} only when it is called after the method
  // * {@code close} has been called.
  // * <p>
  // * Implementations may choose to send a no-op request to the
  // * underlying Directory Server in order to determine if the
  // underlying
  // * connection is still valid.
  // *
  // * @param timeout
  // * The maximum time to wait.
  // * @param unit
  // * The time unit of the timeout argument.
  // * @return {@code true} if this connection is valid, or {@code
  // false}
  // * otherwise.
  // * @throws InterruptedException
  // * If the current thread was interrupted while waiting.
  // * @throws TimeoutException
  // * If the wait timed out.
  // */
  // boolean isValid(long timeout, TimeUnit unit)
  // throws InterruptedException, TimeoutException;
  /**
   * Modifies an entry in the Directory Server using the provided modify
   * request.
   *
   * @param request
   *          The modify request.
   * @return The result of the operation.
   * @throws ErrorResultException
   *           If the result code indicates that the request failed for
   *           some reason.
   * @throws InterruptedException
   *           If the current thread was interrupted while waiting.
   * @throws UnsupportedOperationException
   *           If this connection does not support modify operations.
   * @throws IllegalStateException
   *           If this connection has already been closed, i.e. if
   *           {@code isClosed() == true}.
   * @throws NullPointerException
   *           If {@code request} was {@code null}.
   */
  Result modify(ModifyRequest request) throws ErrorResultException,
      InterruptedException, UnsupportedOperationException,
      IllegalStateException, NullPointerException;
  /**
   * Modifies an entry in the Directory Server using the provided lines
   * of LDIF.
   * <p>
   * This method is equivalent to the following code:
   *
   * <pre>
   * ModifyRequest request = new ModifyRequest(name, ldifChanges);
   * connection.modify(request);
   * </pre>
   *
   * @param ldifLines
   *          Lines of LDIF containing the a single LDIF modify change
   *          record.
   * @return The result of the operation.
   * @throws ErrorResultException
   *           If the result code indicates that the request failed for
   *           some reason.
   * @throws InterruptedException
   *           If the current thread was interrupted while waiting.
   * @throws UnsupportedOperationException
   *           If this connection does not support modify operations.
   * @throws LocalizedIllegalArgumentException
   *           If {@code ldifLines} was empty, or contained invalid
   *           LDIF, or could not be decoded using the default schema.
   * @throws IllegalStateException
   *           If this connection has already been closed, i.e. if
   *           {@code isClosed() == true}.
   * @throws NullPointerException
   *           If {@code ldifLines} was {@code null} .
   */
  Result modify(String... ldifLines) throws ErrorResultException,
      InterruptedException, UnsupportedOperationException,
      LocalizedIllegalArgumentException, IllegalStateException,
      NullPointerException;
  /**
   * Renames an entry in the Directory Server using the provided modify
   * DN request.
   *
   * @param request
   *          The modify DN request.
   * @return The result of the operation.
   * @throws ErrorResultException
   *           If the result code indicates that the request failed for
   *           some reason.
   * @throws InterruptedException
   *           If the current thread was interrupted while waiting.
   * @throws UnsupportedOperationException
   *           If this connection does not support modify DN operations.
   * @throws IllegalStateException
   *           If this connection has already been closed, i.e. if
   *           {@code isClosed() == true}.
   * @throws NullPointerException
   *           If {@code request} was {@code null}.
   */
  Result modifyDN(ModifyDNRequest request) throws ErrorResultException,
      InterruptedException, UnsupportedOperationException,
      IllegalStateException, NullPointerException;
  /**
   * Renames the named entry in the Directory Server using the provided
   * new RDN.
   * <p>
   * This method is equivalent to the following code:
   *
   * <pre>
   * ModifyDNRequest request = new ModifyDNRequest(name, newRDN);
   * connection.modifyDN(request);
   * </pre>
   *
   * @param name
   *          The distinguished name of the entry to be renamed.
   * @param newRDN
   *          The new RDN of the entry.
   * @return The result of the operation.
   * @throws ErrorResultException
   *           If the result code indicates that the request failed for
   *           some reason.
   * @throws InterruptedException
   *           If the current thread was interrupted while waiting.
   * @throws LocalizedIllegalArgumentException
   *           If {@code name} or {@code newRDN} could not be decoded
   *           using the default schema.
   * @throws UnsupportedOperationException
   *           If this connection does not support modify DN operations.
   * @throws IllegalStateException
   *           If this connection has already been closed, i.e. if
   *           {@code isClosed() == true}.
   * @throws NullPointerException
   *           If {@code name} or {@code newRDN} was {@code null}.
   */
  Result modifyDN(String name, String newRDN)
      throws ErrorResultException, LocalizedIllegalArgumentException,
      InterruptedException, UnsupportedOperationException,
      IllegalStateException, NullPointerException;
  /**
   * Searches the Directory Server using the provided search request.
   * Any matching entries returned by the search as well as any search
   * result references will be passed to the provided search result
   * handler.
   *
   * @param <P>
   *          The type of the additional parameter to the handler's
   *          methods.
   * @param request
   *          The search request.
   * @param handler
   *          A search result handler which can be used to process the
   *          search result entries and references as they are received,
   *          may be {@code null}.
   * @param p
   *          Optional additional handler parameter.
   * @return The result of the operation.
   * @throws ErrorResultException
   *           If the result code indicates that the request failed for
   *           some reason.
   * @throws InterruptedException
   *           If the current thread was interrupted while waiting.
   * @throws UnsupportedOperationException
   *           If this connection does not support search operations.
   * @throws IllegalStateException
   *           If this connection has already been closed, i.e. if
   *           {@code isClosed() == true}.
   * @throws NullPointerException
   *           If {@code request} was {@code null}.
   */
  <P> Result search(SearchRequest request,
      SearchResultHandler<P> handler, P p) throws ErrorResultException,
      InterruptedException, UnsupportedOperationException,
      IllegalStateException, NullPointerException;
  /**
   * Searches the Directory Server using the provided search request.
   * Any matching entries returned by the search will be added to
   * {@code entries}, even if the final search result indicates that the
   * search failed. Search result references will be discarded.
   * <p>
   * <b>Warning:</b> Usage of this method is discouraged if the search
   * request is expected to yield a large number of search results since
   * the entire set of results will be stored in memory, potentially
   * causing an {@code OutOfMemoryError}.
   * <p>
   * This method is equivalent to the following code:
   *
   * <pre>
   * connection.search(request, entries, null);
   * </pre>
   *
   * @param request
   *          The search request.
   * @param entries
   *          The collection to which matching entries should be added.
   * @return The result of the operation.
   * @throws ErrorResultException
   *           If the result code indicates that the request failed for
   *           some reason.
   * @throws InterruptedException
   *           If the current thread was interrupted while waiting.
   * @throws UnsupportedOperationException
   *           If this connection does not support search operations.
   * @throws IllegalStateException
   *           If this connection has already been closed, i.e. if
   *           {@code isClosed() == true}.
   * @throws NullPointerException
   *           If {@code request} or {@code entries} was {@code null}.
   */
  Result search(SearchRequest request,
      Collection<? super SearchResultEntry> entries)
      throws ErrorResultException, InterruptedException,
      UnsupportedOperationException, IllegalStateException,
      NullPointerException;
  /**
   * Searches the Directory Server using the provided search request.
   * Any matching entries returned by the search will be added to
   * {@code entries}, even if the final search result indicates that the
   * search failed. Similarly, search result references returned by the
   * search will be added to {@code references}.
   * <p>
   * <b>Warning:</b> Usage of this method is discouraged if the search
   * request is expected to yield a large number of search results since
   * the entire set of results will be stored in memory, potentially
   * causing an {@code OutOfMemoryError}.
   *
   * @param request
   *          The search request.
   * @param entries
   *          The collection to which matching entries should be added.
   * @param references
   *          The collection to which search result references should be
   *          added, or {@code null} if references are to be discarded.
   * @return The result of the operation.
   * @throws ErrorResultException
   *           If the result code indicates that the request failed for
   *           some reason.
   * @throws InterruptedException
   *           If the current thread was interrupted while waiting.
   * @throws UnsupportedOperationException
   *           If this connection does not support search operations.
   * @throws IllegalStateException
   *           If this connection has already been closed, i.e. if
   *           {@code isClosed() == true}.
   * @throws NullPointerException
   *           If {@code request} or {@code entries} was {@code null}.
   */
  Result search(SearchRequest request,
      Collection<? super SearchResultEntry> entries,
      Collection<? super SearchResultReference> references)
      throws ErrorResultException, InterruptedException,
      UnsupportedOperationException, IllegalStateException,
      NullPointerException;
  /**
   * Searches the Directory Server using the provided search parameters.
   * Any matching entries returned by the search will be added to a
   * {@code List} which is returned if the search succeeds. Search
   * result references will be discarded.
   * <p>
   * <b>Warning:</b> Usage of this method is discouraged if the search
   * request is expected to yield a large number of search results since
   * the entire set of results will be stored in memory, potentially
   * causing an {@code OutOfMemoryError}.
   * <p>
   * This method is equivalent to the following code:
   *
   * <pre>
   * SearchRequest request = new SearchRequest(baseDN, scope, filter,
   *     attributeDescriptions);
   * connection.search(request, new LinkedList&lt;SearchResultEntry&gt;());
   * </pre>
   *
   * @param baseObject
   *          The distinguished name of the base entry relative to which
   *          the search is to be performed.
   * @param scope
   *          The scope of the search.
   * @param filter
   *          The filter that defines the conditions that must be
   *          fulfilled in order for an entry to be returned.
   * @param attributeDescriptions
   *          The names of the attributes to be included with each
   *          entry.
   * @return A list containing any matching entries returned by the
   *         search.
   * @throws ErrorResultException
   *           If the result code indicates that the request failed for
   *           some reason.
   * @throws InterruptedException
   *           If the current thread was interrupted while waiting.
   * @throws LocalizedIllegalArgumentException
   *           If {@code baseObject} could not be decoded using the
   *           default schema or if {@code filter} is not a valid LDAP
   *           string representation of a filter.
   * @throws UnsupportedOperationException
   *           If this connection does not support search operations.
   * @throws IllegalStateException
   *           If this connection has already been closed, i.e. if
   *           {@code isClosed() == true}.
   * @throws NullPointerException
   *           If the {@code baseObject}, {@code scope}, or {@code
   *           filter} were {@code null}.
   */
  List<SearchResultEntry> search(String baseObject, SearchScope scope,
      String filter, String... attributeDescriptions)
      throws ErrorResultException, InterruptedException,
      LocalizedIllegalArgumentException, UnsupportedOperationException,
      IllegalStateException, NullPointerException;
  /**
   * Searches the Directory Server for a single entry using the provided
   * search request. If the search returns more than one entry then an
   * {@code ErrorResultException} is thrown. If no entry is found then
   * this method returns {@code null}.
   *
   * @param request
   *          The search request.
   * @return The single search result entry returned from the search.
   * @throws ErrorResultException
   *           If the result code indicates that the request failed for
   *           some reason.
   * @throws InterruptedException
   *           If the current thread was interrupted while waiting.
   * @throws UnsupportedOperationException
   *           If this connection does not support search operations.
   * @throws IllegalStateException
   *           If this connection has already been closed, i.e. if
   *           {@code isClosed() == true}.
   * @throws NullPointerException
   *           If the {@code request} was {@code null}.
   */
  SearchResultEntry searchSingleEntry(SearchRequest request)
      throws ErrorResultException, InterruptedException,
      UnsupportedOperationException, IllegalStateException,
      NullPointerException;
  /**
   * Searches the Directory Server for a single entry using the provided
   * search parameters. If the search returns more than one entry then
   * an {@code ErrorResultException} is thrown. If no entry is found
   * then this method returns {@code null}.
   * <p>
   * This method is equivalent to the following code:
   *
   * <pre>
   * SearchRequest request = new SearchRequest(baseObject, scope, filter,
   *     attributeDescriptions);
   * connection.searchSingleEntry(request);
   * </pre>
   *
   * @param baseObject
   *          The distinguished name of the base entry relative to which
   *          the search is to be performed.
   * @param scope
   *          The scope of the search.
   * @param filter
   *          The filter that defines the conditions that must be
   *          fulfilled in order for an entry to be returned.
   * @param attributeDescriptions
   *          The names of the attributes to be included with each
   *          entry.
   * @return The single search result entry returned from the search.
   * @throws ErrorResultException
   *           If the result code indicates that the request failed for
   *           some reason.
   * @throws InterruptedException
   *           If the current thread was interrupted while waiting.
   * @throws LocalizedIllegalArgumentException
   *           If {@code baseObject} could not be decoded using the
   *           default schema or if {@code filter} is not a valid LDAP
   *           string representation of a filter.
   * @throws UnsupportedOperationException
   *           If this connection does not support search operations.
   * @throws IllegalStateException
   *           If this connection has already been closed, i.e. if
   *           {@code isClosed() == true}.
   * @throws NullPointerException
   *           If the {@code baseObject}, {@code scope}, or {@code
   *           filter} were {@code null}.
   */
  SearchResultEntry searchSingleEntry(String baseObject,
      SearchScope scope, String filter, String... attributeDescriptions)
      throws ErrorResultException, InterruptedException,
      LocalizedIllegalArgumentException, UnsupportedOperationException,
      IllegalStateException, NullPointerException;
  /**
   * Reads the named entry from the Directory Server. If no entry is
   * found then this method returns {@code null}.
   * <p>
   * This method is equivalent to the following code:
   *
   * <pre>
   * SearchRequest request = new SearchRequest(baseObject,
   *     SearchScope.BASE_OBJECT, &quot;(objectClass=*)&quot;, attributeDescriptions);
   * connection.searchSingleEntry(request);
   * </pre>
   *
   * @param baseObject
   *          The distinguished name of the entry to be read.
   * @param attributeDescriptions
   *          The names of the attributes to be included with the entry.
   * @return The single search result entry returned from the search.
   * @throws ErrorResultException
   *           If the result code indicates that the request failed for
   *           some reason.
   * @throws InterruptedException
   *           If the current thread was interrupted while waiting.
   * @throws LocalizedIllegalArgumentException
   *           If {@code baseObject} could not be decoded using the
   *           default schema.
   * @throws UnsupportedOperationException
   *           If this connection does not support search operations.
   * @throws IllegalStateException
   *           If this connection has already been closed, i.e. if
   *           {@code isClosed() == true}.
   * @throws NullPointerException
   *           If the {@code baseObject} was {@code null}.
   */
  SearchResultEntry readEntry(String baseObject,
      String... attributeDescriptions) throws ErrorResultException,
      InterruptedException, LocalizedIllegalArgumentException,
      UnsupportedOperationException, IllegalStateException,
      NullPointerException;
  /**
   * Reads the named entry from the Directory Server. If no entry is
   * found then this method returns {@code null}.
   * <p>
   * This method is equivalent to the following code:
   *
   * <pre>
   * SearchRequest request = new SearchRequest(baseObject,
   *     SearchScope.BASE_OBJECT, &quot;(objectClass=*)&quot;, attributeDescriptions);
   * connection.searchSingleEntry(request);
   * </pre>
   *
   * @param baseObject
   *          The distinguished name of the entry to be read.
   * @param attributeDescriptions
   *          The names of the attributes to be included with the entry.
   * @return The single search result entry returned from the search.
   * @throws ErrorResultException
   *           If the result code indicates that the request failed for
   *           some reason.
   * @throws InterruptedException
   *           If the current thread was interrupted while waiting.
   * @throws UnsupportedOperationException
   *           If this connection does not support search operations.
   * @throws IllegalStateException
   *           If this connection has already been closed, i.e. if
   *           {@code isClosed() == true}.
   * @throws NullPointerException
   *           If the {@code baseObject} was {@code null}.
   */
  SearchResultEntry readEntry(DN baseObject,
      String... attributeDescriptions) throws ErrorResultException,
      InterruptedException, UnsupportedOperationException,
      IllegalStateException, NullPointerException;
  /**
   * Registers the provided connection event listener so that it will be
   * notified when this connection is closed by the application,
   * receives an unsolicited notification, or experiences a fatal error.
   *
   * @param listener
   *          The listener which wants to be notified when events occur
   *          on this connection.
   * @throws IllegalStateException
   *           If this connection has already been closed, i.e. if
   *           {@code isClosed() == true}.
   * @throws NullPointerException
   *           If the {@code listener} was {@code null}.
   */
  void addConnectionEventListener(ConnectionEventListener listener)
      throws IllegalStateException, NullPointerException;
  /**
   * Removes the provided connection event listener from this connection
   * so that it will no longer be notified when this connection is
   * closed by the application, receives an unsolicited notification, or
   * experiences a fatal error.
   *
   * @param listener
   *          The listener which no longer wants to be notified when
   *          events occur on this connection.
   * @throws NullPointerException
   *           If the {@code listener} was {@code null}.
   */
  void removeConnectionEventListener(ConnectionEventListener listener)
      throws NullPointerException;
}
opendj-sdk/sdk/src/org/opends/sdk/ConnectionEventListener.java
New file
@@ -0,0 +1,109 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Copyright 2009 Sun Microsystems, Inc.
 */
package org.opends.sdk;
import java.util.EventListener;
import org.opends.sdk.responses.GenericExtendedResult;
/**
 * An object that registers to be notified when a connection is closed
 * by the application, receives an unsolicited notification, or
 * experiences a fatal error.
 * <p>
 * TODO: isolate fatal connection errors as a sub-type of
 * ErrorResultException.
 * <p>
 * TODO: do we need client initiated close notification as in JCA /
 * JDBC? A simpler approach would be for the connection pool to wrap the
 * underlying physical connection with its own. It can then intercept
 * the close request from the client. This has the disadvantage in that
 * we lose any specialized methods exposed by the underlying physical
 * connection (i.e. if the physical connection extends Connection and
 * provides additional methods) since the connection pool effectively
 * hides them via its wrapper.
 */
public interface ConnectionEventListener extends EventListener
{
  // /**
  // * Notifies this connection event listener that the application has
  // * called {@link Connection#close} on the connection. The connection
  // * event listener will be notified immediately after the application
  // * calls the {@link Connection#close} method on the associated
  // * connection.
  // *
  // * @param connection
  // * The connection that has just been closed by the
  // * application.
  // */
  // void connectionClosed(Connection connection);
  /**
   * Notifies this connection event listener that the connection has
   * just received the provided unsolicited notification from the
   * server.
   * <p>
   * <b>Note:</b> disconnect notifications are treated as fatal
   * connection errors and are handled by the
   * {@link #connectionErrorOccurred} method.
   *
   * @param notification
   *          The unsolicited notification
   */
  void connectionReceivedUnsolicitedNotification(
      GenericExtendedResult notification);
  /**
   * Notifies this connection event listener that a fatal error has
   * occurred and the connection can no longer be used - the server has
   * crashed, for example. The connection implementation makes this
   * notification just before it throws the provided
   * {@link ErrorResultException} to the application.
   * <p>
   * <b>Note:</b> disconnect notifications are treated as fatal
   * connection errors and are handled by this method. In this case
   * {@code isDisconnectNotification} will be {@code true} and {@code
   * error} will contain the result code and any diagnostic information
   * contained in the notification message.
   *
   * @param isDisconnectNotification
   *          {@code true} if the error was triggered by a disconnect
   *          notification sent by the server, otherwise {@code false}.
   * @param error
   *          The exception that is about to be thrown to the
   *          application.
   */
  void connectionErrorOccurred(boolean isDisconnectNotification,
      ErrorResultException error);
}
opendj-sdk/sdk/src/org/opends/sdk/ConnectionFactory.java
New file
@@ -0,0 +1,95 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Copyright 2009 Sun Microsystems, Inc.
 */
package org.opends.sdk;
/**
 * A connection factory provides an interface for obtaining a connection
 * to a Directory Server. Connection factories can be used to wrap other
 * connection factories in order to provide enhanced capabilities in a
 * manner which is transparent to the application. For example:
 * <ul>
 * <li>Connection pooling
 * <li>Load balancing
 * <li>Keep alive
 * <li>Transactional connections
 * <li>Connections to LDIF files
 * <li>Data transformations
 * <li>Logging connections
 * <li>Read-only connections
 * <li>Pre-authenticated connections
 * <li>Recording connections, with primitive roll-back functionality
 * </ul>
 * An application typically obtains a connection from a connection
 * factory, performs one or more operations, and then closes the
 * connection. Applications should aim to close connections as soon as
 * possible in order to avoid resource contention.
 *
 * @param <C>
 *          The type of asynchronous connection returned by this
 *          connection factory.
 */
public interface ConnectionFactory<C extends AsynchronousConnection>
{
  /**
   * Returns a connection to the Directory Server associated with this
   * connection factory. The connection returned by this method can be
   * used immediately.
   *
   * @return A connection to the Directory Server associated with this
   *         connection factory.
   * @throws ErrorResultException
   *           If the connection request failed for some reason.
   */
  Connection getConnection() throws ErrorResultException;
  /**
   * Initiates an asynchronous connection request to the Directory
   * Server associated with this connection factory. The returned
   * {@code ConnectionFuture} can be used to retrieve the completed
   * asynchronous connection. Alternatively, if a {@code
   * ConnectionResultHandler} is provided, the handler will be notified
   * when the connection is available and ready for use.
   *
   * @param <P>
   *          The type of the additional parameter to the handler's
   *          methods.
   * @param handler
   *          The completion handler, or {@code null} if no handler is
   *          to be used.
   * @param p
   *          Optional additional handler parameter.
   * @return A future which can be used to retrieve the asynchronous
   *         connection.
   */
  <P> ConnectionFuture<? extends C> getAsynchronousConnection(
      ConnectionResultHandler<? super C, P> handler, P p);
}
opendj-sdk/sdk/src/org/opends/sdk/ConnectionFuture.java
New file
@@ -0,0 +1,150 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Copyright 2009 Sun Microsystems, Inc.
 */
package org.opends.sdk;
import java.util.concurrent.CancellationException;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
/**
 * A handle which can be used to retrieve a requested {@code
 * AsynchronousConnection}.
 * <p>
 * TODO: Do we want to throw an ErrorResultException? I think we do
 * because exceptions are not limited to connection related errors. For
 * example, a transacted connection would already have a physical
 * connection; an error could occur when sending the start txn extended
 * op.
 *
 * @param <C>
 *          The type of asynchronous connection returned by this
 *          connection future.
 */
public interface ConnectionFuture<C extends AsynchronousConnection>
    extends Future<C>
{
  /**
   * Attempts to cancel the request. This attempt will fail if the
   * request has already completed or has already been cancelled. If
   * successful, then cancellation results in an abandon or cancel
   * request (if configured) being sent to the server.
   * <p>
   * After this method returns, subsequent calls to {@link #isDone} will
   * always return {@code true}. Subsequent calls to
   * {@link #isCancelled} will always return {@code true} if this method
   * returned {@code true}.
   *
   * @param mayInterruptIfRunning
   *          {@code true} if the thread executing executing the
   *          response handler should be interrupted; otherwise,
   *          in-progress response handlers are allowed to complete.
   * @return {@code false} if the request could not be cancelled,
   *         typically because it has already completed normally;
   *         {@code true} otherwise.
   */
  boolean cancel(boolean mayInterruptIfRunning);
  /**
   * Waits if necessary for the connection request to complete, and then
   * returns the asynchronous connection if the connection request
   * succeeded. If the connection request failed (i.e. a non-successful
   * result code was obtained) then a {@link ErrorResultException} is
   * thrown.
   *
   * @return The asynchronous connection, but only if the the connection
   *         request succeeded.
   * @throws CancellationException
   *           If the connection request was cancelled using a call to
   *           {@link #cancel}.
   * @throws ErrorResultException
   *           If the connection request failed for some reason.
   * @throws InterruptedException
   *           If the current thread was interrupted while waiting.
   */
  C get() throws InterruptedException, ErrorResultException;
  /**
   * Waits if necessary for at most the given time for the connection
   * request to complete, and then returns the asynchronous connection
   * if the connection request succeeded. If the connection request
   * failed (i.e. a non-successful result code was obtained) then a
   * {@link ErrorResultException} is thrown.
   *
   * @param timeout
   *          The maximum time to wait.
   * @param unit
   *          The time unit of the timeout argument.
   * @return The asynchronous connection, but only if the the connection
   *         request succeeded.
   * @throws CancellationException
   *           If the connection request was cancelled using a call to
   *           {@link #cancel}.
   * @throws ErrorResultException
   *           If the connection request failed for some reason.
   * @throws InterruptedException
   *           If the current thread was interrupted while waiting.
   * @throws TimeoutException
   *           If the wait timed out.
   */
  C get(long timeout, TimeUnit unit) throws InterruptedException,
      TimeoutException, ErrorResultException;
  /**
   * Returns {@code true} if the connection request was cancelled before
   * it completed normally.
   *
   * @return {@code true} if the connection request was cancelled before
   *         it completed normally, otherwise {@code false}.
   */
  boolean isCancelled();
  /**
   * Returns {@code true} if the connection request has completed.
   * <p>
   * Completion may be due to normal termination, an exception, or
   * cancellation. In all of these cases, this method will return
   * {@code true}.
   *
   * @return {@code true} if the connection request has completed,
   *         otherwise {@code false}.
   */
  boolean isDone();
}
opendj-sdk/sdk/src/org/opends/sdk/ConnectionResultHandler.java
New file
@@ -0,0 +1,81 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Copyright 2009 Sun Microsystems, Inc.
 */
package org.opends.sdk;
/**
 * A completion handler which is notified when an asynchronous
 * connection attempt has completed.
 * <p>
 * {@link ConnectionFactory} objects allow a connection result
 * completion handler to be specified when attempting to connect to a
 * Directory Server. The {@link #handleConnection} method is invoked
 * when the operation completes successfully. The
 * {@link #handleConnectionError} method is invoked if the operations
 * fails.
 * <p>
 * Implementations of these methods should complete in a timely manner
 * so as to avoid keeping the invoking thread from dispatching to other
 * completion handlers.
 *
 * @param <C>
 *          The type of asynchronous connection handled by this
 *          connection result handler.
 * @param <P>
 *          The type of the additional parameter to this handler's
 *          methods. Use {@link java.lang.Void} for visitors that do not
 *          need an additional parameter.
 */
public interface ConnectionResultHandler<C extends AsynchronousConnection, P>
{
  /**
   * Invoked when the asynchronous connection has completed
   * successfully.
   *
   * @param p
   *          A handler specified parameter.
   * @param connection
   *          The connection which can be used to interact with the
   *          Directory Server.
   */
  void handleConnection(P p, C connection);
  /**
   * Invoked when the asynchronous connection attempt has failed.
   *
   * @param p
   *          A handler specified parameter.
   * @param error
   *          The error result exception indicating why the asynchronous
   *          connection attempt has failed.
   */
  void handleConnectionError(P p, ErrorResultException error);
}
opendj-sdk/sdk/src/org/opends/sdk/DN.java
New file
@@ -0,0 +1,763 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Copyright 2009 Sun Microsystems, Inc.
 */
package org.opends.sdk;
import static org.opends.messages.SchemaMessages.*;
import java.util.*;
import org.opends.messages.Message;
import org.opends.sdk.schema.Schema;
import org.opends.sdk.schema.UnknownSchemaElementException;
import org.opends.sdk.util.LocalizedIllegalArgumentException;
import org.opends.sdk.util.SubstringReader;
import org.opends.sdk.util.Validator;
/**
 * A distinguished name (DN) as defined in RFC 4512 section 2.3 is the
 * concatenation of its relative distinguished name (RDN) and its
 * immediate superior's DN. A DN unambiguously refers to an entry in the
 * Directory.
 * <p>
 * The following are examples of string representations of DNs:
 *
 * <pre>
 * UID=nobody@example.com,DC=example,DC=com CN=John
 * Smith,OU=Sales,O=ACME Limited,L=Moab,ST=Utah,C=US
 * </pre>
 *
 * @see <a href="http://tools.ietf.org/html/rfc4512#section-2.3">RFC
 *      4512 - Lightweight Directory Access Protocol (LDAP): Directory
 *      Information Models </a>
 */
public final class DN implements Iterable<RDN>, Comparable<DN>
{
  private static final DN ROOT_DN = new DN(null, null, "");
  // This is the size of the per-thread per-schema DN cache. We should
  // be conservative here in case there are many threads. We will only
  // cache parent DNs, so there's no need for it to be big.
  private static final int DN_CACHE_SIZE = 32;
  private static final ThreadLocal<WeakHashMap<Schema, Map<String, DN>>> CACHE = new ThreadLocal<WeakHashMap<Schema, Map<String, DN>>>()
  {
    /**
     * {@inheritDoc}
     */
    @Override
    protected WeakHashMap<Schema, Map<String, DN>> initialValue()
    {
      return new WeakHashMap<Schema, Map<String, DN>>();
    }
  };
  /**
   * Returns the Root DN. The Root DN does not contain and RDN
   * components and is superior to all other DNs.
   *
   * @return The Root DN.
   */
  public static DN rootDN()
  {
    return ROOT_DN;
  }
  /**
   * Parses the provided LDAP string representation of a DN using the
   * default schema.
   *
   * @param dn
   *          The LDAP string representation of a DN.
   * @return The parsed DN.
   * @throws LocalizedIllegalArgumentException
   *           If {@code dn} is not a valid LDAP string representation
   *           of a DN.
   * @throws NullPointerException
   *           If {@code dn} was {@code null}.
   */
  public static DN valueOf(String dn)
      throws LocalizedIllegalArgumentException, NullPointerException
  {
    return valueOf(dn, Schema.getDefaultSchema());
  }
  /**
   * Parses the provided LDAP string representation of a DN using the
   * provided schema.
   *
   * @param dn
   *          The LDAP string representation of a DN.
   * @param schema
   *          The schema to use when parsing the DN.
   * @return The parsed DN.
   * @throws LocalizedIllegalArgumentException
   *           If {@code dn} is not a valid LDAP string representation
   *           of a DN.
   * @throws NullPointerException
   *           If {@code dn} or {@code schema} was {@code null}.
   */
  public static DN valueOf(String dn, Schema schema)
      throws LocalizedIllegalArgumentException
  {
    Validator.ensureNotNull(schema);
    if (dn.length() == 0)
    {
      return ROOT_DN;
    }
    // First check if DN is already cached.
    final Map<String, DN> cache = getCache(schema);
    final DN cachedDN = cache.get(dn);
    if (cachedDN != null)
    {
      return cachedDN;
    }
    // Not in cache so decode.
    final SubstringReader reader = new SubstringReader(dn);
    return decode(dn, reader, schema, cache);
  }
  // Decodes a DN using the provided reader and schema.
  private static DN decode(String dnString, SubstringReader reader,
      Schema schema, Map<String, DN> cache)
      throws LocalizedIllegalArgumentException
  {
    reader.skipWhitespaces();
    if (reader.remaining() == 0)
    {
      return ROOT_DN;
    }
    RDN rdn;
    try
    {
      rdn = RDN.decode(null, reader, schema);
    }
    catch (final UnknownSchemaElementException e)
    {
      final Message message = ERR_DN_TYPE_NOT_FOUND.get(reader
          .getString(), e.getMessageObject());
      throw new LocalizedIllegalArgumentException(message);
    }
    DN parent;
    if (reader.remaining() > 0 && reader.read() == ',')
    {
      reader.mark();
      final String parentString = reader.read(reader.remaining());
      parent = cache.get(parentString);
      if (parent == null)
      {
        reader.reset();
        parent = decode(parentString, reader, schema, cache);
        // Only cache parent DNs since leaf DNs are likely to make the
        // cache to volatile.
        cache.put(parentString, parent);
      }
    }
    else
    {
      parent = ROOT_DN;
    }
    return new DN(rdn, parent, dnString);
  }
  @SuppressWarnings("serial")
  private static Map<String, DN> getCache(Schema schema)
  {
    final WeakHashMap<Schema, Map<String, DN>> threadLocalMap = CACHE
        .get();
    Map<String, DN> schemaLocalMap = threadLocalMap.get(schema);
    if (schemaLocalMap == null)
    {
      schemaLocalMap = new LinkedHashMap<String, DN>(DN_CACHE_SIZE,
          0.75f, true)
      {
        @Override
        protected boolean removeEldestEntry(Map.Entry<String, DN> e)
        {
          return size() > DN_CACHE_SIZE;
        }
      };
      threadLocalMap.put(schema, schemaLocalMap);
    }
    return schemaLocalMap;
  }
  private final RDN rdn;
  private final DN parent;
  private final int size;
  // We need to store the original string value if provided in order to
  // preserve the original whitespace.
  private String stringValue;
  private String normalizedStringValue = null;
  // Private constructor.
  private DN(RDN rdn, DN parent, String stringValue)
  {
    this.rdn = rdn;
    this.parent = parent;
    this.stringValue = stringValue;
    this.size = parent != null ? parent.size + 1 : 0;
  }
  /**
   * Returns a DN which is subordinate to this DN and having the
   * additional RDN components contained in the provided DN.
   *
   * @param dn
   *          The DN containing the RDN components to be added to this
   *          DN.
   * @return The subordinate DN.
   * @throws NullPointerException
   *           If {@code dn} was {@code null}.
   */
  public DN child(DN dn) throws NullPointerException
  {
    Validator.ensureNotNull(dn);
    if (dn.isRootDN())
    {
      return this;
    }
    else if (isRootDN())
    {
      return dn;
    }
    else
    {
      final RDN[] rdns = new RDN[dn.size()];
      int i = rdns.length;
      for (DN next = dn; next.rdn != null; next = next.parent)
      {
        rdns[--i] = next.rdn;
      }
      DN newDN = this;
      for (i = 0; i < rdns.length; i++)
      {
        newDN = new DN(rdns[i], newDN, null);
      }
      return newDN;
    }
  }
  /**
   * Returns a DN which is an immediate child of this DN and having the
   * specified RDN.
   *
   * @param rdn
   *          The RDN for the child DN.
   * @return The child DN.
   * @throws NullPointerException
   *           If {@code rdn} was {@code null}.
   */
  public DN child(RDN rdn) throws NullPointerException
  {
    Validator.ensureNotNull(rdn);
    return new DN(rdn, this, null);
  }
  /**
   * Returns a DN which is subordinate to this DN and having the
   * additional RDN components contained in the provided DN decoded
   * using the default schema.
   *
   * @param dn
   *          The DN containing the RDN components to be added to this
   *          DN.
   * @return The subordinate DN.
   * @throws LocalizedIllegalArgumentException
   *           If {@code dn} is not a valid LDAP string representation
   *           of a DN.
   * @throws NullPointerException
   *           If {@code dn} was {@code null}.
   */
  public DN child(String dn) throws LocalizedIllegalArgumentException,
      NullPointerException
  {
    Validator.ensureNotNull(dn);
    return child(valueOf(dn));
  }
  /**
   * {@inheritDoc}
   */
  public int compareTo(DN dn)
  {
    final String s1 = toNormalizedString();
    final String s2 = dn.toNormalizedString();
    return s1.compareTo(s2);
  }
  /**
   * {@inheritDoc}
   */
  public boolean equals(Object obj)
  {
    if (this == obj)
    {
      return true;
    }
    else if (obj instanceof DN)
    {
      final String s1 = toNormalizedString();
      final String s2 = ((DN) obj).toNormalizedString();
      return s1.equals(s2);
    }
    else
    {
      return false;
    }
  }
  /**
   * {@inheritDoc}
   */
  public int hashCode()
  {
    final String s = toNormalizedString();
    return s.hashCode();
  }
  /**
   * Returns {@code true} if this DN is an immediate child of the
   * provided DN.
   *
   * @param dn
   *          The potential parent DN.
   * @return {@code true} if this DN is the immediate child of the
   *         provided DN, otherwise {@code false}.
   * @throws NullPointerException
   *           If {@code dn} was {@code null}.
   */
  public boolean isChildOf(DN dn) throws NullPointerException
  {
    // If this is the Root DN then parent will be null but this is ok.
    return dn.equals(parent);
  }
  /**
   * Returns {@code true} if this DN is an immediate child of the
   * provided DN decoded using the default schema.
   *
   * @param dn
   *          The potential parent DN.
   * @return {@code true} if this DN is the immediate child of the
   *         provided DN, otherwise {@code false}.
   * @throws LocalizedIllegalArgumentException
   *           If {@code dn} is not a valid LDAP string representation
   *           of a DN.
   * @throws NullPointerException
   *           If {@code dn} was {@code null}.
   */
  public boolean isChildOf(String dn)
      throws LocalizedIllegalArgumentException, NullPointerException
  {
    // If this is the Root DN then parent will be null but this is ok.
    return isChildOf(valueOf(dn));
  }
  /**
   * Returns {@code true} if this DN is the immediate parent of the
   * provided DN.
   *
   * @param dn
   *          The potential child DN.
   * @return {@code true} if this DN is the immediate parent of the
   *         provided DN, otherwise {@code false}.
   * @throws NullPointerException
   *           If {@code dn} was {@code null}.
   */
  public boolean isParentOf(DN dn) throws NullPointerException
  {
    // If dn is the Root DN then parent will be null but this is ok.
    return equals(dn.parent);
  }
  /**
   * Returns {@code true} if this DN is the immediate parent of the
   * provided DN.
   *
   * @param dn
   *          The potential child DN.
   * @return {@code true} if this DN is the immediate parent of the
   *         provided DN, otherwise {@code false}.
   * @throws LocalizedIllegalArgumentException
   *           If {@code dn} is not a valid LDAP string representation
   *           of a DN.
   * @throws NullPointerException
   *           If {@code dn} was {@code null}.
   */
  public boolean isParentOf(String dn)
      throws LocalizedIllegalArgumentException, NullPointerException
  {
    // If dn is the Root DN then parent will be null but this is ok.
    return isParentOf(valueOf(dn));
  }
  /**
   * Returns {@code true} if this DN is the Root DN.
   *
   * @return {@code true} if this DN is the Root DN, otherwise {@code
   *         false}.
   */
  public boolean isRootDN()
  {
    return size == 0;
  }
  /**
   * Returns {@code true} if this DN is subordinate to or equal to the
   * provided DN.
   *
   * @param dn
   *          The potential child DN.
   * @return {@code true} if this DN is subordinate to or equal to the
   *         provided DN, otherwise {@code false}.
   * @throws NullPointerException
   *           If {@code dn} was {@code null}.
   */
  public boolean isSubordinateOrEqualTo(DN dn)
      throws NullPointerException
  {
    if (size < dn.size)
    {
      return false;
    }
    else if (size == dn.size)
    {
      return equals(dn);
    }
    else
    {
      // dn is a potential superior of this.
      return parent(dn.size - size).equals(dn);
    }
  }
  /**
   * Returns {@code true} if this DN is subordinate to or equal to the
   * provided DN.
   *
   * @param dn
   *          The potential child DN.
   * @return {@code true} if this DN is subordinate to or equal to the
   *         provided DN, otherwise {@code false}.
   * @throws LocalizedIllegalArgumentException
   *           If {@code dn} is not a valid LDAP string representation
   *           of a DN.
   * @throws NullPointerException
   *           If {@code dn} was {@code null}.
   */
  public boolean isSubordinateOrEqualTo(String dn)
      throws LocalizedIllegalArgumentException, NullPointerException
  {
    return isSubordinateOrEqualTo(valueOf(dn));
  }
  /**
   * Returns {@code true} if this DN is superior to or equal to the
   * provided DN.
   *
   * @param dn
   *          The potential child DN.
   * @return {@code true} if this DN is superior to or equal to the
   *         provided DN, otherwise {@code false}.
   * @throws NullPointerException
   *           If {@code dn} was {@code null}.
   */
  public boolean isSuperiorOrEqualTo(DN dn) throws NullPointerException
  {
    if (size > dn.size)
    {
      return false;
    }
    else if (size == dn.size)
    {
      return equals(dn);
    }
    else
    {
      // dn is a potential subordinate of this.
      return dn.parent(dn.size - size).equals(this);
    }
  }
  /**
   * Returns {@code true} if this DN is superior to or equal to the
   * provided DN.
   *
   * @param dn
   *          The potential child DN.
   * @return {@code true} if this DN is superior to or equal to the
   *         provided DN, otherwise {@code false}.
   * @throws LocalizedIllegalArgumentException
   *           If {@code dn} is not a valid LDAP string representation
   *           of a DN.
   * @throws NullPointerException
   *           If {@code dn} was {@code null}.
   */
  public boolean isSuperiorOrEqualTo(String dn)
      throws LocalizedIllegalArgumentException, NullPointerException
  {
    return isSuperiorOrEqualTo(valueOf(dn));
  }
  /**
   * Returns an iterator of the RDNs contained in this DN. The RDNs will
   * be returned in the order starting with this DN's RDN, followed by
   * the RDN of the parent DN, and so on.
   * <p>
   * Attempts to remove RDNs using an iterator's {@code remove()} method
   * are not permitted and will result in an {@code
   * UnsupportedOperationException} being thrown.
   *
   * @return An iterator of the RDNs contained in this DN.
   */
  public Iterator<RDN> iterator()
  {
    return new Iterator<RDN>()
    {
      private DN dn = DN.this;
      public boolean hasNext()
      {
        return dn.rdn != null;
      }
      public RDN next()
      {
        if (dn.rdn == null)
        {
          throw new NoSuchElementException();
        }
        final RDN rdn = dn.rdn;
        dn = dn.parent;
        return rdn;
      }
      public void remove()
      {
        throw new UnsupportedOperationException();
      }
    };
  }
  /**
   * Returns the DN which is the immediate parent of this DN, or {@code
   * null} if this DN is the Root DN.
   * <p>
   * This method is equivalent to:
   *
   * <pre>
   * parent(1);
   * </pre>
   *
   * @return The DN which is the immediate parent of this DN, or {@code
   *         null} if this DN is the Root DN.
   */
  public DN parent()
  {
    return parent;
  }
  /**
   * Returns the DN which is equal to this DN with the specified number
   * of RDNs removed. Note that if {@code index} is zero then this DN
   * will be returned (identity).
   *
   * @param index
   *          The number of RDNs to be removed.
   * @return The DN which is equal to this DN with the specified number
   *         of RDNs removed, or {@code null} if the parent of the Root
   *         DN is reached.
   * @throws IllegalArgumentException
   *           If {@code index} is less than zero.
   */
  public DN parent(int index) throws IllegalArgumentException
  {
    // We allow size + 1 so that we can return null as the parent of the
    // Root DN.
    Validator.ensureTrue(index >= 0, "index less than zero");
    DN parentDN = this;
    for (int i = 0; parentDN != null && i < index; i++)
    {
      parentDN = parentDN.parent;
    }
    return parentDN;
  }
  /**
   * Returns the RDN of this DN, or {@code null} if this DN is the Root
   * DN.
   *
   * @return The RDN of this DN, or {@code null} if this DN is the Root
   *         DN.
   */
  public RDN rdn()
  {
    return rdn;
  }
  /**
   * Returns the number of RDN components in this DN.
   *
   * @return The number of RDN components in this DN.
   */
  public int size()
  {
    return size();
  }
  /**
   * Returns the normalized string representation of this DN.
   *
   * @return The normalized string representation of this DN.
   */
  public String toNormalizedString()
  {
    if (normalizedStringValue == null)
    {
      final StringBuilder builder = new StringBuilder();
      if (!parent.isRootDN())
      {
        builder.append(parent.toNormalizedString());
        builder.append(',');
      }
      rdn.toNormalizedString(builder);
      normalizedStringValue = builder.toString();
    }
    return normalizedStringValue;
  }
  /**
   * Returns the RFC 4514 string representation of this DN.
   *
   * @return The RFC 4514 string representation of this DN.
   * @see <a href="http://tools.ietf.org/html/rfc4514">RFC 4514 -
   *      Lightweight Directory Access Protocol (LDAP): String
   *      Representation of Distinguished Names </a>
   */
  public String toString()
  {
    // We don't care about potential race conditions here.
    if (stringValue == null)
    {
      final StringBuilder builder = new StringBuilder();
      rdn.toString(builder);
      if (!parent.isRootDN())
      {
        builder.append(',');
        builder.append(parent.toString());
      }
      stringValue = builder.toString();
    }
    return stringValue;
  }
}
opendj-sdk/sdk/src/org/opends/sdk/DecodeException.java
New file
@@ -0,0 +1,154 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Copyright 2009 Sun Microsystems, Inc.
 */
package org.opends.sdk;
import java.io.IOException;
import org.opends.messages.Message;
import org.opends.sdk.util.LocalizableException;
/**
 * Thrown when data from an input source cannot be decoded, perhaps due
 * to the data being malformed in some way. By default decoding
 * exceptions are fatal, indicating that the associated input source is
 * no longer usable.
 */
@SuppressWarnings("serial")
public final class DecodeException extends IOException implements
    LocalizableException
{
  private final Message message;
  private final boolean isFatal;
  /**
   * Creates a new fatal decode exception with the provided message. The
   * associated input source can no longer be used.
   *
   * @param message
   *          The message that explains the problem that occurred.
   * @return The new fatal decode exception.
   */
  public static DecodeException fatalError(Message message)
  {
    return new DecodeException(message, true, null);
  }
  /**
   * Creates a new fatal decode exception with the provided message and
   * root cause. The associated input source can no longer be used.
   *
   * @param message
   *          The message that explains the problem that occurred.
   * @param cause
   *          The underlying cause of this exception.
   * @return The new fatal decode exception.
   */
  public static DecodeException fatalError(Message message,
      Throwable cause)
  {
    return new DecodeException(message, true, cause);
  }
  /**
   * Creates a new non-fatal decode exception with the provided message.
   *
   * @param message
   *          The message that explains the problem that occurred.
   * @return The new non-fatal decode exception.
   */
  public static DecodeException error(Message message)
  {
    return new DecodeException(message, false, null);
  }
  /**
   * Creates a new non-fatal decode exception with the provided message
   * and root cause.
   *
   * @param message
   *          The message that explains the problem that occurred.
   * @param cause
   *          The underlying cause of this exception.
   * @return The new non-fatal decode exception.
   */
  public static DecodeException error(Message message, Throwable cause)
  {
    return new DecodeException(message, false, cause);
  }
  // Construction is provided via factory methods.
  private DecodeException(Message message, boolean isFatal,
      Throwable cause)
  {
    super(message.toString(), cause);
    this.message = message;
    this.isFatal = isFatal;
  }
  /**
   * Returns the message that explains the problem that occurred.
   *
   * @return Message of the problem
   */
  public Message getMessageObject()
  {
    return message;
  }
  /**
   * Indicates whether or not the error was fatal and the associated
   * input source can no longer be used.
   *
   * @return {@code true} if the error was fatal and the associated
   *         input source can no longer be used, otherwise {@code false}
   *         .
   */
  public boolean isFatal()
  {
    return isFatal;
  }
}
opendj-sdk/sdk/src/org/opends/sdk/DereferenceAliasesPolicy.java
New file
@@ -0,0 +1,223 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Copyright 2009 Sun Microsystems, Inc.
 */
package org.opends.sdk;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
/**
 * A Search operation alias dereferencing policy as defined in RFC 4511
 * section 4.5.1.3 is used to indicate whether or not alias entries (as
 * defined in RFC 4512) are to be dereferenced during stages of a Search
 * operation. The act of dereferencing an alias includes recursively
 * dereferencing aliases that refer to aliases.
 *
 * @see <a href="http://tools.ietf.org/html/rfc4511#section-4.5.1.3">RFC
 *      4511 - Lightweight Directory Access Protocol (LDAP): The
 *      Protocol </a>
 * @see <a href="http://tools.ietf.org/html/rfc4512">RFC 4512 -
 *      Lightweight Directory Access Protocol (LDAP): Directory
 *      Information Models </a>
 */
public final class DereferenceAliasesPolicy
{
  private static final DereferenceAliasesPolicy[] ELEMENTS = new DereferenceAliasesPolicy[4];
  private static final List<DereferenceAliasesPolicy> IMMUTABLE_ELEMENTS = Collections
      .unmodifiableList(Arrays.asList(ELEMENTS));
  /**
   * Do not dereference aliases in searching or in locating the base
   * object of a Search operation.
   */
  public static final DereferenceAliasesPolicy NEVER = register(0,
      "never");
  /**
   * While searching subordinates of the base object, dereference any
   * alias within the scope of the Search operation. Dereferenced
   * objects become the vertices of further search scopes where the
   * Search operation is also applied. If the search scope is {@code
   * WHOLE_SUBTREE}, the Search continues in the subtree(s) of any
   * dereferenced object. If the search scope is {@code SINGLE_LEVEL},
   * the search is applied to any dereferenced objects and is not
   * applied to their subordinates.
   */
  public static final DereferenceAliasesPolicy IN_SEARCHING = register(
      1, "search");
  /**
   * Dereference aliases in locating the base object of a Search
   * operation, but not when searching subordinates of the base object.
   */
  public static final DereferenceAliasesPolicy FINDING_BASE = register(
      2, "find");
  /**
   * Dereference aliases both in searching and in locating the base
   * object of a Search operation.
   */
  public static final DereferenceAliasesPolicy ALWAYS = register(3,
      "always");
  /**
   * Returns the alias dereferencing policy having the specified integer
   * value as defined in RFC 4511 section 4.5.1.
   *
   * @param intValue
   *          The integer value of the alias dereferencing policy.
   * @return The dereference aliases policy, or {@code null} if there
   *         was no alias dereferencing policy associated with {@code
   *         intValue}.
   */
  public static DereferenceAliasesPolicy valueOf(int intValue)
  {
    if (intValue < 0 || intValue >= ELEMENTS.length)
    {
      return null;
    }
    return ELEMENTS[intValue];
  }
  /**
   * Returns an unmodifiable list containing the set of available alias
   * dereferencing policies indexed on their integer value as defined in
   * RFC 4511 section 4.5.1.
   *
   * @return An unmodifiable list containing the set of available alias
   *         dereferencing policies.
   */
  public static List<DereferenceAliasesPolicy> values()
  {
    return IMMUTABLE_ELEMENTS;
  }
  /**
   * Creates and registers a new alias dereferencing policy with the
   * application.
   *
   * @param intValue
   *          The integer value of the alias dereferencing policy as
   *          defined in RFC 4511 section 4.5.1.
   * @param name
   *          The name of the alias dereferencing policy.
   * @return The new alias dereferencing policy.
   */
  private static DereferenceAliasesPolicy register(int intValue,
      String name)
  {
    final DereferenceAliasesPolicy t = new DereferenceAliasesPolicy(
        intValue, name);
    ELEMENTS[intValue] = t;
    return t;
  }
  private final int intValue;
  private final String name;
  // Prevent direct instantiation.
  private DereferenceAliasesPolicy(int intValue, String name)
  {
    this.intValue = intValue;
    this.name = name;
  }
  /**
   * {@inheritDoc}
   */
  public boolean equals(Object obj)
  {
    if (this == obj)
    {
      return true;
    }
    else if (obj instanceof DereferenceAliasesPolicy)
    {
      return this.intValue == ((DereferenceAliasesPolicy) obj).intValue;
    }
    else
    {
      return false;
    }
  }
  /**
   * {@inheritDoc}
   */
  public int hashCode()
  {
    return intValue;
  }
  /**
   * Returns the integer value of this alias dereferencing policy as
   * defined in RFC 4511 section 4.5.1.
   *
   * @return The integer value of this alias dereferencing policy.
   */
  public int intValue()
  {
    return intValue;
  }
  /**
   * Returns the string representation of this alias dereferencing
   * policy.
   *
   * @return The string representation of this alias dereferencing
   *         policy.
   */
  public String toString()
  {
    return name;
  }
}
opendj-sdk/sdk/src/org/opends/sdk/Entry.java
New file
@@ -0,0 +1,603 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Copyright 2009 Sun Microsystems, Inc.
 */
package org.opends.sdk;
import java.util.Collection;
import org.opends.sdk.schema.ObjectClass;
import org.opends.sdk.util.ByteString;
import org.opends.sdk.util.LocalizedIllegalArgumentException;
/**
 * An entry, comprising of a distinguished name and zero or more
 * attributes.
 * <p>
 * Some methods require a schema in order to decode their parameters
 * (e.g. {@link #addAttribute(String, Object...)} and
 * {@link #setName(String)}). In these cases the default schema is used
 * unless an alternative schema is specified in the {@code Entry}
 * constructor. The default schema is not used for any other purpose. In
 * particular, an {@code Entry} will permit attributes to be added which
 * have been decoded using a different schema.
 * <p>
 * Full LDAP modify semantics are provided via the {@link #addAttribute}, {@link #removeAttribute}, and {@link #replaceAttribute} methods.
 * <p>
 * Implementations should specify any constraints or special behavior.
 * In particular, which methods are supported, and the order in which
 * attributes are returned using the {@link #getAttributes()} method.
 * <p>
 * TODO: can we return collections/lists instead of iterables?
 * <p>
 * TODO: containsAttributeValue(String, Object)
 */
public interface Entry
{
  /**
   * Adds all of the attribute values contained in {@code attribute} to
   * this entry, merging with any existing attribute values (optional
   * operation). If {@code attribute} is empty then this entry is left
   * unchanged.
   * <p>
   * <b>NOTE:</b> This method implements LDAP Modify add semantics.
   *
   * @param attribute
   *          The attribute values to be added to this entry, merging
   *          with any existing attribute values.
   * @param duplicateValues
   *          A collection into which duplicate values will be added, or
   *          {@code null} if duplicate values should not be saved.
   * @return {@code true} if this entry changed as a result of this
   *         call.
   * @throws UnsupportedOperationException
   *           If this entry does not permit attributes or their values
   *           to be added.
   * @throws NullPointerException
   *           If {@code attribute} was {@code null}.
   */
  boolean addAttribute(Attribute attribute,
      Collection<ByteString> duplicateValues)
      throws UnsupportedOperationException, NullPointerException;
  /**
   * Adds all of the attribute values contained in {@code attribute} to
   * this entry, merging with any existing attribute values (optional
   * operation). If {@code attribute} is empty then this entry is left
   * unchanged.
   * <p>
   * If {@code attribute} is an instance of {@code Attribute} then it
   * will be added to this entry as if {@link #addAttribute} was called.
   * <p>
   * If {@code attribute} is not an instance of {@code Attribute} then
   * its attribute description will be decoded using the schema
   * associated with this entry, and any attribute values which are not
   * instances of {@code ByteString} will be converted using the
   * {@link ByteString#valueOf(Object)} method.
   * <p>
   * <b>NOTE:</b> This method implements LDAP Modify add semantics.
   *
   * @param attribute
   *          The attribute values to be added to this entry merging
   *          with any existing attribute values.
   * @return {@code true} if this entry changed as a result of this
   *         call.
   * @throws UnsupportedOperationException
   *           If this entry does not permit attributes or their values
   *           to be added.
   * @throws NullPointerException
   *           If {@code attribute} was {@code null}.
   */
  boolean addAttribute(Attribute attribute)
      throws UnsupportedOperationException, NullPointerException;
  /**
   * Adds all of the attribute values contained in {@code values} to
   * this entry, merging with any existing attribute values (optional
   * operation). If {@code values} is {@code null} or empty then this
   * entry is left unchanged.
   * <p>
   * The attribute description will be decoded using the schema
   * associated with this entry.
   * <p>
   * Any attribute values which are not instances of {@code ByteString}
   * will be converted using the {@link ByteString#valueOf(Object)}
   * method.
   * <p>
   * <b>NOTE:</b> This method implements LDAP Modify add semantics.
   *
   * @param attributeDescription
   *          The name of the attribute whose values are to be added.
   * @param values
   *          The attribute values to be added to this entry, merging
   *          any existing attribute values.
   * @return This entry.
   * @throws LocalizedIllegalArgumentException
   *           If {@code attributeDescription} could not be decoded
   *           using the schema associated with this entry.
   * @throws UnsupportedOperationException
   *           If this entry does not permit attributes or their values
   *           to be added.
   * @throws NullPointerException
   *           If {@code attribute} was {@code null}.
   */
  Entry addAttribute(String attributeDescription, Object... values)
      throws LocalizedIllegalArgumentException,
      UnsupportedOperationException, NullPointerException;
  /**
   * Removes all the attributes from this entry (optional operation).
   *
   * @return This entry.
   * @throws UnsupportedOperationException
   *           If this entry does not permit attributes to be removed.
   */
  Entry clearAttributes() throws UnsupportedOperationException;
  /**
   * Indicates whether or not this entry contains the named attribute.
   *
   * @param attributeDescription
   *          The name of the attribute.
   * @return {@code true} if this entry contains the named attribute,
   *         otherwise {@code false}.
   * @throws NullPointerException
   *           If {@code attributeDescription} was {@code null}.
   */
  boolean containsAttribute(AttributeDescription attributeDescription)
      throws NullPointerException;
  /**
   * Indicates whether or not this entry contains the named attribute.
   * <p>
   * The attribute description will be decoded using the schema
   * associated with this entry.
   *
   * @param attributeDescription
   *          The name of the attribute.
   * @return {@code true} if this entry contains the named attribute,
   *         otherwise {@code false}.
   * @throws LocalizedIllegalArgumentException
   *           If {@code attributeDescription} could not be decoded
   *           using the schema associated with this entry.
   * @throws NullPointerException
   *           If {@code attributeDescription} was {@code null}.
   */
  boolean containsAttribute(String attributeDescription)
      throws LocalizedIllegalArgumentException, NullPointerException;
  /**
   * Indicates whether or not this entry contains the provided object
   * class.
   *
   * @param objectClass
   *          The object class.
   * @return {@code true} if this entry contains the object class,
   *         otherwise {@code false}.
   * @throws NullPointerException
   *           If {@code objectClass} was {@code null}.
   */
  boolean containsObjectClass(ObjectClass objectClass)
      throws NullPointerException;
  /**
   * Indicates whether or not this entry contains the named object
   * class.
   *
   * @param objectClass
   *          The name of the object class.
   * @return {@code true} if this entry contains the object class,
   *         otherwise {@code false}.
   * @throws NullPointerException
   *           If {@code objectClass} was {@code null}.
   */
  boolean containsObjectClass(String objectClass)
      throws NullPointerException;
  /**
   * Returns {@code true} if {@code object} is an entry which is equal
   * to this entry. Two entries are considered equal if their
   * distinguished names are equal, they both have the same number of
   * attributes, and every attribute contained in the first entry is
   * also contained in the second entry.
   *
   * @param object
   *          The object to be tested for equality with this entry.
   * @return {@code true} if {@code object} is an entry which is equal
   *         to this entry, or {@code false} if not.
   */
  boolean equals(Object object);
  /**
   * Returns an {@code Iterable} containing all the attributes in this
   * entry having an attribute description which is a sub-type of the
   * provided attribute description. The returned {@code Iterable} may
   * be used to remove attributes if permitted by this entry.
   *
   * @param attributeDescription
   *          The name of the attributes to be returned.
   * @return An {@code Iterable} containing the matching attributes.
   * @throws NullPointerException
   *           If {@code attributeDescription} was {@code null}.
   */
  Iterable<Attribute> findAttributes(
      AttributeDescription attributeDescription)
      throws NullPointerException;
  /**
   * Returns an {@code Iterable} containing all the attributes in this
   * entry having an attribute description which is a sub-type of the
   * provided attribute description. The returned {@code Iterable} may
   * be used to remove attributes if permitted by this entry.
   * <p>
   * The attribute description will be decoded using the schema
   * associated with this entry.
   *
   * @param attributeDescription
   *          The name of the attributes to be returned.
   * @return An {@code Iterable} containing the matching attributes.
   * @throws LocalizedIllegalArgumentException
   *           If {@code attributeDescription} could not be decoded
   *           using the schema associated with this entry.
   * @throws NullPointerException
   *           If {@code attributeDescription} was {@code null}.
   */
  Iterable<Attribute> findAttributes(String attributeDescription)
      throws LocalizedIllegalArgumentException, NullPointerException;
  /**
   * Returns the named attribute contained in this entry, or {@code
   * null} if it is not included with this entry.
   *
   * @param attributeDescription
   *          The name of the attribute to be returned.
   * @return The named attribute, or {@code null} if it is not included
   *         with this entry.
   * @throws NullPointerException
   *           If {@code attributeDescription} was {@code null}.
   */
  Attribute getAttribute(AttributeDescription attributeDescription)
      throws NullPointerException;
  /**
   * Returns the named attribute contained in this entry, or {@code
   * null} if it is not included with this entry.
   * <p>
   * The attribute description will be decoded using the schema
   * associated with this entry.
   *
   * @param attributeDescription
   *          The name of the attribute to be returned.
   * @return The named attribute, or {@code null} if it is not included
   *         with this entry.
   * @throws LocalizedIllegalArgumentException
   *           If {@code attributeDescription} could not be decoded
   *           using the schema associated with this entry.
   * @throws NullPointerException
   *           If {@code attributeDescription} was {@code null}.
   */
  Attribute getAttribute(String attributeDescription)
      throws LocalizedIllegalArgumentException, NullPointerException;
  /**
   * Returns the number of attributes in this entry.
   *
   * @return The number of attributes.
   */
  int getAttributeCount();
  /**
   * Returns an {@code Iterable} containing the attributes in this
   * entry. The returned {@code Iterable} may be used to remove
   * attributes if permitted by this entry.
   *
   * @return An {@code Iterable} containing the attributes.
   */
  Iterable<Attribute> getAttributes();
  /**
   * Returns the string representation of the distinguished name of this
   * entry.
   *
   * @return The string representation of the distinguished name.
   */
  DN getName();
  /**
   * Returns an {@code Iterable} containing the names of the object
   * classes in this entry. The returned {@code Iterable} may be used to
   * remove object classes if permitted by this entry.
   *
   * @return An {@code Iterable} containing the object classes.
   */
  Iterable<String> getObjectClasses();
  /**
   * Returns the hash code for this entry. It will be calculated as the
   * sum of the hash codes of the distinguished name and all of the
   * attributes.
   *
   * @return The hash code for this entry.
   */
  int hashCode();
  /**
   * Removes all of the attribute values contained in {@code attribute}
   * from this entry if it is present (optional operation). If {@code
   * attribute} is empty then the entire attribute will be removed if it
   * is present.
   * <p>
   * <b>NOTE:</b> This method implements LDAP Modify delete semantics.
   *
   * @param attribute
   *          The attribute values to be removed from this entry, which
   *          may be empty if the entire attribute is to be removed.
   * @param missingValues
   *          A collection into which missing values will be added, or
   *          {@code null} if missing values should not be saved.
   * @return {@code true} if this entry changed as a result of this
   *         call.
   * @throws UnsupportedOperationException
   *           If this entry does not permit attributes or their values
   *           to be removed.
   * @throws NullPointerException
   *           If {@code attribute} was {@code null}.
   */
  boolean removeAttribute(Attribute attribute,
      Collection<ByteString> missingValues)
      throws UnsupportedOperationException, NullPointerException;
  /**
   * Removes the named attribute from this entry if it is present
   * (optional operation). If this attribute does not contain the
   * attribute, the call leaves this entry unchanged and returns {@code
   * false}.
   *
   * @param attributeDescription
   *          The name of the attribute to be removed.
   * @return {@code true} if this entry changed as a result of this
   *         call.
   * @throws UnsupportedOperationException
   *           If this entry does not permit attributes to be removed.
   * @throws NullPointerException
   *           If {@code attributeDescription} was {@code null}.
   */
  boolean removeAttribute(AttributeDescription attributeDescription)
      throws UnsupportedOperationException, NullPointerException;
  /**
   * Removes the named attribute from this entry if it is present
   * (optional operation). If this attribute does not contain the
   * attribute, the call leaves this entry unchanged.
   * <p>
   * The attribute description will be decoded using the schema
   * associated with this entry.
   *
   * @param attributeDescription
   *          The name of the attribute to be removed.
   * @return This entry.
   * @throws LocalizedIllegalArgumentException
   *           If {@code attributeDescription} could not be decoded
   *           using the schema associated with this entry.
   * @throws UnsupportedOperationException
   *           If this entry does not permit attributes to be removed.
   * @throws NullPointerException
   *           If {@code attributeDescription} was {@code null}.
   */
  Entry removeAttribute(String attributeDescription)
      throws LocalizedIllegalArgumentException,
      UnsupportedOperationException, NullPointerException;
  /**
   * Removes all of the attribute values contained in {@code values}
   * from the named attribute in this entry if it is present (optional
   * operation). If {@code values} is {@code null} or empty then the
   * entire attribute will be removed if it is present.
   * <p>
   * The attribute description will be decoded using the schema
   * associated with this entry.
   * <p>
   * Any attribute values which are not instances of {@code ByteString}
   * will be converted using the {@link ByteString#valueOf(Object)}
   * method.
   * <p>
   * <b>NOTE:</b> This method implements LDAP Modify delete semantics.
   *
   * @param attributeDescription
   *          The name of the attribute whose values are to be removed.
   * @param values
   *          The attribute values to be removed from this entry, which
   *          may be {@code null} or empty if the entire attribute is to
   *          be removed.
   * @return This entry.
   * @throws LocalizedIllegalArgumentException
   *           If {@code attributeDescription} could not be decoded
   *           using the schema associated with this entry.
   * @throws UnsupportedOperationException
   *           If this entry does not permit attributes or their values
   *           to be removed.
   * @throws NullPointerException
   *           If {@code attributeDescription} was {@code null}.
   */
  Entry removeAttribute(String attributeDescription, Object... values)
      throws LocalizedIllegalArgumentException,
      UnsupportedOperationException, NullPointerException;
  /**
   * Adds all of the attribute values contained in {@code attribute} to
   * this entry, replacing any existing attribute values (optional
   * operation). If {@code attribute} is empty then the entire attribute
   * will be removed if it is present.
   * <p>
   * <b>NOTE:</b> This method implements LDAP Modify replace semantics.
   *
   * @param attribute
   *          The attribute values to be added to this entry, replacing
   *          any existing attribute values, and which may be empty if
   *          the entire attribute is to be removed.
   * @return {@code true} if this entry changed as a result of this
   *         call.
   * @throws UnsupportedOperationException
   *           If this entry does not permit attributes or their values
   *           to be replaced.
   * @throws NullPointerException
   *           If {@code attribute} was {@code null}.
   */
  boolean replaceAttribute(Attribute attribute)
      throws UnsupportedOperationException, NullPointerException;
  /**
   * Adds all of the attribute values contained in {@code values} to
   * this entry, replacing any existing attribute values (optional
   * operation). If {@code values} is {@code null} or empty then the
   * entire attribute will be removed if it is present.
   * <p>
   * The attribute description will be decoded using the schema
   * associated with this entry.
   * <p>
   * Any attribute values which are not instances of {@code ByteString}
   * will be converted using the {@link ByteString#valueOf(Object)}
   * method.
   * <p>
   * <b>NOTE:</b> This method implements LDAP Modify replace semantics.
   *
   * @param attributeDescription
   *          The name of the attribute whose values are to be replaced.
   * @param values
   *          The attribute values to be added to this entry, replacing
   *          any existing attribute values, and which may be {@code
   *          null} or empty if the entire attribute is to be removed.
   * @return This entry.
   * @throws LocalizedIllegalArgumentException
   *           If {@code attributeDescription} could not be decoded
   *           using the schema associated with this entry.
   * @throws UnsupportedOperationException
   *           If this entry does not permit attributes or their values
   *           to be replaced.
   * @throws NullPointerException
   *           If {@code attribute} was {@code null}.
   */
  Entry replaceAttribute(String attributeDescription, Object... values)
      throws LocalizedIllegalArgumentException,
      UnsupportedOperationException, NullPointerException;
  /**
   * Sets the distinguished name of this entry (optional operation).
   *
   * @param dn
   *          The string representation of the distinguished name.
   * @return This entry.
   * @throws LocalizedIllegalArgumentException
   *           If {@code dn} could not be decoded using the schema
   *           associated with this entry.
   * @throws UnsupportedOperationException
   *           If this entry does not permit the distinguished name to
   *           be set.
   * @throws NullPointerException
   *           If {@code dn} was {@code null}.
   */
  Entry setName(String dn) throws LocalizedIllegalArgumentException,
      UnsupportedOperationException, NullPointerException;
  /**
   * Sets the distinguished name of this entry (optional operation).
   *
   * @param dn
   *          The distinguished name.
   * @return This entry.
   * @throws UnsupportedOperationException
   *           If this entry does not permit the distinguished name to
   *           be set.
   * @throws NullPointerException
   *           If {@code dn} was {@code null}.
   */
  Entry setName(DN dn) throws UnsupportedOperationException,
      NullPointerException;
  /**
   * Returns a string representation of this entry.
   *
   * @return The string representation of this entry.
   */
  String toString();
}
opendj-sdk/sdk/src/org/opends/sdk/ErrorResultException.java
New file
@@ -0,0 +1,103 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Copyright 2009 Sun Microsystems, Inc.
 */
package org.opends.sdk;
import java.util.concurrent.ExecutionException;
import org.opends.sdk.responses.Result;
/**
 * Thrown when the result code returned in a Result indicates that the
 * Request was unsuccessful.
 */
@SuppressWarnings("serial")
public class ErrorResultException extends ExecutionException
{
  private final Result result;
  /**
   * Wraps the provided result in an appropriate error result exception.
   * The type of error result exception used depends on the underlying
   * result code.
   *
   * @param result
   *          The result whose result code indicates a failure.
   * @return The error result exception wrapping the provided result.
   * @throws IllegalArgumentException
   *           If the provided result does not represent a failure.
   * @throws NullPointerException
   *           If {@code result} was {@code null}.
   */
  public static ErrorResultException wrap(Result result)
      throws IllegalArgumentException, NullPointerException
  {
    if (!result.getResultCode().isExceptional())
    {
      throw new IllegalArgumentException(
          "Attempted to wrap a successful result: " + result);
    }
    // TODO: choose type of exception based on result code (e.g.
    // referral).
    return new ErrorResultException(result);
  }
  /**
   * Creates a new error result exception using the provided result.
   *
   * @param result
   *          The error result.
   */
  ErrorResultException(Result result)
  {
    super(result.getResultCode() + ": " + result.getDiagnosticMessage());
    this.result = result;
  }
  /**
   * Returns the error result which caused this exception to be thrown.
   * The type of result returned corresponds to the expected result type
   * of the original request.
   *
   * @return The error result which caused this exception to be thrown.
   */
  public Result getResult()
  {
    return result;
  }
}
opendj-sdk/sdk/src/org/opends/sdk/ErrorResultIOException.java
New file
@@ -0,0 +1,75 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Copyright 2009 Sun Microsystems, Inc.
 */
package org.opends.sdk;
import java.io.IOException;
import org.opends.sdk.util.Validator;
/**
 * An {@code ErrorResultIOException} adapts an {@code
 * ErrorResultException} to an {@code IOException}.
 */
@SuppressWarnings("serial")
public final class ErrorResultIOException extends IOException
{
  private final ErrorResultException cause;
  /**
   * Creates a new error result IO exception with the provided cause.
   *
   * @param cause
   *          The cause which may be later retrieved by the
   *          {@link #getCause} method.
   * @throws NullPointerException
   *           If {@code cause} was {@code null}.
   */
  public ErrorResultIOException(ErrorResultException cause)
      throws NullPointerException
  {
    super(Validator.ensureNotNull(cause));
    this.cause = cause;
  }
  /**
   * {@inheritDoc}
   */
  public ErrorResultException getCause()
  {
    return cause;
  }
}
opendj-sdk/sdk/src/org/opends/sdk/Filter.java
New file
@@ -0,0 +1,1978 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Copyright 2009 Sun Microsystems, Inc.
 */
package org.opends.sdk;
import static org.opends.messages.ProtocolMessages.*;
import static org.opends.sdk.util.StaticUtils.byteToHex;
import static org.opends.sdk.util.StaticUtils.getBytes;
import static org.opends.sdk.util.StaticUtils.toLowerCase;
import java.util.*;
import org.opends.messages.Message;
import org.opends.sdk.schema.Schema;
import org.opends.sdk.util.*;
/**
 * A search filter as defined in RFC 4511. In addition this class also
 * provides support for the absolute true and absolute false filters as
 * defined in RFC 4526.
 * <p>
 * This class provides many factory methods for creating common types of
 * filter. Applications interact with a filter using
 * {@link FilterVisitor} which is applied to a filter using the
 * {@link #accept(FilterVisitor, Object)} method.
 * <p>
 * The RFC 4515 string representation of a filter can be generated using
 * the {@link #toString} methods and parsed using the
 * {@link #valueOf(String)} factory method.
 *
 * @see <a href="http://tools.ietf.org/html/rfc4511">RFC 4511 -
 *      Lightweight Directory Access Protocol (LDAP): The Protocol </a>
 * @see <a href="http://tools.ietf.org/html/rfc4515">RFC 4515 - String
 *      Representation of Search Filters </a>
 * @see <a href="http://tools.ietf.org/html/rfc4526">RFC 4526 - Absolute
 *      True and False Filters </a>
 */
public final class Filter
{
  private static final class AndImpl extends Impl
  {
    private final List<Filter> subFilters;
    public AndImpl(List<Filter> subFilters)
    {
      this.subFilters = subFilters;
    }
    @Override
    public <R, P> R accept(FilterVisitor<R, P> v, P p)
    {
      return v.visitAndFilter(p, subFilters);
    }
  }
  private static final class ApproxMatchImpl extends Impl
  {
    private final ByteSequence assertionValue;
    private final String attributeDescription;
    public ApproxMatchImpl(String attributeDescription,
        ByteSequence assertionValue)
    {
      this.attributeDescription = attributeDescription;
      this.assertionValue = assertionValue;
    }
    @Override
    public <R, P> R accept(FilterVisitor<R, P> v, P p)
    {
      return v.visitApproxMatchFilter(p, attributeDescription,
          assertionValue);
    }
  }
  private static final class EqualityMatchImpl extends Impl
  {
    private final ByteSequence assertionValue;
    private final String attributeDescription;
    public EqualityMatchImpl(String attributeDescription,
        ByteSequence assertionValue)
    {
      this.attributeDescription = attributeDescription;
      this.assertionValue = assertionValue;
    }
    @Override
    public <R, P> R accept(FilterVisitor<R, P> v, P p)
    {
      return v.visitEqualityMatchFilter(p, attributeDescription,
          assertionValue);
    }
  }
  private static final class ExtensibleMatchImpl extends Impl
  {
    private final String attributeDescription;
    private final boolean dnAttributes;
    private final String matchingRule;
    private final ByteSequence matchValue;
    public ExtensibleMatchImpl(String matchingRule,
        String attributeDescription, ByteSequence matchValue,
        boolean dnAttributes)
    {
      this.matchingRule = matchingRule;
      this.attributeDescription = attributeDescription;
      this.matchValue = matchValue;
      this.dnAttributes = dnAttributes;
    }
    @Override
    public <R, P> R accept(FilterVisitor<R, P> v, P p)
    {
      return v.visitExtensibleMatchFilter(p, matchingRule,
          attributeDescription, matchValue, dnAttributes);
    }
  }
  private static final class GreaterOrEqualImpl extends Impl
  {
    private final ByteSequence assertionValue;
    private final String attributeDescription;
    public GreaterOrEqualImpl(String attributeDescription,
        ByteSequence assertionValue)
    {
      this.attributeDescription = attributeDescription;
      this.assertionValue = assertionValue;
    }
    @Override
    public <R, P> R accept(FilterVisitor<R, P> v, P p)
    {
      return v.visitGreaterOrEqualFilter(p, attributeDescription,
          assertionValue);
    }
  }
  private static abstract class Impl
  {
    protected Impl()
    {
      // Nothing to do.
    }
    public abstract <R, P> R accept(FilterVisitor<R, P> v, P p);
  }
  private static final class LessOrEqualImpl extends Impl
  {
    private final ByteSequence assertionValue;
    private final String attributeDescription;
    public LessOrEqualImpl(String attributeDescription,
        ByteSequence assertionValue)
    {
      this.attributeDescription = attributeDescription;
      this.assertionValue = assertionValue;
    }
    @Override
    public <R, P> R accept(FilterVisitor<R, P> v, P p)
    {
      return v.visitLessOrEqualFilter(p, attributeDescription,
          assertionValue);
    }
  }
  private static final class NotImpl extends Impl
  {
    private final Filter subFilter;
    public NotImpl(Filter subFilter)
    {
      this.subFilter = subFilter;
    }
    @Override
    public <R, P> R accept(FilterVisitor<R, P> v, P p)
    {
      return v.visitNotFilter(p, subFilter);
    }
  }
  private static final class OrImpl extends Impl
  {
    private final List<Filter> subFilters;
    public OrImpl(List<Filter> subFilters)
    {
      this.subFilters = subFilters;
    }
    @Override
    public <R, P> R accept(FilterVisitor<R, P> v, P p)
    {
      return v.visitOrFilter(p, subFilters);
    }
  }
  private static final class PresentImpl extends Impl
  {
    private final String attributeDescription;
    public PresentImpl(String attributeDescription)
    {
      this.attributeDescription = attributeDescription;
    }
    @Override
    public <R, P> R accept(FilterVisitor<R, P> v, P p)
    {
      return v.visitPresentFilter(p, attributeDescription);
    }
  }
  private static final class SubstringsImpl extends Impl
  {
    private final List<ByteSequence> anyStrings;
    private final String attributeDescription;
    private final ByteSequence finalString;
    private final ByteSequence initialString;
    public SubstringsImpl(String attributeDescription,
        ByteSequence initialString, List<ByteSequence> anyStrings,
        ByteSequence finalString)
    {
      this.attributeDescription = attributeDescription;
      this.initialString = initialString;
      this.anyStrings = anyStrings;
      this.finalString = finalString;
    }
    @Override
    public <R, P> R accept(FilterVisitor<R, P> v, P p)
    {
      return v.visitSubstringsFilter(p, attributeDescription,
          initialString, anyStrings, finalString);
    }
  }
  private static final class UnrecognizedImpl extends Impl
  {
    private final ByteSequence filterBytes;
    private final byte filterTag;
    public UnrecognizedImpl(byte filterTag, ByteSequence filterBytes)
    {
      this.filterTag = filterTag;
      this.filterBytes = filterBytes;
    }
    @Override
    public <R, P> R accept(FilterVisitor<R, P> v, P p)
    {
      return v.visitUnrecognizedFilter(p, filterTag, filterBytes);
    }
  }
  // RFC 4526 - FALSE filter.
  private static final Filter FALSE = new Filter(new OrImpl(Collections
      .<Filter> emptyList()));
  // Heavily used (objectClass=*) filter.
  private static final Filter OBJECT_CLASS_PRESENT = new Filter(
      new PresentImpl("objectClass"));
  private static final FilterVisitor<StringBuilder, StringBuilder> TO_STRING_VISITOR = new FilterVisitor<StringBuilder, StringBuilder>()
  {
    public StringBuilder visitAndFilter(StringBuilder builder,
        List<Filter> subFilters)
    {
      builder.append("(&");
      for (Filter subFilter : subFilters)
      {
        subFilter.accept(this, builder);
      }
      builder.append(')');
      return builder;
    }
    public StringBuilder visitApproxMatchFilter(StringBuilder builder,
        String attributeDescription, ByteSequence assertionValue)
    {
      builder.append('(');
      builder.append(attributeDescription);
      builder.append("~=");
      valueToFilterString(builder, assertionValue);
      builder.append(')');
      return builder;
    }
    public StringBuilder visitEqualityMatchFilter(
        StringBuilder builder, String attributeDescription,
        ByteSequence assertionValue)
    {
      builder.append('(');
      builder.append(attributeDescription);
      builder.append("=");
      valueToFilterString(builder, assertionValue);
      builder.append(')');
      return builder;
    }
    public StringBuilder visitExtensibleMatchFilter(
        StringBuilder builder, String matchingRule,
        String attributeDescription, ByteSequence assertionValue,
        boolean dnAttributes)
    {
      builder.append('(');
      if (attributeDescription != null)
      {
        builder.append(attributeDescription);
      }
      if (dnAttributes)
      {
        builder.append(":dn");
      }
      if (matchingRule != null)
      {
        builder.append(':');
        builder.append(matchingRule);
      }
      builder.append(":=");
      valueToFilterString(builder, assertionValue);
      builder.append(')');
      return builder;
    }
    public StringBuilder visitGreaterOrEqualFilter(
        StringBuilder builder, String attributeDescription,
        ByteSequence assertionValue)
    {
      builder.append('(');
      builder.append(attributeDescription);
      builder.append(">=");
      valueToFilterString(builder, assertionValue);
      builder.append(')');
      return builder;
    }
    public StringBuilder visitLessOrEqualFilter(StringBuilder builder,
        String attributeDescription, ByteSequence assertionValue)
    {
      builder.append('(');
      builder.append(attributeDescription);
      builder.append("<=");
      valueToFilterString(builder, assertionValue);
      builder.append(')');
      return builder;
    }
    public StringBuilder visitNotFilter(StringBuilder builder,
        Filter subFilter)
    {
      builder.append("(|");
      subFilter.accept(this, builder);
      builder.append(')');
      return builder;
    }
    public StringBuilder visitOrFilter(StringBuilder builder,
        List<Filter> subFilters)
    {
      builder.append("(|");
      for (Filter subFilter : subFilters)
      {
        subFilter.accept(this, builder);
      }
      builder.append(')');
      return builder;
    }
    public StringBuilder visitPresentFilter(StringBuilder builder,
        String attributeDescription)
    {
      builder.append('(');
      builder.append(attributeDescription);
      builder.append("=*)");
      return builder;
    }
    public StringBuilder visitSubstringsFilter(StringBuilder builder,
        String attributeDescription, ByteSequence initialSubstring,
        List<ByteSequence> anySubstrings, ByteSequence finalSubstring)
    {
      builder.append('(');
      builder.append(attributeDescription);
      builder.append("=");
      if (initialSubstring != null)
      {
        valueToFilterString(builder, initialSubstring);
      }
      for (ByteSequence anySubstring : anySubstrings)
      {
        builder.append('*');
        valueToFilterString(builder, anySubstring);
      }
      builder.append('*');
      if (finalSubstring != null)
      {
        valueToFilterString(builder, finalSubstring);
      }
      builder.append(')');
      return builder;
    }
    public StringBuilder visitUnrecognizedFilter(StringBuilder builder,
        byte filterTag, ByteSequence filterBytes)
    {
      // Fake up a representation.
      builder.append('(');
      builder.append(byteToHex(filterTag));
      builder.append(':');
      StaticUtils.toHex(filterBytes, builder);
      builder.append(')');
      return builder;
    }
  };
  // RFC 4526 - TRUE filter.
  private static final Filter TRUE = new Filter(new AndImpl(Collections
      .<Filter> emptyList()));
  /**
   * Returns the {@code absolute false} filter as defined in RFC 4526
   * which is comprised of an {@code or} filter containing zero
   * components.
   *
   * @return The absolute false filter.
   * @see <a href="http://tools.ietf.org/html/rfc4526">RFC 4526</a>
   */
  public static Filter getAbsoluteFalseFilter()
  {
    return FALSE;
  }
  /**
   * Returns the {@code absolute true} filter as defined in RFC 4526
   * which is comprised of an {@code and} filter containing zero
   * components.
   *
   * @return The absolute true filter.
   * @see <a href="http://tools.ietf.org/html/rfc4526">RFC 4526</a>
   */
  public static Filter getAbsoluteTrueFilter()
  {
    return TRUE;
  }
  /**
   * Returns the {@code objectClass} presence filter {@code
   * (objectClass=*)}.
   * <p>
   * A call to this method is equivalent to but more efficient than the
   * following code:
   *
   * <pre>
   * Filter.present(&quot;objectClass&quot;);
   * </pre>
   *
   * @return The {@code objectClass} presence filter {@code
   *         (objectClass=*)}.
   */
  public static Filter getObjectClassPresentFilter()
  {
    return OBJECT_CLASS_PRESENT;
  }
  /**
   * Creates a new {@code and} filter using the provided list of
   * sub-filters.
   * <p>
   * Creating a new {@code and} filter with a {@code null} or empty list
   * of sub-filters is equivalent to calling
   * {@link #getAbsoluteTrueFilter()}.
   *
   * @param subFilters
   *          The list of sub-filters, may be empty or {@code null}.
   * @return The newly created {@code and} filter.
   */
  public static Filter newAndFilter(Collection<Filter> subFilters)
  {
    if (subFilters == null || subFilters.isEmpty())
    {
      // RFC 4526 - TRUE filter.
      return getAbsoluteTrueFilter();
    }
    else if (subFilters.size() == 1)
    {
      Filter subFilter = subFilters.iterator().next();
      Validator.ensureNotNull(subFilter);
      return new Filter(new AndImpl(Collections
          .singletonList(subFilter)));
    }
    else
    {
      List<Filter> subFiltersList = new ArrayList<Filter>(subFilters
          .size());
      for (Filter subFilter : subFilters)
      {
        Validator.ensureNotNull(subFilter);
        subFiltersList.add(subFilter);
      }
      return new Filter(new AndImpl(Collections
          .unmodifiableList(subFiltersList)));
    }
  }
  /**
   * Creates a new {@code and} filter using the provided list of
   * sub-filters.
   * <p>
   * Creating a new {@code and} filter with a {@code null} or empty list
   * of sub-filters is equivalent to calling
   * {@link #getAbsoluteTrueFilter()}.
   *
   * @param subFilters
   *          The list of sub-filters, may be empty or {@code null}.
   * @return The newly created {@code and} filter.
   */
  public static Filter newAndFilter(Filter... subFilters)
  {
    if ((subFilters == null) || (subFilters.length == 0))
    {
      // RFC 4526 - TRUE filter.
      return getAbsoluteTrueFilter();
    }
    else if (subFilters.length == 1)
    {
      Validator.ensureNotNull(subFilters[0]);
      return new Filter(new AndImpl(Collections
          .singletonList(subFilters[0])));
    }
    else
    {
      List<Filter> subFiltersList = new ArrayList<Filter>(
          subFilters.length);
      for (Filter subFilter : subFilters)
      {
        Validator.ensureNotNull(subFilter);
        subFiltersList.add(subFilter);
      }
      return new Filter(new AndImpl(Collections
          .unmodifiableList(subFiltersList)));
    }
  }
  /**
   * Creates a new {@code approximate match} filter using the provided
   * attribute description and assertion value.
   *
   * @param attributeDescription
   *          The attribute description.
   * @param assertionValue
   *          The assertion value.
   * @return The newly created {@code approximate match} filter.
   */
  public static Filter newApproxMatchFilter(
      String attributeDescription, ByteSequence assertionValue)
  {
    Validator.ensureNotNull(attributeDescription);
    Validator.ensureNotNull(assertionValue);
    return new Filter(new ApproxMatchImpl(attributeDescription,
        assertionValue));
  }
  /**
   * Creates a new {@code equality match} filter using the provided
   * attribute description and assertion value.
   *
   * @param attributeDescription
   *          The attribute description.
   * @param assertionValue
   *          The assertion value.
   * @return The newly created {@code equality match} filter.
   */
  public static Filter newEqualityMatchFilter(
      String attributeDescription, ByteSequence assertionValue)
  {
    Validator.ensureNotNull(attributeDescription);
    Validator.ensureNotNull(assertionValue);
    return new Filter(new EqualityMatchImpl(attributeDescription,
        assertionValue));
  }
  /**
   * Creates a new {@code extensible match} filter.
   *
   * @param matchingRule
   *          The matching rule name, may be {@code null} if {@code
   *          attributeDescription} is specified.
   * @param attributeDescription
   *          The attribute description, may be {@code null} if {@code
   *          matchingRule} is specified.
   * @param assertionValue
   *          The assertion value.
   * @param dnAttributes
   *          Indicates whether DN matching should be performed.
   * @return The newly created {@code extensible match} filter.
   */
  public static Filter newExtensibleMatchFilter(String matchingRule,
      String attributeDescription, ByteSequence assertionValue,
      boolean dnAttributes)
  {
    Validator.ensureTrue((matchingRule != null)
        || (attributeDescription != null), "matchingRule and/or "
        + "attributeDescription must not be null");
    Validator.ensureNotNull(assertionValue);
    return new Filter(new ExtensibleMatchImpl(matchingRule,
        attributeDescription, assertionValue, dnAttributes));
  }
  /**
   * Creates a new {@code greater or equal} filter using the provided
   * attribute description and assertion value.
   *
   * @param attributeDescription
   *          The attribute description.
   * @param assertionValue
   *          The assertion value.
   * @return The newly created {@code greater or equal} filter.
   */
  public static Filter newGreaterOrEqualFilter(
      String attributeDescription, ByteSequence assertionValue)
  {
    Validator.ensureNotNull(attributeDescription);
    Validator.ensureNotNull(assertionValue);
    return new Filter(new GreaterOrEqualImpl(attributeDescription,
        assertionValue));
  }
  /**
   * Creates a new {@code less or equal} filter using the provided
   * attribute description and assertion value.
   *
   * @param attributeDescription
   *          The attribute description.
   * @param assertionValue
   *          The assertion value.
   * @return The newly created {@code less or equal} filter.
   */
  public static Filter newLessOrEqualFilter(
      String attributeDescription, ByteSequence assertionValue)
  {
    Validator.ensureNotNull(attributeDescription);
    Validator.ensureNotNull(assertionValue);
    return new Filter(new LessOrEqualImpl(attributeDescription,
        assertionValue));
  }
  /**
   * Creates a new {@code not} filter using the provided sub-filter.
   *
   * @param subFilter
   *          The sub-filter.
   * @return The newly created {@code not} filter.
   */
  public static Filter newNotFilter(Filter subFilter)
  {
    Validator.ensureNotNull(subFilter);
    return new Filter(new NotImpl(subFilter));
  }
  /**
   * Creates a new {@code or} filter using the provided list of
   * sub-filters.
   * <p>
   * Creating a new {@code or} filter with a {@code null} or empty list
   * of sub-filters is equivalent to calling
   * {@link #getAbsoluteFalseFilter()}.
   *
   * @param subFilters
   *          The list of sub-filters, may be empty or {@code null}.
   * @return The newly created {@code or} filter.
   */
  public static Filter newOrFilter(Collection<Filter> subFilters)
  {
    if (subFilters == null || subFilters.isEmpty())
    {
      // RFC 4526 - FALSE filter.
      return getAbsoluteFalseFilter();
    }
    else if (subFilters.size() == 1)
    {
      Filter subFilter = subFilters.iterator().next();
      Validator.ensureNotNull(subFilter);
      return new Filter(
          new OrImpl(Collections.singletonList(subFilter)));
    }
    else
    {
      List<Filter> subFiltersList = new ArrayList<Filter>(subFilters
          .size());
      for (Filter subFilter : subFilters)
      {
        Validator.ensureNotNull(subFilter);
        subFiltersList.add(subFilter);
      }
      return new Filter(new OrImpl(Collections
          .unmodifiableList(subFiltersList)));
    }
  }
  /**
   * Creates a new {@code or} filter using the provided list of
   * sub-filters.
   * <p>
   * Creating a new {@code or} filter with a {@code null} or empty list
   * of sub-filters is equivalent to calling
   * {@link #getAbsoluteFalseFilter()}.
   *
   * @param subFilters
   *          The list of sub-filters, may be empty or {@code null}.
   * @return The newly created {@code or} filter.
   */
  public static Filter newOrFilter(Filter... subFilters)
  {
    if ((subFilters == null) || (subFilters.length == 0))
    {
      // RFC 4526 - FALSE filter.
      return getAbsoluteFalseFilter();
    }
    else if (subFilters.length == 1)
    {
      Validator.ensureNotNull(subFilters[0]);
      return new Filter(new OrImpl(Collections
          .singletonList(subFilters[0])));
    }
    else
    {
      List<Filter> subFiltersList = new ArrayList<Filter>(
          subFilters.length);
      for (Filter subFilter : subFilters)
      {
        Validator.ensureNotNull(subFilter);
        subFiltersList.add(subFilter);
      }
      return new Filter(new OrImpl(Collections
          .unmodifiableList(subFiltersList)));
    }
  }
  /**
   * Creates a new {@code present} filter using the provided attribute
   * description.
   *
   * @param attributeDescription
   *          The attribute description.
   * @return The newly created {@code present} filter.
   */
  public static Filter newPresentFilter(String attributeDescription)
  {
    Validator.ensureNotNull(attributeDescription);
    if (toLowerCase(attributeDescription).equals("objectclass"))
    {
      return OBJECT_CLASS_PRESENT;
    }
    return new Filter(new PresentImpl(attributeDescription));
  }
  /**
   * Creates a new {@code substrings} filter using the provided
   * attribute description, {@code initial}, {@code final}, and {@code
   * any} sub-strings.
   *
   * @param attributeDescription
   *          The attribute description.
   * @param initialSubstring
   *          The initial sub-string, may be {@code null} if either
   *          {@code finalSubstring} or {@code anySubstrings} are
   *          specified.
   * @param anySubstrings
   *          The final sub-string, may be {@code null} or empty if
   *          either {@code finalSubstring} or {@code initialSubstring}
   *          are specified.
   * @param finalSubstring
   *          The final sub-string, may be {@code null}, may be {@code
   *          null} if either {@code initialSubstring} or {@code
   *          anySubstrings} are specified.
   * @return The newly created {@code substrings} filter.
   */
  public static Filter newSubstringsFilter(String attributeDescription,
      ByteSequence initialSubstring, ByteSequence[] anySubstrings,
      ByteSequence finalSubstring)
  {
    Validator.ensureNotNull(attributeDescription);
    Validator.ensureTrue((initialSubstring != null)
        || (finalSubstring != null)
        || ((anySubstrings != null) && (anySubstrings.length > 0)),
        "at least one substring (initial, any or final)"
            + " must be specified");
    List<ByteSequence> anySubstringList;
    if ((anySubstrings == null) || (anySubstrings.length == 0))
    {
      anySubstringList = Collections.emptyList();
    }
    else if (anySubstrings.length == 1)
    {
      Validator.ensureNotNull(anySubstrings[0]);
      anySubstringList = Collections.singletonList(anySubstrings[0]);
    }
    else
    {
      anySubstringList = new ArrayList<ByteSequence>(
          anySubstrings.length);
      for (ByteSequence anySubstring : anySubstrings)
      {
        Validator.ensureNotNull(anySubstring);
        anySubstringList.add(anySubstring);
      }
      anySubstringList = Collections.unmodifiableList(anySubstringList);
    }
    return new Filter(new SubstringsImpl(attributeDescription,
        initialSubstring, anySubstringList, finalSubstring));
  }
  /**
   * Creates a new {@code substrings} filter using the provided
   * attribute description, {@code initial}, {@code final}, and {@code
   * any} sub-strings.
   *
   * @param attributeDescription
   *          The attribute description.
   * @param initialSubstring
   *          The initial sub-string, may be {@code null} if either
   *          {@code finalSubstring} or {@code anySubstrings} are
   *          specified.
   * @param anySubstrings
   *          The final sub-string, may be {@code null} or empty if
   *          either {@code finalSubstring} or {@code initialSubstring}
   *          are specified.
   * @param finalSubstring
   *          The final sub-string, may be {@code null}, may be {@code
   *          null} if either {@code initialSubstring} or {@code
   *          anySubstrings} are specified.
   * @return The newly created {@code substrings} filter.
   */
  public static Filter newSubstringsFilter(String attributeDescription,
      ByteSequence initialSubstring,
      Collection<ByteSequence> anySubstrings,
      ByteSequence finalSubstring)
  {
    Validator.ensureNotNull(attributeDescription);
    Validator.ensureTrue((initialSubstring != null)
        || (finalSubstring != null)
        || ((anySubstrings != null) && (anySubstrings.size() > 0)),
        "at least one substring (initial, any or final)"
            + " must be specified");
    List<ByteSequence> anySubstringList;
    if ((anySubstrings == null) || (anySubstrings.size() == 0))
    {
      anySubstringList = Collections.emptyList();
    }
    else if (anySubstrings.size() == 1)
    {
      ByteSequence anySubstring = anySubstrings.iterator().next();
      Validator.ensureNotNull(anySubstring);
      anySubstringList = Collections.singletonList(anySubstring);
    }
    else
    {
      anySubstringList = new ArrayList<ByteSequence>(anySubstrings
          .size());
      for (ByteSequence anySubstring : anySubstrings)
      {
        Validator.ensureNotNull(anySubstring);
        anySubstringList.add(anySubstring);
      }
      anySubstringList = Collections.unmodifiableList(anySubstringList);
    }
    return new Filter(new SubstringsImpl(attributeDescription,
        initialSubstring, anySubstringList, finalSubstring));
  }
  /**
   * Creates a new {@code unrecognized} filter using the provided ASN1
   * filter tag and content. This type of filter should be used for
   * filters which are not part of the standard filter definition.
   *
   * @param filterTag
   *          The ASN.1 tag.
   * @param filterBytes
   *          The filter content.
   * @return The newly created {@code unrecognized} filter.
   */
  public static Filter newUnrecognizedFilter(byte filterTag,
      ByteSequence filterBytes)
  {
    Validator.ensureNotNull(filterBytes);
    return new Filter(new UnrecognizedImpl(filterTag, filterBytes));
  }
  /**
   * Parses the provided LDAP string representation of a filter as a
   * {@code Filter}.
   *
   * @param string
   *          The LDAP string representation of a filter.
   * @return The parsed {@code Filter}.
   * @throws LocalizedIllegalArgumentException
   *           If {@code string} is not a valid LDAP string
   *           representation of a filter.
   */
  public static Filter valueOf(String string)
      throws LocalizedIllegalArgumentException
  {
    Validator.ensureNotNull(string);
    // If the filter is enclosed in a pair of single quotes it
    // is invalid (issue #1024).
    if ((string.length() > 1) && string.startsWith("'")
        && string.endsWith("'"))
    {
      Message message = ERR_LDAP_FILTER_ENCLOSED_IN_APOSTROPHES
          .get(string);
      throw new LocalizedIllegalArgumentException(message);
    }
    if (string.startsWith("("))
    {
      if (string.endsWith(")"))
      {
        return valueOf0(string, 1, string.length() - 1);
      }
      else
      {
        Message message = ERR_LDAP_FILTER_MISMATCHED_PARENTHESES.get(
            string, 1, string.length());
        throw new LocalizedIllegalArgumentException(message);
      }
    }
    else
    {
      // We tolerate the top level filter component not being surrounded
      // by parentheses.
      return valueOf0(string, 0, string.length());
    }
  }
  private static Filter valueOf0(String string,
      int beginIndex /* inclusive */, int endIndex /* exclusive */)
      throws LocalizedIllegalArgumentException
  {
    if (beginIndex >= endIndex)
    {
      Message message = ERR_LDAP_FILTER_STRING_NULL.get();
      throw new LocalizedIllegalArgumentException(message);
    }
    int index = beginIndex;
    char c = string.charAt(index);
    if (c == '&')
    {
      List<Filter> subFilters = valueOfFilterList(string, index + 1,
          endIndex);
      if (subFilters.isEmpty())
      {
        return getAbsoluteTrueFilter();
      }
      else
      {
        return new Filter(new AndImpl(subFilters));
      }
    }
    else if (c == '|')
    {
      List<Filter> subFilters = valueOfFilterList(string, index + 1,
          endIndex);
      if (subFilters.isEmpty())
      {
        return getAbsoluteFalseFilter();
      }
      else
      {
        return new Filter(new OrImpl(subFilters));
      }
    }
    else if (c == '!')
    {
      if ((string.charAt(index + 1) != '(')
          || (string.charAt(endIndex - 1) != ')'))
      {
        Message message = ERR_LDAP_FILTER_COMPOUND_MISSING_PARENTHESES
            .get(string, index, endIndex - 1);
        throw new LocalizedIllegalArgumentException(message);
      }
      Filter subFilter = valueOf0(string, index + 2, endIndex - 1);
      return new Filter(new NotImpl(subFilter));
    }
    else
    {
      // It must be a simple filter. It must have an equal sign at some
      // point, so find it.
      int equalPos = -1;
      for (int i = index; i < endIndex; i++)
      {
        if (string.charAt(i) == '=')
        {
          equalPos = i;
          break;
        }
      }
      // Look at the character immediately before the equal sign,
      // because it may help determine the filter type.
      String attributeDescription;
      ByteSequence assertionValue;
      switch (string.charAt(equalPos - 1))
      {
      case '~':
        attributeDescription = valueOfAttributeDescription(string,
            index, equalPos - 1);
        assertionValue = valueOfAssertionValue(string, equalPos + 1,
            endIndex);
        return new Filter(new ApproxMatchImpl(attributeDescription,
            assertionValue));
      case '>':
        attributeDescription = valueOfAttributeDescription(string,
            index, equalPos - 1);
        assertionValue = valueOfAssertionValue(string, equalPos + 1,
            endIndex);
        return new Filter(new GreaterOrEqualImpl(attributeDescription,
            assertionValue));
      case '<':
        attributeDescription = valueOfAttributeDescription(string,
            index, equalPos - 1);
        assertionValue = valueOfAssertionValue(string, equalPos + 1,
            endIndex);
        return new Filter(new LessOrEqualImpl(attributeDescription,
            assertionValue));
      case ':':
        return valueOfExtensibleFilter(string, index, equalPos,
            endIndex);
      default:
        attributeDescription = valueOfAttributeDescription(string,
            index, equalPos);
        return valueOfGenericFilter(string, attributeDescription,
            equalPos + 1, endIndex);
      }
    }
  }
  private static ByteSequence valueOfAssertionValue(String string,
      int startIndex, int endIndex)
      throws LocalizedIllegalArgumentException
  {
    boolean hasEscape = false;
    byte[] valueBytes = getBytes(string.substring(startIndex, endIndex));
    for (byte valueByte : valueBytes)
    {
      if (valueByte == 0x5C) // The backslash character
      {
        hasEscape = true;
        break;
      }
    }
    if (hasEscape)
    {
      ByteStringBuilder valueBuffer = new ByteStringBuilder(
          valueBytes.length);
      for (int i = 0; i < valueBytes.length; i++)
      {
        if (valueBytes[i] == 0x5C) // The backslash character
        {
          // The next two bytes must be the hex characters that comprise
          // the binary value.
          if ((i + 2) >= valueBytes.length)
          {
            Message message = ERR_LDAP_FILTER_INVALID_ESCAPED_BYTE.get(
                string, startIndex + i + 1);
            throw new LocalizedIllegalArgumentException(message);
          }
          byte byteValue = 0;
          switch (valueBytes[++i])
          {
          case 0x30: // '0'
            break;
          case 0x31: // '1'
            byteValue = (byte) 0x10;
            break;
          case 0x32: // '2'
            byteValue = (byte) 0x20;
            break;
          case 0x33: // '3'
            byteValue = (byte) 0x30;
            break;
          case 0x34: // '4'
            byteValue = (byte) 0x40;
            break;
          case 0x35: // '5'
            byteValue = (byte) 0x50;
            break;
          case 0x36: // '6'
            byteValue = (byte) 0x60;
            break;
          case 0x37: // '7'
            byteValue = (byte) 0x70;
            break;
          case 0x38: // '8'
            byteValue = (byte) 0x80;
            break;
          case 0x39: // '9'
            byteValue = (byte) 0x90;
            break;
          case 0x41: // 'A'
          case 0x61: // 'a'
            byteValue = (byte) 0xA0;
            break;
          case 0x42: // 'B'
          case 0x62: // 'b'
            byteValue = (byte) 0xB0;
            break;
          case 0x43: // 'C'
          case 0x63: // 'c'
            byteValue = (byte) 0xC0;
            break;
          case 0x44: // 'D'
          case 0x64: // 'd'
            byteValue = (byte) 0xD0;
            break;
          case 0x45: // 'E'
          case 0x65: // 'e'
            byteValue = (byte) 0xE0;
            break;
          case 0x46: // 'F'
          case 0x66: // 'f'
            byteValue = (byte) 0xF0;
            break;
          default:
            Message message = ERR_LDAP_FILTER_INVALID_ESCAPED_BYTE.get(
                string, startIndex + i + 1);
            throw new LocalizedIllegalArgumentException(message);
          }
          switch (valueBytes[++i])
          {
          case 0x30: // '0'
            break;
          case 0x31: // '1'
            byteValue |= (byte) 0x01;
            break;
          case 0x32: // '2'
            byteValue |= (byte) 0x02;
            break;
          case 0x33: // '3'
            byteValue |= (byte) 0x03;
            break;
          case 0x34: // '4'
            byteValue |= (byte) 0x04;
            break;
          case 0x35: // '5'
            byteValue |= (byte) 0x05;
            break;
          case 0x36: // '6'
            byteValue |= (byte) 0x06;
            break;
          case 0x37: // '7'
            byteValue |= (byte) 0x07;
            break;
          case 0x38: // '8'
            byteValue |= (byte) 0x08;
            break;
          case 0x39: // '9'
            byteValue |= (byte) 0x09;
            break;
          case 0x41: // 'A'
          case 0x61: // 'a'
            byteValue |= (byte) 0x0A;
            break;
          case 0x42: // 'B'
          case 0x62: // 'b'
            byteValue |= (byte) 0x0B;
            break;
          case 0x43: // 'C'
          case 0x63: // 'c'
            byteValue |= (byte) 0x0C;
            break;
          case 0x44: // 'D'
          case 0x64: // 'd'
            byteValue |= (byte) 0x0D;
            break;
          case 0x45: // 'E'
          case 0x65: // 'e'
            byteValue |= (byte) 0x0E;
            break;
          case 0x46: // 'F'
          case 0x66: // 'f'
            byteValue |= (byte) 0x0F;
            break;
          default:
            Message message = ERR_LDAP_FILTER_INVALID_ESCAPED_BYTE.get(
                string, startIndex + i + 1);
            throw new LocalizedIllegalArgumentException(message);
          }
          valueBuffer.append(byteValue);
        }
        else
        {
          valueBuffer.append(valueBytes[i]);
        }
      }
      return valueBuffer.toByteString();
    }
    else
    {
      return ByteString.wrap(valueBytes);
    }
  }
  private static String valueOfAttributeDescription(String string,
      int startIndex, int endIndex)
      throws LocalizedIllegalArgumentException
  {
    // The part of the filter string before the equal sign should be the
    // attribute type. Make sure that the characters it contains are
    // acceptable for attribute types, including those allowed by
    // attribute name exceptions (ASCII letters and digits, the dash,
    // and the underscore). We also need to allow attribute options,
    // which includes the semicolon and the equal sign.
    String attrType = string.substring(startIndex, endIndex);
    for (int i = 0; i < attrType.length(); i++)
    {
      switch (attrType.charAt(i))
      {
      case '-':
      case '0':
      case '1':
      case '2':
      case '3':
      case '4':
      case '5':
      case '6':
      case '7':
      case '8':
      case '9':
      case ';':
      case '=':
      case 'A':
      case 'B':
      case 'C':
      case 'D':
      case 'E':
      case 'F':
      case 'G':
      case 'H':
      case 'I':
      case 'J':
      case 'K':
      case 'L':
      case 'M':
      case 'N':
      case 'O':
      case 'P':
      case 'Q':
      case 'R':
      case 'S':
      case 'T':
      case 'U':
      case 'V':
      case 'W':
      case 'X':
      case 'Y':
      case 'Z':
      case '_':
      case 'a':
      case 'b':
      case 'c':
      case 'd':
      case 'e':
      case 'f':
      case 'g':
      case 'h':
      case 'i':
      case 'j':
      case 'k':
      case 'l':
      case 'm':
      case 'n':
      case 'o':
      case 'p':
      case 'q':
      case 'r':
      case 's':
      case 't':
      case 'u':
      case 'v':
      case 'w':
      case 'x':
      case 'y':
      case 'z':
        // These are all OK.
        break;
      case '.':
      case '/':
      case ':':
      case '<':
      case '>':
      case '?':
      case '@':
      case '[':
      case '\\':
      case ']':
      case '^':
      case '`':
        // These are not allowed, but they are explicitly called out
        // because they are included in the range of values between '-'
        // and 'z', and making sure all possible characters are included
        // can help make the switch statement more efficient. We'll fall
        // through to the default clause to reject them.
      default:
        Message message = ERR_LDAP_FILTER_INVALID_CHAR_IN_ATTR_TYPE
            .get(attrType, String.valueOf(attrType.charAt(i)), i);
        throw new LocalizedIllegalArgumentException(message);
      }
    }
    return attrType;
  }
  private static Filter valueOfExtensibleFilter(String string,
      int startIndex, int equalIndex, int endIndex)
      throws LocalizedIllegalArgumentException
  {
    String attributeDescription = null;
    boolean dnAttributes = false;
    String matchingRule = null;
    // Look at the first character. If it is a colon, then it must be
    // followed by either the string "dn" or the matching rule ID. If it
    // is not, then must be the attribute type.
    String lowerLeftStr = toLowerCase(string.substring(startIndex,
        equalIndex));
    if (string.charAt(startIndex) == ':')
    {
      // See if it starts with ":dn". Otherwise, it much be the matching
      // rule ID.
      if (lowerLeftStr.startsWith(":dn:"))
      {
        dnAttributes = true;
        if ((startIndex + 4) < (equalIndex - 1))
        {
          matchingRule = string.substring(startIndex + 4,
              equalIndex - 1);
        }
      }
      else
      {
        matchingRule = string.substring(startIndex + 1, equalIndex - 1);
      }
    }
    else
    {
      int colonPos = string.indexOf(':', startIndex);
      if (colonPos < 0)
      {
        Message message = ERR_LDAP_FILTER_EXTENSIBLE_MATCH_NO_COLON
            .get(string, startIndex);
        throw new LocalizedIllegalArgumentException(message);
      }
      attributeDescription = string.substring(startIndex, colonPos);
      // If there is anything left, then it should be ":dn" and/or ":"
      // followed by the matching rule ID.
      if (colonPos < (equalIndex - 1))
      {
        if (lowerLeftStr.startsWith(":dn:", colonPos - startIndex))
        {
          dnAttributes = true;
          if ((colonPos + 4) < (equalIndex - 1))
          {
            matchingRule = string.substring(colonPos + 4,
                equalIndex - 1);
          }
        }
        else
        {
          matchingRule = string.substring(colonPos + 1, equalIndex - 1);
        }
      }
    }
    // Parse out the attribute value.
    ByteSequence matchValue = valueOfAssertionValue(string,
        equalIndex + 1, endIndex);
    // Make sure that the filter has at least one of an attribute
    // description and/or a matching rule ID.
    if ((attributeDescription == null) && (matchingRule == null))
    {
      Message message = ERR_LDAP_FILTER_EXTENSIBLE_MATCH_NO_AD_OR_MR
          .get(string, startIndex);
      throw new LocalizedIllegalArgumentException(message);
    }
    return new Filter(new ExtensibleMatchImpl(matchingRule,
        attributeDescription, matchValue, dnAttributes));
  }
  private static List<Filter> valueOfFilterList(String string,
      int startIndex, int endIndex)
      throws LocalizedIllegalArgumentException
  {
    // If the end index is equal to the start index, then there are no
    // components.
    if (startIndex >= endIndex)
    {
      return Collections.emptyList();
    }
    // At least one sub-filter.
    Filter firstFilter = null;
    List<Filter> subFilters = null;
    // The first and last characters must be parentheses. If not, then
    // that's an error.
    if ((string.charAt(startIndex) != '(')
        || (string.charAt(endIndex - 1) != ')'))
    {
      Message message = ERR_LDAP_FILTER_COMPOUND_MISSING_PARENTHESES
          .get(string, startIndex, endIndex);
      throw new LocalizedIllegalArgumentException(message);
    }
    // Iterate through the characters in the value. Whenever an open
    // parenthesis is found, locate the corresponding close parenthesis
    // by counting the number of intermediate open/close parentheses.
    int pendingOpens = 0;
    int openIndex = -1;
    for (int i = startIndex; i < endIndex; i++)
    {
      char c = string.charAt(i);
      if (c == '(')
      {
        if (openIndex < 0)
        {
          openIndex = i;
        }
        pendingOpens++;
      }
      else if (c == ')')
      {
        pendingOpens--;
        if (pendingOpens == 0)
        {
          Filter subFilter = valueOf0(string, openIndex + 1, i);
          if (subFilters != null)
          {
            subFilters.add(subFilter);
          }
          else if (firstFilter != null)
          {
            subFilters = new LinkedList<Filter>();
            subFilters.add(firstFilter);
            subFilters.add(subFilter);
            firstFilter = null;
          }
          else
          {
            firstFilter = subFilter;
          }
          openIndex = -1;
        }
        else if (pendingOpens < 0)
        {
          Message message = ERR_LDAP_FILTER_NO_CORRESPONDING_OPEN_PARENTHESIS
              .get(string, i);
          throw new LocalizedIllegalArgumentException(message);
        }
      }
      else if (pendingOpens <= 0)
      {
        Message message = ERR_LDAP_FILTER_COMPOUND_MISSING_PARENTHESES
            .get(string, startIndex, endIndex);
        throw new LocalizedIllegalArgumentException(message);
      }
    }
    // At this point, we have parsed the entire set of filter
    // components. The list of open parenthesis positions must be empty.
    if (pendingOpens != 0)
    {
      Message message = ERR_LDAP_FILTER_NO_CORRESPONDING_CLOSE_PARENTHESIS
          .get(string, openIndex);
      throw new LocalizedIllegalArgumentException(message);
    }
    if (subFilters != null)
    {
      return Collections.unmodifiableList(subFilters);
    }
    else
    {
      return Collections.singletonList(firstFilter);
    }
  }
  private static Filter valueOfGenericFilter(String string,
      String attributeDescription, int startIndex, int endIndex)
      throws LocalizedIllegalArgumentException
  {
    if (startIndex >= endIndex)
    {
      // Equality filter with empty assertion value.
      return new Filter(new EqualityMatchImpl(attributeDescription,
          ByteString.empty()));
    }
    else if ((endIndex - startIndex == 1)
        && (string.charAt(startIndex) == '*'))
    {
      // Single asterisk is a present filter.
      return newPresentFilter(attributeDescription);
    }
    else
    {
      // Either an equality or substring filter.
      ByteSequence assertionValue = valueOfAssertionValue(string,
          startIndex, endIndex);
      ByteSequence initialString = null;
      ByteSequence finalString = null;
      LinkedList<ByteSequence> anyStrings = null;
      int lastAsteriskIndex = -1;
      int length = assertionValue.length();
      for (int i = 0; i < length; i++)
      {
        if (assertionValue.byteAt(i) == '*')
        {
          if (lastAsteriskIndex == -1)
          {
            if (i > 0)
            {
              // Got an initial substring.
              initialString = assertionValue.subSequence(0, i);
            }
            lastAsteriskIndex = i;
          }
          else
          {
            // Got an any substring.
            if (anyStrings == null)
            {
              anyStrings = new LinkedList<ByteSequence>();
            }
            int s = lastAsteriskIndex + 1;
            if (s == i)
            {
              // A zero length substring.
              Message message = ERR_LDAP_FILTER_BAD_SUBSTRING.get(
                  string, string.subSequence(startIndex, endIndex));
              throw new LocalizedIllegalArgumentException(message);
            }
            anyStrings.add(assertionValue.subSequence(s, i));
            lastAsteriskIndex = i;
          }
        }
      }
      if (lastAsteriskIndex >= 0 && lastAsteriskIndex < length - 1)
      {
        // Got a final substring.
        finalString = assertionValue.subSequence(lastAsteriskIndex + 1,
            length);
      }
      if ((initialString == null) && (anyStrings == null)
          && (finalString == null))
      {
        return new Filter(new EqualityMatchImpl(attributeDescription,
            assertionValue));
      }
      else
      {
        List<ByteSequence> tmp;
        if (anyStrings == null)
        {
          tmp = Collections.emptyList();
        }
        else if (anyStrings.size() == 1)
        {
          tmp = Collections.singletonList(anyStrings.getFirst());
        }
        else
        {
          tmp = Collections.unmodifiableList(anyStrings);
        }
        return new Filter(new SubstringsImpl(attributeDescription,
            initialString, tmp, finalString));
      }
    }
  }
  /**
   * Appends a properly-cleaned version of the provided value to the
   * given builder so that it can be safely used in string
   * representations of this search filter. The formatting changes that
   * may be performed will be in compliance with the specification in
   * RFC 2254.
   *
   * @param builder
   *          The builder to which the "safe" version of the value will
   *          be appended.
   * @param value
   *          The value to be appended to the builder.
   */
  private static void valueToFilterString(StringBuilder builder,
      ByteSequence value)
  {
    // Get the binary representation of the value and iterate through
    // it to see if there are any unsafe characters. If there are,
    // then escape them and replace them with a two-digit hex
    // equivalent.
    builder.ensureCapacity(builder.length() + value.length());
    for (int i = 0; i < value.length(); i++)
    {
      // TODO: this is a bit overkill - it will escape all non-ascii
      // chars!
      byte b = value.byteAt(i);
      if (((b & 0x7F) != b) || // Not 7-bit clean
          (b <= 0x1F) || // Below the printable character range
          (b == 0x28) || // Open parenthesis
          (b == 0x29) || // Close parenthesis
          (b == 0x2A) || // Asterisk
          (b == 0x5C) || // Backslash
          (b == 0x7F)) // Delete character
      {
        builder.append('\\');
        builder.append(byteToHex(b));
      }
      else
      {
        builder.append((char) b);
      }
    }
  }
  private final Impl pimpl;
  private Filter(Impl pimpl)
  {
    this.pimpl = pimpl;
  }
  /**
   * Applies a {@code FilterVisitor} to this {@code Filter}.
   *
   * @param <R>
   *          The return type of the visitor's methods.
   * @param <P>
   *          The type of the additional parameters to the visitor's
   *          methods.
   * @param v
   *          The filter visitor.
   * @param p
   *          Optional additional visitor parameter.
   * @return A result as specified by the visitor.
   */
  public <R, P> R accept(FilterVisitor<R, P> v, P p)
  {
    return pimpl.accept(v, p);
  }
  /**
   * Returns a {@code Matcher} which can be used to compare this {@code
   * Filter} against entries using the provided {@code Schema}.
   *
   * @param schema
   *          The schema which the {@code Matcher} should use for
   *          comparisons.
   * @return The {@code Matcher}.
   */
  public Matcher matcher(Schema schema)
  {
    return new Matcher(this, schema);
  }
  /**
   * Returns a {@code Matcher} which can be used to compare this {@code
   * Filter} against entries using the default schema.
   *
   * @return The {@code Matcher}.
   */
  public Matcher matcher()
  {
    return new Matcher(this, Schema.getDefaultSchema());
  }
  /**
   * Indicates whether this {@code Filter} matches the provided {@code
   * Entry} using the schema associated with the entry.
   * <p>
   * Calling this method is equivalent to the following:
   *
   * <pre>
   * boolean b = matcher(entry.getSchema()).matches(entry);
   * </pre>
   *
   * @param entry
   *          The entry to be matched.
   * @return {@code true} if this {@code Filter} matches the provided
   *         {@code Entry}.
   */
  public ConditionResult matches(Entry entry)
  {
    return matcher(Schema.getDefaultSchema()).matches(entry);
  }
  /**
   * Returns a {@code String} whose contents is the LDAP string
   * representation of this {@code Filter}.
   *
   * @return The LDAP string representation of this {@code Filter}.
   */
  @Override
  public String toString()
  {
    StringBuilder builder = new StringBuilder();
    return toString(builder).toString();
  }
  /**
   * Appends the LDAP string representation of this {@code Filter} to
   * the provided {@code StringBuilder}.
   *
   * @param builder
   *          The {@code StringBuilder} to which the LDAP string
   *          representation of this {@code Filter} should be appended.
   * @return The updated {@code StringBuilder}.
   */
  public StringBuilder toString(StringBuilder builder)
  {
    return pimpl.accept(TO_STRING_VISITOR, builder);
  }
}
opendj-sdk/sdk/src/org/opends/sdk/FilterVisitor.java
New file
@@ -0,0 +1,238 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Copyright 2009 Sun Microsystems, Inc.
 */
package org.opends.sdk;
import java.util.List;
import org.opends.sdk.util.ByteSequence;
/**
 * A visitor of {@code Filter}s, in the style of the visitor design
 * pattern.
 * <p>
 * Classes implementing this interface can query filters in a type-safe
 * manner. When a visitor is passed to a filter's accept method, the
 * corresponding visit method most applicable to that filter is invoked.
 *
 * @param <R>
 *          The return type of this visitor's methods. Use
 *          {@link java.lang.Void} for visitors that do not need to
 *          return results.
 * @param <P>
 *          The type of the additional parameter to this visitor's
 *          methods. Use {@link java.lang.Void} for visitors that do not
 *          need an additional parameter.
 */
public interface FilterVisitor<R, P>
{
  /**
   * Visits an {@code and} filter.
   * <p>
   * <b>Implementation note</b>: for the purposes of matching an empty
   * sub-filter list should always evaluate to {@code true} as per RFC
   * 4526.
   *
   * @param p
   *          A visitor specified parameter.
   * @param subFilters
   *          The unmodifiable list of sub-filters.
   * @return Returns a visitor specified result.
   */
  R visitAndFilter(P p, List<Filter> subFilters);
  /**
   * Visits an {@code approximate match} filter.
   *
   * @param p
   *          A visitor specified parameter.
   * @param attributeDescription
   *          The attribute description.
   * @param assertionValue
   *          The assertion value.
   * @return Returns a visitor specified result.
   */
  R visitApproxMatchFilter(P p, String attributeDescription,
      ByteSequence assertionValue);
  /**
   * Visits an {@code equality match} filter.
   *
   * @param p
   *          A visitor specified parameter.
   * @param attributeDescription
   *          The attribute description.
   * @param assertionValue
   *          The assertion value.
   * @return Returns a visitor specified result.
   */
  R visitEqualityMatchFilter(P p, String attributeDescription,
      ByteSequence assertionValue);
  /**
   * Visits an {@code extensible} filter.
   *
   * @param p
   *          A visitor specified parameter.
   * @param matchingRule
   *          The matching rule name, may be {@code null} if {@code
   *          attributeDescription} is specified.
   * @param attributeDescription
   *          The attribute description, may be {@code null} if {@code
   *          matchingRule} is specified.
   * @param assertionValue
   *          The assertion value.
   * @param dnAttributes
   *          Indicates whether DN matching should be performed.
   * @return Returns a visitor specified result.
   */
  R visitExtensibleMatchFilter(P p, String matchingRule,
      String attributeDescription, ByteSequence assertionValue,
      boolean dnAttributes);
  /**
   * Visits a {@code greater or equal} filter.
   *
   * @param p
   *          A visitor specified parameter.
   * @param attributeDescription
   *          The attribute description.
   * @param assertionValue
   *          The assertion value.
   * @return Returns a visitor specified result.
   */
  R visitGreaterOrEqualFilter(P p, String attributeDescription,
      ByteSequence assertionValue);
  /**
   * Visits a {@code less or equal} filter.
   *
   * @param p
   *          A visitor specified parameter.
   * @param attributeDescription
   *          The attribute description.
   * @param assertionValue
   *          The assertion value.
   * @return Returns a visitor specified result.
   */
  R visitLessOrEqualFilter(P p, String attributeDescription,
      ByteSequence assertionValue);
  /**
   * Visits a {@code not} filter.
   *
   * @param p
   *          A visitor specified parameter.
   * @param subFilter
   *          The sub-filter.
   * @return Returns a visitor specified result.
   */
  R visitNotFilter(P p, Filter subFilter);
  /**
   * Visits an {@code or} filter.
   * <p>
   * <b>Implementation note</b>: for the purposes of matching an empty
   * sub-filter list should always evaluate to {@code false} as per RFC
   * 4526.
   *
   * @param p
   *          A visitor specified parameter.
   * @param subFilters
   *          The unmodifiable list of sub-filters.
   * @return Returns a visitor specified result.
   */
  R visitOrFilter(P p, List<Filter> subFilters);
  /**
   * Visits a {@code present} filter.
   *
   * @param p
   *          A visitor specified parameter.
   * @param attributeDescription
   *          The attribute description.
   * @return Returns a visitor specified result.
   */
  R visitPresentFilter(P p, String attributeDescription);
  /**
   * Visits a {@code substrings} filter.
   *
   * @param p
   *          A visitor specified parameter.
   * @param attributeDescription
   *          The attribute description.
   * @param initialSubstring
   *          The initial sub-string, may be {@code null}.
   * @param anySubstrings
   *          The unmodifiable list of any sub-strings, may be empty.
   * @param finalSubstring
   *          The final sub-string, may be {@code null}.
   * @return Returns a visitor specified result.
   */
  R visitSubstringsFilter(P p, String attributeDescription,
      ByteSequence initialSubstring, List<ByteSequence> anySubstrings,
      ByteSequence finalSubstring);
  /**
   * Visits an {@code unrecognized} filter.
   *
   * @param p
   *          A visitor specified parameter.
   * @param filterTag
   *          The ASN.1 tag.
   * @param filterBytes
   *          The filter content.
   * @return Returns a visitor specified result.
   */
  R visitUnrecognizedFilter(P p, byte filterTag, ByteSequence filterBytes);
}
opendj-sdk/sdk/src/org/opends/sdk/LinkedAttribute.java
New file
@@ -0,0 +1,1063 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Copyright 2009 Sun Microsystems, Inc.
 */
package org.opends.sdk;
import java.util.*;
import org.opends.sdk.util.ByteString;
import org.opends.sdk.util.LocalizedIllegalArgumentException;
import org.opends.sdk.util.Validator;
/**
 * An implementation of the {@code Attribute} interface with predictable
 * iteration order.
 * <p>
 * Internally, attribute values are stored in a linked list and it's
 * this list which defines the iteration ordering, which is the order in
 * which elements were inserted into the set (insertion-order). This
 * ordering is particularly useful in LDAP where clients generally
 * appreciate having things returned in the same order they were
 * presented.
 * <p>
 * All operations are supported by this implementation.
 */
public final class LinkedAttribute extends AbstractAttribute
{
  private static abstract class Impl
  {
    abstract boolean add(LinkedAttribute attribute, ByteString value);
    boolean addAll(LinkedAttribute attribute,
        Collection<? extends ByteString> values,
        Collection<? super ByteString> duplicateValues)
        throws NullPointerException
    {
      // TODO: could optimize if values is a BasicAttribute.
      ensureCapacity(attribute, values.size());
      boolean modified = false;
      for (ByteString value : values)
      {
        if (add(attribute, value))
        {
          modified = true;
        }
        else if (duplicateValues != null)
        {
          duplicateValues.add(value);
        }
      }
      resize(attribute);
      return modified;
    }
    abstract void clear(LinkedAttribute attribute);
    abstract boolean contains(LinkedAttribute attribute,
        ByteString value);
    boolean containsAll(LinkedAttribute attribute, Collection<?> values)
    {
      // TODO: could optimize if objects is a BasicAttribute.
      for (Object value : values)
      {
        if (!contains(attribute, ByteString.valueOf(value)))
        {
          return false;
        }
      }
      return true;
    }
    abstract void ensureCapacity(LinkedAttribute attribute, int size);
    abstract ByteString firstValue(LinkedAttribute attribute)
        throws NoSuchElementException;
    abstract Iterator<ByteString> iterator(LinkedAttribute attribute);
    abstract boolean remove(LinkedAttribute attribute, ByteString value);
    <T> boolean removeAll(LinkedAttribute attribute,
        Collection<T> values, Collection<? super T> missingValues)
    {
      // TODO: could optimize if objects is a BasicAttribute.
      boolean modified = false;
      for (T value : values)
      {
        if (remove(attribute, ByteString.valueOf(value)))
        {
          modified = true;
        }
        else if (missingValues != null)
        {
          missingValues.add(value);
        }
      }
      return modified;
    }
    abstract void resize(LinkedAttribute attribute);
    abstract <T> boolean retainAll(LinkedAttribute attribute,
        Collection<T> values, Collection<? super T> missingValues);
    abstract int size(LinkedAttribute attribute);
  }
  private static final class MultiValueImpl extends Impl
  {
    boolean add(LinkedAttribute attribute, ByteString value)
    {
      ByteString normalizedValue = normalizeValue(attribute, value);
      if (attribute.multipleValues.put(normalizedValue, value) == null)
      {
        return true;
      }
      else
      {
        return false;
      }
    }
    void clear(LinkedAttribute attribute)
    {
      attribute.multipleValues = null;
      attribute.pimpl = ZERO_VALUE_IMPL;
    }
    boolean contains(LinkedAttribute attribute, ByteString value)
    {
      return attribute.multipleValues.containsKey(normalizeValue(
          attribute, value));
    }
    void ensureCapacity(LinkedAttribute attribute, int size)
    {
      // Nothing to do.
    }
    ByteString firstValue(LinkedAttribute attribute)
        throws NoSuchElementException
    {
      return attribute.multipleValues.values().iterator().next();
    }
    Iterator<ByteString> iterator(final LinkedAttribute attribute)
    {
      return new Iterator<ByteString>()
      {
        private Impl expectedImpl = MULTI_VALUE_IMPL;
        private Iterator<ByteString> iterator = attribute.multipleValues
            .values().iterator();
        public boolean hasNext()
        {
          return iterator.hasNext();
        }
        public ByteString next()
        {
          if (attribute.pimpl != expectedImpl)
          {
            throw new ConcurrentModificationException();
          }
          else
          {
            return iterator.next();
          }
        }
        public void remove()
        {
          if (attribute.pimpl != expectedImpl)
          {
            throw new ConcurrentModificationException();
          }
          else
          {
            iterator.remove();
            // Resize if we have removed the second to last value.
            if (attribute.multipleValues != null
                && attribute.multipleValues.size() == 1)
            {
              resize(attribute);
              iterator = attribute.pimpl.iterator(attribute);
            }
            // Always update since we may change to single or zero value
            // impl.
            expectedImpl = attribute.pimpl;
          }
        }
      };
    }
    boolean remove(LinkedAttribute attribute, ByteString value)
    {
      ByteString normalizedValue = normalizeValue(attribute, value);
      if (attribute.multipleValues.remove(normalizedValue) != null)
      {
        resize(attribute);
        return true;
      }
      else
      {
        return false;
      }
    }
    void resize(LinkedAttribute attribute)
    {
      // May need to resize if initial size estimate was wrong (e.g. all
      // values in added collection were the same).
      switch (attribute.multipleValues.size())
      {
      case 0:
        attribute.multipleValues = null;
        attribute.pimpl = ZERO_VALUE_IMPL;
        break;
      case 1:
        Map.Entry<ByteString, ByteString> e = attribute.multipleValues
            .entrySet().iterator().next();
        attribute.singleValue = e.getValue();
        attribute.normalizedSingleValue = e.getKey();
        attribute.multipleValues = null;
        attribute.pimpl = SINGLE_VALUE_IMPL;
        break;
      default:
        // Nothing to do.
        break;
      }
    }
    <T> boolean retainAll(LinkedAttribute attribute,
        Collection<T> values, Collection<? super T> missingValues)
    {
      // TODO: could optimize if objects is a BasicAttribute.
      if (values.isEmpty())
      {
        clear(attribute);
        return true;
      }
      Map<ByteString, T> valuesToRetain = new HashMap<ByteString, T>(
          values.size());
      for (T value : values)
      {
        valuesToRetain.put(normalizeValue(attribute, ByteString
            .valueOf(value)), value);
      }
      boolean modified = false;
      Iterator<ByteString> iterator = attribute.multipleValues.keySet()
          .iterator();
      while (iterator.hasNext())
      {
        ByteString normalizedValue = iterator.next();
        if (valuesToRetain.remove(normalizedValue) == null)
        {
          modified = true;
          iterator.remove();
        }
      }
      if (missingValues != null)
      {
        missingValues.addAll(valuesToRetain.values());
      }
      resize(attribute);
      return modified;
    }
    int size(LinkedAttribute attribute)
    {
      return attribute.multipleValues.size();
    }
  }
  private static final class SingleValueImpl extends Impl
  {
    boolean add(LinkedAttribute attribute, ByteString value)
    {
      ByteString normalizedValue = normalizeValue(attribute, value);
      if (attribute.normalizedSingleValue().equals(normalizedValue))
      {
        return false;
      }
      attribute.multipleValues = new LinkedHashMap<ByteString, ByteString>(
          2);
      attribute.multipleValues.put(attribute.normalizedSingleValue,
          attribute.singleValue);
      attribute.multipleValues.put(normalizedValue, value);
      attribute.singleValue = null;
      attribute.normalizedSingleValue = null;
      attribute.pimpl = MULTI_VALUE_IMPL;
      return true;
    }
    void clear(LinkedAttribute attribute)
    {
      attribute.singleValue = null;
      attribute.normalizedSingleValue = null;
      attribute.pimpl = ZERO_VALUE_IMPL;
    }
    boolean contains(LinkedAttribute attribute, ByteString value)
    {
      ByteString normalizedValue = normalizeValue(attribute, value);
      return attribute.normalizedSingleValue().equals(normalizedValue);
    }
    void ensureCapacity(LinkedAttribute attribute, int size)
    {
      if (size == 0)
      {
        return;
      }
      attribute.multipleValues = new LinkedHashMap<ByteString, ByteString>(
          1 + size);
      attribute.multipleValues.put(attribute.normalizedSingleValue,
          attribute.singleValue);
      attribute.singleValue = null;
      attribute.normalizedSingleValue = null;
      attribute.pimpl = MULTI_VALUE_IMPL;
    }
    ByteString firstValue(LinkedAttribute attribute)
        throws NoSuchElementException
    {
      if (attribute.singleValue != null)
      {
        return attribute.singleValue;
      }
      else
      {
        throw new NoSuchElementException();
      }
    }
    Iterator<ByteString> iterator(final LinkedAttribute attribute)
    {
      return new Iterator<ByteString>()
      {
        private Impl expectedImpl = SINGLE_VALUE_IMPL;
        private boolean hasNext = true;
        public boolean hasNext()
        {
          return hasNext;
        }
        public ByteString next()
        {
          if (attribute.pimpl != expectedImpl)
          {
            throw new ConcurrentModificationException();
          }
          else if (hasNext)
          {
            hasNext = false;
            return attribute.singleValue;
          }
          else
          {
            throw new NoSuchElementException();
          }
        }
        public void remove()
        {
          if (attribute.pimpl != expectedImpl)
          {
            throw new ConcurrentModificationException();
          }
          else if (hasNext || attribute.singleValue == null)
          {
            throw new IllegalStateException();
          }
          else
          {
            clear(attribute);
            expectedImpl = attribute.pimpl;
          }
        }
      };
    }
    boolean remove(LinkedAttribute attribute, ByteString value)
    {
      if (contains(attribute, value))
      {
        clear(attribute);
        return true;
      }
      else
      {
        return false;
      }
    }
    void resize(LinkedAttribute attribute)
    {
      // Nothing to do.
    }
    <T> boolean retainAll(LinkedAttribute attribute,
        Collection<T> values, Collection<? super T> missingValues)
    {
      // TODO: could optimize if objects is a BasicAttribute.
      if (values.isEmpty())
      {
        clear(attribute);
        return true;
      }
      ByteString normalizedSingleValue = attribute
          .normalizedSingleValue();
      boolean retained = false;
      for (T value : values)
      {
        ByteString normalizedValue = normalizeValue(attribute,
            ByteString.valueOf(value));
        if (normalizedSingleValue.equals(normalizedValue))
        {
          if (missingValues == null)
          {
            // We can stop now.
            return false;
          }
          retained = true;
        }
        else if (missingValues != null)
        {
          missingValues.add(value);
        }
      }
      if (!retained)
      {
        clear(attribute);
        return true;
      }
      else
      {
        return false;
      }
    }
    int size(LinkedAttribute attribute)
    {
      return 1;
    }
  }
  private static final class ZeroValueImpl extends Impl
  {
    boolean add(LinkedAttribute attribute, ByteString value)
    {
      attribute.singleValue = value;
      attribute.pimpl = SINGLE_VALUE_IMPL;
      return true;
    }
    void clear(LinkedAttribute attribute)
    {
      // Nothing to do.
    }
    boolean contains(LinkedAttribute attribute, ByteString value)
    {
      return false;
    }
    boolean containsAll(LinkedAttribute attribute, Collection<?> values)
    {
      return values.isEmpty();
    }
    void ensureCapacity(LinkedAttribute attribute, int size)
    {
      if (size < 2)
      {
        return;
      }
      attribute.multipleValues = new LinkedHashMap<ByteString, ByteString>(
          size);
      attribute.pimpl = MULTI_VALUE_IMPL;
    }
    ByteString firstValue(LinkedAttribute attribute)
        throws NoSuchElementException
    {
      throw new NoSuchElementException();
    }
    Iterator<ByteString> iterator(final LinkedAttribute attribute)
    {
      return new Iterator<ByteString>()
      {
        public boolean hasNext()
        {
          return false;
        }
        public ByteString next()
        {
          if (attribute.pimpl != ZERO_VALUE_IMPL)
          {
            throw new ConcurrentModificationException();
          }
          else
          {
            throw new NoSuchElementException();
          }
        }
        public void remove()
        {
          if (attribute.pimpl != ZERO_VALUE_IMPL)
          {
            throw new ConcurrentModificationException();
          }
          else
          {
            throw new IllegalStateException();
          }
        }
      };
    }
    boolean remove(LinkedAttribute attribute, ByteString value)
    {
      return false;
    }
    void resize(LinkedAttribute attribute)
    {
      // Nothing to do.
    }
    <T> boolean retainAll(LinkedAttribute attribute,
        Collection<T> values, Collection<? super T> missingValues)
    {
      if (missingValues != null)
      {
        missingValues.addAll(values);
      }
      return false;
    }
    int size(LinkedAttribute attribute)
    {
      return 0;
    }
  }
  private static final MultiValueImpl MULTI_VALUE_IMPL = new MultiValueImpl();
  private static final SingleValueImpl SINGLE_VALUE_IMPL = new SingleValueImpl();
  private static final ZeroValueImpl ZERO_VALUE_IMPL = new ZeroValueImpl();
  private final AttributeDescription attributeDescription;
  private Map<ByteString, ByteString> multipleValues = null;
  private ByteString normalizedSingleValue = null;
  private Impl pimpl = ZERO_VALUE_IMPL;
  private ByteString singleValue = null;
  /**
   * Creates a new attribute having the same attribute description and
   * attribute values as {@code attribute}.
   *
   * @param attribute
   *          The attribute to be copied.
   * @throws NullPointerException
   *           If {@code attribute} was {@code null}.
   */
  public LinkedAttribute(Attribute attribute)
      throws NullPointerException
  {
    this.attributeDescription = attribute.getAttributeDescription();
    if (attribute instanceof LinkedAttribute)
    {
      LinkedAttribute other = (LinkedAttribute) attribute;
      this.pimpl = other.pimpl;
      this.singleValue = other.singleValue;
      this.normalizedSingleValue = other.normalizedSingleValue;
      if (other.multipleValues != null)
      {
        this.multipleValues = new LinkedHashMap<ByteString, ByteString>(
            other.multipleValues);
      }
    }
    else
    {
      addAll(attribute);
    }
  }
  /**
   * Creates a new attribute having the specified attribute description
   * and no attribute values.
   *
   * @param attributeDescription
   *          The attribute description.
   * @throws NullPointerException
   *           If {@code attributeDescription} was {@code null}.
   */
  public LinkedAttribute(AttributeDescription attributeDescription)
      throws NullPointerException
  {
    Validator.ensureNotNull(attributeDescription);
    this.attributeDescription = attributeDescription;
  }
  /**
   * Creates a new attribute having the specified attribute description
   * and no attribute values. The attribute description will be decoded
   * using the default schema.
   *
   * @param attributeDescription
   *          The attribute description.
   * @throws LocalizedIllegalArgumentException
   *           If {@code attributeDescription} could not be decoded
   *           using the default schema.
   * @throws NullPointerException
   *           If {@code attributeDescription} was {@code null}.
   */
  public LinkedAttribute(String attributeDescription)
      throws LocalizedIllegalArgumentException, NullPointerException
  {
    this(AttributeDescription.valueOf(attributeDescription));
  }
  /**
   * Creates a new attribute having the specified attribute description
   * and single attribute value.
   *
   * @param attributeDescription
   *          The attribute description.
   * @param value
   *          The single attribute value.
   * @throws NullPointerException
   *           If {@code attributeDescription} or {@code value} was
   *           {@code null}.
   */
  public LinkedAttribute(AttributeDescription attributeDescription,
      ByteString value) throws NullPointerException
  {
    this(attributeDescription);
    add(value);
  }
  /**
   * Creates a new attribute having the specified attribute description
   * and attribute values.
   *
   * @param attributeDescription
   *          The attribute description.
   * @param values
   *          The attribute values.
   * @throws NullPointerException
   *           If {@code attributeDescription} or {@code values} was
   *           {@code null}.
   */
  public LinkedAttribute(AttributeDescription attributeDescription,
      ByteString... values) throws NullPointerException
  {
    this(attributeDescription);
    addAll(Arrays.asList(values));
  }
  /**
   * Creates a new attribute having the specified attribute description
   * and attribute values.
   *
   * @param attributeDescription
   *          The attribute description.
   * @param values
   *          The attribute values.
   * @throws NullPointerException
   *           If {@code attributeDescription} or {@code values} was
   *           {@code null}.
   */
  public LinkedAttribute(AttributeDescription attributeDescription,
      Collection<ByteString> values) throws NullPointerException
  {
    this(attributeDescription);
    addAll(values);
  }
  /**
   * Creates a new attribute having the specified attribute description
   * and single attribute value. The attribute description will be
   * decoded using the default schema.
   * <p>
   * If {@code value} is not an instance of {@code ByteString} then it
   * will be converted using the {@link ByteString#valueOf(Object)}
   * method.
   *
   * @param attributeDescription
   *          The attribute description.
   * @param value
   *          The single attribute value.
   * @throws LocalizedIllegalArgumentException
   *           If {@code attributeDescription} could not be decoded
   *           using the default schema.
   * @throws NullPointerException
   *           If {@code attributeDescription} or {@code value} was
   *           {@code null}.
   */
  public LinkedAttribute(String attributeDescription, Object value)
      throws LocalizedIllegalArgumentException, NullPointerException
  {
    this(attributeDescription);
    add(ByteString.valueOf(value));
  }
  /**
   * Creates a new attribute having the specified attribute description
   * and attribute values. The attribute description will be decoded
   * using the default schema.
   * <p>
   * Any attribute values which are not instances of {@code ByteString}
   * will be converted using the {@link ByteString#valueOf(Object)}
   * method.
   *
   * @param attributeDescription
   *          The attribute description.
   * @param values
   *          The attribute values.
   * @throws LocalizedIllegalArgumentException
   *           If {@code attributeDescription} could not be decoded
   *           using the default schema.
   * @throws NullPointerException
   *           If {@code attributeDescription} or {@code values} was
   *           {@code null}.
   */
  public LinkedAttribute(String attributeDescription, Object... values)
      throws LocalizedIllegalArgumentException, NullPointerException
  {
    this(attributeDescription);
    for (Object value : values)
    {
      add(ByteString.valueOf(value));
    }
  }
  /**
   * {@inheritDoc}
   */
  public boolean add(ByteString value) throws NullPointerException
  {
    Validator.ensureNotNull(value);
    return pimpl.add(this, value);
  }
  /**
   * {@inheritDoc}
   */
  public boolean addAll(Collection<? extends ByteString> values,
      Collection<? super ByteString> duplicateValues)
      throws NullPointerException
  {
    Validator.ensureNotNull(values);
    return pimpl.addAll(this, values, duplicateValues);
  }
  /**
   * {@inheritDoc}
   */
  public void clear()
  {
    pimpl.clear(this);
  }
  /**
   * {@inheritDoc}
   */
  public boolean containsAll(Collection<?> values)
      throws NullPointerException
  {
    Validator.ensureNotNull(values);
    return pimpl.containsAll(this, values);
  }
  /**
   * {@inheritDoc}
   */
  public ByteString firstValue() throws NoSuchElementException
  {
    return pimpl.firstValue(this);
  }
  /**
   * {@inheritDoc}
   */
  public AttributeDescription getAttributeDescription()
  {
    return attributeDescription;
  }
  /**
   * {@inheritDoc}
   */
  public Iterator<ByteString> iterator()
  {
    return pimpl.iterator(this);
  }
  /**
   * {@inheritDoc}
   */
  public <T> boolean removeAll(Collection<T> values,
      Collection<? super T> missingValues) throws NullPointerException
  {
    Validator.ensureNotNull(values);
    return pimpl.removeAll(this, values, missingValues);
  }
  /**
   * {@inheritDoc}
   */
  public <T> boolean retainAll(Collection<T> values,
      Collection<? super T> missingValues) throws NullPointerException
  {
    Validator.ensureNotNull(values);
    return pimpl.retainAll(this, values, missingValues);
  }
  /**
   * {@inheritDoc}
   */
  public int size()
  {
    return pimpl.size(this);
  }
  /**
   * {@inheritDoc}
   */
  public boolean contains(Object value) throws NullPointerException
  {
    Validator.ensureNotNull(value);
    return pimpl.contains(this, ByteString.valueOf(value));
  }
  /**
   * {@inheritDoc}
   */
  public boolean remove(Object value) throws NullPointerException
  {
    Validator.ensureNotNull(value);
    return pimpl.remove(this, ByteString.valueOf(value));
  }
  // Lazily computes the normalized single value.
  private ByteString normalizedSingleValue()
  {
    if (normalizedSingleValue == null)
    {
      normalizedSingleValue = normalizeValue(this, singleValue);
    }
    return normalizedSingleValue;
  }
}
opendj-sdk/sdk/src/org/opends/sdk/Matcher.java
New file
@@ -0,0 +1,871 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Copyright 2009 Sun Microsystems, Inc.
 */
package org.opends.sdk;
import static org.opends.sdk.util.StaticUtils.*;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import org.opends.sdk.schema.MatchingRule;
import org.opends.sdk.schema.MatchingRuleUse;
import org.opends.sdk.schema.Schema;
import org.opends.sdk.schema.UnknownSchemaElementException;
import org.opends.sdk.util.ByteSequence;
import org.opends.sdk.util.ByteString;
import org.opends.sdk.util.LocalizedIllegalArgumentException;
import org.opends.sdk.util.StaticUtils;
/**
 * An interface for determining whether entries match a {@code Filter}.
 */
public final class Matcher
{
  private static class AndMatcherImpl extends MatcherImpl
  {
    private final List<MatcherImpl> subMatchers;
    private AndMatcherImpl(List<MatcherImpl> subMatchers)
    {
      this.subMatchers = subMatchers;
    }
    @Override
    public ConditionResult matches(Entry entry)
    {
      ConditionResult r = ConditionResult.TRUE;
      for (final MatcherImpl m : subMatchers)
      {
        final ConditionResult p = m.matches(entry);
        if (p == ConditionResult.FALSE)
        {
          return p;
        }
        r = ConditionResult.and(r, p);
      }
      return r;
    }
  }
  private static class AssertionMatcherImpl extends MatcherImpl
  {
    private final Assertion assertion;
    private final AttributeDescription attributeDescription;
    private final boolean dnAttributes;
    private final MatchingRule rule;
    private final MatchingRuleUse ruleUse;
    private AssertionMatcherImpl(
        AttributeDescription attributeDescription, MatchingRule rule,
        MatchingRuleUse ruleUse, Assertion assertion,
        boolean dnAttributes)
    {
      this.attributeDescription = attributeDescription;
      this.rule = rule;
      this.ruleUse = ruleUse;
      this.assertion = assertion;
      this.dnAttributes = dnAttributes;
    }
    @Override
    public ConditionResult matches(Entry entry)
    {
      ConditionResult r = ConditionResult.FALSE;
      if (attributeDescription != null)
      {
        // If the matchingRule field is absent, the type field will be
        // present and the default equality matching rule is used,
        // and an equality match is performed for that type.
        // If the type field is present and the matchingRule is present,
        // the matchValue is compared against the specified attribute
        // type and its subtypes.
        final ConditionResult p = Matcher.matches(
            entry.getAttribute(attributeDescription), rule, assertion);
        if (p == ConditionResult.TRUE)
        {
          return p;
        }
        r = ConditionResult.or(r, p);
      }
      else
      {
        // If the type field is absent and the matchingRule is present,
        // the matchValue is compared against all attributes in an entry
        // that support that matchingRule.
        for (final Attribute a : entry.getAttributes())
        {
          if (ruleUse.hasAttribute(a.getAttributeDescription()
              .getAttributeType()))
          {
            final ConditionResult p = Matcher.matches(a, rule, assertion);
            if (p == ConditionResult.TRUE)
            {
              return p;
            }
            r = ConditionResult.or(r, p);
          }
        }
      }
      if (dnAttributes)
      {
        // If the dnAttributes field is set to TRUE, the match is
        // additionally applied against all the AttributeValueAssertions
        // in an entry's distinguished name, and it evaluates to TRUE if
        // there is at least one attribute or subtype in the
        // distinguished name for which the filter item evaluates to
        // TRUE.
        final DN dn = entry.getName();
        for (final RDN rdn : dn)
        {
          for (final RDN.AVA ava : rdn)
          {
            if (ruleUse.hasAttribute(ava.getAttributeType()))
            {
              final ConditionResult p =
                  Matcher.matches(ava.getAttributeValue(), rule, assertion);
              if (p == ConditionResult.TRUE)
              {
                return p;
              }
              r = ConditionResult.or(r, p);
            }
          }
        }
      }
      return r;
    }
  }
  private static class FalseMatcherImpl extends MatcherImpl
  {
    @Override
    public ConditionResult matches(Entry entry)
    {
      return ConditionResult.FALSE;
    }
  }
  private static abstract class MatcherImpl
  {
    public abstract ConditionResult matches(Entry entry);
  }
  private static class NotMatcherImpl extends MatcherImpl
  {
    private final MatcherImpl subFilter;
    private NotMatcherImpl(MatcherImpl subFilter)
    {
      this.subFilter = subFilter;
    }
    @Override
    public ConditionResult matches(Entry entry)
    {
      return ConditionResult.not(subFilter.matches(entry));
    }
  }
  private static class OrMatcherImpl extends MatcherImpl
  {
    private final List<MatcherImpl> subMatchers;
    private OrMatcherImpl(List<MatcherImpl> subMatchers)
    {
      this.subMatchers = subMatchers;
    }
    @Override
    public ConditionResult matches(Entry entry)
    {
      ConditionResult r = ConditionResult.FALSE;
      for (final MatcherImpl m : subMatchers)
      {
        final ConditionResult p = m.matches(entry);
        if (p == ConditionResult.TRUE)
        {
          return p;
        }
        r = ConditionResult.or(r, p);
      }
      return r;
    }
  }
  private static class PresentMatcherImpl extends MatcherImpl
  {
    private final AttributeDescription attribute;
    private PresentMatcherImpl(AttributeDescription attribute)
    {
      this.attribute = attribute;
    }
    @Override
    public ConditionResult matches(Entry entry)
    {
      return entry.getAttribute(attribute) == null ? ConditionResult.FALSE
                                                   : ConditionResult.TRUE;
    }
  }
  private static class TrueMatcherImpl extends MatcherImpl
  {
    @Override
    public ConditionResult matches(Entry entry)
    {
      return ConditionResult.TRUE;
    }
  }
  private static class UndefinedMatcherImpl extends MatcherImpl
  {
    @Override
    public ConditionResult matches(Entry entry)
    {
      return ConditionResult.UNDEFINED;
    }
  }
  /**
   * A visitor which is used to transform a filter into a matcher.
   */
  private static final class Visitor implements
                                     FilterVisitor<MatcherImpl, Schema>
  {
    public MatcherImpl visitAndFilter(Schema schema,
                                      List<Filter> subFilters)
    {
      if (subFilters.isEmpty())
      {
        if(DEBUG_LOG.isLoggable(Level.FINER))
        {
          DEBUG_LOG.finer("Empty add filter component. " +
                          "Will always return TRUE");
        }
        return TRUE;
      }
      final List<MatcherImpl> subMatchers =
          new ArrayList<MatcherImpl>(subFilters.size());
      for (final Filter f : subFilters)
      {
        subMatchers.add(f.accept(this, schema));
      }
      return new AndMatcherImpl(subMatchers);
    }
    public MatcherImpl visitApproxMatchFilter(Schema schema,
                                              String attributeDescription, ByteSequence assertionValue)
    {
      AttributeDescription ad;
      MatchingRule rule;
      Assertion assertion;
      try
      {
        ad = AttributeDescription.valueOf(attributeDescription, schema);
      }
      catch (final LocalizedIllegalArgumentException e)
      {
        if(DEBUG_LOG.isLoggable(Level.WARNING))
        {
          DEBUG_LOG.warning(
              "Attribute description " + attributeDescription  +
              " is not recognized: " + e.toString());
        }
        return UNDEFINED;
      }
      if ((rule = ad.getAttributeType().getApproximateMatchingRule()) == null)
      {
        if(DEBUG_LOG.isLoggable(Level.WARNING))
        {
          DEBUG_LOG.warning(
              "The attribute type " + attributeDescription +
              " does not define an approximate matching rule");
        }
        return UNDEFINED;
      }
      try
      {
        assertion = rule.getAssertion(assertionValue);
      }
      catch (final DecodeException de)
      {
        if(DEBUG_LOG.isLoggable(Level.WARNING))
        {
          DEBUG_LOG.warning(
              "The assertion value " + assertionValue + " is invalid: " +
              de.toString());
        }
        return UNDEFINED;
      }
      return new AssertionMatcherImpl(ad, rule, null, assertion, false);
    }
    public MatcherImpl visitEqualityMatchFilter(Schema schema,
                                                String attributeDescription, ByteSequence assertionValue)
    {
      AttributeDescription ad;
      MatchingRule rule;
      Assertion assertion;
      try
      {
        ad = AttributeDescription.valueOf(attributeDescription, schema);
      }
      catch (final LocalizedIllegalArgumentException e)
      {
        if(DEBUG_LOG.isLoggable(Level.WARNING))
        {
          DEBUG_LOG.warning(
              "Attribute description " + attributeDescription  +
              " is not recognized: " + e.toString());
        }
        return UNDEFINED;
      }
      if ((rule = ad.getAttributeType().getEqualityMatchingRule()) == null)
      {
        if(DEBUG_LOG.isLoggable(Level.WARNING))
        {
          DEBUG_LOG.warning(
              "The attribute type " + attributeDescription +
              " does not define an equality matching rule");
        }
        return UNDEFINED;
      }
      try
      {
        assertion = rule.getAssertion(assertionValue);
      }
      catch (final DecodeException de)
      {
        if(DEBUG_LOG.isLoggable(Level.WARNING))
        {
          DEBUG_LOG.warning(
              "The assertion value " + assertionValue + " is invalid: " +
              de.toString());
        }
        return UNDEFINED;
      }
      return new AssertionMatcherImpl(ad, rule, null, assertion, false);
    }
    public MatcherImpl visitExtensibleMatchFilter(Schema schema,
                                                  String matchingRule,
                                                  String attributeDescription,
                                                  ByteSequence assertionValue,
                                                  boolean dnAttributes)
    {
      AttributeDescription ad = null;
      MatchingRule rule = null;
      MatchingRuleUse ruleUse = null;
      Assertion assertion;
      if (matchingRule != null)
      {
        try
        {
          rule = schema.getMatchingRule(matchingRule);
        }
        catch(final UnknownSchemaElementException e)
        {
          if(DEBUG_LOG.isLoggable(Level.WARNING))
          {
            DEBUG_LOG.warning(
                "Matching rule " + matchingRule  + " is not recognized: " +
                e.toString());
          }
          return UNDEFINED;
        }
      }
      if (attributeDescription != null)
      {
        try
        {
          ad =
              AttributeDescription
                  .valueOf(attributeDescription, schema);
        }
        catch (final LocalizedIllegalArgumentException e)
        {
          if(DEBUG_LOG.isLoggable(Level.WARNING))
          {
            DEBUG_LOG.warning(
                "Attribute description " + attributeDescription  +
                " is not recognized: " + e.toString());
          }
          return UNDEFINED;
        }
        if (rule == null)
        {
          if ((rule = ad.getAttributeType().getEqualityMatchingRule()) == null)
          {
            if(DEBUG_LOG.isLoggable(Level.WARNING))
            {
              DEBUG_LOG.warning(
                  "The attribute type " + attributeDescription +
                  " does not define an equality matching rule");
            }
            return UNDEFINED;
          }
        }
        else
        {
          try
          {
            ruleUse = schema.getMatchingRuleUse(rule);
          }
          catch(final UnknownSchemaElementException e)
          {
            if(DEBUG_LOG.isLoggable(Level.WARNING))
            {
              DEBUG_LOG.warning("No matching rule use is defined for " +
                                "matching rule " + matchingRule);
              return UNDEFINED;
            }
          }
          if(!ruleUse.hasAttribute(ad.getAttributeType()))
          {
            if(DEBUG_LOG.isLoggable(Level.WARNING))
            {
              DEBUG_LOG.warning("The matching rule " + matchingRule +
                                " is not valid for attribute type " +
                                attributeDescription);
            }
            return UNDEFINED;
          }
        }
      }
      else
      {
        try
        {
          ruleUse = schema.getMatchingRuleUse(rule);
        }
        catch(final UnknownSchemaElementException e)
        {
          if(DEBUG_LOG.isLoggable(Level.WARNING))
          {
            DEBUG_LOG.warning("No matching rule use is defined for " +
                              "matching rule " + matchingRule);
          }
          return UNDEFINED;
        }
      }
      try
      {
        assertion = rule.getAssertion(assertionValue);
      }
      catch (final DecodeException de)
      {
        if(DEBUG_LOG.isLoggable(Level.WARNING))
        {
          DEBUG_LOG.warning(
              "The assertion value " + assertionValue + " is invalid: " +
              de.toString());
        }
        return UNDEFINED;
      }
      return new AssertionMatcherImpl(ad, rule, ruleUse, assertion,
                                      dnAttributes);
    }
    public MatcherImpl visitGreaterOrEqualFilter(Schema schema,
                                                 String attributeDescription,
                                                 ByteSequence assertionValue)
    {
      AttributeDescription ad;
      MatchingRule rule;
      Assertion assertion;
      try
      {
        ad = AttributeDescription.valueOf(attributeDescription, schema);
      }
      catch (final LocalizedIllegalArgumentException e)
      {
        if(DEBUG_LOG.isLoggable(Level.WARNING))
        {
          DEBUG_LOG.warning(
              "Attribute description " + attributeDescription  +
              " is not recognized: " + e.toString());
        }
        return UNDEFINED;
      }
      if ((rule = ad.getAttributeType().getOrderingMatchingRule()) == null)
      {
        if(DEBUG_LOG.isLoggable(Level.WARNING))
        {
          DEBUG_LOG.warning(
              "The attribute type " + attributeDescription +
              " does not define an ordering matching rule");
        }
        return UNDEFINED;
      }
      try
      {
        assertion = rule.getGreaterOrEqualAssertion(assertionValue);
      }
      catch (final DecodeException de)
      {
        if(DEBUG_LOG.isLoggable(Level.WARNING))
        {
          DEBUG_LOG.warning(
              "The assertion value " + assertionValue + " is invalid: " +
              de.toString());
        }
        return UNDEFINED;
      }
      return new AssertionMatcherImpl(ad, rule, null, assertion, false);
    }
    public MatcherImpl visitLessOrEqualFilter(Schema schema,
                                              String attributeDescription,
                                              ByteSequence assertionValue)
    {
      AttributeDescription ad;
      MatchingRule rule;
      Assertion assertion;
      try
      {
        ad = AttributeDescription.valueOf(attributeDescription, schema);
      }
      catch (final LocalizedIllegalArgumentException e)
      {
        if(DEBUG_LOG.isLoggable(Level.WARNING))
        {
          DEBUG_LOG.warning(
              "Attribute description " + attributeDescription  +
              " is not recognized: " + e.toString());
        }
        return UNDEFINED;
      }
      if ((rule = ad.getAttributeType().getOrderingMatchingRule()) == null)
      {
        if(DEBUG_LOG.isLoggable(Level.WARNING))
        {
          DEBUG_LOG.warning(
              "The attribute type " + attributeDescription +
              " does not define an ordering matching rule");
        }
        return UNDEFINED;
      }
      try
      {
        assertion = rule.getLessOrEqualAssertion(assertionValue);
      }
      catch (final DecodeException de)
      {
        if(DEBUG_LOG.isLoggable(Level.WARNING))
        {
          DEBUG_LOG.warning(
              "The assertion value " + assertionValue + " is invalid: " +
              de.toString());
        }
        return UNDEFINED;
      }
      return new AssertionMatcherImpl(ad, rule, null, assertion, false);
    }
    public MatcherImpl visitNotFilter(Schema schema, Filter subFilter)
    {
      final MatcherImpl subMatcher = subFilter.accept(this, schema);
      return new NotMatcherImpl(subMatcher);
    }
    public MatcherImpl visitOrFilter(Schema schema,
                                     List<Filter> subFilters)
    {
      if (subFilters.isEmpty())
      {
        if(DEBUG_LOG.isLoggable(Level.FINER))
        {
          DEBUG_LOG.finer("Empty or filter component. " +
                          "Will always return FALSE");
        }
        return FALSE;
      }
      final List<MatcherImpl> subMatchers =
          new ArrayList<MatcherImpl>(subFilters.size());
      for (final Filter f : subFilters)
      {
        subMatchers.add(f.accept(this, schema));
      }
      return new OrMatcherImpl(subMatchers);
    }
    public MatcherImpl visitPresentFilter(Schema schema,
                                          String attributeDescription)
    {
      AttributeDescription ad;
      try
      {
        ad = AttributeDescription.valueOf(attributeDescription, schema);
      }
      catch (final LocalizedIllegalArgumentException e)
      {
        if(DEBUG_LOG.isLoggable(Level.WARNING))
        {
          DEBUG_LOG.warning(
              "Attribute description " + attributeDescription  +
              " is not recognized: " + e.toString());
        }
        return UNDEFINED;
      }
      return new PresentMatcherImpl(ad);
    }
    public MatcherImpl visitSubstringsFilter(Schema schema,
                                             String attributeDescription,
                                             ByteSequence initialSubstring,
                                             List<ByteSequence> anySubstrings,
                                             ByteSequence finalSubstring)
    {
      AttributeDescription ad;
      MatchingRule rule;
      Assertion assertion;
      try
      {
        ad = AttributeDescription.valueOf(attributeDescription, schema);
      }
      catch (final LocalizedIllegalArgumentException e)
      {
        if(DEBUG_LOG.isLoggable(Level.WARNING))
        {
          DEBUG_LOG.warning(
              "Attribute description " + attributeDescription  +
              " is not recognized: " + e.toString());
        }
        return UNDEFINED;
      }
      if ((rule = ad.getAttributeType().getSubstringMatchingRule()) == null)
      {
        if(DEBUG_LOG.isLoggable(Level.WARNING))
        {
          DEBUG_LOG.warning(
              "The attribute type " + attributeDescription +
              " does not define an substring matching rule");
        }
        return UNDEFINED;
      }
      try
      {
        assertion =
            rule.getAssertion(initialSubstring, anySubstrings,
                              finalSubstring);
      }
      catch (final DecodeException de)
      {
        if(DEBUG_LOG.isLoggable(Level.WARNING))
        {
          DEBUG_LOG.warning(
              "The substring assertion values contain an invalid value: " +
              de.toString());
        }
        return UNDEFINED;
      }
      return new AssertionMatcherImpl(ad, rule, null, assertion, false);
    }
    public MatcherImpl visitUnrecognizedFilter(Schema schema,
                                               byte filterTag,
                                               ByteSequence filterBytes)
    {
      if(DEBUG_LOG.isLoggable(Level.WARNING))
      {
        DEBUG_LOG.warning("The type of filtering requested with tag " +
                          StaticUtils.byteToHex(filterTag) +
                          " is not implemented");
      }
      return UNDEFINED;
    }
  }
  private static final MatcherImpl FALSE = new FalseMatcherImpl();
  private static final MatcherImpl TRUE = new TrueMatcherImpl();
  private static final MatcherImpl UNDEFINED =
      new UndefinedMatcherImpl();
  private static final FilterVisitor<MatcherImpl, Schema> VISITOR =
      new Visitor();
  private static ConditionResult matches(Attribute a,
                                         MatchingRule rule, Assertion assertion)
  {
    ConditionResult r = ConditionResult.FALSE;
    if (a != null)
    {
      for (final ByteString v : a)
      {
        switch (matches(v, rule, assertion))
        {
          case TRUE:
            return ConditionResult.TRUE;
          case UNDEFINED:
            r = ConditionResult.UNDEFINED;
        }
      }
    }
    return r;
  }
  private static ConditionResult matches(ByteString v,
                                         MatchingRule rule, Assertion assertion)
  {
    try
    {
      final ByteString normalizedValue =
          rule.normalizeAttributeValue(v);
      return assertion.matches(normalizedValue);
    }
    catch (final DecodeException de)
    {
      if(DEBUG_LOG.isLoggable(Level.WARNING))
      {
        DEBUG_LOG.warning("The attribute value " + v.toString() + " is " +
                         "invalid for matching rule " + rule.getNameOrOID() +
                         ". Possible schema error? : " + de.toString());
      }
      return ConditionResult.UNDEFINED;
    }
  }
  private final MatcherImpl impl;
  Matcher(Filter filter, Schema schema)
  {
    this.impl = filter.accept(VISITOR, schema);
  }
  /**
   * Indicates whether this filter {@code Matcher} matches the provided
   * {@code Entry}.
   *
   * @param entry
   *          The entry to be matched.
   * @return {@code true} if this filter {@code Matcher} matches the
   *         provided {@code Entry}.
   */
  public ConditionResult matches(Entry entry)
  {
    return impl.matches(entry);
  }
}
opendj-sdk/sdk/src/org/opends/sdk/ModificationType.java
New file
@@ -0,0 +1,212 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Copyright 2009 Sun Microsystems, Inc.
 */
package org.opends.sdk;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
/**
 * A Modify operation change type as defined in RFC 4511 section 4.6 is
 * used to specify the type of modification being performed on an
 * attribute.
 *
 * @see <a href="http://tools.ietf.org/html/rfc4511#section-4.6">RFC
 *      4511 - Lightweight Directory Access Protocol (LDAP): The
 *      Protocol </a>
 * @see <a href="http://tools.ietf.org/html/rfc4525">RFC 4525 -
 *      Lightweight Directory Access Protocol (LDAP) Modify-Increment
 *      Extension </a>
 */
public final class ModificationType
{
  private static final ModificationType[] ELEMENTS = new ModificationType[4];
  private static final List<ModificationType> IMMUTABLE_ELEMENTS = Collections
      .unmodifiableList(Arrays.asList(ELEMENTS));
  /**
   * Add the values listed in the modification to the attribute,
   * creating the attribute if necessary.
   */
  public static final ModificationType ADD = register(0, "add");
  /**
   * Delete the values listed in the modification from the attribute. If
   * no values are listed, or if all current values of the attribute are
   * listed, the entire attribute is removed.
   */
  public static final ModificationType DELETE = register(1, "delete");
  /**
   * Replace all existing values of the attribute with the new values
   * listed in the modification, creating the attribute if it did not
   * already exist. A replace with no listed values will delete the
   * entire attribute if it exists, and it is ignored if the attribute
   * does not exist.
   */
  public static final ModificationType REPLACE = register(2, "replace");
  /**
   * Increment all existing values of the attribute by the amount
   * specified in the modification value.
   */
  public static final ModificationType INCREMENT = register(3,
      "increment");
  /**
   * Creates and registers a new modification change type with the
   * application.
   *
   * @param intValue
   *          The integer value of the modification change type as
   *          defined in RFC 4511 section 4.6.
   * @param name
   *          The name of the modification change type.
   * @return The new modification change type.
   */
  private static ModificationType register(int intValue, String name)
  {
    ModificationType t = new ModificationType(intValue, name);
    ELEMENTS[intValue] = t;
    return t;
  }
  /**
   * Returns the modification change type having the specified integer
   * value as defined in RFC 4511 section 4.6.
   *
   * @param intValue
   *          The integer value of the modification change type.
   * @return The modification change type, or {@code null} if there was
   *         no modification change type associated with {@code
   *         intValue}.
   */
  public static ModificationType valueOf(int intValue)
  {
    if (intValue < 0 || intValue >= ELEMENTS.length)
    {
      return null;
    }
    return ELEMENTS[intValue];
  }
  /**
   * Returns an unmodifiable list containing the set of available
   * modification change types indexed on their integer value as defined
   * in RFC 4511 section 4.6.
   *
   * @return An unmodifiable list containing the set of available
   *         modification change types.
   */
  public static List<ModificationType> values()
  {
    return IMMUTABLE_ELEMENTS;
  }
  private final int intValue;
  private final String name;
  // Prevent direct instantiation.
  private ModificationType(int intValue, String name)
  {
    this.intValue = intValue;
    this.name = name;
  }
  /**
   * {@inheritDoc}
   */
  public boolean equals(Object obj)
  {
    if (this == obj)
    {
      return true;
    }
    else if (obj instanceof ModificationType)
    {
      return this.intValue == ((ModificationType) obj).intValue;
    }
    else
    {
      return false;
    }
  }
  /**
   * {@inheritDoc}
   */
  public int hashCode()
  {
    return intValue;
  }
  /**
   * Returns the integer value of this modification change type as
   * defined in RFC 4511 section 4.6.
   *
   * @return The integer value of this modification change type.
   */
  public int intValue()
  {
    return intValue;
  }
  /**
   * Returns the string representation of this modification change type.
   *
   * @return The string representation of this modification change type.
   */
  public String toString()
  {
    return name;
  }
}
opendj-sdk/sdk/src/org/opends/sdk/RDN.java
New file
@@ -0,0 +1,899 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Copyright 2009 Sun Microsystems, Inc.
 */
package org.opends.sdk;
import static org.opends.messages.SchemaMessages.*;
import static org.opends.sdk.util.StaticUtils.*;
import java.util.*;
import org.opends.messages.Message;
import org.opends.sdk.schema.*;
import org.opends.sdk.util.*;
/**
 * A relative distinguished name (RDN) as defined in RFC 4512 section
 * 2.3 is the name of an entry relative to its immediate superior. An
 * RDN is composed of an unordered set of one or more attribute value
 * assertions (AVA) consisting of an attribute description with zero
 * options and an attribute value. These AVAs are chosen to match
 * attribute values (each a distinguished value) of the entry.
 * <p>
 * An entry's relative distinguished name must be unique among all
 * immediate subordinates of the entry's immediate superior (i.e. all
 * siblings).
 * <p>
 * The following are examples of string representations of RDNs:
 *
 * <pre>
 * uid=12345
 * ou=Engineering
 * cn=Kurt Zeilenga+L=Redwood Shores
 * </pre>
 *
 * The last is an example of a multi-valued RDN; that is, an RDN
 * composed of multiple AVAs.
 * <p>
 * TODO: need more constructors.
 *
 * @see <a href="http://tools.ietf.org/html/rfc4512#section-2.3">RFC
 *      4512 - Lightweight Directory Access Protocol (LDAP): Directory
 *      Information Models </a>
 */
public final class RDN implements Iterable<RDN.AVA>, Comparable<RDN>
{
  /**
   * An attribute value assertion (AVA) as defined in RFC 4512 section
   * 2.3 consists of an attribute description with zero options and an
   * attribute value.
   */
  public static final class AVA implements Comparable<AVA>
  {
    private final AttributeType attributeType;
    private final ByteString attributeValue;
    /**
     * Creates a new attribute value assertion (AVA) using the provided
     * attribute type and value.
     *
     * @param attributeType
     *          The attribute type.
     * @param attributeValue
     *          The attribute value.
     * @throws NullPointerException
     *           If {@code attributeType} or {@code attributeValue} was
     *           {@code null}.
     */
    public AVA(AttributeType attributeType, ByteString attributeValue)
        throws NullPointerException
    {
      Validator.ensureNotNull(attributeType, attributeValue);
      this.attributeType = attributeType;
      this.attributeValue = attributeValue;
    }
    /**
     * {@inheritDoc}
     */
    public int compareTo(AVA ava)
    {
      int result = attributeType.compareTo(ava.attributeType);
      if (result == 0)
      {
        final ByteString nv1 = getNormalizeValue();
        final ByteString nv2 = ava.getNormalizeValue();
        result = nv1.compareTo(nv2);
      }
      return result;
    }
    /**
     * {@inheritDoc}
     */
    public boolean equals(Object obj)
    {
      if (this == obj)
      {
        return true;
      }
      else if (obj instanceof AVA)
      {
        return compareTo((AVA) obj) == 0;
      }
      else
      {
        return false;
      }
    }
    /**
     * Returns the attribute type associated with this AVA.
     *
     * @return The attribute type associated with this AVA.
     */
    public AttributeType getAttributeType()
    {
      return attributeType;
    }
    /**
     * Returns the attribute value associated with this AVA.
     *
     * @return The attribute value associated with this AVA.
     */
    public ByteString getAttributeValue()
    {
      return attributeValue;
    }
    /**
     * {@inheritDoc}
     */
    public int hashCode()
    {
      return attributeType.hashCode() * 31
          + getNormalizeValue().hashCode();
    }
    /**
     * {@inheritDoc}
     */
    public String toString()
    {
      final StringBuilder builder = new StringBuilder();
      return toString(builder).toString();
    }
    private ByteString getNormalizeValue()
    {
      final MatchingRule matchingRule = attributeType
          .getEqualityMatchingRule();
      if (matchingRule != null)
      {
        try
        {
          return matchingRule.normalizeAttributeValue(attributeValue);
        }
        catch (final DecodeException de)
        {
          // Ignore - we'll drop back to the user provided value.
        }
      }
      return attributeValue;
    }
    private StringBuilder toNormalizedString(StringBuilder builder)
    {
      return toString(builder, true);
    }
    private StringBuilder toString(StringBuilder builder)
    {
      return toString(builder, false);
    }
    private StringBuilder toString(StringBuilder builder,
        boolean normalize)
    {
      final ByteString value = normalize ? getNormalizeValue()
          : attributeValue;
      if (!attributeType.getNames().iterator().hasNext())
      {
        builder.append(attributeType.getOID());
        builder.append("=#");
        StaticUtils.toHex(value, builder);
      }
      else
      {
        final String name = attributeType.getNameOrOID();
        if (normalize)
        {
          // Normalizing.
          StaticUtils.toLowerCase(name, builder);
        }
        else
        {
          builder.append(name);
        }
        builder.append("=");
        final Syntax syntax = attributeType.getSyntax();
        if (!syntax.isHumanReadable())
        {
          builder.append("#");
          StaticUtils.toHex(value, builder);
        }
        else
        {
          final String str = value.toString();
          char c;
          for (int si = 0; si < str.length(); si++)
          {
            c = str.charAt(si);
            if (c == ' ' || c == '#' || c == '"' || c == '+'
                || c == ',' || c == ';' || c == '<' || c == '='
                || c == '>' || c == '\\' || c == '\u0000')
            {
              builder.append('\\');
            }
            builder.append(c);
          }
        }
      }
      return builder;
    }
  }
  private static final char[] SPECIAL_CHARS = new char[] { '\"', '+',
      ',', ';', '<', '>', ' ', '#', '=', '\\' };
  private static final char[] DELIMITER_CHARS = new char[] { '+', ',',
      ';' };
  private static final char[] DQUOTE_CHAR = new char[] { '\"' };
  private static final Comparator<AVA> ATV_COMPARATOR = new Comparator<AVA>()
  {
    public int compare(AVA o1, AVA o2)
    {
      return o1.getAttributeType().compareTo(o2.getAttributeType());
    }
  };
  /**
   * Parses the provided LDAP string representation of an RDN using the
   * default schema.
   *
   * @param rdn
   *          The LDAP string representation of a RDN.
   * @return The parsed RDN.
   * @throws LocalizedIllegalArgumentException
   *           If {@code rdn} is not a valid LDAP string representation
   *           of a RDN.
   * @throws NullPointerException
   *           If {@code rdn} was {@code null}.
   */
  public static RDN valueOf(String rdn)
      throws LocalizedIllegalArgumentException
  {
    return valueOf(rdn, Schema.getDefaultSchema());
  }
  /**
   * Parses the provided LDAP string representation of a RDN using the
   * provided schema.
   *
   * @param rdn
   *          The LDAP string representation of a RDN.
   * @param schema
   *          The schema to use when parsing the RDN.
   * @return The parsed RDN.
   * @throws LocalizedIllegalArgumentException
   *           If {@code rdn} is not a valid LDAP string representation
   *           of a RDN.
   * @throws NullPointerException
   *           If {@code rdn} or {@code schema} was {@code null}.
   */
  public static RDN valueOf(String rdn, Schema schema)
      throws LocalizedIllegalArgumentException
  {
    final SubstringReader reader = new SubstringReader(rdn);
    try
    {
      return decode(rdn, reader, schema);
    }
    catch (final UnknownSchemaElementException e)
    {
      final Message message = ERR_RDN_TYPE_NOT_FOUND.get(rdn, e
          .getMessageObject());
      throw new LocalizedIllegalArgumentException(message);
    }
  }
  private static AVA readAttributeTypeAndValue(SubstringReader reader,
      Schema schema) throws LocalizedIllegalArgumentException,
      UnknownSchemaElementException
  {
    // Skip over any spaces at the beginning.
    reader.skipWhitespaces();
    final AttributeType attribute = readDNAttributeName(reader, schema);
    // Make sure that we're not at the end of the DN string because
    // that would be invalid.
    if (reader.remaining() == 0)
    {
      final Message message = ERR_ATTR_SYNTAX_DN_END_WITH_ATTR_NAME
          .get(reader.getString(), attribute.getNameOrOID());
      throw new LocalizedIllegalArgumentException(message);
    }
    // The next character must be an equal sign. If it is not, then
    // that's an error.
    char c;
    if ((c = reader.read()) != '=')
    {
      final Message message = ERR_ATTR_SYNTAX_DN_NO_EQUAL.get(reader
          .getString(), attribute.getNameOrOID(), c);
      throw new LocalizedIllegalArgumentException(message);
    }
    // Skip over any spaces after the equal sign.
    reader.skipWhitespaces();
    // Parse the value for this RDN component.
    final ByteString value = readDNAttributeValue(reader);
    return new AVA(attribute, value);
  }
  private static AttributeType readDNAttributeName(
      SubstringReader reader, Schema schema)
      throws LocalizedIllegalArgumentException,
      UnknownSchemaElementException
  {
    int length = 1;
    reader.mark();
    // The next character must be either numeric (for an OID) or
    // alphabetic (for
    // an attribute description).
    char c = reader.read();
    if (isDigit(c))
    {
      boolean lastWasPeriod = false;
      do
      {
        if (c == '.')
        {
          if (lastWasPeriod)
          {
            final Message message = ERR_ATTR_SYNTAX_OID_CONSECUTIVE_PERIODS
                .get(reader.getString(), reader.pos() - 1);
            throw new LocalizedIllegalArgumentException(message);
          }
          else
          {
            lastWasPeriod = true;
          }
        }
        else if (!isDigit(c))
        {
          // This must have been an illegal character.
          final Message message = ERR_ATTR_SYNTAX_OID_ILLEGAL_CHARACTER
              .get(reader.getString(), reader.pos() - 1);
          throw new LocalizedIllegalArgumentException(message);
        }
        else
        {
          lastWasPeriod = false;
        }
        length++;
      } while ((c = reader.read()) != '=');
    }
    if (isAlpha(c))
    {
      // This must be an attribute description. In this case, we will
      // only
      // accept alphabetic characters, numeric digits, and the hyphen.
      while ((c = reader.read()) != '=')
      {
        if (length == 0 && !isAlpha(c))
        {
          // This is an illegal character.
          final Message message = ERR_ATTR_SYNTAX_DN_ATTR_ILLEGAL_CHAR
              .get(reader.getString(), c, reader.pos() - 1);
          throw new LocalizedIllegalArgumentException(message);
        }
        if (!isAlpha(c) && !isDigit(c) && c != '-')
        {
          // This is an illegal character.
          final Message message = ERR_ATTR_SYNTAX_DN_ATTR_ILLEGAL_CHAR
              .get(reader.getString(), c, reader.pos() - 1);
          throw new LocalizedIllegalArgumentException(message);
        }
        length++;
      }
    }
    else
    {
      final Message message = ERR_ATTR_SYNTAX_DN_ATTR_ILLEGAL_CHAR.get(
          reader.getString(), c, reader.pos() - 1);
      throw new LocalizedIllegalArgumentException(message);
    }
    reader.reset();
    // Return the position of the first non-space character after the
    // token.
    return schema.getAttributeType(reader.read(length));
  }
  private static ByteString readDNAttributeValue(SubstringReader reader)
      throws LocalizedIllegalArgumentException
  {
    // All leading spaces have already been stripped so we can start
    // reading the value. However, it may be empty so check for that.
    if (reader.remaining() == 0)
    {
      return ByteString.empty();
    }
    reader.mark();
    // Look at the first character. If it is an octothorpe (#), then
    // that means that the value should be a hex string.
    char c = reader.read();
    int length = 0;
    if (c == '#')
    {
      // The first two characters must be hex characters.
      reader.mark();
      if (reader.remaining() < 2)
      {
        final Message message = ERR_ATTR_SYNTAX_DN_HEX_VALUE_TOO_SHORT
            .get(reader.getString());
        throw new LocalizedIllegalArgumentException(message);
      }
      for (int i = 0; i < 2; i++)
      {
        c = reader.read();
        if (isHexDigit(c))
        {
          length++;
        }
        else
        {
          final Message message = ERR_ATTR_SYNTAX_DN_INVALID_HEX_DIGIT
              .get(reader.getString(), c);
          throw new LocalizedIllegalArgumentException(message);
        }
      }
      // The rest of the value must be a multiple of two hex
      // characters. The end of the value may be designated by the
      // end of the DN, a comma or semicolon, or a space.
      while (reader.remaining() > 0)
      {
        c = reader.read();
        if (isHexDigit(c))
        {
          length++;
          if (reader.remaining() > 0)
          {
            c = reader.read();
            if (isHexDigit(c))
            {
              length++;
            }
            else
            {
              final Message message = ERR_ATTR_SYNTAX_DN_INVALID_HEX_DIGIT
                  .get(reader.getString(), c);
              throw new LocalizedIllegalArgumentException(message);
            }
          }
          else
          {
            final Message message = ERR_ATTR_SYNTAX_DN_HEX_VALUE_TOO_SHORT
                .get(reader.getString());
            throw new LocalizedIllegalArgumentException(message);
          }
        }
        else if ((c == ' ') || (c == ',') || (c == ';'))
        {
          // This denotes the end of the value.
          break;
        }
        else
        {
          final Message message = ERR_ATTR_SYNTAX_DN_INVALID_HEX_DIGIT
              .get(reader.getString(), c);
          throw new LocalizedIllegalArgumentException(message);
        }
      }
      // At this point, we should have a valid hex string. Convert it
      // to a byte array and set that as the value of the provided
      // octet string.
      try
      {
        reader.reset();
        return ByteString
            .wrap(hexStringToByteArray(reader.read(length)));
      }
      catch (final Exception e)
      {
        final Message message = ERR_ATTR_SYNTAX_DN_ATTR_VALUE_DECODE_FAILURE
            .get(reader.getString(), String.valueOf(e));
        throw new LocalizedIllegalArgumentException(message);
      }
    }
    // If the first character is a quotation mark, then the value
    // should continue until the corresponding closing quotation mark.
    else if (c == '"')
    {
      try
      {
        return StaticUtils.evaluateEscapes(reader, DQUOTE_CHAR, false);
      }
      catch (final DecodeException e)
      {
        throw new LocalizedIllegalArgumentException(e
            .getMessageObject());
      }
    }
    // Otherwise, use general parsing to find the end of the value.
    else
    {
      reader.reset();
      ByteString bytes;
      try
      {
        bytes = StaticUtils.evaluateEscapes(reader, SPECIAL_CHARS,
            DELIMITER_CHARS, true);
      }
      catch (final DecodeException e)
      {
        throw new LocalizedIllegalArgumentException(e
            .getMessageObject());
      }
      if (bytes.length() == 0)
      {
        // We don't allow an empty attribute value.
        final Message message = ERR_ATTR_SYNTAX_DN_INVALID_REQUIRES_ESCAPE_CHAR
            .get(reader.getString(), reader.pos());
        throw new LocalizedIllegalArgumentException(message);
      }
      return bytes;
    }
  }
  // FIXME: ensure that the decoded RDN does not contain multiple AVAs
  // with the same type.
  static RDN decode(String rdnString, SubstringReader reader,
      Schema schema) throws LocalizedIllegalArgumentException,
      UnknownSchemaElementException
  {
    final AVA firstAVA = readAttributeTypeAndValue(reader, schema);
    // Skip over any spaces that might be after the attribute value.
    reader.skipWhitespaces();
    reader.mark();
    if (reader.remaining() > 0 && reader.read() == '+')
    {
      final List<AVA> avas = new ArrayList<AVA>();
      avas.add(firstAVA);
      do
      {
        avas.add(readAttributeTypeAndValue(reader, schema));
        // Skip over any spaces that might be after the attribute value.
        reader.skipWhitespaces();
        reader.mark();
      } while (reader.read() == '+');
      reader.reset();
      return new RDN(avas.toArray(new AVA[avas.size()]), rdnString);
    }
    else
    {
      reader.reset();
      return new RDN(new AVA[] { firstAVA }, rdnString);
    }
  }
  // In original order.
  private final AVA[] avas;
  // We need to store the original string value if provided in order to
  // preserve the original whitespace.
  private String stringValue;
  private RDN(AVA[] avas, String stringValue)
  {
    this.avas = avas;
    this.stringValue = stringValue;
  }
  /**
   * {@inheritDoc}
   */
  public int compareTo(RDN rdn)
  {
    final int sz1 = avas.length;
    final int sz2 = rdn.avas.length;
    if (sz1 != sz2)
    {
      return sz1 - sz2;
    }
    if (sz1 == 1)
    {
      return avas[0].compareTo(rdn.avas[0]);
    }
    // Need to sort the AVAs before comparing.
    final AVA[] a1 = new AVA[sz1];
    System.arraycopy(avas, 0, a1, 0, sz1);
    Arrays.sort(a1, ATV_COMPARATOR);
    final AVA[] a2 = new AVA[sz1];
    System.arraycopy(rdn.avas, 0, a2, 0, sz1);
    Arrays.sort(a2, ATV_COMPARATOR);
    for (int i = 0; i < sz1; i++)
    {
      final int result = a1[i].compareTo(a2[i]);
      if (result != 0)
      {
        return result;
      }
    }
    return 0;
  }
  /**
   * {@inheritDoc}
   */
  public boolean equals(Object obj)
  {
    if (this == obj)
    {
      return true;
    }
    else if (obj instanceof RDN)
    {
      return compareTo((RDN) obj) == 0;
    }
    else
    {
      return false;
    }
  }
  /**
   * Returns the attribute value contained in this RDN which is
   * associated with the provided attribute type, or {@code null} if
   * this RDN does not include such an attribute value.
   *
   * @param attributeType
   *          The attribute type.
   * @return The attribute value.
   */
  public ByteString getAttributeValue(AttributeType attributeType)
  {
    for (final AVA ava : avas)
    {
      if (ava.getAttributeType().equals(attributeType))
      {
        return ava.getAttributeValue();
      }
    }
    return null;
  }
  /**
   * Returns the first AVA contained in this RDN.
   *
   * @return The first AVA contained in this RDN.
   */
  public AVA getFirstAVA()
  {
    return avas[0];
  }
  /**
   * {@inheritDoc}
   */
  public int hashCode()
  {
    // Avoid an algorithm that requires the AVAs to be sorted.
    int hash = 0;
    for (int i = 0; i < avas.length; i++)
    {
      hash += avas[i].hashCode();
    }
    return hash;
  }
  /**
   * Returns {@code true} if this RDN contains more than one AVA.
   *
   * @return {@code true} if this RDN contains more than one AVA,
   *         otherwise {@code false}.
   */
  public boolean isMultiValued()
  {
    return avas.length > 1;
  }
  /**
   * Returns an iterator of the AVAs contained in this RDN. The AVAs
   * will be returned in the user provided order.
   * <p>
   * Attempts to remove AVAs using an iterator's {@code remove()} method
   * are not permitted and will result in an {@code
   * UnsupportedOperationException} being thrown.
   *
   * @return An iterator of the AVAs contained in this RDN.
   */
  public Iterator<AVA> iterator()
  {
    return Iterators.arrayIterator(avas);
  }
  /**
   * Returns the number of AVAs in this RDN.
   *
   * @return The number of AVAs in this RDN.
   */
  public int size()
  {
    return avas.length;
  }
  /**
   * Returns the RFC 4514 string representation of this RDN.
   *
   * @return The RFC 4514 string representation of this RDN.
   * @see <a href="http://tools.ietf.org/html/rfc4514">RFC 4514 -
   *      Lightweight Directory Access Protocol (LDAP): String
   *      Representation of Distinguished Names </a>
   */
  public String toString()
  {
    // We don't care about potential race conditions here.
    if (stringValue == null)
    {
      final StringBuilder builder = new StringBuilder();
      avas[0].toString(builder);
      for (int i = 1; i < avas.length; i++)
      {
        builder.append(',');
        avas[i].toString(builder);
      }
      stringValue = builder.toString();
    }
    return stringValue;
  }
  StringBuilder toNormalizedString(StringBuilder builder)
  {
    final int sz = avas.length;
    if (sz == 1)
    {
      return avas[0].toNormalizedString(builder);
    }
    else
    {
      // Need to sort the AVAs before comparing.
      final AVA[] a = new AVA[sz];
      System.arraycopy(avas, 0, a, 0, sz);
      Arrays.sort(a, ATV_COMPARATOR);
      a[0].toString(builder);
      for (int i = 1; i < sz; i++)
      {
        builder.append(',');
        a[i].toNormalizedString(builder);
      }
      return builder;
    }
  }
  StringBuilder toString(StringBuilder builder)
  {
    return builder.append(toString());
  }
}
opendj-sdk/sdk/src/org/opends/sdk/ResultCode.java
New file
@@ -0,0 +1,764 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Copyright 2009 Sun Microsystems, Inc.
 */
package org.opends.sdk;
import static org.opends.messages.CoreMessages.*;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import org.opends.messages.Message;
/**
 * An operation result code as defined in RFC 4511 section 4.1.9 is used
 * to indicate the final status of an operation. If a server detects
 * multiple errors for an operation, only one result code is returned.
 * The server should return the result code that best indicates the
 * nature of the error encountered. Servers may return substituted
 * result codes to prevent unauthorized disclosures.
 *
 * @see <a href="http://tools.ietf.org/html/rfc4511#section-4.1.9">RFC
 *      4511 - Lightweight Directory Access Protocol (LDAP): The
 *      Protocol </a>
 */
public final class ResultCode
{
  private static final ResultCode[] ELEMENTS = new ResultCode[16655];
  private static final List<ResultCode> IMMUTABLE_ELEMENTS = Collections
      .unmodifiableList(Arrays.asList(ELEMENTS));
  /**
   * The result code that indicates that the operation completed
   * successfully.
   */
  public static final ResultCode SUCCESS = registerSuccessResultCode(0,
      INFO_RESULT_SUCCESS.get());
  /**
   * The result code that indicates that an internal error prevented the
   * operation from being processed properly.
   */
  public static final ResultCode OPERATIONS_ERROR = registerErrorResultCode(
      1, INFO_RESULT_OPERATIONS_ERROR.get());
  /**
   * The result code that indicates that the client sent a malformed or
   * illegal request to the server.
   */
  public static final ResultCode PROTOCOL_ERROR = registerErrorResultCode(
      2, INFO_RESULT_PROTOCOL_ERROR.get());
  /**
   * The result code that indicates that a time limit was exceeded while
   * attempting to process the request.
   */
  public static final ResultCode TIME_LIMIT_EXCEEDED = registerErrorResultCode(
      3, INFO_RESULT_TIME_LIMIT_EXCEEDED.get());
  /**
   * The result code that indicates that a size limit was exceeded while
   * attempting to process the request.
   */
  public static final ResultCode SIZE_LIMIT_EXCEEDED = registerErrorResultCode(
      4, INFO_RESULT_SIZE_LIMIT_EXCEEDED.get());
  /**
   * The result code that indicates that the attribute value assertion
   * included in a compare request did not match the targeted entry.
   */
  public static final ResultCode COMPARE_FALSE = registerSuccessResultCode(
      5, INFO_RESULT_COMPARE_FALSE.get());
  /**
   * The result code that indicates that the attribute value assertion
   * included in a compare request did match the targeted entry.
   */
  public static final ResultCode COMPARE_TRUE = registerSuccessResultCode(
      6, INFO_RESULT_COMPARE_TRUE.get());
  /**
   * The result code that indicates that the requested authentication
   * attempt failed because it referenced an invalid SASL mechanism.
   */
  public static final ResultCode AUTH_METHOD_NOT_SUPPORTED = registerErrorResultCode(
      7, INFO_RESULT_AUTH_METHOD_NOT_SUPPORTED.get());
  /**
   * The result code that indicates that the requested operation could
   * not be processed because it requires that the client has completed
   * a strong form of authentication.
   */
  public static final ResultCode STRONG_AUTH_REQUIRED = registerErrorResultCode(
      8, INFO_RESULT_STRONG_AUTH_REQUIRED.get());
  /**
   * The result code that indicates that a referral was encountered.
   * <p>
   * Strictly speaking this result code should not be exceptional since
   * it is considered as a "success" response. However, referrals should
   * occur rarely in practice and, when they do occur, should not be
   * ignored since the application may believe that a request has
   * succeeded when, in fact, nothing was done.
   */
  public static final ResultCode REFERRAL = registerErrorResultCode(10,
      INFO_RESULT_REFERRAL.get());
  /**
   * The result code that indicates that processing on the requested
   * operation could not continue because an administrative limit was
   * exceeded.
   */
  public static final ResultCode ADMIN_LIMIT_EXCEEDED = registerErrorResultCode(
      11, INFO_RESULT_ADMIN_LIMIT_EXCEEDED.get());
  /**
   * The result code that indicates that the requested operation failed
   * because it included a critical extension that is unsupported or
   * inappropriate for that request.
   */
  public static final ResultCode UNAVAILABLE_CRITICAL_EXTENSION = registerErrorResultCode(
      12, INFO_RESULT_UNAVAILABLE_CRITICAL_EXTENSION.get());
  /**
   * The result code that indicates that the requested operation could
   * not be processed because it requires confidentiality for the
   * communication between the client and the server.
   */
  public static final ResultCode CONFIDENTIALITY_REQUIRED = registerErrorResultCode(
      13, INFO_RESULT_CONFIDENTIALITY_REQUIRED.get());
  /**
   * The result code that should be used for intermediate responses in
   * multi-stage SASL bind operations.
   */
  public static final ResultCode SASL_BIND_IN_PROGRESS = registerSuccessResultCode(
      14, INFO_RESULT_SASL_BIND_IN_PROGRESS.get());
  /**
   * The result code that indicates that the requested operation failed
   * because it targeted an attribute or attribute value that did not
   * exist in the specified entry.
   */
  public static final ResultCode NO_SUCH_ATTRIBUTE = registerErrorResultCode(
      16, INFO_RESULT_NO_SUCH_ATTRIBUTE.get());
  /**
   * The result code that indicates that the requested operation failed
   * because it referenced an attribute that is not defined in the
   * server schema.
   */
  public static final ResultCode UNDEFINED_ATTRIBUTE_TYPE = registerErrorResultCode(
      17, INFO_RESULT_UNDEFINED_ATTRIBUTE_TYPE.get());
  /**
   * The result code that indicates that the requested operation failed
   * because it attempted to perform an inappropriate type of matching
   * against an attribute.
   */
  public static final ResultCode INAPPROPRIATE_MATCHING = registerErrorResultCode(
      18, INFO_RESULT_INAPPROPRIATE_MATCHING.get());
  /**
   * The result code that indicates that the requested operation failed
   * because it would have violated some constraint defined in the
   * server.
   */
  public static final ResultCode CONSTRAINT_VIOLATION = registerErrorResultCode(
      19, INFO_RESULT_CONSTRAINT_VIOLATION.get());
  /**
   * The result code that indicates that the requested operation failed
   * because it would have resulted in a conflict with an existing
   * attribute or attribute value in the target entry.
   */
  public static final ResultCode ATTRIBUTE_OR_VALUE_EXISTS = registerErrorResultCode(
      20, INFO_RESULT_ATTRIBUTE_OR_VALUE_EXISTS.get());
  /**
   * The result code that indicates that the requested operation failed
   * because it violated the syntax for a specified attribute.
   */
  public static final ResultCode INVALID_ATTRIBUTE_SYNTAX = registerErrorResultCode(
      21, INFO_RESULT_INVALID_ATTRIBUTE_SYNTAX.get());
  /**
   * The result code that indicates that the requested operation failed
   * because it referenced an entry that does not exist.
   */
  public static final ResultCode NO_SUCH_OBJECT = registerErrorResultCode(
      32, INFO_RESULT_NO_SUCH_OBJECT.get());
  /**
   * The result code that indicates that the requested operation failed
   * because it attempted to perform an illegal operation on an alias.
   */
  public static final ResultCode ALIAS_PROBLEM = registerErrorResultCode(
      33, INFO_RESULT_ALIAS_PROBLEM.get());
  /**
   * The result code that indicates that the requested operation failed
   * because it would have resulted in an entry with an invalid or
   * malformed DN.
   */
  public static final ResultCode INVALID_DN_SYNTAX = registerErrorResultCode(
      34, INFO_RESULT_INVALID_DN_SYNTAX.get());
  /**
   * The result code that indicates that a problem was encountered while
   * attempting to dereference an alias for a search operation.
   */
  public static final ResultCode ALIAS_DEREFERENCING_PROBLEM = registerErrorResultCode(
      36, INFO_RESULT_ALIAS_DEREFERENCING_PROBLEM.get());
  /**
   * The result code that indicates that an authentication attempt
   * failed because the requested type of authentication was not
   * appropriate for the targeted entry.
   */
  public static final ResultCode INAPPROPRIATE_AUTHENTICATION = registerErrorResultCode(
      48, INFO_RESULT_INAPPROPRIATE_AUTHENTICATION.get());
  /**
   * The result code that indicates that an authentication attempt
   * failed because the user did not provide a valid set of credentials.
   */
  public static final ResultCode INVALID_CREDENTIALS = registerErrorResultCode(
      49, INFO_RESULT_INVALID_CREDENTIALS.get());
  /**
   * The result code that indicates that the client does not have
   * sufficient permission to perform the requested operation.
   */
  public static final ResultCode INSUFFICIENT_ACCESS_RIGHTS = registerErrorResultCode(
      50, INFO_RESULT_INSUFFICIENT_ACCESS_RIGHTS.get());
  /**
   * The result code that indicates that the server is too busy to
   * process the requested operation.
   */
  public static final ResultCode BUSY = registerErrorResultCode(51,
      INFO_RESULT_BUSY.get());
  /**
   * The result code that indicates that either the entire server or one
   * or more required resources were not available for use in processing
   * the request.
   */
  public static final ResultCode UNAVAILABLE = registerErrorResultCode(
      52, INFO_RESULT_UNAVAILABLE.get());
  /**
   * The result code that indicates that the server is unwilling to
   * perform the requested operation.
   */
  public static final ResultCode UNWILLING_TO_PERFORM = registerErrorResultCode(
      53, INFO_RESULT_UNWILLING_TO_PERFORM.get());
  /**
   * The result code that indicates that a referral or chaining loop was
   * detected while processing the request.
   */
  public static final ResultCode LOOP_DETECT = registerErrorResultCode(
      54, INFO_RESULT_LOOP_DETECT.get());
  /**
   * The result code that indicates that a search request included a VLV
   * request control without a server-side sort control.
   */
  public static final ResultCode SORT_CONTROL_MISSING = registerErrorResultCode(
      60, INFO_RESULT_SORT_CONTROL_MISSING.get());
  /**
   * The result code that indicates that a search request included a VLV
   * request control with an invalid offset.
   */
  public static final ResultCode OFFSET_RANGE_ERROR = registerErrorResultCode(
      61, INFO_RESULT_OFFSET_RANGE_ERROR.get());
  /**
   * The result code that indicates that the requested operation failed
   * because it would have violated the server's naming configuration.
   */
  public static final ResultCode NAMING_VIOLATION = registerErrorResultCode(
      64, INFO_RESULT_NAMING_VIOLATION.get());
  /**
   * The result code that indicates that the requested operation failed
   * because it would have resulted in an entry that violated the server
   * schema.
   */
  public static final ResultCode OBJECTCLASS_VIOLATION = registerErrorResultCode(
      65, INFO_RESULT_OBJECTCLASS_VIOLATION.get());
  /**
   * The result code that indicates that the requested operation is not
   * allowed for non-leaf entries.
   */
  public static final ResultCode NOT_ALLOWED_ON_NONLEAF = registerErrorResultCode(
      66, INFO_RESULT_NOT_ALLOWED_ON_NONLEAF.get());
  /**
   * The result code that indicates that the requested operation is not
   * allowed on an RDN attribute.
   */
  public static final ResultCode NOT_ALLOWED_ON_RDN = registerErrorResultCode(
      67, INFO_RESULT_NOT_ALLOWED_ON_RDN.get());
  /**
   * The result code that indicates that the requested operation failed
   * because it would have resulted in an entry that conflicts with an
   * entry that already exists.
   */
  public static final ResultCode ENTRY_ALREADY_EXISTS = registerErrorResultCode(
      68, INFO_RESULT_ENTRY_ALREADY_EXISTS.get());
  /**
   * The result code that indicates that the operation could not be
   * processed because it would have modified the objectclasses
   * associated with an entry in an illegal manner.
   */
  public static final ResultCode OBJECTCLASS_MODS_PROHIBITED = registerErrorResultCode(
      69, INFO_RESULT_OBJECTCLASS_MODS_PROHIBITED.get());
  /**
   * The result code that indicates that the operation could not be
   * processed because it would impact multiple DSAs or other
   * repositories.
   */
  public static final ResultCode AFFECTS_MULTIPLE_DSAS = registerErrorResultCode(
      71, INFO_RESULT_AFFECTS_MULTIPLE_DSAS.get());
  /**
   * The result code that indicates that the operation could not be
   * processed because there was an error while processing the virtual
   * list view control.
   */
  public static final ResultCode VIRTUAL_LIST_VIEW_ERROR = registerErrorResultCode(
      76, INFO_RESULT_VIRTUAL_LIST_VIEW_ERROR.get());
  /**
   * The result code that should be used if no other result code is
   * appropriate.
   */
  public static final ResultCode OTHER = registerErrorResultCode(80,
      INFO_RESULT_OTHER.get());
  /**
   * The client-side result code that indicates that a
   * previously-established connection to the server was lost. This is
   * for client-side use only and should never be transferred over
   * protocol.
   */
  public static final ResultCode CLIENT_SIDE_SERVER_DOWN = registerErrorResultCode(
      81, INFO_RESULT_CLIENT_SIDE_SERVER_DOWN.get());
  /**
   * The client-side result code that indicates that a local error
   * occurred that had nothing to do with interaction with the server.
   * This is for client-side use only and should never be transferred
   * over protocol.
   */
  public static final ResultCode CLIENT_SIDE_LOCAL_ERROR = registerErrorResultCode(
      82, INFO_RESULT_CLIENT_SIDE_LOCAL_ERROR.get());
  /**
   * The client-side result code that indicates that an error occurred
   * while encoding a request to send to the server. This is for
   * client-side use only and should never be transferred over protocol.
   */
  public static final ResultCode CLIENT_SIDE_ENCODING_ERROR = registerErrorResultCode(
      83, INFO_RESULT_CLIENT_SIDE_ENCODING_ERROR.get());
  /**
   * The client-side result code that indicates that an error occurred
   * while decoding a response from the server. This is for client-side
   * use only and should never be transferred over protocol.
   */
  public static final ResultCode CLIENT_SIDE_DECODING_ERROR = registerErrorResultCode(
      84, INFO_RESULT_CLIENT_SIDE_DECODING_ERROR.get());
  /**
   * The client-side result code that indicates that the client did not
   * receive an expected response in a timely manner. This is for
   * client-side use only and should never be transferred over protocol.
   */
  public static final ResultCode CLIENT_SIDE_TIMEOUT = registerErrorResultCode(
      85, INFO_RESULT_CLIENT_SIDE_TIMEOUT.get());
  /**
   * The client-side result code that indicates that the user requested
   * an unknown or unsupported authentication mechanism. This is for
   * client-side use only and should never be transferred over protocol.
   */
  public static final ResultCode CLIENT_SIDE_AUTH_UNKNOWN = registerErrorResultCode(
      86, INFO_RESULT_CLIENT_SIDE_AUTH_UNKNOWN.get());
  /**
   * The client-side result code that indicates that the filter provided
   * by the user was malformed and could not be parsed. This is for
   * client-side use only and should never be transferred over protocol.
   */
  public static final ResultCode CLIENT_SIDE_FILTER_ERROR = registerErrorResultCode(
      87, INFO_RESULT_CLIENT_SIDE_FILTER_ERROR.get());
  /**
   * The client-side result code that indicates that the user cancelled
   * an operation. This is for client-side use only and should never be
   * transferred over protocol.
   */
  public static final ResultCode CLIENT_SIDE_USER_CANCELLED = registerErrorResultCode(
      88, INFO_RESULT_CLIENT_SIDE_USER_CANCELLED.get());
  /**
   * The client-side result code that indicates that there was a problem
   * with one or more of the parameters provided by the user. This is
   * for client-side use only and should never be transferred over
   * protocol.
   */
  public static final ResultCode CLIENT_SIDE_PARAM_ERROR = registerErrorResultCode(
      89, INFO_RESULT_CLIENT_SIDE_PARAM_ERROR.get());
  /**
   * The client-side result code that indicates that the client
   * application was not able to allocate enough memory for the
   * requested operation. This is for client-side use only and should
   * never be transferred over protocol.
   */
  public static final ResultCode CLIENT_SIDE_NO_MEMORY = registerErrorResultCode(
      90, INFO_RESULT_CLIENT_SIDE_NO_MEMORY.get());
  /**
   * The client-side result code that indicates that the client was not
   * able to establish a connection to the server. This is for
   * client-side use only and should never be transferred over protocol.
   */
  public static final ResultCode CLIENT_SIDE_CONNECT_ERROR = registerErrorResultCode(
      91, INFO_RESULT_CLIENT_SIDE_CONNECT_ERROR.get());
  /**
   * The client-side result code that indicates that the user requested
   * an operation that is not supported. This is for client-side use
   * only and should never be transferred over protocol.
   */
  public static final ResultCode CLIENT_SIDE_NOT_SUPPORTED = registerErrorResultCode(
      92, INFO_RESULT_CLIENT_SIDE_NOT_SUPPORTED.get());
  /**
   * The client-side result code that indicates that the client expected
   * a control to be present in the response from the server but it was
   * not included. This is for client-side use only and should never be
   * transferred over protocol.
   */
  public static final ResultCode CLIENT_SIDE_CONTROL_NOT_FOUND = registerErrorResultCode(
      93, INFO_RESULT_CLIENT_SIDE_CONTROL_NOT_FOUND.get());
  /**
   * The client-side result code that indicates that the server did not
   * return any results for a search operation that was expected to
   * match at least one entry. This is for client-side use only and
   * should never be transferred over protocol.
   */
  public static final ResultCode CLIENT_SIDE_NO_RESULTS_RETURNED = registerErrorResultCode(
      94, INFO_RESULT_CLIENT_SIDE_NO_RESULTS_RETURNED.get());
  /**
   * The client-side result code that indicates that the server has
   * returned more matching entries for a search operation than have
   * been processed so far. This is for client-side use only and should
   * never be transferred over protocol.
   */
  public static final ResultCode CLIENT_SIDE_MORE_RESULTS_TO_RETURN = registerErrorResultCode(
      95, INFO_RESULT_CLIENT_SIDE_MORE_RESULTS_TO_RETURN.get());
  /**
   * The client-side result code that indicates that the client detected
   * a referral loop caused by servers referencing each other in a
   * circular manner. This is for client-side use only and should never
   * be transferred over protocol.
   */
  public static final ResultCode CLIENT_SIDE_CLIENT_LOOP = registerErrorResultCode(
      96, INFO_RESULT_CLIENT_SIDE_CLIENT_LOOP.get());
  /**
   * The client-side result code that indicates that the client reached
   * the maximum number of hops allowed when attempting to follow a
   * referral (i.e., following one referral resulted in another referral
   * which resulted in another referral and so on). This is for
   * client-side use only and should never be transferred over protocol.
   */
  public static final ResultCode CLIENT_SIDE_REFERRAL_LIMIT_EXCEEDED = registerErrorResultCode(
      97, INFO_RESULT_CLIENT_SIDE_REFERRAL_LIMIT_EXCEEDED.get());
  /**
   * The result code that indicates that a cancel request was
   * successful, or that the specified operation was canceled.
   */
  public static final ResultCode CANCELED = registerErrorResultCode(
      118, INFO_RESULT_CANCELED.get());
  /**
   * The result code that indicates that a cancel request was
   * unsuccessful because the targeted operation did not exist or had
   * already completed.
   */
  public static final ResultCode NO_SUCH_OPERATION = registerErrorResultCode(
      119, INFO_RESULT_NO_SUCH_OPERATION.get());
  /**
   * The result code that indicates that a cancel request was
   * unsuccessful because processing on the targeted operation had
   * already reached a point at which it could not be canceled.
   */
  public static final ResultCode TOO_LATE = registerErrorResultCode(
      120, INFO_RESULT_TOO_LATE.get());
  /**
   * The result code that indicates that a cancel request was
   * unsuccessful because the targeted operation was one that could not
   * be canceled.
   */
  public static final ResultCode CANNOT_CANCEL = registerErrorResultCode(
      121, INFO_RESULT_CANNOT_CANCEL.get());
  /**
   * The result code that indicates that the filter contained in an
   * assertion control failed to match the target entry.
   */
  public static final ResultCode ASSERTION_FAILED = registerErrorResultCode(
      122, INFO_RESULT_ASSERTION_FAILED.get());
  /**
   * The result code that should be used if the server will not allow
   * the client to use the requested authorization.
   */
  public static final ResultCode AUTHORIZATION_DENIED = registerErrorResultCode(
      123, INFO_RESULT_AUTHORIZATION_DENIED.get());
  /**
   * The result code that should be used if the server did not actually
   * complete processing on the associated operation because the request
   * included the LDAP No-Op control.
   */
  public static final ResultCode NO_OPERATION = registerErrorResultCode(
      16654, INFO_RESULT_NO_OPERATION.get());
  /**
   * Creates and registers a new error result code with the application.
   *
   * @param intValue
   *          The integer value of the error result code as defined in
   *          RFC 4511 section 4.1.9.
   * @param name
   *          The name of the error result code.
   * @return The new error result code.
   */
  private static ResultCode registerErrorResultCode(int intValue,
      Message name)
  {
    ResultCode t = new ResultCode(intValue, name, true);
    ELEMENTS[intValue] = t;
    return t;
  }
  /**
   * Creates and registers a new success result code with the
   * application.
   *
   * @param intValue
   *          The integer value of the success result code as defined in
   *          RFC 4511 section 4.1.9.
   * @param name
   *          The name of the success result code.
   * @return The new success result code.
   */
  private static ResultCode registerSuccessResultCode(int intValue,
      Message name)
  {
    ResultCode t = new ResultCode(intValue, name, false);
    ELEMENTS[intValue] = t;
    return t;
  }
  /**
   * Returns the result code having the specified integer value as
   * defined in RFC 4511 section 4.1.9. If there is no result code
   * associated with the specified integer value then a temporary result
   * code is automatically created in order to handle cases where
   * unexpected result codes are returned from the server.
   *
   * @param intValue
   *          The integer value of the result code.
   * @return The result code.
   */
  public static ResultCode valueOf(int intValue)
  {
    ResultCode resultCode = null;
    if (intValue >= 0 || intValue < ELEMENTS.length)
    {
      resultCode = ELEMENTS[intValue];
    }
    if (resultCode == null)
    {
      resultCode = new ResultCode(intValue, Message.raw("undefined("
          + intValue + ")"), true);
    }
    return resultCode;
  }
  /**
   * Returns an unmodifiable list containing the set of available result
   * codes indexed on their integer value as defined in RFC 4511 section
   * 4.1.9.
   *
   * @return An unmodifiable list containing the set of available result
   *         codes.
   */
  public static List<ResultCode> values()
  {
    return IMMUTABLE_ELEMENTS;
  }
  private final int intValue;
  private final Message name;
  private final boolean exceptional;
  // Prevent direct instantiation.
  private ResultCode(int intValue, Message name, boolean exceptional)
  {
    this.intValue = intValue;
    this.name = name;
    this.exceptional = exceptional;
  }
  /**
   * Indicates whether or not this result code represents an error
   * result. In order to make it easier for application to detect
   * referrals, the {@code REFERRAL} result code is treated as an error
   * result (the LDAP RFCs treat referrals as a success response).
   *
   * @return {@code true} if this result code represents an error
   *         result, otherwise {@code false}.
   */
  public boolean isExceptional()
  {
    return exceptional;
  }
  /**
   * Returns the short human-readable name of this result code.
   *
   * @return The short human-readable name of this result code.
   */
  public Message getName()
  {
    return name;
  }
  /**
   * {@inheritDoc}
   */
  public boolean equals(Object obj)
  {
    if (this == obj)
    {
      return true;
    }
    else if (obj instanceof ResultCode)
    {
      return this.intValue == ((ResultCode) obj).intValue;
    }
    else
    {
      return false;
    }
  }
  /**
   * {@inheritDoc}
   */
  public int hashCode()
  {
    return intValue;
  }
  /**
   * Returns the integer value of this result code.
   *
   * @return The integer value of this result code.
   */
  public int intValue()
  {
    return intValue;
  }
  /**
   * Returns the string representation of this result code.
   *
   * @return The string representation of this result code.
   */
  public String toString()
  {
    return name.toString();
  }
}
opendj-sdk/sdk/src/org/opends/sdk/ResultFuture.java
New file
@@ -0,0 +1,153 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Copyright 2009 Sun Microsystems, Inc.
 */
package org.opends.sdk;
import java.util.concurrent.CancellationException;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import org.opends.sdk.responses.Result;
/**
 * A handle which can be used to retrieve the Result of an asynchronous
 * Request.
 *
 * @param <S>
 *          The type of result returned by this future.
 */
public interface ResultFuture<S extends Result> extends Future<S>
{
  /**
   * Attempts to cancel the request. This attempt will fail if the
   * request has already completed or has already been cancelled. If
   * successful, then cancellation results in an abandon or cancel
   * request (if configured) being sent to the server.
   * <p>
   * After this method returns, subsequent calls to {@link #isDone} will
   * always return {@code true}. Subsequent calls to
   * {@link #isCancelled} will always return {@code true} if this method
   * returned {@code true}.
   *
   * @param mayInterruptIfRunning
   *          {@code true} if the thread executing executing the
   *          response handler should be interrupted; otherwise,
   *          in-progress response handlers are allowed to complete.
   * @return {@code false} if the request could not be cancelled,
   *         typically because it has already completed normally;
   *         {@code true} otherwise.
   */
  boolean cancel(boolean mayInterruptIfRunning);
  /**
   * Waits if necessary for the request to complete, and then returns
   * the result if the request succeeded. If the request failed (i.e. a
   * non-successful result code was obtained) then the result is thrown
   * as an {@link ErrorResultException}.
   *
   * @return The result, but only if the result code indicates that the
   *         request succeeded.
   * @throws CancellationException
   *           If the request was cancelled using a call to
   *           {@link #cancel}.
   * @throws ErrorResultException
   *           If the result code indicates that the request failed for
   *           some reason.
   * @throws InterruptedException
   *           If the current thread was interrupted while waiting.
   */
  S get() throws InterruptedException, ErrorResultException;
  /**
   * Waits if necessary for at most the given time for the request to
   * complete, and then returns the result if the request succeeded. If
   * the request failed (i.e. a non-successful result code was obtained)
   * then the result is thrown as an {@link ErrorResultException}.
   *
   * @param timeout
   *          The maximum time to wait.
   * @param unit
   *          The time unit of the timeout argument.
   * @return The result, but only if the result code indicates that the
   *         request succeeded.
   * @throws CancellationException
   *           If the request was cancelled using a call to
   *           {@link #cancel}.
   * @throws ErrorResultException
   *           If the result code indicates that the request failed for
   *           some reason.
   * @throws InterruptedException
   *           If the current thread was interrupted while waiting.
   * @throws TimeoutException
   *           If the wait timed out.
   */
  S get(long timeout, TimeUnit unit) throws InterruptedException,
      TimeoutException, ErrorResultException;
  /**
   * Returns the message ID of the request.
   *
   * @return The message ID.
   */
  int getMessageID();
  /**
   * Returns {@code true} if the request was cancelled before it
   * completed normally.
   *
   * @return {@code true} if the request was cancelled before it
   *         completed normally, otherwise {@code false}.
   */
  boolean isCancelled();
  /**
   * Returns {@code true} if the request has completed.
   * <p>
   * Completion may be due to normal termination, an exception, or
   * cancellation. In all of these cases, this method will return
   * {@code true}.
   *
   * @return {@code true} if the request has completed, otherwise
   *         {@code false}.
   */
  boolean isDone();
}
opendj-sdk/sdk/src/org/opends/sdk/ResultHandler.java
New file
@@ -0,0 +1,81 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Copyright 2009 Sun Microsystems, Inc.
 */
package org.opends.sdk;
import org.opends.sdk.responses.Result;
/**
 * A completion handler for consuming the result of an asynchronous
 * operation.
 * <p>
 * {@link Connection} objects allow a result completion handler to be
 * specified when sending operation requests to a Directory Server. The
 * {@link #handleResult} method is invoked when the operation completes
 * successfully. The {@link #handleErrorResult} method is invoked if the
 * operation fails.
 * <p>
 * Implementations of these methods should complete in a timely manner
 * so as to avoid keeping the invoking thread from dispatching to other
 * completion handlers.
 *
 * @param <S>
 *          The type of result handled by this result handler.
 * @param <P>
 *          The type of the additional parameter to this handler's
 *          methods. Use {@link java.lang.Void} for visitors that do not
 *          need an additional parameter.
 */
public interface ResultHandler<S extends Result, P>
{
  /**
   * Invoked when the asynchronous operation has failed.
   *
   * @param p
   *          A handler specified parameter.
   * @param error
   *          The error result exception indicating why the asynchronous
   *          operation has failed.
   */
  void handleErrorResult(P p, ErrorResultException error);
  /**
   * Invoked when the asynchronous operation has completed successfully.
   *
   * @param p
   *          A handler specified parameter.
   * @param result
   *          The result of the asynchronous operation.
   */
  void handleResult(P p, S result);
}
opendj-sdk/sdk/src/org/opends/sdk/RootDSE.java
New file
@@ -0,0 +1,463 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Copyright 2009 Sun Microsystems, Inc.
 */
package org.opends.sdk;
import java.util.Collection;
import java.util.Collections;
import org.opends.sdk.responses.SearchResultEntry;
import org.opends.sdk.schema.SchemaNotFoundException;
import org.opends.sdk.util.ByteString;
import org.opends.sdk.util.Functions;
import org.opends.sdk.util.Iterables;
import org.opends.sdk.util.Validator;
/**
 * Root DSE Entry.
 */
public class RootDSE extends AbstractEntry
{
  private static final AttributeDescription ATTR_ALT_SERVER = AttributeDescription
      .valueOf("altServer");
  private static final AttributeDescription ATTR_NAMING_CONTEXTS = AttributeDescription
      .valueOf("namingContexts");
  private static final AttributeDescription ATTR_SUPPORTED_CONTROL = AttributeDescription
      .valueOf("supportedControl");
  private static final AttributeDescription ATTR_SUPPORTED_EXTENSION = AttributeDescription
      .valueOf("supportedExtension");
  private static final AttributeDescription ATTR_SUPPORTED_FEATURE = AttributeDescription
      .valueOf("supportedFeatures");
  private static final AttributeDescription ATTR_SUPPORTED_LDAP_VERSION = AttributeDescription
      .valueOf("supportedLDAPVersion");
  private static final AttributeDescription ATTR_SUPPORTED_SASL_MECHANISMS = AttributeDescription
      .valueOf("supportedSASLMechanisms");
  private static final AttributeDescription ATTR_SUPPORTED_AUTH_PASSWORD_SCHEMES = AttributeDescription
      .valueOf("supportedAuthPasswordSchemes");
  private static final AttributeDescription ATTR_VENDOR_NAME = AttributeDescription
      .valueOf("vendorName");
  private static final AttributeDescription ATTR_VENDOR_VERSION = AttributeDescription
      .valueOf("vendorVersion");
  private static String[] ROOTDSE_ATTRS = new String[] {
      ATTR_ALT_SERVER.toString(), ATTR_NAMING_CONTEXTS.toString(),
      ATTR_SUPPORTED_CONTROL.toString(),
      ATTR_SUPPORTED_EXTENSION.toString(),
      ATTR_SUPPORTED_FEATURE.toString(),
      ATTR_SUPPORTED_LDAP_VERSION.toString(),
      ATTR_SUPPORTED_SASL_MECHANISMS.toString(),
      ATTR_VENDOR_NAME.toString(), ATTR_VENDOR_VERSION.toString(),
      ATTR_SUPPORTED_AUTH_PASSWORD_SCHEMES.toString(), "*" };
  private final Entry entry;
  private final Iterable<String> altServers;
  private final Iterable<DN> namingContexts;
  private final Iterable<String> supportedControls;
  private final Iterable<String> supportedExtensions;
  private final Iterable<String> supportedFeatures;
  private final Iterable<Integer> supportedLDAPVerions;
  private final Iterable<String> supportedSASLMechanisms;
  private final Iterable<String> supportedAuthPasswordSchemes;
  private final String vendorName;
  private final String vendorVersion;
  private RootDSE(Entry entry) throws IllegalArgumentException
  {
    this.entry = Types.unmodifiableEntry(entry);
    Attribute attr = getAttribute(ATTR_ALT_SERVER);
    if (attr == null)
    {
      altServers = Collections.emptyList();
    }
    else
    {
      altServers = Iterables.unmodifiable(Iterables.transform(attr,
          Functions.valueToString()));
    }
    attr = getAttribute(ATTR_NAMING_CONTEXTS);
    if (attr == null)
    {
      namingContexts = Collections.emptyList();
    }
    else
    {
      namingContexts = Iterables.unmodifiable(Iterables.transform(attr,
          Functions.valueToDN()));
    }
    attr = getAttribute(ATTR_SUPPORTED_CONTROL);
    if (attr == null)
    {
      supportedControls = Collections.emptyList();
    }
    else
    {
      supportedControls = Iterables.unmodifiable(Iterables.transform(
          attr, Functions.valueToString()));
    }
    attr = getAttribute(ATTR_SUPPORTED_EXTENSION);
    if (attr == null)
    {
      supportedExtensions = Collections.emptyList();
    }
    else
    {
      supportedExtensions = Iterables.unmodifiable(Iterables.transform(
          attr, Functions.valueToString()));
    }
    attr = getAttribute(ATTR_SUPPORTED_FEATURE);
    if (attr == null)
    {
      supportedFeatures = Collections.emptyList();
    }
    else
    {
      supportedFeatures = Iterables.unmodifiable(Iterables.transform(
          attr, Functions.valueToString()));
    }
    attr = getAttribute(ATTR_SUPPORTED_LDAP_VERSION);
    if (attr == null)
    {
      supportedLDAPVerions = Collections.emptyList();
    }
    else
    {
      supportedLDAPVerions = Iterables.unmodifiable(Iterables
          .transform(attr, Functions.valueToInteger()));
    }
    attr = getAttribute(ATTR_SUPPORTED_SASL_MECHANISMS);
    if (attr == null)
    {
      supportedSASLMechanisms = Collections.emptyList();
    }
    else
    {
      supportedSASLMechanisms = Iterables.unmodifiable(Iterables
          .transform(attr, Functions.valueToString()));
    }
    attr = getAttribute(ATTR_SUPPORTED_AUTH_PASSWORD_SCHEMES);
    if (attr == null)
    {
      supportedAuthPasswordSchemes = Collections.emptyList();
    }
    else
    {
      supportedAuthPasswordSchemes = Iterables.unmodifiable(Iterables
          .transform(attr, Functions.valueToString()));
    }
    attr = getAttribute(ATTR_VENDOR_NAME);
    vendorName = attr == null ? "" : attr.firstValueAsString();
    attr = getAttribute(ATTR_VENDOR_VERSION);
    vendorVersion = attr == null ? "" : attr.firstValueAsString();
  }
  public static RootDSE getRootDSE(Connection connection)
      throws ErrorResultException, InterruptedException,
      DecodeException, SchemaNotFoundException
  {
    SearchResultEntry result = connection.readEntry(DN.rootDN(),
        ROOTDSE_ATTRS);
    return new RootDSE(result);
  }
  public Iterable<String> getAltServers()
  {
    return altServers;
  }
  public Iterable<DN> getNamingContexts()
  {
    return namingContexts;
  }
  public Iterable<String> getSupportedControls()
  {
    return supportedControls;
  }
  public boolean supportsControl(String oid)
  {
    Validator.ensureNotNull(oid);
    for (String supported : supportedControls)
    {
      if (supported.equals(oid))
      {
        return true;
      }
    }
    return false;
  }
  public Iterable<String> getSupportedExtendedOperations()
  {
    return supportedExtensions;
  }
  public boolean supportsExtendedOperation(String oid)
  {
    Validator.ensureNotNull(oid);
    for (String supported : supportedExtensions)
    {
      if (supported.equals(oid))
      {
        return true;
      }
    }
    return false;
  }
  public Iterable<String> getSupportedFeatures()
  {
    return supportedFeatures;
  }
  public boolean supportsFeature(String oid)
  {
    Validator.ensureNotNull(oid);
    for (String supported : supportedFeatures)
    {
      if (supported.equals(oid))
      {
        return true;
      }
    }
    return false;
  }
  public Iterable<Integer> getSupportedLDAPVersions()
  {
    return supportedLDAPVerions;
  }
  public boolean supportsLDAPVersion(int version)
  {
    for (int supported : supportedLDAPVerions)
    {
      if (supported == version)
      {
        return true;
      }
    }
    return false;
  }
  public Iterable<String> getSupportedSASLMechanismNames()
  {
    return supportedSASLMechanisms;
  }
  public boolean supportsSASLMechanism(String name)
  {
    Validator.ensureNotNull(name);
    for (String supported : supportedSASLMechanisms)
    {
      if (supported.equals(name))
      {
        return true;
      }
    }
    return false;
  }
  public Iterable<String> getSupportedAuthPasswordSchemes()
  {
    return supportedSASLMechanisms;
  }
  public boolean supportsAuthPasswordScheme(String name)
  {
    Validator.ensureNotNull(name);
    for (String supported : supportedAuthPasswordSchemes)
    {
      if (supported.equals(name))
      {
        return true;
      }
    }
    return false;
  }
  public String getVendorName()
  {
    return vendorName;
  }
  public String getVendorVersion()
  {
    return vendorVersion;
  }
  /**
   * {@inheritDoc}
   */
  public boolean addAttribute(Attribute attribute,
      Collection<ByteString> duplicateValues)
      throws UnsupportedOperationException, NullPointerException
  {
    throw new UnsupportedOperationException();
  }
  public Entry clearAttributes() throws UnsupportedOperationException
  {
    throw new UnsupportedOperationException();
  }
  public boolean containsAttribute(
      AttributeDescription attributeDescription)
      throws NullPointerException
  {
    Validator.ensureNotNull(attributeDescription);
    return entry.containsAttribute(attributeDescription);
  }
  public Attribute getAttribute(
      AttributeDescription attributeDescription)
      throws NullPointerException
  {
    Validator.ensureNotNull(attributeDescription);
    return entry.getAttribute(attributeDescription);
  }
  public int getAttributeCount()
  {
    return entry.getAttributeCount();
  }
  public Iterable<Attribute> getAttributes()
  {
    return entry.getAttributes();
  }
  public DN getName()
  {
    return DN.rootDN();
  }
  /**
   * {@inheritDoc}
   */
  public boolean removeAttribute(Attribute attribute,
      Collection<ByteString> missingValues)
      throws UnsupportedOperationException, NullPointerException
  {
    throw new UnsupportedOperationException();
  }
  public Entry setName(DN dn) throws UnsupportedOperationException,
      NullPointerException
  {
    throw new UnsupportedOperationException();
  }
}
opendj-sdk/sdk/src/org/opends/sdk/SearchResultHandler.java
New file
@@ -0,0 +1,82 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Copyright 2009 Sun Microsystems, Inc.
 */
package org.opends.sdk;
import org.opends.sdk.responses.SearchResultEntry;
import org.opends.sdk.responses.SearchResultReference;
/**
 * A completion handler for consuming the results of an asynchronous
 * Search operation.
 * <p>
 * {@link Connection} objects allow a search result completion handler
 * to be specified when sending Search operation requests to a Directory
 * Server. The {@link #handleEntry} method is invoked each time a Search
 * Result Entry is returned from the Directory Server. The
 * {@link #handleReference} method is invoked for each Search Result
 * Reference returned from the Directory Server.
 * <p>
 * Implementations of these methods should complete in a timely manner
 * so as to avoid keeping the invoking thread from dispatching to other
 * completion handlers.
 *
 * @param <P>
 *          The type of the additional parameter to this handler's
 *          methods. Use {@link java.lang.Void} for visitors that do not
 *          need an additional parameter.
 */
public interface SearchResultHandler<P>
{
  /**
   * Invoked each time a search result entry is returned from an
   * asynchronous search operation.
   *
   * @param p
   *          A handler specified parameter.
   * @param entry
   *          The search result entry.
   */
  void handleEntry(P p, SearchResultEntry entry);
  /**
   * Invoked each time a search result reference is returned from an
   * asynchronous search operation.
   *
   * @param p
   *          A handler specified parameter.
   * @param reference
   *          The search result reference.
   */
  void handleReference(P p, SearchResultReference reference);
}
opendj-sdk/sdk/src/org/opends/sdk/SearchScope.java
New file
@@ -0,0 +1,207 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Copyright 2009 Sun Microsystems, Inc.
 */
package org.opends.sdk;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
/**
 * A Search operation search scope as defined in RFC 4511 section
 * 4.5.1.2 is used to specify the scope of a Search operation.
 *
 * @see <a href="http://tools.ietf.org/html/rfc4511#section-4.5.1.2">RFC
 *      4511 - Lightweight Directory Access Protocol (LDAP): The
 *      Protocol </a>
 * @see <a
 *      href="http://tools.ietf.org/html/draft-sermersheim-ldap-subordinate-scope">
 *      draft-sermersheim-ldap-subordinate-scope - Subordinate Subtree
 *      Search Scope for LDAP </a>
 */
public final class SearchScope
{
  private static final SearchScope[] ELEMENTS = new SearchScope[4];
  private static final List<SearchScope> IMMUTABLE_ELEMENTS = Collections
      .unmodifiableList(Arrays.asList(ELEMENTS));
  /**
   * The scope is constrained to the search base entry.
   */
  public static final SearchScope BASE_OBJECT = register(0, "base");
  /**
   * The scope is constrained to the immediate subordinates of the
   * search base entry.
   */
  public static final SearchScope SINGLE_LEVEL = register(1, "one");
  /**
   * The scope is constrained to the search base entry and to all its
   * subordinates.
   */
  public static final SearchScope WHOLE_SUBTREE = register(2, "sub");
  /**
   * The scope is constrained to all the subordinates of the search base
   * entry, but does not include the search base entry itself (as
   * wholeSubtree does).
   */
  public static final SearchScope SUBORDINATES = register(3,
      "subordinates");
  /**
   * Creates and registers a new search scope with the application.
   *
   * @param intValue
   *          The integer value of the search scope as defined in RFC
   *          4511 section 4.5.1.2.
   * @param name
   *          The name of the search scope as defined in RFC 4516.
   * @return The new search scope.
   */
  private static SearchScope register(int intValue, String name)
  {
    SearchScope t = new SearchScope(intValue, name);
    ELEMENTS[intValue] = t;
    return t;
  }
  /**
   * Returns the search scope having the specified integer value as
   * defined in RFC 4511 section 4.5.1.2.
   *
   * @param intValue
   *          The integer value of the search scope.
   * @return The search scope, or {@code null} if there was no search
   *         scope associated with {@code intValue}.
   */
  public static SearchScope valueOf(int intValue)
  {
    if (intValue < 0 || intValue >= ELEMENTS.length)
    {
      return null;
    }
    return ELEMENTS[intValue];
  }
  /**
   * Returns an unmodifiable list containing the set of available search
   * scopes indexed on their integer value as defined in RFC 4511
   * section 4.5.1.2.
   *
   * @return An unmodifiable list containing the set of available search
   *         scopes.
   */
  public static List<SearchScope> values()
  {
    return IMMUTABLE_ELEMENTS;
  }
  private final int intValue;
  private final String name;
  // Prevent direct instantiation.
  private SearchScope(int intValue, String name)
  {
    this.intValue = intValue;
    this.name = name;
  }
  /**
   * {@inheritDoc}
   */
  public boolean equals(Object obj)
  {
    if (this == obj)
    {
      return true;
    }
    else if (obj instanceof SearchScope)
    {
      return this.intValue == ((SearchScope) obj).intValue;
    }
    else
    {
      return false;
    }
  }
  /**
   * {@inheritDoc}
   */
  public int hashCode()
  {
    return intValue;
  }
  /**
   * Returns the integer value of this search scope as defined in RFC
   * 4511 section 4.5.1.2.
   *
   * @return The integer value of this search scope.
   */
  public int intValue()
  {
    return intValue;
  }
  /**
   * Returns the string representation of this search scope as defined
   * in RFC 4516.
   *
   * @return The string representation of this search scope.
   */
  public String toString()
  {
    return name;
  }
}
opendj-sdk/sdk/src/org/opends/sdk/SortedEntry.java
New file
@@ -0,0 +1,295 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Copyright 2009 Sun Microsystems, Inc.
 */
package org.opends.sdk;
import java.util.Collection;
import java.util.SortedMap;
import java.util.TreeMap;
import org.opends.sdk.requests.Requests;
import org.opends.sdk.util.ByteString;
import org.opends.sdk.util.LocalizedIllegalArgumentException;
import org.opends.sdk.util.Validator;
/**
 * An implementation of the {@code Entry} interface which uses a {@code
 * SortedMap} for storing attributes. Attributes are returned in
 * ascending order of attribute description, with {@code objectClass}
 * first, then all user attributes, and finally any operational
 * attributes. All operations are supported by this implementation.
 */
public final class SortedEntry extends AbstractEntry
{
  private final SortedMap<AttributeDescription, Attribute> attributes = new TreeMap<AttributeDescription, Attribute>();
  private DN name;
  /**
   * Creates an empty sorted entry and an empty (root) distinguished
   * name.
   */
  public SortedEntry()
  {
    this(DN.rootDN());
  }
  /**
   * Creates an empty sorted entry using the provided distinguished
   * name.
   *
   * @param name
   *          The distinguished name of this entry.
   * @throws NullPointerException
   *           If {@code name} was {@code null}.
   */
  public SortedEntry(DN name) throws NullPointerException
  {
    Validator.ensureNotNull(name);
    this.name = name;
  }
  /**
   * Creates an empty sorted entry using the provided distinguished name
   * decoded using the default schema.
   *
   * @param name
   *          The distinguished name of this entry.
   * @throws LocalizedIllegalArgumentException
   *           If {@code name} could not be decoded using the default
   *           schema.
   * @throws NullPointerException
   *           If {@code name} was {@code null}.
   */
  public SortedEntry(String name)
      throws LocalizedIllegalArgumentException, NullPointerException
  {
    this(DN.valueOf(name));
  }
  /**
   * Creates a sorted entry having the same distinguished name,
   * attributes, and object classes of the provided entry.
   *
   * @param entry
   *          The entry to be copied.
   * @throws NullPointerException
   *           If {@code entry} was {@code null}.
   */
  public SortedEntry(Entry entry)
  {
    Validator.ensureNotNull(entry);
    this.name = entry.getName();
    for (Attribute attribute : entry.getAttributes())
    {
      addAttribute(attribute);
    }
  }
  /**
   * Creates a new sorted entry using the provided lines of LDIF decoded
   * using the default schema.
   *
   * @param ldifLines
   *          Lines of LDIF containing the an LDIF add change record or
   *          an LDIF entry record.
   * @throws LocalizedIllegalArgumentException
   *           If {@code ldifLines} was empty, or contained invalid
   *           LDIF, or could not be decoded using the default schema.
   * @throws NullPointerException
   *           If {@code ldifLines} was {@code null} .
   */
  public SortedEntry(String... ldifLines)
      throws LocalizedIllegalArgumentException, NullPointerException
  {
    this(Requests.newAddRequest(ldifLines));
  }
  /**
   * {@inheritDoc}
   */
  public boolean addAttribute(Attribute attribute,
      Collection<ByteString> duplicateValues)
      throws NullPointerException
  {
    Validator.ensureNotNull(attribute);
    if (!attribute.isEmpty())
    {
      AttributeDescription attributeDescription = attribute
          .getAttributeDescription();
      Attribute oldAttribute = attributes.get(attributeDescription);
      if (oldAttribute != null)
      {
        return oldAttribute.addAll(attribute, duplicateValues);
      }
      else
      {
        attributes.put(attributeDescription, attribute);
        return true;
      }
    }
    return false;
  }
  /**
   * {@inheritDoc}
   */
  public Entry clearAttributes()
  {
    attributes.clear();
    return this;
  }
  /**
   * {@inheritDoc}
   */
  public boolean containsAttribute(
      AttributeDescription attributeDescription)
      throws NullPointerException
  {
    Validator.ensureNotNull(attributeDescription);
    return attributes.containsKey(attributeDescription);
  }
  /**
   * {@inheritDoc}
   */
  public Attribute getAttribute(
      AttributeDescription attributeDescription)
      throws NullPointerException
  {
    Validator.ensureNotNull(attributeDescription);
    return attributes.get(attributeDescription);
  }
  /**
   * {@inheritDoc}
   */
  public int getAttributeCount()
  {
    return attributes.size();
  }
  /**
   * {@inheritDoc}
   */
  public Iterable<Attribute> getAttributes()
  {
    return attributes.values();
  }
  /**
   * {@inheritDoc}
   */
  public DN getName()
  {
    return name;
  }
  /**
   * {@inheritDoc}
   */
  public boolean removeAttribute(Attribute attribute,
      Collection<ByteString> missingValues) throws NullPointerException
  {
    Validator.ensureNotNull(attribute);
    AttributeDescription attributeDescription = attribute
        .getAttributeDescription();
    if (attribute.isEmpty())
    {
      return attributes.remove(attributeDescription) != null;
    }
    else
    {
      Attribute oldAttribute = attributes.get(attributeDescription);
      if (oldAttribute != null)
      {
        boolean modified = oldAttribute.removeAll(attribute,
            missingValues);
        if (oldAttribute.isEmpty())
        {
          attributes.remove(attributeDescription);
          return true;
        }
        return modified;
      }
      else
      {
        return false;
      }
    }
  }
  /**
   * {@inheritDoc}
   */
  public Entry setName(DN dn) throws NullPointerException
  {
    Validator.ensureNotNull(dn);
    this.name = dn;
    return this;
  }
}
opendj-sdk/sdk/src/org/opends/sdk/SynchronousConnection.java
New file
@@ -0,0 +1,261 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Copyright 2009 Sun Microsystems, Inc.
 */
package org.opends.sdk;
import org.opends.sdk.requests.*;
import org.opends.sdk.responses.BindResult;
import org.opends.sdk.responses.CompareResult;
import org.opends.sdk.responses.Result;
import org.opends.sdk.util.Validator;
/**
 * A {@code SynchronousConnection} adapts an {@code
 * AsynchronousConnection} into a synchronous {@code Connection}.
 */
public class SynchronousConnection extends AbstractConnection
{
  private final AsynchronousConnection connection;
  /**
   * Creates a new abstract connection which will route all synchronous
   * requests to the provided asynchronous connection.
   *
   * @param connection
   *          The asynchronous connection to be used.
   * @throws NullPointerException
   *           If {@code connection} was {@code null}.
   */
  public SynchronousConnection(AsynchronousConnection connection)
      throws NullPointerException
  {
    Validator.ensureNotNull(connection);
    this.connection = connection;
  }
  /**
   * {@inheritDoc}
   */
  public Result add(AddRequest request) throws ErrorResultException,
      InterruptedException, UnsupportedOperationException,
      IllegalStateException, NullPointerException
  {
    ResultFuture<Result> future = connection.add(request, null, null);
    try
    {
      return future.get();
    }
    finally
    {
      // Cancel the request if it hasn't completed.
      future.cancel(false);
    }
  }
  public void addConnectionEventListener(
      ConnectionEventListener listener) throws IllegalStateException,
      NullPointerException
  {
    connection.addConnectionEventListener(listener);
  }
  public BindResult bind(BindRequest request)
      throws ErrorResultException, InterruptedException,
      UnsupportedOperationException, IllegalStateException,
      NullPointerException
  {
    ResultFuture<BindResult> future = connection.bind(request, null,
        null);
    try
    {
      return future.get();
    }
    finally
    {
      // Cancel the request if it hasn't completed.
      future.cancel(false);
    }
  }
  public void close()
  {
    connection.close();
  }
  public void close(UnbindRequest request) throws NullPointerException
  {
    connection.close(request);
  }
  public CompareResult compare(CompareRequest request)
      throws ErrorResultException, InterruptedException,
      UnsupportedOperationException, IllegalStateException,
      NullPointerException
  {
    ResultFuture<CompareResult> future = connection.compare(request,
        null, null);
    try
    {
      return future.get();
    }
    finally
    {
      // Cancel the request if it hasn't completed.
      future.cancel(false);
    }
  }
  public Result delete(DeleteRequest request)
      throws ErrorResultException, InterruptedException,
      UnsupportedOperationException, IllegalStateException,
      NullPointerException
  {
    ResultFuture<Result> future = connection
        .delete(request, null, null);
    try
    {
      return future.get();
    }
    finally
    {
      // Cancel the request if it hasn't completed.
      future.cancel(false);
    }
  }
  public <R extends Result> R extendedRequest(ExtendedRequest<R> request)
      throws ErrorResultException, InterruptedException,
      UnsupportedOperationException, IllegalStateException,
      NullPointerException
  {
    ResultFuture<R> future = connection.extendedRequest(request, null,
        null);
    try
    {
      return future.get();
    }
    finally
    {
      // Cancel the request if it hasn't completed.
      future.cancel(false);
    }
  }
  public Result modify(ModifyRequest request)
      throws ErrorResultException, InterruptedException,
      UnsupportedOperationException, IllegalStateException,
      NullPointerException
  {
    ResultFuture<Result> future = connection
        .modify(request, null, null);
    try
    {
      return future.get();
    }
    finally
    {
      // Cancel the request if it hasn't completed.
      future.cancel(false);
    }
  }
  public Result modifyDN(ModifyDNRequest request)
      throws ErrorResultException, InterruptedException,
      UnsupportedOperationException, IllegalStateException,
      NullPointerException
  {
    ResultFuture<Result> future = connection.modifyDN(request, null,
        null);
    try
    {
      return future.get();
    }
    finally
    {
      // Cancel the request if it hasn't completed.
      future.cancel(false);
    }
  }
  public void removeConnectionEventListener(
      ConnectionEventListener listener) throws NullPointerException
  {
    connection.removeConnectionEventListener(listener);
  }
  /**
   * {@inheritDoc}
   */
  public <P> Result search(SearchRequest request,
      SearchResultHandler<P> handler, P p) throws ErrorResultException,
      InterruptedException, UnsupportedOperationException,
      IllegalStateException, NullPointerException
  {
    ResultFuture<Result> future = connection.search(request, null,
        handler, p);
    try
    {
      return future.get();
    }
    finally
    {
      // Cancel the request if it hasn't completed.
      future.cancel(false);
    }
  }
}
opendj-sdk/sdk/src/org/opends/sdk/Types.java
New file
@@ -0,0 +1,985 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Copyright 2009 Sun Microsystems, Inc.
 */
package org.opends.sdk;
import java.util.Collection;
import java.util.Iterator;
import java.util.NoSuchElementException;
import org.opends.sdk.schema.AttributeType;
import org.opends.sdk.schema.ObjectClass;
import org.opends.sdk.util.*;
/**
 * This class contains methods for creating and manipulating attributes,
 * entries, and other types of object.
 */
public final class Types
{
  /**
   * Empty attribute.
   */
  private static final class EmptyAttribute extends AbstractAttribute
  {
    private final AttributeDescription attributeDescription;
    private EmptyAttribute(AttributeDescription attributeDescription)
    {
      this.attributeDescription = attributeDescription;
    }
    public boolean add(ByteString value)
        throws UnsupportedOperationException, NullPointerException
    {
      throw new UnsupportedOperationException();
    }
    public void clear() throws UnsupportedOperationException
    {
      throw new UnsupportedOperationException();
    }
    public AttributeDescription getAttributeDescription()
    {
      return attributeDescription;
    }
    public boolean isEmpty()
    {
      return true;
    }
    public Iterator<ByteString> iterator()
    {
      return Iterators.empty();
    }
    public int size()
    {
      return 0;
    }
    public boolean contains(Object value) throws NullPointerException
    {
      return false;
    }
    public boolean remove(Object value)
        throws UnsupportedOperationException, NullPointerException
    {
      throw new UnsupportedOperationException();
    }
  }
  /**
   * Renamed attribute.
   */
  private static final class RenamedAttribute implements Attribute
  {
    private final Attribute attribute;
    private final AttributeDescription attributeDescription;
    private RenamedAttribute(Attribute attribute,
        AttributeDescription attributeDescription)
    {
      this.attribute = attribute;
      this.attributeDescription = attributeDescription;
    }
    public boolean add(ByteString value)
        throws UnsupportedOperationException, NullPointerException
    {
      return attribute.add(value);
    }
    public boolean add(Object firstValue, Object... remainingValues)
        throws UnsupportedOperationException, NullPointerException
    {
      return attribute.add(firstValue, remainingValues);
    }
    public boolean addAll(Collection<? extends ByteString> values)
        throws UnsupportedOperationException, NullPointerException
    {
      return attribute.addAll(values);
    }
    public boolean addAll(Collection<? extends ByteString> values,
        Collection<? super ByteString> duplicateValues)
        throws UnsupportedOperationException, NullPointerException
    {
      return attribute.addAll(values, duplicateValues);
    }
    public void clear() throws UnsupportedOperationException
    {
      attribute.clear();
    }
    public boolean contains(Object value) throws NullPointerException
    {
      return attribute.contains(value);
    }
    public boolean containsAll(Collection<?> values)
        throws NullPointerException
    {
      return attribute.containsAll(values);
    }
    public boolean equals(Object object)
    {
      return AbstractAttribute.equals(this, object);
    }
    public ByteString firstValue() throws NoSuchElementException
    {
      return attribute.firstValue();
    }
    public <T> T firstValueAsObject(
        Function<? super ByteString, T, Void> type)
        throws NoSuchElementException
    {
      return attribute.firstValueAsObject(type);
    }
    public <T, P> T firstValueAsObject(
        Function<? super ByteString, T, P> type, P p)
        throws NoSuchElementException
    {
      return attribute.firstValueAsObject(type, p);
    }
    public String firstValueAsString() throws NoSuchElementException
    {
      return attribute.firstValueAsString();
    }
    public AttributeDescription getAttributeDescription()
    {
      return attributeDescription;
    }
    public String getAttributeDescriptionAsString()
    {
      return attributeDescription.toString();
    }
    public int hashCode()
    {
      return AbstractAttribute.hashCode(this);
    }
    public boolean isEmpty()
    {
      return attribute.isEmpty();
    }
    public Iterator<ByteString> iterator()
    {
      return attribute.iterator();
    }
    public boolean remove(Object value)
        throws UnsupportedOperationException, NullPointerException
    {
      return attribute.remove(value);
    }
    public boolean removeAll(Collection<?> values)
        throws UnsupportedOperationException, NullPointerException
    {
      return attribute.removeAll(values);
    }
    public <T> boolean removeAll(Collection<T> values,
        Collection<? super T> missingValues)
        throws UnsupportedOperationException, NullPointerException
    {
      return attribute.removeAll(values, missingValues);
    }
    public boolean retainAll(Collection<?> values)
        throws UnsupportedOperationException, NullPointerException
    {
      return attribute.retainAll(values);
    }
    public <T> boolean retainAll(Collection<T> values,
        Collection<? super T> missingValues)
        throws UnsupportedOperationException, NullPointerException
    {
      return attribute.retainAll(values, missingValues);
    }
    public int size()
    {
      return attribute.size();
    }
    public ByteString[] toArray()
    {
      return attribute.toArray();
    }
    public <T> T[] toArray(T[] array) throws ArrayStoreException,
        NullPointerException
    {
      return attribute.toArray(array);
    }
    public String toString()
    {
      return AbstractAttribute.toString(this);
    }
  }
  /**
   * Unmodifiable attribute.
   */
  private static final class UnmodifiableAttribute implements Attribute
  {
    private final Attribute attribute;
    private UnmodifiableAttribute(Attribute attribute)
    {
      this.attribute = attribute;
    }
    public boolean add(ByteString value)
        throws UnsupportedOperationException, NullPointerException
    {
      throw new UnsupportedOperationException();
    }
    public boolean add(Object firstValue, Object... remainingValues)
        throws UnsupportedOperationException, NullPointerException
    {
      throw new UnsupportedOperationException();
    }
    public boolean addAll(Collection<? extends ByteString> values)
        throws UnsupportedOperationException, NullPointerException
    {
      throw new UnsupportedOperationException();
    }
    public boolean addAll(Collection<? extends ByteString> values,
        Collection<? super ByteString> duplicateValues)
        throws UnsupportedOperationException, NullPointerException
    {
      throw new UnsupportedOperationException();
    }
    public void clear() throws UnsupportedOperationException
    {
      throw new UnsupportedOperationException();
    }
    public boolean contains(Object value) throws NullPointerException
    {
      return attribute.contains(value);
    }
    public boolean containsAll(Collection<?> values)
        throws NullPointerException
    {
      return attribute.containsAll(values);
    }
    public boolean equals(Object object)
    {
      return (object == this || attribute.equals(object));
    }
    public ByteString firstValue() throws NoSuchElementException
    {
      return attribute.firstValue();
    }
    public <T> T firstValueAsObject(
        Function<? super ByteString, T, Void> type)
        throws NoSuchElementException
    {
      return attribute.firstValueAsObject(type);
    }
    public <T, P> T firstValueAsObject(
        Function<? super ByteString, T, P> type, P p)
        throws NoSuchElementException
    {
      return attribute.firstValueAsObject(type, p);
    }
    public String firstValueAsString() throws NoSuchElementException
    {
      return attribute.firstValueAsString();
    }
    public AttributeDescription getAttributeDescription()
    {
      return attribute.getAttributeDescription();
    }
    public String getAttributeDescriptionAsString()
    {
      return attribute.getAttributeDescriptionAsString();
    }
    public int hashCode()
    {
      return attribute.hashCode();
    }
    public boolean isEmpty()
    {
      return attribute.isEmpty();
    }
    public Iterator<ByteString> iterator()
    {
      return Iterators.unmodifiable(attribute.iterator());
    }
    public boolean remove(Object value)
        throws UnsupportedOperationException, NullPointerException
    {
      throw new UnsupportedOperationException();
    }
    public boolean removeAll(Collection<?> values)
        throws UnsupportedOperationException, NullPointerException
    {
      throw new UnsupportedOperationException();
    }
    public <T> boolean removeAll(Collection<T> values,
        Collection<? super T> missingValues)
        throws UnsupportedOperationException, NullPointerException
    {
      throw new UnsupportedOperationException();
    }
    public boolean retainAll(Collection<?> values)
        throws UnsupportedOperationException, NullPointerException
    {
      throw new UnsupportedOperationException();
    }
    public <T> boolean retainAll(Collection<T> values,
        Collection<? super T> missingValues)
        throws UnsupportedOperationException, NullPointerException
    {
      throw new UnsupportedOperationException();
    }
    public int size()
    {
      return attribute.size();
    }
    public ByteString[] toArray()
    {
      return attribute.toArray();
    }
    public <T> T[] toArray(T[] array) throws ArrayStoreException,
        NullPointerException
    {
      return attribute.toArray(array);
    }
    public String toString()
    {
      return attribute.toString();
    }
  }
  private static final class UnmodifiableEntry implements Entry
  {
    private final Entry entry;
    private UnmodifiableEntry(Entry entry)
    {
      this.entry = entry;
    }
    /**
     * {@inheritDoc}
     */
    public boolean addAttribute(Attribute attribute,
        Collection<ByteString> duplicateValues)
        throws UnsupportedOperationException, NullPointerException
    {
      throw new UnsupportedOperationException();
    }
    /**
     * {@inheritDoc}
     */
    public boolean addAttribute(Attribute attribute)
        throws UnsupportedOperationException, NullPointerException
    {
      throw new UnsupportedOperationException();
    }
    /**
     * {@inheritDoc}
     */
    public Entry addAttribute(String attributeDescription,
        Object... values) throws LocalizedIllegalArgumentException,
        UnsupportedOperationException, NullPointerException
    {
      throw new UnsupportedOperationException();
    }
    public Entry clearAttributes() throws UnsupportedOperationException
    {
      throw new UnsupportedOperationException();
    }
    public boolean containsAttribute(
        AttributeDescription attributeDescription)
    {
      return entry.containsAttribute(attributeDescription);
    }
    /**
     * {@inheritDoc}
     */
    public boolean containsAttribute(String attributeDescription)
        throws LocalizedIllegalArgumentException, NullPointerException
    {
      return entry.containsAttribute(attributeDescription);
    }
    public boolean containsObjectClass(ObjectClass objectClass)
    {
      return entry.containsObjectClass(objectClass);
    }
    public boolean containsObjectClass(String objectClass)
    {
      return entry.containsObjectClass(objectClass);
    }
    /**
     * {@inheritDoc}
     */
    public boolean equals(Object object)
    {
      return (object == this || entry.equals(object));
    }
    public Iterable<Attribute> findAttributes(
        AttributeDescription attributeDescription)
    {
      return Iterables.unmodifiable(Iterables.transform(entry
          .findAttributes(attributeDescription),
          UNMODIFIABLE_ATTRIBUTE_FUNCTION));
    }
    /**
     * {@inheritDoc}
     */
    public Iterable<Attribute> findAttributes(
        String attributeDescription)
        throws LocalizedIllegalArgumentException, NullPointerException
    {
      return Iterables.unmodifiable(Iterables.transform(entry
          .findAttributes(attributeDescription),
          UNMODIFIABLE_ATTRIBUTE_FUNCTION));
    }
    public Attribute getAttribute(
        AttributeDescription attributeDescription)
    {
      Attribute attribute = entry.getAttribute(attributeDescription);
      if (attribute != null)
      {
        return unmodifiableAttribute(attribute);
      }
      else
      {
        return null;
      }
    }
    /**
     * {@inheritDoc}
     */
    public Attribute getAttribute(String attributeDescription)
        throws LocalizedIllegalArgumentException, NullPointerException
    {
      Attribute attribute = entry.getAttribute(attributeDescription);
      if (attribute != null)
      {
        return unmodifiableAttribute(attribute);
      }
      else
      {
        return null;
      }
    }
    public int getAttributeCount()
    {
      return entry.getAttributeCount();
    }
    public Iterable<Attribute> getAttributes()
    {
      return Iterables.unmodifiable(Iterables.transform(entry
          .getAttributes(), UNMODIFIABLE_ATTRIBUTE_FUNCTION));
    }
    /**
     * {@inheritDoc}
     */
    public DN getName()
    {
      return entry.getName();
    }
    public Iterable<String> getObjectClasses()
    {
      return Iterables.unmodifiable(entry.getObjectClasses());
    }
    /**
     * {@inheritDoc}
     */
    public int hashCode()
    {
      return entry.hashCode();
    }
    /**
     * {@inheritDoc}
     */
    public boolean removeAttribute(Attribute attribute,
        Collection<ByteString> missingValues)
        throws UnsupportedOperationException, NullPointerException
    {
      throw new UnsupportedOperationException();
    }
    public boolean removeAttribute(
        AttributeDescription attributeDescription)
        throws UnsupportedOperationException, NullPointerException
    {
      throw new UnsupportedOperationException();
    }
    /**
     * {@inheritDoc}
     */
    public Entry removeAttribute(String attributeDescription)
        throws LocalizedIllegalArgumentException,
        UnsupportedOperationException, NullPointerException
    {
      throw new UnsupportedOperationException();
    }
    /**
     * {@inheritDoc}
     */
    public Entry removeAttribute(String attributeDescription,
        Object... values) throws LocalizedIllegalArgumentException,
        UnsupportedOperationException, NullPointerException
    {
      throw new UnsupportedOperationException();
    }
    /**
     * {@inheritDoc}
     */
    public boolean replaceAttribute(Attribute attribute)
        throws UnsupportedOperationException, NullPointerException
    {
      throw new UnsupportedOperationException();
    }
    /**
     * {@inheritDoc}
     */
    public Entry replaceAttribute(String attributeDescription,
        Object... values) throws LocalizedIllegalArgumentException,
        UnsupportedOperationException, NullPointerException
    {
      throw new UnsupportedOperationException();
    }
    /**
     * {@inheritDoc}
     */
    public Entry setName(String dn)
        throws LocalizedIllegalArgumentException,
        UnsupportedOperationException, NullPointerException
    {
      throw new UnsupportedOperationException();
    }
    public Entry setName(DN dn) throws UnsupportedOperationException,
        NullPointerException
    {
      throw new UnsupportedOperationException();
    }
    /**
     * {@inheritDoc}
     */
    public String toString()
    {
      return entry.toString();
    }
  }
  private static final Function<Attribute, Attribute, Void> UNMODIFIABLE_ATTRIBUTE_FUNCTION = new Function<Attribute, Attribute, Void>()
  {
    public Attribute apply(Attribute value, Void p)
    {
      return unmodifiableAttribute(value);
    }
  };
  /**
   * Returns a read-only empty attribute having the specified attribute
   * description.
   *
   * @param attributeDescription
   *          The attribute description.
   * @return The empty attribute.
   * @throws NullPointerException
   *           If {@code attributeDescription} was {@code null}.
   */
  public static final Attribute emptyAttribute(
      AttributeDescription attributeDescription)
      throws NullPointerException
  {
    return new EmptyAttribute(attributeDescription);
  }
  /**
   * Returns a view of {@code attribute} having a different attribute
   * description. All operations on the returned attribute
   * "pass-through" to the underlying attribute.
   *
   * @param attribute
   *          The attribute to be renamed.
   * @param attributeDescription
   *          The new attribute description for {@code attribute}, which
   *          must be compatible with {@code attribute}'s attribute
   *          description.
   * @return A renamed view of {@code attribute}.
   * @throws IllegalArgumentException
   *           If {@code attributeDescription} does not have the same
   *           attribute type as {@code attribute}'s attribute
   *           description.
   * @throws NullPointerException
   *           If {@code attribute} or {@code attributeDescription} was
   *           {@code null}.
   */
  public static final Attribute renameAttribute(Attribute attribute,
      AttributeDescription attributeDescription)
      throws IllegalArgumentException, NullPointerException
  {
    AttributeType oldType = attribute.getAttributeDescription()
        .getAttributeType();
    AttributeType newType = attributeDescription.getAttributeType();
    // We could relax a bit by ensuring that they are both compatible
    // (e.g. one sub-type of another, or same equality matching rule,
    // etc).
    Validator.ensureTrue(oldType.equals(newType),
        "Old and new attribute type are not the same");
    return new RenamedAttribute(attribute, attributeDescription);
  }
  /**
   * Returns a read-only view of {@code attribute}. Query operations on
   * the returned attribute "read-through" to the underlying attribute,
   * and attempts to modify the returned attribute either directly or
   * indirectly via an iterator result in an {@code
   * UnsupportedOperationException}.
   *
   * @param attribute
   *          The attribute for which a read-only view is to be
   *          returned.
   * @return A read-only view of {@code attribute}.
   * @throws NullPointerException
   *           If {@code attribute} was {@code null}.
   */
  public static final Attribute unmodifiableAttribute(
      Attribute attribute) throws NullPointerException
  {
    return new UnmodifiableAttribute(attribute);
  }
  /**
   * Returns a read-only view of {@code entry} and its attributes. Query
   * operations on the returned entry and its attributes"read-through"
   * to the underlying entry or attribute, and attempts to modify the
   * returned entry and its attributes either directly or indirectly via
   * an iterator result in an {@code UnsupportedOperationException}.
   *
   * @param entry
   *          The entry for which a read-only view is to be returned.
   * @return A read-only view of {@code entry}.
   * @throws NullPointerException
   *           If {@code entry} was {@code null}.
   */
  public static final Entry unmodifiableEntry(Entry entry)
      throws NullPointerException
  {
    return new UnmodifiableEntry(entry);
  }
  // Prevent instantiation.
  private Types()
  {
    // Nothing to do.
  }
}
opendj-sdk/sdk/src/org/opends/sdk/asn1/ASN1.java
New file
@@ -0,0 +1,221 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Copyright 2006-2008 Sun Microsystems, Inc.
 */
package org.opends.sdk.asn1;
import java.io.InputStream;
import java.io.OutputStream;
import org.opends.sdk.util.*;
/**
 * This class contains various static factory methods for creating ASN.1
 * readers and writers.
 *
 * @see ASN1Reader
 * @see ASN1Writer
 */
public final class ASN1
{
  /**
   * Returns an ASN.1 reader whose source is the provided byte array and
   * having an unlimited maximum BER element size.
   *
   * @param array
   *          The byte array to use.
   * @return The new ASN.1 reader.
   */
  public static ASN1Reader getReader(byte[] array)
  {
    return getReader(array, 0);
  }
  /**
   * Returns an ASN.1 reader whose source is the provided byte array and
   * having a user defined maximum BER element size.
   *
   * @param array
   *          The byte array to use.
   * @param maxElementSize
   *          The maximum BER element size, or {@code 0} to indicate
   *          that there is no limit.
   * @return The new ASN.1 reader.
   */
  public static ASN1Reader getReader(byte[] array, int maxElementSize)
  {
    return getReader(ByteString.wrap(array), maxElementSize);
  }
  /**
   * Returns an ASN.1 reader whose source is the provided byte sequence
   * and having an unlimited maximum BER element size.
   *
   * @param sequence
   *          The byte sequence to use.
   * @return The new ASN.1 reader.
   */
  public static ASN1Reader getReader(ByteSequence sequence)
  {
    return getReader(sequence, 0);
  }
  /**
   * Returns an ASN.1 reader whose source is the provided byte sequence
   * and having a user defined maximum BER element size.
   *
   * @param sequence
   *          The byte sequence to use.
   * @param maxElementSize
   *          The maximum BER element size, or {@code 0} to indicate
   *          that there is no limit.
   * @return The new ASN.1 reader.
   */
  public static ASN1Reader getReader(ByteSequence sequence,
      int maxElementSize)
  {
    return new ASN1ByteSequenceReader(sequence.asReader(),
        maxElementSize);
  }
  /**
   * Returns an ASN.1 reader whose source is the provided byte sequence
   * reader and having an unlimited maximum BER element size.
   *
   * @param reader
   *          The byte sequence reader to use.
   * @return The new ASN.1 reader.
   */
  public static ASN1Reader getReader(ByteSequenceReader reader)
  {
    return getReader(reader, 0);
  }
  /**
   * Returns an ASN.1 reader whose source is the provided byte sequence
   * reader and having a user defined maximum BER element size.
   *
   * @param reader
   *          The byte sequence reader to use.
   * @param maxElementSize
   *          The maximum BER element size, or {@code 0} to indicate
   *          that there is no limit.
   * @return The new ASN.1 reader.
   */
  public static ASN1Reader getReader(ByteSequenceReader reader,
      int maxElementSize)
  {
    return new ASN1ByteSequenceReader(reader, maxElementSize);
  }
  /**
   * Returns an ASN.1 reader whose source is the provided input stream
   * and having an unlimited maximum BER element size.
   *
   * @param stream
   *          The input stream to use.
   * @return The new ASN.1 reader.
   */
  public static ASN1Reader getReader(InputStream stream)
  {
    return getReader(stream, 0);
  }
  /**
   * Returns an ASN.1 reader whose source is the provided input stream
   * and having a user defined maximum BER element size.
   *
   * @param stream
   *          The input stream to use.
   * @param maxElementSize
   *          The maximum BER element size, or {@code 0} to indicate
   *          that there is no limit.
   * @return The new ASN.1 reader.
   */
  public static ASN1Reader getReader(InputStream stream,
      int maxElementSize)
  {
    return new ASN1InputStreamReader(stream, maxElementSize);
  }
  /**
   * Returns an ASN.1 writer whose destination is the provided byte
   * string builder.
   *
   * @param builder
   *          The byte string builder to use.
   * @return The new ASN.1 writer.
   */
  public static ASN1Writer getWriter(ByteStringBuilder builder)
  {
    ByteSequenceOutputStream outputStream =
        new ByteSequenceOutputStream(builder);
    return getWriter(outputStream);
  }
  /**
   * Returns an ASN.1 writer whose destination is the provided output
   * stream.
   *
   * @param stream
   *          The output stream to use.
   * @return The new ASN.1 writer.
   */
  public static ASN1Writer getWriter(OutputStream stream)
  {
    return new ASN1OutputStreamWriter(stream);
  }
  // Prevent instantiation.
  private ASN1()
  {
    // Nothing to do.
  }
}
opendj-sdk/sdk/src/org/opends/sdk/asn1/ASN1ByteSequenceReader.java
New file
@@ -0,0 +1,563 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Copyright 2006-2008 Sun Microsystems, Inc.
 */
package org.opends.sdk.asn1;
import static org.opends.messages.ProtocolMessages.*;
import static org.opends.sdk.asn1.ASN1Constants.ELEMENT_READ_STATE_NEED_FIRST_LENGTH_BYTE;
import static org.opends.sdk.asn1.ASN1Constants.ELEMENT_READ_STATE_NEED_TYPE;
import static org.opends.sdk.asn1.ASN1Constants.ELEMENT_READ_STATE_NEED_VALUE_BYTES;
import java.io.IOException;
import java.util.LinkedList;
import java.util.logging.Level;
import org.opends.messages.Message;
import org.opends.sdk.DecodeException;
import org.opends.sdk.util.ByteSequenceReader;
import org.opends.sdk.util.ByteString;
import org.opends.sdk.util.ByteStringBuilder;
import org.opends.sdk.util.StaticUtils;
/**
 * An ASN.1 reader that reads from a {@link ByteSequenceReader}.
 */
final class ASN1ByteSequenceReader extends AbstractASN1Reader implements
    ASN1Reader
{
  private int state = ELEMENT_READ_STATE_NEED_TYPE;
  private byte peekType = 0;
  private int peekLength = -1;
  private final int maxElementSize;
  private ByteSequenceReader reader;
  private final LinkedList<ByteSequenceReader> readerStack;
  /**
   * Creates a new ASN1 reader whose source is the provided byte
   * sequence reader and having a user defined maximum BER element size.
   *
   * @param reader
   *          The byte sequence reader to be read.
   * @param maxElementSize
   *          The maximum BER element size, or <code>0</code> to
   *          indicate that there is no limit.
   */
  ASN1ByteSequenceReader(ByteSequenceReader reader, int maxElementSize)
  {
    this.reader = reader;
    this.readerStack = new LinkedList<ByteSequenceReader>();
    this.maxElementSize = maxElementSize;
  }
  /**
   * {@inheritDoc}
   */
  public void close() throws IOException
  {
    readerStack.clear();
  }
  /**
   * {@inheritDoc}
   */
  public boolean elementAvailable() throws IOException
  {
    if ((state == ELEMENT_READ_STATE_NEED_TYPE)
        && !needTypeState(false))
    {
      return false;
    }
    if ((state == ELEMENT_READ_STATE_NEED_FIRST_LENGTH_BYTE)
        && !needFirstLengthByteState(false))
    {
      return false;
    }
    return peekLength <= reader.remaining();
  }
  /**
   * {@inheritDoc}
   */
  public boolean hasNextElement() throws IOException
  {
    return (state != ELEMENT_READ_STATE_NEED_TYPE)
        || needTypeState(false);
  }
  /**
   * {@inheritDoc}
   */
  public int peekLength() throws IOException
  {
    peekType();
    if (state == ELEMENT_READ_STATE_NEED_FIRST_LENGTH_BYTE)
    {
      needFirstLengthByteState(true);
    }
    return peekLength;
  }
  /**
   * {@inheritDoc}
   */
  public byte peekType() throws IOException
  {
    if (state == ELEMENT_READ_STATE_NEED_TYPE)
    {
      // Read just the type.
      if (reader.remaining() <= 0)
      {
        Message message = ERR_ASN1_TRUCATED_TYPE_BYTE.get();
        throw DecodeException.fatalError(message);
      }
      int type = reader.get();
      peekType = (byte) type;
      state = ELEMENT_READ_STATE_NEED_FIRST_LENGTH_BYTE;
    }
    return peekType;
  }
  /**
   * {@inheritDoc}
   */
  public boolean readBoolean() throws IOException
  {
    // Read the header if haven't done so already
    peekLength();
    if (peekLength != 1)
    {
      Message message = ERR_ASN1_BOOLEAN_INVALID_LENGTH.get(peekLength);
      throw DecodeException.fatalError(message);
    }
    if (reader.remaining() < peekLength)
    {
      Message message = ERR_ASN1_BOOLEAN_TRUNCATED_VALUE
          .get(peekLength);
      throw DecodeException.fatalError(message);
    }
    int readByte = reader.get();
    state = ELEMENT_READ_STATE_NEED_TYPE;
    return readByte != 0x00;
  }
  /**
   * {@inheritDoc}
   */
  public void readEndSequence() throws IOException,
      IllegalStateException
  {
    if (readerStack.isEmpty())
    {
      Message message = ERR_ASN1_SEQUENCE_READ_NOT_STARTED.get();
      throw new IllegalStateException(message.toString());
    }
    if ((reader.remaining() > 0)
        && StaticUtils.DEBUG_LOG.isLoggable(Level.FINE))
    {
      StaticUtils.DEBUG_LOG.fine("Ignoring " + reader.remaining()
          + " unused trailing bytes in " + "ASN.1 SEQUENCE");
    }
    reader = readerStack.removeFirst();
    // Reset the state
    state = ELEMENT_READ_STATE_NEED_TYPE;
  }
  /**
   * {@inheritDoc}
   */
  public void readEndSet() throws IOException
  {
    // From an implementation point of view, a set is equivalent to a
    // sequence.
    readEndSequence();
  }
  /**
   * {@inheritDoc}
   */
  public int readEnumerated() throws IOException
  {
    // Read the header if haven't done so already
    peekLength();
    if ((peekLength < 1) || (peekLength > 4))
    {
      Message message = ERR_ASN1_INTEGER_INVALID_LENGTH.get(peekLength);
      throw DecodeException.fatalError(message);
    }
    // From an implementation point of view, an enumerated value is
    // equivalent to an integer.
    return (int) readInteger();
  }
  /**
   * {@inheritDoc}
   */
  public long readInteger() throws IOException
  {
    // Read the header if haven't done so already
    peekLength();
    if ((peekLength < 1) || (peekLength > 8))
    {
      Message message = ERR_ASN1_INTEGER_INVALID_LENGTH.get(peekLength);
      throw DecodeException.fatalError(message);
    }
    if (reader.remaining() < peekLength)
    {
      Message message = ERR_ASN1_INTEGER_TRUNCATED_VALUE
          .get(peekLength);
      throw DecodeException.fatalError(message);
    }
    if (peekLength > 4)
    {
      long longValue = 0;
      for (int i = 0; i < peekLength; i++)
      {
        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 IOException
  {
    // 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 DecodeException.fatalError(message);
    }
    state = ELEMENT_READ_STATE_NEED_TYPE;
  }
  /**
   * {@inheritDoc}
   */
  public ByteString readOctetString() throws IOException
  {
    // Read the header if haven't done so already
    peekLength();
    if (reader.remaining() < peekLength)
    {
      Message message = ERR_ASN1_OCTET_STRING_TRUNCATED_VALUE
          .get(peekLength);
      throw DecodeException.fatalError(message);
    }
    state = ELEMENT_READ_STATE_NEED_TYPE;
    return reader.getByteString(peekLength);
  }
  /**
   * {@inheritDoc}
   */
  public ByteStringBuilder readOctetString(ByteStringBuilder builder)
      throws IOException
  {
    // 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 DecodeException.fatalError(message);
    }
    builder.append(reader, peekLength);
    state = ELEMENT_READ_STATE_NEED_TYPE;
    return builder;
  }
  /**
   * {@inheritDoc}
   */
  public String readOctetStringAsString() throws IOException
  {
    // Read the header if haven't done so already
    peekLength();
    if (reader.remaining() < peekLength)
    {
      Message message = ERR_ASN1_OCTET_STRING_TRUNCATED_VALUE
          .get(peekLength);
      throw DecodeException.fatalError(message);
    }
    state = ELEMENT_READ_STATE_NEED_TYPE;
    return reader.getString(peekLength);
  }
  /**
   * {@inheritDoc}
   */
  public void readStartSequence() throws IOException
  {
    // Read the header if haven't done so already
    peekLength();
    if (reader.remaining() < peekLength)
    {
      Message message = ERR_ASN1_SEQUENCE_SET_TRUNCATED_VALUE
          .get(peekLength);
      throw DecodeException.fatalError(message);
    }
    ByteSequenceReader subByteString = reader.getByteSequence(
        peekLength).asReader();
    readerStack.addFirst(reader);
    reader = subByteString;
    // Reset the state
    state = ELEMENT_READ_STATE_NEED_TYPE;
  }
  /**
   * {@inheritDoc}
   */
  public void readStartSet() throws IOException
  {
    // From an implementation point of view, a set is equivalent to a
    // sequence.
    readStartSequence();
  }
  /**
   * {@inheritDoc}
   */
  public ASN1Reader skipElement() throws IOException
  {
    // Read the header if haven't done so already
    peekLength();
    if (reader.remaining() < peekLength)
    {
      Message message = ERR_ASN1_SKIP_TRUNCATED_VALUE.get(peekLength);
      throw DecodeException.fatalError(message);
    }
    state = ELEMENT_READ_STATE_NEED_TYPE;
    reader.skip(peekLength);
    return this;
  }
  /**
   * Internal helper method reading the first length bytes and
   * transition to the next state if successful.
   *
   * @param throwEofException
   *          <code>true</code> to throw an exception when the end of
   *          the sequence is encountered.
   * @return <code>true</code> if the length bytes was successfully read
   * @throws IOException
   *           If an error occurs while trying to decode an ASN1
   *           element.
   */
  private boolean needFirstLengthByteState(boolean throwEofException)
      throws IOException
  {
    if (reader.remaining() <= 0)
    {
      if (throwEofException)
      {
        Message message = ERR_ASN1_TRUNCATED_LENGTH_BYTE.get();
        throw DecodeException.fatalError(message);
      }
      return false;
    }
    int readByte = reader.get();
    peekLength = (readByte & 0x7F);
    if (peekLength != readByte)
    {
      int lengthBytesNeeded = peekLength;
      if (lengthBytesNeeded > 4)
      {
        Message message = ERR_ASN1_INVALID_NUM_LENGTH_BYTES
            .get(lengthBytesNeeded);
        throw DecodeException.fatalError(message);
      }
      peekLength = 0x00;
      if (reader.remaining() < lengthBytesNeeded)
      {
        if (throwEofException)
        {
          Message message = ERR_ASN1_TRUNCATED_LENGTH_BYTES
              .get(lengthBytesNeeded);
          throw DecodeException.fatalError(message);
        }
        return false;
      }
      while (lengthBytesNeeded > 0)
      {
        readByte = reader.get();
        peekLength = (peekLength << 8) | (readByte & 0xFF);
        lengthBytesNeeded--;
      }
    }
    // Make sure that the element is not larger than the maximum allowed
    // message size.
    if ((maxElementSize > 0) && (peekLength > maxElementSize))
    {
      Message message = ERR_LDAP_CLIENT_DECODE_MAX_REQUEST_SIZE_EXCEEDED
          .get(peekLength, maxElementSize);
      throw DecodeException.fatalError(message);
    }
    state = ELEMENT_READ_STATE_NEED_VALUE_BYTES;
    return true;
  }
  /**
   * Internal helper method reading the ASN.1 type byte and transition
   * to the next state if successful.
   *
   * @param throwEofException
   *          <code>true</code> to throw an exception when the end of
   *          the sequence is encountered.
   * @return <code>true</code> if the type byte was successfully read
   * @throws IOException
   *           If an error occurs while trying to decode an ASN1
   *           element.
   */
  private boolean needTypeState(boolean throwEofException)
      throws IOException
  {
    // Read just the type.
    if (reader.remaining() <= 0)
    {
      if (throwEofException)
      {
        Message message = ERR_ASN1_TRUCATED_TYPE_BYTE.get();
        throw DecodeException.fatalError(message);
      }
      return false;
    }
    int type = reader.get();
    peekType = (byte) type;
    state = ELEMENT_READ_STATE_NEED_FIRST_LENGTH_BYTE;
    return true;
  }
}
opendj-sdk/sdk/src/org/opends/sdk/asn1/ASN1Constants.java
New file
@@ -0,0 +1,167 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Copyright 2006-2008 Sun Microsystems, Inc.
 */
package org.opends.sdk.asn1;
/**
 * This class defines a number of constants that may be used when
 * interacting with ASN.1 elements.
 */
public final class ASN1Constants
{
  // Prevent instantiation.
  private ASN1Constants()
  {
    // Nothing to do.
  }
  /**
   * The ASN.1 element decoding state that indicates that the next byte
   * read should be the BER type for a new element.
   */
  static final int ELEMENT_READ_STATE_NEED_TYPE = 0;
  /**
   * The ASN.1 element decoding state that indicates that the next byte
   * read should be the first byte for the element length.
   */
  static final int ELEMENT_READ_STATE_NEED_FIRST_LENGTH_BYTE = 1;
  /**
   * The ASN.1 element decoding state that indicates that the next byte
   * read should be additional bytes of a multi-byte length.
   */
  static final int ELEMENT_READ_STATE_NEED_ADDITIONAL_LENGTH_BYTES = 2;
  /**
   * The ASN.1 element decoding state that indicates that the next byte
   * read should be applied to the value of the element.
   */
  static final int ELEMENT_READ_STATE_NEED_VALUE_BYTES = 3;
  /**
   * The BER type that is assigned to the universal Boolean element.
   */
  public static final byte UNIVERSAL_BOOLEAN_TYPE = 0x01;
  /**
   * The BER type that is assigned to the universal integer type.
   */
  public static final byte UNIVERSAL_INTEGER_TYPE = 0x02;
  /**
   * The BER type that is assigned to the universal octet string type.
   */
  public static final byte UNIVERSAL_OCTET_STRING_TYPE = 0x04;
  /**
   * The BER type that is assigned to the universal null type.
   */
  public static final byte UNIVERSAL_NULL_TYPE = 0x05;
  /**
   * The BER type that is assigned to the universal enumerated type.
   */
  public static final byte UNIVERSAL_ENUMERATED_TYPE = 0x0A;
  /**
   * The BER type that is assigned to the universal sequence type.
   */
  public static final byte UNIVERSAL_SEQUENCE_TYPE = 0x30;
  /**
   * The BER type that is assigned to the universal set type.
   */
  public static final byte UNIVERSAL_SET_TYPE = 0x31;
  /**
   * The byte array that will be used for ASN.1 elements with no value.
   */
  static final byte[] NO_VALUE = new byte[0];
  /**
   * The bitmask that can be ANDed with the BER type to zero out all
   * bits except those used in the class.
   */
  static final byte TYPE_MASK_ALL_BUT_CLASS = (byte) 0xC0;
  /**
   * The bitmask that can be ANDed with the BER type to determine if the
   * element is in the universal class.
   */
  static final byte TYPE_MASK_UNIVERSAL = 0x00;
  /**
   * The bitmask that can be ANDed with the BER type to determine if the
   * element is in the application-specific class.
   */
  static final byte TYPE_MASK_APPLICATION = 0x40;
  /**
   * The bitmask that can be ANDed with the BER type to determine if the
   * element is in the context-specific class.
   */
  static final byte TYPE_MASK_CONTEXT = (byte) 0x80;
  /**
   * The bitmask that can be ANDed with the BER type to determine if the
   * element is in the private class.
   */
  static final byte TYPE_MASK_PRIVATE = (byte) 0xC0;
  /**
   * The bitmask that can be ANDed with the BER type to zero out all
   * bits except the primitive/constructed bit.
   */
  static final byte TYPE_MASK_ALL_BUT_PC = (byte) 0x20;
  /**
   * The bitmask that can be ANDed with the BER type to determine if the
   * element is a primitive.
   */
  static final byte TYPE_MASK_PRIMITIVE = 0x00;
  /**
   * The bitmask that can be ANDed with the BER type to determine if the
   * element is constructed.
   */
  static final byte TYPE_MASK_CONSTRUCTED = 0x20;
  /**
   * The byte array containing the pre-encoded ASN.1 encoding for a
   * boolean value of "false".
   */
  public static final byte BOOLEAN_VALUE_FALSE = 0x00;
  /**
   * The byte array containing the pre-encoded ASN.1 encoding for a
   * boolean value of "false".
   */
  public static final byte BOOLEAN_VALUE_TRUE = (byte) 0xFF;
}
opendj-sdk/sdk/src/org/opends/sdk/asn1/ASN1InputStreamReader.java
New file
@@ -0,0 +1,789 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Copyright 2006-2008 Sun Microsystems, Inc.
 */
package org.opends.sdk.asn1;
import static org.opends.messages.ProtocolMessages.*;
import static org.opends.sdk.asn1.ASN1Constants.ELEMENT_READ_STATE_NEED_ADDITIONAL_LENGTH_BYTES;
import static org.opends.sdk.asn1.ASN1Constants.ELEMENT_READ_STATE_NEED_FIRST_LENGTH_BYTE;
import static org.opends.sdk.asn1.ASN1Constants.ELEMENT_READ_STATE_NEED_TYPE;
import static org.opends.sdk.asn1.ASN1Constants.ELEMENT_READ_STATE_NEED_VALUE_BYTES;
import java.io.IOException;
import java.io.InputStream;
import java.util.LinkedList;
import java.util.logging.Level;
import org.opends.messages.Message;
import org.opends.sdk.DecodeException;
import org.opends.sdk.util.ByteString;
import org.opends.sdk.util.ByteStringBuilder;
import org.opends.sdk.util.SizeLimitInputStream;
import org.opends.sdk.util.StaticUtils;
/**
 * An ASN1Reader that reads from an input stream.
 */
final class ASN1InputStreamReader extends AbstractASN1Reader implements
    ASN1Reader
{
  private int state = ELEMENT_READ_STATE_NEED_TYPE;
  private byte peekType = 0;
  private int peekLength = -1;
  private int lengthBytesNeeded = 0;
  private final int maxElementSize;
  private InputStream in;
  private final LinkedList<InputStream> streamStack;
  private byte[] buffer;
  /**
   * Creates a new ASN1 reader whose source is the provided input stream
   * and having a user defined maximum BER element size.
   *
   * @param stream
   *          The input stream to be read.
   * @param maxElementSize
   *          The maximum BER element size, or <code>0</code> to
   *          indicate that there is no limit.
   */
  ASN1InputStreamReader(InputStream stream, int maxElementSize)
  {
    this.in = stream;
    this.streamStack = new LinkedList<InputStream>();
    this.buffer = new byte[512];
    this.maxElementSize = maxElementSize;
  }
  /**
   * {@inheritDoc}
   */
  public void close() throws IOException
  {
    // Calling close of SizeLimitInputStream should close the parent
    // stream.
    in.close();
    streamStack.clear();
  }
  /**
   * {@inheritDoc}
   */
  public boolean elementAvailable() throws IOException
  {
    if ((state == ELEMENT_READ_STATE_NEED_TYPE)
        && !needTypeState(false, false))
    {
      return false;
    }
    if ((state == ELEMENT_READ_STATE_NEED_FIRST_LENGTH_BYTE)
        && !needFirstLengthByteState(false, false))
    {
      return false;
    }
    if ((state == ELEMENT_READ_STATE_NEED_ADDITIONAL_LENGTH_BYTES)
        && !needAdditionalLengthBytesState(false, false))
    {
      return false;
    }
    return peekLength <= in.available();
  }
  /**
   * {@inheritDoc}
   */
  public boolean hasNextElement() throws IOException
  {
    if (!streamStack.isEmpty())
    {
      // We are reading a sub sequence. Return true as long as we
      // haven't exhausted the size limit for the sub sequence sub input
      // stream.
      SizeLimitInputStream subSq = (SizeLimitInputStream) in;
      return (subSq.getSizeLimit() - subSq.getBytesRead() > 0);
    }
    return (state != ELEMENT_READ_STATE_NEED_TYPE)
        || needTypeState(true, false);
  }
  /**
   * {@inheritDoc}
   */
  public int peekLength() throws IOException
  {
    peekType();
    switch (state)
    {
    case ELEMENT_READ_STATE_NEED_FIRST_LENGTH_BYTE:
      needFirstLengthByteState(true, true);
      break;
    case ELEMENT_READ_STATE_NEED_ADDITIONAL_LENGTH_BYTES:
      needAdditionalLengthBytesState(true, true);
    }
    return peekLength;
  }
  /**
   * {@inheritDoc}
   */
  public byte peekType() throws IOException
  {
    if (state == ELEMENT_READ_STATE_NEED_TYPE)
    {
      needTypeState(true, true);
    }
    return peekType;
  }
  /**
   * {@inheritDoc}
   */
  public boolean readBoolean() throws IOException
  {
    // Read the header if haven't done so already
    peekLength();
    if (peekLength != 1)
    {
      Message message = ERR_ASN1_BOOLEAN_INVALID_LENGTH.get(peekLength);
      throw DecodeException.fatalError(message);
    }
    int readByte = in.read();
    if (readByte == -1)
    {
      Message message = ERR_ASN1_BOOLEAN_TRUNCATED_VALUE
          .get(peekLength);
      throw DecodeException.fatalError(message);
    }
    if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINEST))
    {
      StaticUtils.DEBUG_LOG.finest(String.format(
          "READ ASN.1 BOOLEAN(type=0x%x, length=%d, value=%s)",
          peekType, peekLength, String.valueOf(readByte != 0x00)));
    }
    state = ELEMENT_READ_STATE_NEED_TYPE;
    return readByte != 0x00;
  }
  /**
   * {@inheritDoc}
   */
  public void readEndSequence() throws IOException,
      IllegalStateException
  {
    if (streamStack.isEmpty())
    {
      Message message = ERR_ASN1_SEQUENCE_READ_NOT_STARTED.get();
      throw new IllegalStateException(message.toString());
    }
    // Ignore all unused trailing components.
    SizeLimitInputStream subSq = (SizeLimitInputStream) in;
    if (subSq.getSizeLimit() - subSq.getBytesRead() > 0)
    {
      if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINE))
      {
        StaticUtils.DEBUG_LOG.fine(String.format(
            "Ignoring %d unused trailing bytes in ASN.1 SEQUENCE",
            subSq.getSizeLimit() - subSq.getBytesRead()));
      }
      subSq.skip(subSq.getSizeLimit() - subSq.getBytesRead());
    }
    if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINEST))
    {
      StaticUtils.DEBUG_LOG.finest(String
          .format("READ ASN.1 END SEQUENCE"));
    }
    in = streamStack.removeFirst();
    // Reset the state
    state = ELEMENT_READ_STATE_NEED_TYPE;
  }
  /**
   * {@inheritDoc}
   */
  public void readEndSet() throws IOException
  {
    // From an implementation point of view, a set is equivalent to a
    // sequence.
    readEndSequence();
  }
  /**
   * {@inheritDoc}
   */
  public int readEnumerated() throws IOException
  {
    // Read the header if haven't done so already
    peekLength();
    if ((peekLength < 1) || (peekLength > 4))
    {
      Message message = ERR_ASN1_INTEGER_INVALID_LENGTH.get(peekLength);
      throw DecodeException.fatalError(message);
    }
    // From an implementation point of view, an enumerated value is
    // equivalent to an integer.
    return (int) readInteger();
  }
  /**
   * {@inheritDoc}
   */
  public long readInteger() throws IOException
  {
    // Read the header if haven't done so already
    peekLength();
    if ((peekLength < 1) || (peekLength > 8))
    {
      Message message = ERR_ASN1_INTEGER_INVALID_LENGTH.get(peekLength);
      throw DecodeException.fatalError(message);
    }
    if (peekLength > 4)
    {
      long longValue = 0;
      for (int i = 0; i < peekLength; i++)
      {
        int readByte = in.read();
        if (readByte == -1)
        {
          Message message = ERR_ASN1_INTEGER_TRUNCATED_VALUE
              .get(peekLength);
          throw DecodeException.fatalError(message);
        }
        if ((i == 0) && (((byte) readByte) < 0))
        {
          longValue = 0xFFFFFFFFFFFFFFFFL;
        }
        longValue = (longValue << 8) | (readByte & 0xFF);
      }
      state = ELEMENT_READ_STATE_NEED_TYPE;
      return longValue;
    }
    else
    {
      int intValue = 0;
      for (int i = 0; i < peekLength; i++)
      {
        int readByte = in.read();
        if (readByte == -1)
        {
          Message message = ERR_ASN1_INTEGER_TRUNCATED_VALUE
              .get(peekLength);
          throw DecodeException.fatalError(message);
        }
        if ((i == 0) && (((byte) readByte) < 0))
        {
          intValue = 0xFFFFFFFF;
        }
        intValue = (intValue << 8) | (readByte & 0xFF);
      }
      if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINEST))
      {
        StaticUtils.DEBUG_LOG.finest(String.format(
            "READ ASN.1 INTEGER(type=0x%x, length=%d, value=%d)",
            peekType, peekLength, intValue));
      }
      state = ELEMENT_READ_STATE_NEED_TYPE;
      return intValue;
    }
  }
  /**
   * {@inheritDoc}
   */
  public void readNull() throws IOException
  {
    // Read the header if haven't done so already
    peekLength();
    // Make sure that the decoded length is exactly zero byte.
    if (peekLength != 0)
    {
      Message message = ERR_ASN1_NULL_INVALID_LENGTH.get(peekLength);
      throw DecodeException.fatalError(message);
    }
    if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINEST))
    {
      StaticUtils.DEBUG_LOG.finest(String
          .format("READ ASN.1 NULL(type=0x%x, length=%d)", peekType,
              peekLength));
    }
    state = ELEMENT_READ_STATE_NEED_TYPE;
  }
  /**
   * {@inheritDoc}
   */
  public ByteString readOctetString() throws IOException
  {
    // Read the header if haven't done so already
    peekLength();
    if (peekLength == 0)
    {
      state = ELEMENT_READ_STATE_NEED_TYPE;
      return ByteString.empty();
    }
    // Copy the value and construct the element to return.
    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 DecodeException.fatalError(message);
      }
      bytesNeeded -= bytesRead;
    }
    if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINEST))
    {
      StaticUtils.DEBUG_LOG.finest(String.format(
          "READ ASN.1 OCTETSTRING(type=0x%x, length=%d)", peekType,
          peekLength));
    }
    state = ELEMENT_READ_STATE_NEED_TYPE;
    return ByteString.wrap(value);
  }
  /**
   * {@inheritDoc}
   */
  public ByteStringBuilder readOctetString(ByteStringBuilder builder)
      throws IOException
  {
    // Read the header if haven't done so already
    peekLength();
    if (peekLength == 0)
    {
      state = ELEMENT_READ_STATE_NEED_TYPE;
      return builder;
    }
    // Copy the value and construct the element to return.
    int bytesNeeded = peekLength;
    int bytesRead;
    while (bytesNeeded > 0)
    {
      bytesRead = builder.append(in, bytesNeeded);
      if (bytesRead < 0)
      {
        Message message = ERR_ASN1_OCTET_STRING_TRUNCATED_VALUE
            .get(peekLength);
        throw DecodeException.fatalError(message);
      }
      bytesNeeded -= bytesRead;
    }
    if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINEST))
    {
      StaticUtils.DEBUG_LOG.finest(String.format(
          "READ ASN.1 OCTETSTRING(type=0x%x, length=%d)", peekType,
          peekLength));
    }
    state = ELEMENT_READ_STATE_NEED_TYPE;
    return builder;
  }
  /**
   * {@inheritDoc}
   */
  public String readOctetStringAsString() throws IOException
  {
    // Read the header if haven't done so already
    peekLength();
    if (peekLength == 0)
    {
      state = ELEMENT_READ_STATE_NEED_TYPE;
      return "";
    }
    // Resize the temp buffer if needed
    if (peekLength > buffer.length)
    {
      buffer = new byte[peekLength];
    }
    int bytesNeeded = peekLength;
    int bytesRead;
    while (bytesNeeded > 0)
    {
      bytesRead = in
          .read(buffer, peekLength - bytesNeeded, bytesNeeded);
      if (bytesRead < 0)
      {
        Message message = ERR_ASN1_OCTET_STRING_TRUNCATED_VALUE
            .get(peekLength);
        throw DecodeException.fatalError(message);
      }
      bytesNeeded -= bytesRead;
    }
    state = ELEMENT_READ_STATE_NEED_TYPE;
    String str;
    try
    {
      str = new String(buffer, 0, peekLength, "UTF-8");
    }
    catch (Exception e)
    {
      if (StaticUtils.DEBUG_LOG.isLoggable(Level.WARNING))
      {
        StaticUtils.DEBUG_LOG
            .warning("Unable to decode ASN.1 OCTETSTRING "
                + "bytes as UTF-8 string: " + e.toString());
      }
      str = new String(buffer, 0, peekLength);
    }
    if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINEST))
    {
      StaticUtils.DEBUG_LOG.finest(String.format(
          "READ ASN.1 OCTETSTRING(type=0x%x, length=%d, value=%s)",
          peekType, peekLength, str));
    }
    return str;
  }
  /**
   * {@inheritDoc}
   */
  public void readStartSequence() throws IOException
  {
    // Read the header if haven't done so already
    peekLength();
    SizeLimitInputStream subStream = new SizeLimitInputStream(in,
        peekLength);
    if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINEST))
    {
      StaticUtils.DEBUG_LOG.finest(String.format(
          "READ ASN.1 START SEQUENCE(type=0x%x, length=%d)", peekType,
          peekLength));
    }
    streamStack.addFirst(in);
    in = subStream;
    // Reset the state
    state = ELEMENT_READ_STATE_NEED_TYPE;
  }
  /**
   * {@inheritDoc}
   */
  public void readStartSet() throws IOException
  {
    // From an implementation point of view, a set is equivalent to a
    // sequence.
    readStartSequence();
  }
  /**
   * {@inheritDoc}
   */
  public ASN1Reader skipElement() throws IOException
  {
    // Read the header if haven't done so already
    peekLength();
    long bytesSkipped = in.skip(peekLength);
    if (bytesSkipped != peekLength)
    {
      Message message = ERR_ASN1_SKIP_TRUNCATED_VALUE.get(peekLength);
      throw DecodeException.fatalError(message);
    }
    state = ELEMENT_READ_STATE_NEED_TYPE;
    return this;
  }
  /**
   * Internal helper method reading the additional ASN.1 length bytes
   * and transition to the next state if successful.
   *
   * @param isBlocking
   *          <code>true</code> to block if the type byte is not
   *          available or <code>false</code> to check for availability
   *          first.
   * @param throwEofException
   *          <code>true</code> to throw an exception when an EOF is
   *          encountered or <code>false</code> to return false.
   * @return <code>true</code> if the length bytes was successfully
   *         read.
   * @throws IOException
   *           If an error occurs while reading from the stream.
   */
  private boolean needAdditionalLengthBytesState(boolean isBlocking,
      boolean throwEofException) throws IOException
  {
    if (!isBlocking && (in.available() < lengthBytesNeeded))
    {
      return false;
    }
    int readByte;
    while (lengthBytesNeeded > 0)
    {
      readByte = in.read();
      if (readByte == -1)
      {
        state = ELEMENT_READ_STATE_NEED_ADDITIONAL_LENGTH_BYTES;
        if (throwEofException)
        {
          Message message = ERR_ASN1_TRUNCATED_LENGTH_BYTES
              .get(lengthBytesNeeded);
          throw DecodeException.fatalError(message);
        }
        return false;
      }
      peekLength = (peekLength << 8) | (readByte & 0xFF);
      lengthBytesNeeded--;
    }
    // Make sure that the element is not larger than the maximum allowed
    // message size.
    if ((maxElementSize > 0) && (peekLength > maxElementSize))
    {
      Message message = ERR_LDAP_CLIENT_DECODE_MAX_REQUEST_SIZE_EXCEEDED
          .get(peekLength, maxElementSize);
      throw DecodeException.fatalError(message);
    }
    state = ELEMENT_READ_STATE_NEED_VALUE_BYTES;
    return true;
  }
  /**
   * Internal helper method reading the first length bytes and
   * transition to the next state if successful.
   *
   * @param isBlocking
   *          <code>true</code> to block if the type byte is not
   *          available or <code>false</code> to check for availability
   *          first.
   * @param throwEofException
   *          <code>true</code> to throw an exception when an EOF is
   *          encountered or <code>false</code> to return false.
   * @return <code>true</code> if the length bytes was successfully read
   * @throws IOException
   *           If an error occurs while reading from the stream.
   */
  private boolean needFirstLengthByteState(boolean isBlocking,
      boolean throwEofException) throws IOException
  {
    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 DecodeException.fatalError(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 DecodeException.fatalError(message);
      }
      peekLength = 0x00;
      if (!isBlocking && (in.available() < lengthBytesNeeded))
      {
        state = ELEMENT_READ_STATE_NEED_ADDITIONAL_LENGTH_BYTES;
        return false;
      }
      while (lengthBytesNeeded > 0)
      {
        readByte = in.read();
        if (readByte == -1)
        {
          state = ELEMENT_READ_STATE_NEED_ADDITIONAL_LENGTH_BYTES;
          if (throwEofException)
          {
            Message message = ERR_ASN1_TRUNCATED_LENGTH_BYTES
                .get(lengthBytesNeeded);
            throw DecodeException.fatalError(message);
          }
          return false;
        }
        peekLength = (peekLength << 8) | (readByte & 0xFF);
        lengthBytesNeeded--;
      }
    }
    // Make sure that the element is not larger than the maximum allowed
    // message size.
    if ((maxElementSize > 0) && (peekLength > maxElementSize))
    {
      Message message = ERR_LDAP_CLIENT_DECODE_MAX_REQUEST_SIZE_EXCEEDED
          .get(peekLength, maxElementSize);
      throw DecodeException.fatalError(message);
    }
    state = ELEMENT_READ_STATE_NEED_VALUE_BYTES;
    return true;
  }
  /**
   * Internal helper method reading the ASN.1 type byte and transition
   * to the next state if successful.
   *
   * @param isBlocking
   *          <code>true</code> to block if the type byte is not
   *          available or <code>false</code> to check for availability
   *          first.
   * @param throwEofException
   *          <code>true</code> to throw an exception when an EOF is
   *          encountered or <code>false</code> to return false.
   * @return <code>true</code> if the type byte was successfully read
   * @throws IOException
   *           If an error occurs while reading from the stream.
   */
  private boolean needTypeState(boolean isBlocking,
      boolean throwEofException) throws IOException
  {
    // 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 DecodeException.fatalError(message);
      }
      return false;
    }
    peekType = (byte) type;
    state = ELEMENT_READ_STATE_NEED_FIRST_LENGTH_BYTE;
    return true;
  }
}
opendj-sdk/sdk/src/org/opends/sdk/asn1/ASN1OutputStreamWriter.java
New file
@@ -0,0 +1,560 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Copyright 2006-2009 Sun Microsystems, Inc.
 */
package org.opends.sdk.asn1;
import static org.opends.messages.ProtocolMessages.ERR_ASN1_SEQUENCE_WRITE_NOT_STARTED;
import static org.opends.sdk.asn1.ASN1Constants.BOOLEAN_VALUE_FALSE;
import static org.opends.sdk.asn1.ASN1Constants.BOOLEAN_VALUE_TRUE;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.logging.Level;
import org.opends.messages.Message;
import org.opends.sdk.util.ByteSequence;
import org.opends.sdk.util.ByteSequenceOutputStream;
import org.opends.sdk.util.ByteStringBuilder;
import org.opends.sdk.util.StaticUtils;
/**
 * An ASN1Writer implementation that outputs to an outputstream.
 */
final class ASN1OutputStreamWriter extends AbstractASN1Writer implements
    ASN1Writer
{
  private final OutputStream rootStream;
  private OutputStream out;
  private final ArrayList<ByteSequenceOutputStream> streamStack;
  private int stackDepth;
  /**
   * Creates a new ASN.1 output stream reader.
   *
   * @param stream
   *          The underlying output stream.
   */
  ASN1OutputStreamWriter(OutputStream stream)
  {
    this.out = stream;
    this.rootStream = stream;
    this.streamStack = new ArrayList<ByteSequenceOutputStream>();
    this.stackDepth = -1;
  }
  /**
   * {@inheritDoc}
   */
  public void close() throws IOException
  {
    while (stackDepth >= 0)
    {
      writeEndSequence();
    }
    rootStream.flush();
    streamStack.clear();
    rootStream.close();
  }
  /**
   * {@inheritDoc}
   */
  public void flush() throws IOException
  {
    rootStream.flush();
  }
  /**
   * {@inheritDoc}
   */
  public ASN1Writer writeBoolean(byte type, boolean booleanValue)
      throws IOException
  {
    out.write(type);
    writeLength(1);
    out.write(booleanValue ? BOOLEAN_VALUE_TRUE : BOOLEAN_VALUE_FALSE);
    if(StaticUtils.DEBUG_LOG.isLoggable(Level.FINEST))
    {
      StaticUtils.DEBUG_LOG.finest(String.format(
          "WRITE ASN.1 BOOLEAN(type=0x%x, length=%d, value=%s)", type,
          1, String.valueOf(booleanValue)));
    }
    return this;
  }
  /**
   * {@inheritDoc}
   */
  public ASN1Writer writeEndSequence() throws IOException, IllegalStateException
  {
    if (stackDepth < 0)
    {
      Message message = ERR_ASN1_SEQUENCE_WRITE_NOT_STARTED.get();
      throw new IllegalStateException(message.toString());
    }
    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(StaticUtils.DEBUG_LOG.isLoggable(Level.FINEST))
    {
      StaticUtils.DEBUG_LOG.finest(String.format(
          "WRITE ASN.1 END SEQUENCE(length=%d)", childStream.length()));
    }
    childStream.reset();
    return this;
  }
  /**
   * {@inheritDoc}
   */
  public ASN1Writer writeEndSet() throws IOException
  {
    return writeEndSequence();
  }
  /**
   * {@inheritDoc}
   */
  public ASN1Writer writeEnumerated(byte type, int intValue)
      throws IOException
  {
    return writeInteger(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(StaticUtils.DEBUG_LOG.isLoggable(Level.FINEST))
      {
        StaticUtils.DEBUG_LOG.finest(String.format(
            "WRITE ASN.1 INTEGER(type=0x%x, length=%d, value=%d)",
                type, 1, intValue));
      }
    }
    else if (((intValue < 0) && ((intValue & 0xFFFF8000) == 0xFFFF8000))
        || ((intValue & 0x00007FFF) == intValue))
    {
      writeLength(2);
      out.write((byte) ((intValue >> 8) & 0xFF));
      out.write((byte) (intValue & 0xFF));
      if(StaticUtils.DEBUG_LOG.isLoggable(Level.FINEST))
      {
        StaticUtils.DEBUG_LOG.finest(String.format(
            "WRITE ASN.1 INTEGER(type=0x%x, length=%d, value=%d)",
                type, 2, intValue));
      }
    }
    else if (((intValue < 0) && ((intValue & 0xFF800000) == 0xFF800000))
        || ((intValue & 0x007FFFFF) == intValue))
    {
      writeLength(3);
      out.write((byte) ((intValue >> 16) & 0xFF));
      out.write((byte) ((intValue >> 8) & 0xFF));
      out.write((byte) (intValue & 0xFF));
      if(StaticUtils.DEBUG_LOG.isLoggable(Level.FINEST))
      {
        StaticUtils.DEBUG_LOG.finest(String.format(
            "WRITE ASN.1 INTEGER(type=0x%x, length=%d, value=%d)",
                type, 3, intValue));
      }
    }
    else
    {
      writeLength(4);
      out.write((byte) ((intValue >> 24) & 0xFF));
      out.write((byte) ((intValue >> 16) & 0xFF));
      out.write((byte) ((intValue >> 8) & 0xFF));
      out.write((byte) (intValue & 0xFF));
      if(StaticUtils.DEBUG_LOG.isLoggable(Level.FINEST))
      {
        StaticUtils.DEBUG_LOG.finest(String.format(
            "WRITE ASN.1 INTEGER(type=0x%x, length=%d, value=%d)",
            type, 4, intValue));
      }
    }
    return this;
  }
  /**
   * {@inheritDoc}
   */
  public ASN1Writer writeInteger(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(StaticUtils.DEBUG_LOG.isLoggable(Level.FINEST))
      {
        StaticUtils.DEBUG_LOG.finest(String.format(
            "WRITE ASN.1 INTEGER(type=0x%x, length=%d, value=%d)",
                type, 1, longValue));
      }
    }
    else if (((longValue < 0) && ((longValue & 0xFFFFFFFFFFFF8000L) == 0xFFFFFFFFFFFF8000L))
        || ((longValue & 0x0000000000007FFFL) == longValue))
    {
      writeLength(2);
      out.write((byte) ((longValue >> 8) & 0xFF));
      out.write((byte) (longValue & 0xFF));
      if(StaticUtils.DEBUG_LOG.isLoggable(Level.FINEST))
      {
        StaticUtils.DEBUG_LOG.finest(String.format(
            "WRITE ASN.1 INTEGER(type=0x%x, length=%d, value=%d)",
                type, 2, longValue));
      }
    }
    else if (((longValue < 0) && ((longValue & 0xFFFFFFFFFF800000L) == 0xFFFFFFFFFF800000L))
        || ((longValue & 0x00000000007FFFFFL) == longValue))
    {
      writeLength(3);
      out.write((byte) ((longValue >> 16) & 0xFF));
      out.write((byte) ((longValue >> 8) & 0xFF));
      out.write((byte) (longValue & 0xFF));
      if(StaticUtils.DEBUG_LOG.isLoggable(Level.FINEST))
      {
        StaticUtils.DEBUG_LOG.finest(String.format(
            "WRITE ASN.1 INTEGER(type=0x%x, length=%d, value=%d)",
                type, 3, longValue));
      }
    }
    else if (((longValue < 0) && ((longValue & 0xFFFFFFFF80000000L) == 0xFFFFFFFF80000000L))
        || ((longValue & 0x000000007FFFFFFFL) == longValue))
    {
      writeLength(4);
      out.write((byte) ((longValue >> 24) & 0xFF));
      out.write((byte) ((longValue >> 16) & 0xFF));
      out.write((byte) ((longValue >> 8) & 0xFF));
      out.write((byte) (longValue & 0xFF));
      if(StaticUtils.DEBUG_LOG.isLoggable(Level.FINEST))
      {
        StaticUtils.DEBUG_LOG.finest(String.format(
            "WRITE ASN.1 INTEGER(type=0x%x, length=%d, value=%d)",
                type, 4, longValue));
      }
    }
    else if (((longValue < 0) && ((longValue & 0xFFFFFF8000000000L) == 0xFFFFFF8000000000L))
        || ((longValue & 0x0000007FFFFFFFFFL) == longValue))
    {
      writeLength(5);
      out.write((byte) ((longValue >> 32) & 0xFF));
      out.write((byte) ((longValue >> 24) & 0xFF));
      out.write((byte) ((longValue >> 16) & 0xFF));
      out.write((byte) ((longValue >> 8) & 0xFF));
      out.write((byte) (longValue & 0xFF));
      if(StaticUtils.DEBUG_LOG.isLoggable(Level.FINEST))
      {
        StaticUtils.DEBUG_LOG.finest(String.format(
            "WRITE ASN.1 INTEGER(type=0x%x, length=%d, value=%d)",
                type, 5, longValue));
      }
    }
    else if (((longValue < 0) && ((longValue & 0xFFFF800000000000L) == 0xFFFF800000000000L))
        || ((longValue & 0x00007FFFFFFFFFFFL) == longValue))
    {
      writeLength(6);
      out.write((byte) ((longValue >> 40) & 0xFF));
      out.write((byte) ((longValue >> 32) & 0xFF));
      out.write((byte) ((longValue >> 24) & 0xFF));
      out.write((byte) ((longValue >> 16) & 0xFF));
      out.write((byte) ((longValue >> 8) & 0xFF));
      out.write((byte) (longValue & 0xFF));
      if(StaticUtils.DEBUG_LOG.isLoggable(Level.FINEST))
      {
        StaticUtils.DEBUG_LOG.finest(String.format(
            "WRITE ASN.1 INTEGER(type=0x%x, length=%d, value=%d)",
                type, 6, longValue));
      }
    }
    else if (((longValue < 0) && ((longValue & 0xFF80000000000000L) == 0xFF80000000000000L))
        || ((longValue & 0x007FFFFFFFFFFFFFL) == longValue))
    {
      writeLength(7);
      out.write((byte) ((longValue >> 48) & 0xFF));
      out.write((byte) ((longValue >> 40) & 0xFF));
      out.write((byte) ((longValue >> 32) & 0xFF));
      out.write((byte) ((longValue >> 24) & 0xFF));
      out.write((byte) ((longValue >> 16) & 0xFF));
      out.write((byte) ((longValue >> 8) & 0xFF));
      out.write((byte) (longValue & 0xFF));
      if(StaticUtils.DEBUG_LOG.isLoggable(Level.FINEST))
      {
        StaticUtils.DEBUG_LOG.finest(String.format(
            "WRITE ASN.1 INTEGER(type=0x%x, length=%d, value=%d)",
                type, 7, longValue));
      }
    }
    else
    {
      writeLength(8);
      out.write((byte) ((longValue >> 56) & 0xFF));
      out.write((byte) ((longValue >> 48) & 0xFF));
      out.write((byte) ((longValue >> 40) & 0xFF));
      out.write((byte) ((longValue >> 32) & 0xFF));
      out.write((byte) ((longValue >> 24) & 0xFF));
      out.write((byte) ((longValue >> 16) & 0xFF));
      out.write((byte) ((longValue >> 8) & 0xFF));
      out.write((byte) (longValue & 0xFF));
      if(StaticUtils.DEBUG_LOG.isLoggable(Level.FINEST))
      {
        StaticUtils.DEBUG_LOG.finest(String.format(
            "WRITE ASN.1 INTEGER(type=0x%x, length=%d, value=%d)",
                type, 8, longValue));
      }
    }
    return this;
  }
  /**
   * {@inheritDoc}
   */
  public ASN1Writer writeNull(byte type) throws IOException
  {
    out.write(type);
    writeLength(0);
    if(StaticUtils.DEBUG_LOG.isLoggable(Level.FINEST))
    {
      StaticUtils.DEBUG_LOG.finest(String.format(
          "WRITE ASN.1 NULL(type=0x%x, length=%d)", type, 0));
    }
    return this;
  }
  /**
   * {@inheritDoc}
   */
  public ASN1Writer writeOctetString(byte type, byte[] value,
      int offset, int length) throws IOException
  {
    out.write(type);
    writeLength(length);
    out.write(value, offset, length);
    if(StaticUtils.DEBUG_LOG.isLoggable(Level.FINEST))
    {
      StaticUtils.DEBUG_LOG.finest(String.format(
          "WRITE ASN.1 OCTETSTRING(type=0x%x, length=%d)",
              type, length));
    }
    return this;
  }
  /**
   * {@inheritDoc}
   */
  public ASN1Writer writeOctetString(byte type, ByteSequence value)
      throws IOException
  {
    out.write(type);
    writeLength(value.length());
    value.copyTo(out);
    if(StaticUtils.DEBUG_LOG.isLoggable(Level.FINEST))
    {
      StaticUtils.DEBUG_LOG.finest(String.format(
          "WRITE ASN.1 OCTETSTRING(type=0x%x, length=%d)", type, value
              .length()));
    }
    return this;
  }
  /**
   * {@inheritDoc}
   */
  public ASN1Writer writeOctetString(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(StaticUtils.DEBUG_LOG.isLoggable(Level.FINEST))
    {
      StaticUtils.DEBUG_LOG.finest(String.format(
          "WRITE ASN.1 OCTETSTRING(type=0x%x, length=%d, "
              + "value=%s)", type, bytes.length, value));
    }
    return this;
  }
  /**
   * {@inheritDoc}
   */
  public ASN1Writer writeStartSequence(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(StaticUtils.DEBUG_LOG.isLoggable(Level.FINEST))
    {
      StaticUtils.DEBUG_LOG.finest(String.format(
          "WRITE ASN.1 START SEQUENCE(type=0x%x)", type));
    }
    return this;
  }
  /**
   * {@inheritDoc}
   */
  public ASN1Writer writeStartSet(byte type) throws IOException
  {
    // From an implementation point of view, a set is equivalent to a
    // sequence.
    return writeStartSequence(type);
  }
  /**
   * Writes the provided value for use as the length of an ASN.1
   * element.
   *
   * @param length
   *          The length to encode for use in an ASN.1 element.
   * @throws IOException
   *           if an error occurs while writing.
   */
  private void writeLength(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));
    }
  }
}
opendj-sdk/sdk/src/org/opends/sdk/asn1/ASN1Reader.java
New file
@@ -0,0 +1,448 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Copyright 2006-2008 Sun Microsystems, Inc.
 */
package org.opends.sdk.asn1;
import java.io.Closeable;
import java.io.IOException;
import org.opends.sdk.DecodeException;
import org.opends.sdk.util.ByteString;
import org.opends.sdk.util.ByteStringBuilder;
/**
 * An interface for decoding ASN.1 elements from a data source.
 * <p>
 * Methods for creating {@link ASN1Reader}s are provided in the
 * {@link ASN1} class.
 */
public interface ASN1Reader extends Closeable
{
  /**
   * Closes this ASN.1 reader.
   *
   * @throws IOException
   *           If an error occurs while closing.
   */
  void close() throws IOException;
  /**
   * Indicates whether or not the next element can be read without
   * blocking.
   *
   * @return {@code true} if a complete element is available or {@code
   *         false} otherwise.
   * @throws DecodeException
   *           If the available data was not valid ASN.1.
   * @throws IOException
   *           If an unexpected IO error occurred.
   */
  boolean elementAvailable() throws DecodeException, IOException;
  /**
   * Indicates whether or not the current stream, sequence, or set
   * contains another element. Note that this method may return {@code
   * true} even if a previous call to {@link #elementAvailable} returned
   * {@code false}, indicating that the current set or sequence contains
   * another element but an attempt to read that element may block. This
   * method will block if there is not enough data available to make the
   * determination (typically only the next element's type is required).
   *
   * @return {@code true} if the current stream, sequence, or set
   *         contains another element, or {@code false} if the end of
   *         the stream, sequence, or set has been reached.
   * @throws DecodeException
   *           If the available data was not valid ASN.1.
   * @throws IOException
   *           If an unexpected IO error occurred.
   */
  boolean hasNextElement() throws DecodeException, IOException;
  /**
   * Returns the data length of the next element without actually
   * reading it.
   *
   * @return The data length of the next element, or {@code -1} if the
   *         end of the stream, sequence, or set has been reached.
   * @throws DecodeException
   *           If the available data was not valid ASN.1.
   * @throws IOException
   *           If an unexpected IO error occurred.
   */
  int peekLength() throws DecodeException, IOException;
  /**
   * Returns the type of the next element without actually reading it.
   *
   * @return The type of the next element, or {@code -1} if the end of
   *         the stream, sequence, or set has been reached.
   * @throws DecodeException
   *           If the available data was not valid ASN.1.
   * @throws IOException
   *           If an unexpected IO error occurred.
   */
  byte peekType() throws DecodeException, IOException;
  /**
   * Reads the next element as a boolean having the Universal Boolean
   * ASN.1 type tag.
   *
   * @return The decoded boolean value.
   * @throws DecodeException
   *           If the element cannot be decoded as a boolean.
   * @throws IOException
   *           If an unexpected IO error occurred.
   */
  boolean readBoolean() throws DecodeException, IOException;
  /**
   * Reads the next element as a boolean having the provided type tag.
   *
   * @param type
   *          The expected type tag of the element.
   * @return The decoded boolean value.
   * @throws DecodeException
   *           If the element cannot be decoded as a boolean.
   * @throws IOException
   *           If an unexpected IO error occurred.
   */
  boolean readBoolean(byte type) throws DecodeException, IOException;
  /**
   * Finishes reading a sequence and discards any unread elements.
   *
   * @throws DecodeException
   *           If an error occurs while advancing to the end of the
   *           sequence.
   * @throws IOException
   *           If an unexpected IO error occurred.
   * @throws IllegalStateException
   *           If there is no sequence being read.
   */
  void readEndSequence() throws DecodeException, IOException,
      IllegalStateException;
  /**
   * Finishes reading a set and discards any unread elements.
   *
   * @throws DecodeException
   *           If an error occurs while advancing to the end of the set.
   * @throws IOException
   *           If an unexpected IO error occurred.
   * @throws IllegalStateException
   *           If there is no set being read.
   */
  void readEndSet() throws DecodeException, IOException,
      IllegalStateException;
  /**
   * Reads the next element as an enumerated having the Universal
   * Enumerated ASN.1 type tag.
   *
   * @return The decoded enumerated value.
   * @throws DecodeException
   *           If the element cannot be decoded as an enumerated value.
   * @throws IOException
   *           If an unexpected IO error occurred.
   */
  int readEnumerated() throws DecodeException, IOException;
  /**
   * Reads the next element as an enumerated having the provided type
   * tag.
   *
   * @param type
   *          The expected type tag of the element.
   * @return The decoded enumerated value.
   * @throws DecodeException
   *           If the element cannot be decoded as an enumerated value.
   * @throws IOException
   *           If an unexpected IO error occurred.
   */
  int readEnumerated(byte type) throws DecodeException, IOException;
  /**
   * Reads the next element as an integer having the Universal Integer
   * ASN.1 type tag.
   *
   * @return The decoded integer value.
   * @throws DecodeException
   *           If the element cannot be decoded as an integer.
   * @throws IOException
   *           If an unexpected IO error occurred.
   */
  long readInteger() throws DecodeException, IOException;
  /**
   * Reads the next element as an integer having the provided type tag.
   *
   * @param type
   *          The expected type tag of the element.
   * @return The decoded integer value.
   * @throws DecodeException
   *           If the element cannot be decoded as an integer.
   * @throws IOException
   *           If an unexpected IO error occurred.
   */
  long readInteger(byte type) throws DecodeException, IOException;
  /**
   * Reads the next element as a null element having the Universal Null
   * ASN.1 type tag.
   *
   * @throws DecodeException
   *           If the element cannot be decoded as a null element.
   * @throws IOException
   *           If an unexpected IO error occurred.
   */
  void readNull() throws DecodeException, IOException;
  /**
   * Reads the next element as a null element having the provided type
   * tag.
   *
   * @param type
   *          The expected type tag of the element.
   * @throws DecodeException
   *           If the element cannot be decoded as a null element.
   * @throws IOException
   *           If an unexpected IO error occurred.
   */
  void readNull(byte type) throws DecodeException, IOException;
  /**
   * Reads the next element as an octet string having the Universal
   * Octet String ASN.1 type tag.
   *
   * @return The decoded octet string represented using a
   *         {@link ByteString}.
   * @throws DecodeException
   *           If the element cannot be decoded as an octet string.
   * @throws IOException
   *           If an unexpected IO error occurred.
   */
  ByteString readOctetString() throws DecodeException, IOException;
  /**
   * Reads the next element as an octet string having the provided type
   * tag.
   *
   * @param type
   *          The expected type tag of the element.
   * @return The decoded octet string represented using a
   *         {@link ByteString}.
   * @throws DecodeException
   *           If the element cannot be decoded as an octet string.
   * @throws IOException
   *           If an unexpected IO error occurred.
   */
  ByteString readOctetString(byte type) throws DecodeException,
      IOException;
  /**
   * Reads the next element as an octet string having the provided type
   * tag and appends it to the provided {@link ByteStringBuilder}.
   *
   * @param type
   *          The expected type tag of the element.
   * @param builder
   *          The {@link ByteStringBuilder} to append the octet string
   *          to.
   * @return A reference to {@code builder}.
   * @throws DecodeException
   *           If the element cannot be decoded as an octet string.
   * @throws IOException
   *           If an unexpected IO error occurred.
   */
  ByteStringBuilder readOctetString(byte type, ByteStringBuilder builder)
      throws DecodeException, IOException;
  /**
   * Reads the next element as an octet string having the Universal
   * Octet String ASN.1 type tag and appends it to the provided
   * {@link ByteStringBuilder}.
   *
   * @param builder
   *          The {@link ByteStringBuilder} to append the octet string
   *          to.
   * @return A reference to {@code builder}.
   * @throws DecodeException
   *           If the element cannot be decoded as an octet string.
   * @throws IOException
   *           If an unexpected IO error occurred.
   */
  ByteStringBuilder readOctetString(ByteStringBuilder builder)
      throws DecodeException, IOException;
  /**
   * Reads the next element as an octet string having the Universal
   * Octet String ASN.1 type tag and decodes the value as a UTF-8
   * encoded string.
   *
   * @return The decoded octet string as a UTF-8 encoded string.
   * @throws DecodeException
   *           If the element cannot be decoded as an octet string.
   * @throws IOException
   *           If an unexpected IO error occurred.
   */
  String readOctetStringAsString() throws DecodeException,
      IOException;
  /**
   * Reads the next element as an octet string having the provided type
   * tag and decodes the value as a UTF-8 encoded string.
   *
   * @param type
   *          The expected type tag of the element.
   * @return The decoded octet string as a UTF-8 encoded string.
   * @throws DecodeException
   *           If the element cannot be decoded as an octet string.
   * @throws IOException
   *           If an unexpected IO error occurred.
   */
  String readOctetStringAsString(byte type) throws DecodeException,
      IOException;
  /**
   * Reads the next element as a sequence having the Universal Sequence
   * ASN.1 type tag. All further reads will read the elements in the
   * sequence until {@link #readEndSequence()} is called.
   *
   * @throws DecodeException
   *           If the element cannot be decoded as a sequence.
   * @throws IOException
   *           If an unexpected IO error occurred.
   */
  void readStartSequence() throws DecodeException, IOException;
  /**
   * Reads the next element as a sequence having the provided type tag.
   * All further reads will read the elements in the sequence until
   * {@link #readEndSequence()} is called.
   *
   * @param type
   *          The expected type tag of the element.
   * @throws DecodeException
   *           If the element cannot be decoded as a sequence.
   * @throws IOException
   *           If an unexpected IO error occurred.
   */
  void readStartSequence(byte type) throws DecodeException,
      IOException;
  /**
   * Reads the next element as a set having the Universal Set ASN.1 type
   * tag. All further reads will read the elements in the set until
   * {@link #readEndSet()} is called.
   *
   * @throws DecodeException
   *           If the element cannot be decoded as a set.
   * @throws IOException
   *           If an unexpected IO error occurred.
   */
  void readStartSet() throws DecodeException, IOException;
  /**
   * Reads the next element as a set having the provided type tag. All
   * further reads will read the elements in the set until
   * {@link #readEndSet()} is called.
   *
   * @param type
   *          The expected type tag of the element.
   * @throws DecodeException
   *           If the element cannot be decoded as a set.
   * @throws IOException
   *           If an unexpected IO error occurred.
   */
  void readStartSet(byte type) throws DecodeException, IOException;
  /**
   * Skips the next element without decoding it.
   *
   * @return A reference to this ASN.1 reader.
   * @throws DecodeException
   *           If the next element could not be skipped.
   * @throws IOException
   *           If an unexpected IO error occurred.
   */
  ASN1Reader skipElement() throws DecodeException, IOException;
}
Diff truncated after the above file
opendj-sdk/sdk/src/org/opends/sdk/asn1/ASN1Writer.java opendj-sdk/sdk/src/org/opends/sdk/asn1/AbstractASN1Reader.java opendj-sdk/sdk/src/org/opends/sdk/asn1/AbstractASN1Writer.java opendj-sdk/sdk/src/org/opends/sdk/controls/AccountUsabilityControl.java opendj-sdk/sdk/src/org/opends/sdk/controls/AssertionControl.java opendj-sdk/sdk/src/org/opends/sdk/controls/AuthorizationIdentityControl.java opendj-sdk/sdk/src/org/opends/sdk/controls/Control.java opendj-sdk/sdk/src/org/opends/sdk/controls/ControlDecoder.java opendj-sdk/sdk/src/org/opends/sdk/controls/EntryChangeNotificationControl.java opendj-sdk/sdk/src/org/opends/sdk/controls/GenericControl.java opendj-sdk/sdk/src/org/opends/sdk/controls/GetEffectiveRightsRequestControl.java opendj-sdk/sdk/src/org/opends/sdk/controls/MatchedValuesControl.java opendj-sdk/sdk/src/org/opends/sdk/controls/PagedResultsControl.java opendj-sdk/sdk/src/org/opends/sdk/controls/PasswordExpiredControl.java opendj-sdk/sdk/src/org/opends/sdk/controls/PasswordExpiringControl.java opendj-sdk/sdk/src/org/opends/sdk/controls/PasswordPolicyControl.java opendj-sdk/sdk/src/org/opends/sdk/controls/PasswordPolicyErrorType.java opendj-sdk/sdk/src/org/opends/sdk/controls/PasswordPolicyWarningType.java opendj-sdk/sdk/src/org/opends/sdk/controls/PersistentSearchChangeType.java opendj-sdk/sdk/src/org/opends/sdk/controls/PersistentSearchControl.java opendj-sdk/sdk/src/org/opends/sdk/controls/PostReadControl.java opendj-sdk/sdk/src/org/opends/sdk/controls/PreReadControl.java opendj-sdk/sdk/src/org/opends/sdk/controls/ProxiedAuthV1Control.java opendj-sdk/sdk/src/org/opends/sdk/controls/ProxiedAuthV2Control.java opendj-sdk/sdk/src/org/opends/sdk/controls/ServerSideSortControl.java opendj-sdk/sdk/src/org/opends/sdk/controls/SortKey.java opendj-sdk/sdk/src/org/opends/sdk/controls/SortResult.java opendj-sdk/sdk/src/org/opends/sdk/controls/SubtreeDeleteControl.java opendj-sdk/sdk/src/org/opends/sdk/controls/VLVControl.java opendj-sdk/sdk/src/org/opends/sdk/controls/VLVResult.java opendj-sdk/sdk/src/org/opends/sdk/controls/VLVTarget.java opendj-sdk/sdk/src/org/opends/sdk/extensions/CancelRequest.java opendj-sdk/sdk/src/org/opends/sdk/extensions/ExtendedOperation.java opendj-sdk/sdk/src/org/opends/sdk/extensions/GetConnectionIDRequest.java opendj-sdk/sdk/src/org/opends/sdk/extensions/GetConnectionIDResult.java opendj-sdk/sdk/src/org/opends/sdk/extensions/GetSymmetricKeyRequest.java opendj-sdk/sdk/src/org/opends/sdk/extensions/PasswordModifyRequest.java opendj-sdk/sdk/src/org/opends/sdk/extensions/PasswordModifyResult.java opendj-sdk/sdk/src/org/opends/sdk/extensions/PasswordPolicyStateExtendedOperation.java opendj-sdk/sdk/src/org/opends/sdk/extensions/StartTLSRequest.java opendj-sdk/sdk/src/org/opends/sdk/extensions/WhoAmIRequest.java opendj-sdk/sdk/src/org/opends/sdk/extensions/WhoAmIResult.java opendj-sdk/sdk/src/org/opends/sdk/ldap/ASN1StreamReader.java opendj-sdk/sdk/src/org/opends/sdk/ldap/ASN1StreamWriter.java opendj-sdk/sdk/src/org/opends/sdk/ldap/AbstractLDAPMessageHandler.java opendj-sdk/sdk/src/org/opends/sdk/ldap/AbstractLDAPTransport.java opendj-sdk/sdk/src/org/opends/sdk/ldap/AbstractResultFutureImpl.java opendj-sdk/sdk/src/org/opends/sdk/ldap/BindResultFutureImpl.java opendj-sdk/sdk/src/org/opends/sdk/ldap/CompareResultFutureImpl.java opendj-sdk/sdk/src/org/opends/sdk/ldap/ExtendedResultFutureImpl.java opendj-sdk/sdk/src/org/opends/sdk/ldap/LDAPConnection.java opendj-sdk/sdk/src/org/opends/sdk/ldap/LDAPConnectionFactory.java opendj-sdk/sdk/src/org/opends/sdk/ldap/LDAPConnectionFactoryImpl.java opendj-sdk/sdk/src/org/opends/sdk/ldap/LDAPConnectionOptions.java opendj-sdk/sdk/src/org/opends/sdk/ldap/LDAPConstants.java opendj-sdk/sdk/src/org/opends/sdk/ldap/LDAPDecoder.java opendj-sdk/sdk/src/org/opends/sdk/ldap/LDAPEncoder.java opendj-sdk/sdk/src/org/opends/sdk/ldap/LDAPMessageHandler.java opendj-sdk/sdk/src/org/opends/sdk/ldap/LDAPUtils.java opendj-sdk/sdk/src/org/opends/sdk/ldap/ResolvedSchema.java opendj-sdk/sdk/src/org/opends/sdk/ldap/ResultFutureImpl.java opendj-sdk/sdk/src/org/opends/sdk/ldap/SASLFilter.java opendj-sdk/sdk/src/org/opends/sdk/ldap/SASLStreamReader.java opendj-sdk/sdk/src/org/opends/sdk/ldap/SASLStreamWriter.java opendj-sdk/sdk/src/org/opends/sdk/ldap/SearchResultFutureImpl.java opendj-sdk/sdk/src/org/opends/sdk/ldap/UnexpectedRequestException.java opendj-sdk/sdk/src/org/opends/sdk/ldap/UnexpectedResponseException.java opendj-sdk/sdk/src/org/opends/sdk/ldap/UnsupportedMessageException.java opendj-sdk/sdk/src/org/opends/sdk/ldif/AbstractLDIFReader.java opendj-sdk/sdk/src/org/opends/sdk/ldif/AbstractLDIFStream.java opendj-sdk/sdk/src/org/opends/sdk/ldif/AbstractLDIFWriter.java opendj-sdk/sdk/src/org/opends/sdk/ldif/ChangeRecord.java opendj-sdk/sdk/src/org/opends/sdk/ldif/ChangeRecordReader.java opendj-sdk/sdk/src/org/opends/sdk/ldif/ChangeRecordVisitor.java opendj-sdk/sdk/src/org/opends/sdk/ldif/ChangeRecordVisitorWriter.java opendj-sdk/sdk/src/org/opends/sdk/ldif/ChangeRecordWriter.java opendj-sdk/sdk/src/org/opends/sdk/ldif/ConnectionChangeRecordWriter.java opendj-sdk/sdk/src/org/opends/sdk/ldif/ConnectionEntryWriter.java opendj-sdk/sdk/src/org/opends/sdk/ldif/EntryReader.java opendj-sdk/sdk/src/org/opends/sdk/ldif/EntryWriter.java opendj-sdk/sdk/src/org/opends/sdk/ldif/LDIFChangeRecordReader.java opendj-sdk/sdk/src/org/opends/sdk/ldif/LDIFChangeRecordWriter.java opendj-sdk/sdk/src/org/opends/sdk/ldif/LDIFEntryReader.java opendj-sdk/sdk/src/org/opends/sdk/ldif/LDIFEntryWriter.java opendj-sdk/sdk/src/org/opends/sdk/ldif/package-info.java opendj-sdk/sdk/src/org/opends/sdk/package-info.java opendj-sdk/sdk/src/org/opends/sdk/requests/AbandonRequest.java opendj-sdk/sdk/src/org/opends/sdk/requests/AbandonRequestImpl.java opendj-sdk/sdk/src/org/opends/sdk/requests/AbstractBindRequest.java opendj-sdk/sdk/src/org/opends/sdk/requests/AbstractExtendedRequest.java opendj-sdk/sdk/src/org/opends/sdk/requests/AbstractRequestImpl.java opendj-sdk/sdk/src/org/opends/sdk/requests/AbstractUnmodifiableRequestImpl.java opendj-sdk/sdk/src/org/opends/sdk/requests/AddRequest.java opendj-sdk/sdk/src/org/opends/sdk/requests/AddRequestImpl.java opendj-sdk/sdk/src/org/opends/sdk/requests/BindRequest.java opendj-sdk/sdk/src/org/opends/sdk/requests/CompareRequest.java opendj-sdk/sdk/src/org/opends/sdk/requests/CompareRequestImpl.java opendj-sdk/sdk/src/org/opends/sdk/requests/DeleteRequest.java opendj-sdk/sdk/src/org/opends/sdk/requests/DeleteRequestImpl.java opendj-sdk/sdk/src/org/opends/sdk/requests/ExtendedRequest.java opendj-sdk/sdk/src/org/opends/sdk/requests/GenericBindRequest.java opendj-sdk/sdk/src/org/opends/sdk/requests/GenericBindRequestImpl.java opendj-sdk/sdk/src/org/opends/sdk/requests/GenericExtendedRequest.java opendj-sdk/sdk/src/org/opends/sdk/requests/GenericExtendedRequestImpl.java opendj-sdk/sdk/src/org/opends/sdk/requests/ModifyDNRequest.java opendj-sdk/sdk/src/org/opends/sdk/requests/ModifyDNRequestImpl.java opendj-sdk/sdk/src/org/opends/sdk/requests/ModifyRequest.java opendj-sdk/sdk/src/org/opends/sdk/requests/ModifyRequestImpl.java opendj-sdk/sdk/src/org/opends/sdk/requests/Request.java opendj-sdk/sdk/src/org/opends/sdk/requests/Requests.java opendj-sdk/sdk/src/org/opends/sdk/requests/SearchRequest.java opendj-sdk/sdk/src/org/opends/sdk/requests/SearchRequestImpl.java opendj-sdk/sdk/src/org/opends/sdk/requests/SimpleBindRequest.java opendj-sdk/sdk/src/org/opends/sdk/requests/SimpleBindRequestImpl.java opendj-sdk/sdk/src/org/opends/sdk/requests/UnbindRequest.java opendj-sdk/sdk/src/org/opends/sdk/requests/UnbindRequestImpl.java opendj-sdk/sdk/src/org/opends/sdk/responses/AbstractExtendedResult.java opendj-sdk/sdk/src/org/opends/sdk/responses/AbstractIntermediateResponse.java opendj-sdk/sdk/src/org/opends/sdk/responses/AbstractResponseImpl.java opendj-sdk/sdk/src/org/opends/sdk/responses/AbstractResultImpl.java opendj-sdk/sdk/src/org/opends/sdk/responses/AbstractUnmodifiableResponseImpl.java opendj-sdk/sdk/src/org/opends/sdk/responses/AbstractUnmodifiableResultImpl.java opendj-sdk/sdk/src/org/opends/sdk/responses/BindResult.java opendj-sdk/sdk/src/org/opends/sdk/responses/BindResultImpl.java opendj-sdk/sdk/src/org/opends/sdk/responses/CompareResult.java opendj-sdk/sdk/src/org/opends/sdk/responses/CompareResultImpl.java opendj-sdk/sdk/src/org/opends/sdk/responses/ExtendedResult.java opendj-sdk/sdk/src/org/opends/sdk/responses/GenericExtendedResult.java opendj-sdk/sdk/src/org/opends/sdk/responses/GenericExtendedResultImpl.java opendj-sdk/sdk/src/org/opends/sdk/responses/GenericIntermediateResponse.java opendj-sdk/sdk/src/org/opends/sdk/responses/GenericIntermediateResponseImpl.java opendj-sdk/sdk/src/org/opends/sdk/responses/IntermediateResponse.java opendj-sdk/sdk/src/org/opends/sdk/responses/Response.java opendj-sdk/sdk/src/org/opends/sdk/responses/Responses.java opendj-sdk/sdk/src/org/opends/sdk/responses/Result.java opendj-sdk/sdk/src/org/opends/sdk/responses/ResultImpl.java opendj-sdk/sdk/src/org/opends/sdk/responses/SearchResultEntry.java opendj-sdk/sdk/src/org/opends/sdk/responses/SearchResultEntryImpl.java opendj-sdk/sdk/src/org/opends/sdk/responses/SearchResultReference.java opendj-sdk/sdk/src/org/opends/sdk/responses/SearchResultReferenceImpl.java opendj-sdk/sdk/src/org/opends/sdk/sasl/AbstractSASLContext.java opendj-sdk/sdk/src/org/opends/sdk/sasl/AnonymousSASLBindRequest.java opendj-sdk/sdk/src/org/opends/sdk/sasl/CRAMMD5SASLBindRequest.java opendj-sdk/sdk/src/org/opends/sdk/sasl/DigestMD5SASLBindRequest.java opendj-sdk/sdk/src/org/opends/sdk/sasl/ExternalSASLBindRequest.java opendj-sdk/sdk/src/org/opends/sdk/sasl/GSSAPISASLBindRequest.java opendj-sdk/sdk/src/org/opends/sdk/sasl/GenericSASLBindRequest.java opendj-sdk/sdk/src/org/opends/sdk/sasl/NameCallbackHandler.java opendj-sdk/sdk/src/org/opends/sdk/sasl/PasswordCallbackHandler.java opendj-sdk/sdk/src/org/opends/sdk/sasl/PlainSASLBindRequest.java opendj-sdk/sdk/src/org/opends/sdk/sasl/SASLBindRequest.java opendj-sdk/sdk/src/org/opends/sdk/sasl/SASLContext.java opendj-sdk/sdk/src/org/opends/sdk/sasl/TextInputCallbackHandler.java opendj-sdk/sdk/src/org/opends/sdk/schema/AbstractMatchingRuleImpl.java opendj-sdk/sdk/src/org/opends/sdk/schema/AbstractOrderingMatchingRuleImpl.java opendj-sdk/sdk/src/org/opends/sdk/schema/AbstractSubstringMatchingRuleImpl.java opendj-sdk/sdk/src/org/opends/sdk/schema/AbstractSyntaxImpl.java opendj-sdk/sdk/src/org/opends/sdk/schema/AttributeType.java opendj-sdk/sdk/src/org/opends/sdk/schema/AttributeTypeSyntaxImpl.java opendj-sdk/sdk/src/org/opends/sdk/schema/AttributeUsage.java opendj-sdk/sdk/src/org/opends/sdk/schema/AuthPasswordExactEqualityMatchingRuleImpl.java opendj-sdk/sdk/src/org/opends/sdk/schema/AuthPasswordSyntaxImpl.java opendj-sdk/sdk/src/org/opends/sdk/schema/BinarySyntaxImpl.java opendj-sdk/sdk/src/org/opends/sdk/schema/BitStringEqualityMatchingRuleImpl.java opendj-sdk/sdk/src/org/opends/sdk/schema/BitStringSyntaxImpl.java opendj-sdk/sdk/src/org/opends/sdk/schema/BooleanEqualityMatchingRuleImpl.java opendj-sdk/sdk/src/org/opends/sdk/schema/BooleanSyntaxImpl.java opendj-sdk/sdk/src/org/opends/sdk/schema/CaseExactEqualityMatchingRuleImpl.java opendj-sdk/sdk/src/org/opends/sdk/schema/CaseExactIA5EqualityMatchingRuleImpl.java opendj-sdk/sdk/src/org/opends/sdk/schema/CaseExactIA5SubstringMatchingRuleImpl.java opendj-sdk/sdk/src/org/opends/sdk/schema/CaseExactOrderingMatchingRuleImpl.java opendj-sdk/sdk/src/org/opends/sdk/schema/CaseExactSubstringMatchingRuleImpl.java opendj-sdk/sdk/src/org/opends/sdk/schema/CaseIgnoreEqualityMatchingRuleImpl.java opendj-sdk/sdk/src/org/opends/sdk/schema/CaseIgnoreIA5EqualityMatchingRuleImpl.java opendj-sdk/sdk/src/org/opends/sdk/schema/CaseIgnoreIA5SubstringMatchingRuleImpl.java opendj-sdk/sdk/src/org/opends/sdk/schema/CaseIgnoreListEqualityMatchingRuleImpl.java opendj-sdk/sdk/src/org/opends/sdk/schema/CaseIgnoreListSubstringMatchingRuleImpl.java opendj-sdk/sdk/src/org/opends/sdk/schema/CaseIgnoreOrderingMatchingRuleImpl.java opendj-sdk/sdk/src/org/opends/sdk/schema/CaseIgnoreSubstringMatchingRuleImpl.java opendj-sdk/sdk/src/org/opends/sdk/schema/CertificateListSyntaxImpl.java opendj-sdk/sdk/src/org/opends/sdk/schema/CertificatePairSyntaxImpl.java opendj-sdk/sdk/src/org/opends/sdk/schema/CertificateSyntaxImpl.java opendj-sdk/sdk/src/org/opends/sdk/schema/ConflictingSchemaElementException.java opendj-sdk/sdk/src/org/opends/sdk/schema/CoreSchema.java opendj-sdk/sdk/src/org/opends/sdk/schema/CoreSchemaImpl.java opendj-sdk/sdk/src/org/opends/sdk/schema/CountryStringSyntaxImpl.java opendj-sdk/sdk/src/org/opends/sdk/schema/DITContentRule.java opendj-sdk/sdk/src/org/opends/sdk/schema/DITContentRuleSyntaxImpl.java opendj-sdk/sdk/src/org/opends/sdk/schema/DITStructureRule.java opendj-sdk/sdk/src/org/opends/sdk/schema/DITStructureRuleSyntaxImpl.java opendj-sdk/sdk/src/org/opends/sdk/schema/DeliveryMethodSyntaxImpl.java opendj-sdk/sdk/src/org/opends/sdk/schema/DirectoryStringFirstComponentEqualityMatchingRuleImpl.java opendj-sdk/sdk/src/org/opends/sdk/schema/DirectoryStringSyntaxImpl.java opendj-sdk/sdk/src/org/opends/sdk/schema/DistinguishedNameEqualityMatchingRuleImpl.java opendj-sdk/sdk/src/org/opends/sdk/schema/DistinguishedNameSyntaxImpl.java opendj-sdk/sdk/src/org/opends/sdk/schema/DoubleMetaphoneApproximateMatchingRuleImpl.java opendj-sdk/sdk/src/org/opends/sdk/schema/EnhancedGuideSyntaxImpl.java opendj-sdk/sdk/src/org/opends/sdk/schema/EnumOrderingMatchingRule.java opendj-sdk/sdk/src/org/opends/sdk/schema/EnumSyntaxImpl.java opendj-sdk/sdk/src/org/opends/sdk/schema/EqualLengthApproximateMatchingRuleImpl.java opendj-sdk/sdk/src/org/opends/sdk/schema/FacsimileNumberSyntaxImpl.java opendj-sdk/sdk/src/org/opends/sdk/schema/FaxSyntaxImpl.java opendj-sdk/sdk/src/org/opends/sdk/schema/GeneralizedTimeEqualityMatchingRuleImpl.java opendj-sdk/sdk/src/org/opends/sdk/schema/GeneralizedTimeOrderingMatchingRuleImpl.java opendj-sdk/sdk/src/org/opends/sdk/schema/GeneralizedTimeSyntaxImpl.java opendj-sdk/sdk/src/org/opends/sdk/schema/GenerateCoreSchema.java opendj-sdk/sdk/src/org/opends/sdk/schema/GuideSyntaxImpl.java opendj-sdk/sdk/src/org/opends/sdk/schema/IA5StringSyntaxImpl.java opendj-sdk/sdk/src/org/opends/sdk/schema/IntegerEqualityMatchingRuleImpl.java opendj-sdk/sdk/src/org/opends/sdk/schema/IntegerFirstComponentEqualityMatchingRuleImpl.java opendj-sdk/sdk/src/org/opends/sdk/schema/IntegerOrderingMatchingRuleImpl.java opendj-sdk/sdk/src/org/opends/sdk/schema/IntegerSyntaxImpl.java opendj-sdk/sdk/src/org/opends/sdk/schema/JPEGSyntaxImpl.java opendj-sdk/sdk/src/org/opends/sdk/schema/KeywordEqualityMatchingRuleImpl.java opendj-sdk/sdk/src/org/opends/sdk/schema/LDAPSyntaxDescriptionSyntaxImpl.java opendj-sdk/sdk/src/org/opends/sdk/schema/MatchingRule.java opendj-sdk/sdk/src/org/opends/sdk/schema/MatchingRuleImpl.java opendj-sdk/sdk/src/org/opends/sdk/schema/MatchingRuleSyntaxImpl.java opendj-sdk/sdk/src/org/opends/sdk/schema/MatchingRuleUse.java opendj-sdk/sdk/src/org/opends/sdk/schema/MatchingRuleUseSyntaxImpl.java opendj-sdk/sdk/src/org/opends/sdk/schema/NameAndOptionalUIDSyntaxImpl.java opendj-sdk/sdk/src/org/opends/sdk/schema/NameForm.java opendj-sdk/sdk/src/org/opends/sdk/schema/NameFormSyntaxImpl.java opendj-sdk/sdk/src/org/opends/sdk/schema/NumericStringEqualityMatchingRuleImpl.java opendj-sdk/sdk/src/org/opends/sdk/schema/NumericStringOrderingMatchingRuleImpl.java opendj-sdk/sdk/src/org/opends/sdk/schema/NumericStringSubstringMatchingRuleImpl.java opendj-sdk/sdk/src/org/opends/sdk/schema/NumericStringSyntaxImpl.java opendj-sdk/sdk/src/org/opends/sdk/schema/OIDSyntaxImpl.java opendj-sdk/sdk/src/org/opends/sdk/schema/ObjectClass.java opendj-sdk/sdk/src/org/opends/sdk/schema/ObjectClassSyntaxImpl.java opendj-sdk/sdk/src/org/opends/sdk/schema/ObjectClassType.java opendj-sdk/sdk/src/org/opends/sdk/schema/ObjectIdentifierEqualityMatchingRuleImpl.java opendj-sdk/sdk/src/org/opends/sdk/schema/ObjectIdentifierFirstComponentEqualityMatchingRuleImpl.java opendj-sdk/sdk/src/org/opends/sdk/schema/OctetStringEqualityMatchingRuleImpl.java opendj-sdk/sdk/src/org/opends/sdk/schema/OctetStringOrderingMatchingRuleImpl.java opendj-sdk/sdk/src/org/opends/sdk/schema/OctetStringSubstringMatchingRuleImpl.java opendj-sdk/sdk/src/org/opends/sdk/schema/OctetStringSyntaxImpl.java opendj-sdk/sdk/src/org/opends/sdk/schema/OtherMailboxSyntaxImpl.java opendj-sdk/sdk/src/org/opends/sdk/schema/PostalAddressSyntaxImpl.java opendj-sdk/sdk/src/org/opends/sdk/schema/PresentationAddressEqualityMatchingRuleImpl.java opendj-sdk/sdk/src/org/opends/sdk/schema/PresentationAddressSyntaxImpl.java opendj-sdk/sdk/src/org/opends/sdk/schema/PrintableStringSyntaxImpl.java opendj-sdk/sdk/src/org/opends/sdk/schema/ProtocolInformationEqualityMatchingRuleImpl.java opendj-sdk/sdk/src/org/opends/sdk/schema/ProtocolInformationSyntaxImpl.java opendj-sdk/sdk/src/org/opends/sdk/schema/RegexSyntaxImpl.java opendj-sdk/sdk/src/org/opends/sdk/schema/Schema.java opendj-sdk/sdk/src/org/opends/sdk/schema/SchemaBuilder.java opendj-sdk/sdk/src/org/opends/sdk/schema/SchemaCompatOptions.java opendj-sdk/sdk/src/org/opends/sdk/schema/SchemaConstants.java opendj-sdk/sdk/src/org/opends/sdk/schema/SchemaElement.java opendj-sdk/sdk/src/org/opends/sdk/schema/SchemaException.java opendj-sdk/sdk/src/org/opends/sdk/schema/SchemaLocal.java opendj-sdk/sdk/src/org/opends/sdk/schema/SchemaNotFoundException.java opendj-sdk/sdk/src/org/opends/sdk/schema/SchemaUtils.java opendj-sdk/sdk/src/org/opends/sdk/schema/SubstringAssertionSyntaxImpl.java opendj-sdk/sdk/src/org/opends/sdk/schema/SupportedAlgorithmSyntaxImpl.java opendj-sdk/sdk/src/org/opends/sdk/schema/Syntax.java opendj-sdk/sdk/src/org/opends/sdk/schema/SyntaxImpl.java opendj-sdk/sdk/src/org/opends/sdk/schema/TelephoneNumberEqualityMatchingRuleImpl.java opendj-sdk/sdk/src/org/opends/sdk/schema/TelephoneNumberSubstringMatchingRuleImpl.java opendj-sdk/sdk/src/org/opends/sdk/schema/TelephoneNumberSyntaxImpl.java opendj-sdk/sdk/src/org/opends/sdk/schema/TeletexTerminalIdentifierSyntaxImpl.java opendj-sdk/sdk/src/org/opends/sdk/schema/TelexNumberSyntaxImpl.java opendj-sdk/sdk/src/org/opends/sdk/schema/UTCTimeSyntaxImpl.java opendj-sdk/sdk/src/org/opends/sdk/schema/UUIDEqualityMatchingRuleImpl.java opendj-sdk/sdk/src/org/opends/sdk/schema/UUIDOrderingMatchingRuleImpl.java opendj-sdk/sdk/src/org/opends/sdk/schema/UUIDSyntaxImpl.java opendj-sdk/sdk/src/org/opends/sdk/schema/UniqueMemberEqualityMatchingRuleImpl.java opendj-sdk/sdk/src/org/opends/sdk/schema/UnknownSchemaElementException.java opendj-sdk/sdk/src/org/opends/sdk/schema/UserPasswordExactEqualityMatchingRuleImpl.java opendj-sdk/sdk/src/org/opends/sdk/schema/UserPasswordSyntaxImpl.java opendj-sdk/sdk/src/org/opends/sdk/schema/WordEqualityMatchingRuleImpl.java opendj-sdk/sdk/src/org/opends/sdk/tools/Argument.java opendj-sdk/sdk/src/org/opends/sdk/tools/ArgumentException.java opendj-sdk/sdk/src/org/opends/sdk/tools/ArgumentGroup.java opendj-sdk/sdk/src/org/opends/sdk/tools/ArgumentParser.java opendj-sdk/sdk/src/org/opends/sdk/tools/ArgumentParserConnectionFactory.java opendj-sdk/sdk/src/org/opends/sdk/tools/BooleanArgument.java opendj-sdk/sdk/src/org/opends/sdk/tools/DataSource.java opendj-sdk/sdk/src/org/opends/sdk/tools/FileBasedArgument.java opendj-sdk/sdk/src/org/opends/sdk/tools/IntegerArgument.java opendj-sdk/sdk/src/org/opends/sdk/tools/LDAPCompare.java opendj-sdk/sdk/src/org/opends/sdk/tools/LDAPModify.java opendj-sdk/sdk/src/org/opends/sdk/tools/LDAPPasswordModify.java opendj-sdk/sdk/src/org/opends/sdk/tools/LDAPSearch.java opendj-sdk/sdk/src/org/opends/sdk/tools/ModRate.java opendj-sdk/sdk/src/org/opends/sdk/tools/MultiChoiceArgument.java opendj-sdk/sdk/src/org/opends/sdk/tools/MultiColumnPrinter.java opendj-sdk/sdk/src/org/opends/sdk/tools/PerformanceRunner.java opendj-sdk/sdk/src/org/opends/sdk/tools/SearchRate.java opendj-sdk/sdk/src/org/opends/sdk/tools/StringArgument.java opendj-sdk/sdk/src/org/opends/sdk/tools/Utils.java opendj-sdk/sdk/src/org/opends/sdk/util/ASCIICharProp.java opendj-sdk/sdk/src/org/opends/sdk/util/Base64.java opendj-sdk/sdk/src/org/opends/sdk/util/ByteSequence.java opendj-sdk/sdk/src/org/opends/sdk/util/ByteSequenceOutputStream.java opendj-sdk/sdk/src/org/opends/sdk/util/ByteSequenceReader.java opendj-sdk/sdk/src/org/opends/sdk/util/ByteString.java opendj-sdk/sdk/src/org/opends/sdk/util/ByteStringBuilder.java opendj-sdk/sdk/src/org/opends/sdk/util/Function.java opendj-sdk/sdk/src/org/opends/sdk/util/Functions.java opendj-sdk/sdk/src/org/opends/sdk/util/Iterables.java opendj-sdk/sdk/src/org/opends/sdk/util/Iterators.java opendj-sdk/sdk/src/org/opends/sdk/util/LocalizableException.java opendj-sdk/sdk/src/org/opends/sdk/util/LocalizedIllegalArgumentException.java opendj-sdk/sdk/src/org/opends/sdk/util/Platform.java opendj-sdk/sdk/src/org/opends/sdk/util/Predicate.java opendj-sdk/sdk/src/org/opends/sdk/util/SSLUtils.java opendj-sdk/sdk/src/org/opends/sdk/util/SizeLimitInputStream.java opendj-sdk/sdk/src/org/opends/sdk/util/StaticUtils.java opendj-sdk/sdk/src/org/opends/sdk/util/StringPrepProfile.java opendj-sdk/sdk/src/org/opends/sdk/util/SubstringReader.java opendj-sdk/sdk/src/org/opends/sdk/util/Validator.java opendj-sdk/sdk/src/org/opends/sdk/util/ssl/DistrustAllTrustManager.java opendj-sdk/sdk/src/org/opends/sdk/util/ssl/HostnameMismatchCertificateException.java opendj-sdk/sdk/src/org/opends/sdk/util/ssl/PromptingTrustManager.java opendj-sdk/sdk/src/org/opends/sdk/util/ssl/TrustAllTrustManager.java opendj-sdk/sdk/src/org/opends/sdk/util/ssl/TrustStoreTrustManager.java