Initial import of SDK source from data provider branch.
| New file |
| | |
| | | /* |
| | | * CDDL HEADER START |
| | | * |
| | | * The contents of this file are subject to the terms of the |
| | | * Common Development and Distribution License, Version 1.0 only |
| | | * (the "License"). You may not use this file except in compliance |
| | | * with the License. |
| | | * |
| | | * You can obtain a copy of the license at |
| | | * trunk/opends/resource/legal-notices/OpenDS.LICENSE |
| | | * or https://OpenDS.dev.java.net/OpenDS.LICENSE. |
| | | * See the License for the specific language governing permissions |
| | | * and limitations under the License. |
| | | * |
| | | * When distributing Covered Code, include this CDDL HEADER in each |
| | | * file and include the License file at |
| | | * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable, |
| | | * add the following below this CDDL HEADER, with the fields enclosed |
| | | * 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); |
| | | } |
| | | |
| | | } |
| New file |
| | |
| | | /* |
| | | * CDDL HEADER START |
| | | * |
| | | * The contents of this file are subject to the terms of the |
| | | * Common Development and Distribution License, Version 1.0 only |
| | | * (the "License"). You may not use this file except in compliance |
| | | * with the License. |
| | | * |
| | | * You can obtain a copy of the license at |
| | | * trunk/opends/resource/legal-notices/OpenDS.LICENSE |
| | | * or https://OpenDS.dev.java.net/OpenDS.LICENSE. |
| | | * See the License for the specific language governing permissions |
| | | * and limitations under the License. |
| | | * |
| | | * When distributing Covered Code, include this CDDL HEADER in each |
| | | * file and include the License file at |
| | | * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable, |
| | | * add the following below this CDDL HEADER, with the fields enclosed |
| | | * 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); |
| | | } |
| | | |
| | | } |
| New file |
| | |
| | | /* |
| | | * CDDL HEADER START |
| | | * |
| | | * The contents of this file are subject to the terms of the |
| | | * Common Development and Distribution License, Version 1.0 only |
| | | * (the "License"). You may not use this file except in compliance |
| | | * with the License. |
| | | * |
| | | * You can obtain a copy of the license at |
| | | * trunk/opends/resource/legal-notices/OpenDS.LICENSE |
| | | * or https://OpenDS.dev.java.net/OpenDS.LICENSE. |
| | | * See the License for the specific language governing permissions |
| | | * and limitations under the License. |
| | | * |
| | | * When distributing Covered Code, include this CDDL HEADER in each |
| | | * file and include the License file at |
| | | * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable, |
| | | * add the following below this CDDL HEADER, with the fields enclosed |
| | | * 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); |
| | | } |
| | | } |
| | | } |
| New file |
| | |
| | | /* |
| | | * CDDL HEADER START |
| | | * |
| | | * The contents of this file are subject to the terms of the |
| | | * Common Development and Distribution License, Version 1.0 only |
| | | * (the "License"). You may not use this file except in compliance |
| | | * with the License. |
| | | * |
| | | * You can obtain a copy of the license at |
| | | * trunk/opends/resource/legal-notices/OpenDS.LICENSE |
| | | * or https://OpenDS.dev.java.net/OpenDS.LICENSE. |
| | | * See the License for the specific language governing permissions |
| | | * and limitations under the License. |
| | | * |
| | | * When distributing Covered Code, include this CDDL HEADER in each |
| | | * file and include the License file at |
| | | * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable, |
| | | * add the following below this CDDL HEADER, with the fields enclosed |
| | | * 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); |
| | | } |
| | | |
| | | } |
| New file |
| | |
| | | /* |
| | | * CDDL HEADER START |
| | | * |
| | | * The contents of this file are subject to the terms of the |
| | | * Common Development and Distribution License, Version 1.0 only |
| | | * (the "License"). You may not use this file except in compliance |
| | | * with the License. |
| | | * |
| | | * You can obtain a copy of the license at |
| | | * trunk/opends/resource/legal-notices/OpenDS.LICENSE |
| | | * or https://OpenDS.dev.java.net/OpenDS.LICENSE. |
| | | * See the License for the specific language governing permissions |
| | | * and limitations under the License. |
| | | * |
| | | * When distributing Covered Code, include this CDDL HEADER in each |
| | | * file and include the License file at |
| | | * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable, |
| | | * add the following below this CDDL HEADER, with the fields enclosed |
| | | * 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); |
| | | } |
| | | } |
| New file |
| | |
| | | /* |
| | | * CDDL HEADER START |
| | | * |
| | | * The contents of this file are subject to the terms of the |
| | | * Common Development and Distribution License, Version 1.0 only |
| | | * (the "License"). You may not use this file except in compliance |
| | | * with the License. |
| | | * |
| | | * You can obtain a copy of the license at |
| | | * trunk/opends/resource/legal-notices/OpenDS.LICENSE |
| | | * or https://OpenDS.dev.java.net/OpenDS.LICENSE. |
| | | * See the License for the specific language governing permissions |
| | | * and limitations under the License. |
| | | * |
| | | * When distributing Covered Code, include this CDDL HEADER in each |
| | | * file and include the License file at |
| | | * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable, |
| | | * add the following below this CDDL HEADER, with the fields enclosed |
| | | * 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); |
| | | } |
| New file |
| | |
| | | /* |
| | | * CDDL HEADER START |
| | | * |
| | | * The contents of this file are subject to the terms of the |
| | | * Common Development and Distribution License, Version 1.0 only |
| | | * (the "License"). You may not use this file except in compliance |
| | | * with the License. |
| | | * |
| | | * You can obtain a copy of the license at |
| | | * trunk/opends/resource/legal-notices/OpenDS.LICENSE |
| | | * or https://OpenDS.dev.java.net/OpenDS.LICENSE. |
| | | * See the License for the specific language governing permissions |
| | | * and limitations under the License. |
| | | * |
| | | * When distributing Covered Code, include this CDDL HEADER in each |
| | | * file and include the License file at |
| | | * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable, |
| | | * add the following below this CDDL HEADER, with the fields enclosed |
| | | * 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; |
| | | } |
| New file |
| | |
| | | /* |
| | | * CDDL HEADER START |
| | | * |
| | | * The contents of this file are subject to the terms of the |
| | | * Common Development and Distribution License, Version 1.0 only |
| | | * (the "License"). You may not use this file except in compliance |
| | | * with the License. |
| | | * |
| | | * You can obtain a copy of the license at |
| | | * trunk/opends/resource/legal-notices/OpenDS.LICENSE |
| | | * or https://OpenDS.dev.java.net/OpenDS.LICENSE. |
| | | * See the License for the specific language governing permissions |
| | | * and limitations under the License. |
| | | * |
| | | * When distributing Covered Code, include this CDDL HEADER in each |
| | | * file and include the License file at |
| | | * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable, |
| | | * add the following below this CDDL HEADER, with the fields enclosed |
| | | * 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(); |
| | | } |
| New file |
| | |
| | | /* |
| | | * CDDL HEADER START |
| | | * |
| | | * The contents of this file are subject to the terms of the |
| | | * Common Development and Distribution License, Version 1.0 only |
| | | * (the "License"). You may not use this file except in compliance |
| | | * with the License. |
| | | * |
| | | * You can obtain a copy of the license at |
| | | * trunk/opends/resource/legal-notices/OpenDS.LICENSE |
| | | * or https://OpenDS.dev.java.net/OpenDS.LICENSE. |
| | | * See the License for the specific language governing permissions |
| | | * and limitations under the License. |
| | | * |
| | | * When distributing Covered Code, include this CDDL HEADER in each |
| | | * file and include the License file at |
| | | * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable, |
| | | * add the following below this CDDL HEADER, with the fields enclosed |
| | | * 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; |
| | | } |
| | | } |
| New file |
| | |
| | | /* |
| | | * CDDL HEADER START |
| | | * |
| | | * The contents of this file are subject to the terms of the |
| | | * Common Development and Distribution License, Version 1.0 only |
| | | * (the "License"). You may not use this file except in compliance |
| | | * with the License. |
| | | * |
| | | * You can obtain a copy of the license at |
| | | * trunk/opends/resource/legal-notices/OpenDS.LICENSE |
| | | * or https://OpenDS.dev.java.net/OpenDS.LICENSE. |
| | | * See the License for the specific language governing permissions |
| | | * and limitations under the License. |
| | | * |
| | | * When distributing Covered Code, include this CDDL HEADER in each |
| | | * file and include the License file at |
| | | * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable, |
| | | * add the following below this CDDL HEADER, with the fields enclosed |
| | | * 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(); |
| | | } |
| | | |
| | | } |
| New file |
| | |
| | | /* |
| | | * CDDL HEADER START |
| | | * |
| | | * The contents of this file are subject to the terms of the |
| | | * Common Development and Distribution License, Version 1.0 only |
| | | * (the "License"). You may not use this file except in compliance |
| | | * with the License. |
| | | * |
| | | * You can obtain a copy of the license at |
| | | * trunk/opends/resource/legal-notices/OpenDS.LICENSE |
| | | * or https://OpenDS.dev.java.net/OpenDS.LICENSE. |
| | | * See the License for the specific language governing permissions |
| | | * and limitations under the License. |
| | | * |
| | | * When distributing Covered Code, include this CDDL HEADER in each |
| | | * file and include the License file at |
| | | * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable, |
| | | * add the following below this CDDL HEADER, with the fields enclosed |
| | | * 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(); |
| | | } |
| | | |
| | | } |
| New file |
| | |
| | | /* |
| | | * CDDL HEADER START |
| | | * |
| | | * The contents of this file are subject to the terms of the |
| | | * Common Development and Distribution License, Version 1.0 only |
| | | * (the "License"). You may not use this file except in compliance |
| | | * with the License. |
| | | * |
| | | * You can obtain a copy of the license at |
| | | * trunk/opends/resource/legal-notices/OpenDS.LICENSE |
| | | * or https://OpenDS.dev.java.net/OpenDS.LICENSE. |
| | | * See the License for the specific language governing permissions |
| | | * and limitations under the License. |
| | | * |
| | | * When distributing Covered Code, include this CDDL HEADER in each |
| | | * file and include the License file at |
| | | * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable, |
| | | * add the following below this CDDL HEADER, with the fields enclosed |
| | | * 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; |
| | | } |
| | | } |
| New file |
| | |
| | | /* |
| | | * CDDL HEADER START |
| | | * |
| | | * The contents of this file are subject to the terms of the |
| | | * Common Development and Distribution License, Version 1.0 only |
| | | * (the "License"). You may not use this file except in compliance |
| | | * with the License. |
| | | * |
| | | * You can obtain a copy of the license at |
| | | * trunk/opends/resource/legal-notices/OpenDS.LICENSE |
| | | * or https://OpenDS.dev.java.net/OpenDS.LICENSE. |
| | | * See the License for the specific language governing permissions |
| | | * and limitations under the License. |
| | | * |
| | | * When distributing Covered Code, include this CDDL HEADER in each |
| | | * file and include the License file at |
| | | * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable, |
| | | * add the following below this CDDL HEADER, with the fields enclosed |
| | | * 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<SearchResultEntry>()); |
| | | * </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, "(objectClass=*)", 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, "(objectClass=*)", 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; |
| | | } |
| New file |
| | |
| | | /* |
| | | * CDDL HEADER START |
| | | * |
| | | * The contents of this file are subject to the terms of the |
| | | * Common Development and Distribution License, Version 1.0 only |
| | | * (the "License"). You may not use this file except in compliance |
| | | * with the License. |
| | | * |
| | | * You can obtain a copy of the license at |
| | | * trunk/opends/resource/legal-notices/OpenDS.LICENSE |
| | | * or https://OpenDS.dev.java.net/OpenDS.LICENSE. |
| | | * See the License for the specific language governing permissions |
| | | * and limitations under the License. |
| | | * |
| | | * When distributing Covered Code, include this CDDL HEADER in each |
| | | * file and include the License file at |
| | | * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable, |
| | | * add the following below this CDDL HEADER, with the fields enclosed |
| | | * 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); |
| | | } |
| New file |
| | |
| | | /* |
| | | * CDDL HEADER START |
| | | * |
| | | * The contents of this file are subject to the terms of the |
| | | * Common Development and Distribution License, Version 1.0 only |
| | | * (the "License"). You may not use this file except in compliance |
| | | * with the License. |
| | | * |
| | | * You can obtain a copy of the license at |
| | | * trunk/opends/resource/legal-notices/OpenDS.LICENSE |
| | | * or https://OpenDS.dev.java.net/OpenDS.LICENSE. |
| | | * See the License for the specific language governing permissions |
| | | * and limitations under the License. |
| | | * |
| | | * When distributing Covered Code, include this CDDL HEADER in each |
| | | * file and include the License file at |
| | | * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable, |
| | | * add the following below this CDDL HEADER, with the fields enclosed |
| | | * 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); |
| | | } |
| New file |
| | |
| | | /* |
| | | * CDDL HEADER START |
| | | * |
| | | * The contents of this file are subject to the terms of the |
| | | * Common Development and Distribution License, Version 1.0 only |
| | | * (the "License"). You may not use this file except in compliance |
| | | * with the License. |
| | | * |
| | | * You can obtain a copy of the license at |
| | | * trunk/opends/resource/legal-notices/OpenDS.LICENSE |
| | | * or https://OpenDS.dev.java.net/OpenDS.LICENSE. |
| | | * See the License for the specific language governing permissions |
| | | * and limitations under the License. |
| | | * |
| | | * When distributing Covered Code, include this CDDL HEADER in each |
| | | * file and include the License file at |
| | | * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable, |
| | | * add the following below this CDDL HEADER, with the fields enclosed |
| | | * 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(); |
| | | } |
| New file |
| | |
| | | /* |
| | | * CDDL HEADER START |
| | | * |
| | | * The contents of this file are subject to the terms of the |
| | | * Common Development and Distribution License, Version 1.0 only |
| | | * (the "License"). You may not use this file except in compliance |
| | | * with the License. |
| | | * |
| | | * You can obtain a copy of the license at |
| | | * trunk/opends/resource/legal-notices/OpenDS.LICENSE |
| | | * or https://OpenDS.dev.java.net/OpenDS.LICENSE. |
| | | * See the License for the specific language governing permissions |
| | | * and limitations under the License. |
| | | * |
| | | * When distributing Covered Code, include this CDDL HEADER in each |
| | | * file and include the License file at |
| | | * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable, |
| | | * add the following below this CDDL HEADER, with the fields enclosed |
| | | * 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); |
| | | } |
| New file |
| | |
| | | /* |
| | | * CDDL HEADER START |
| | | * |
| | | * The contents of this file are subject to the terms of the |
| | | * Common Development and Distribution License, Version 1.0 only |
| | | * (the "License"). You may not use this file except in compliance |
| | | * with the License. |
| | | * |
| | | * You can obtain a copy of the license at |
| | | * trunk/opends/resource/legal-notices/OpenDS.LICENSE |
| | | * or https://OpenDS.dev.java.net/OpenDS.LICENSE. |
| | | * See the License for the specific language governing permissions |
| | | * and limitations under the License. |
| | | * |
| | | * When distributing Covered Code, include this CDDL HEADER in each |
| | | * file and include the License file at |
| | | * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable, |
| | | * add the following below this CDDL HEADER, with the fields enclosed |
| | | * 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; |
| | | } |
| | | } |
| New file |
| | |
| | | /* |
| | | * CDDL HEADER START |
| | | * |
| | | * The contents of this file are subject to the terms of the |
| | | * Common Development and Distribution License, Version 1.0 only |
| | | * (the "License"). You may not use this file except in compliance |
| | | * with the License. |
| | | * |
| | | * You can obtain a copy of the license at |
| | | * trunk/opends/resource/legal-notices/OpenDS.LICENSE |
| | | * or https://OpenDS.dev.java.net/OpenDS.LICENSE. |
| | | * See the License for the specific language governing permissions |
| | | * and limitations under the License. |
| | | * |
| | | * When distributing Covered Code, include this CDDL HEADER in each |
| | | * file and include the License file at |
| | | * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable, |
| | | * add the following below this CDDL HEADER, with the fields enclosed |
| | | * 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; |
| | | } |
| | | } |
| New file |
| | |
| | | /* |
| | | * CDDL HEADER START |
| | | * |
| | | * The contents of this file are subject to the terms of the |
| | | * Common Development and Distribution License, Version 1.0 only |
| | | * (the "License"). You may not use this file except in compliance |
| | | * with the License. |
| | | * |
| | | * You can obtain a copy of the license at |
| | | * trunk/opends/resource/legal-notices/OpenDS.LICENSE |
| | | * or https://OpenDS.dev.java.net/OpenDS.LICENSE. |
| | | * See the License for the specific language governing permissions |
| | | * and limitations under the License. |
| | | * |
| | | * When distributing Covered Code, include this CDDL HEADER in each |
| | | * file and include the License file at |
| | | * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable, |
| | | * add the following below this CDDL HEADER, with the fields enclosed |
| | | * 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; |
| | | } |
| | | } |
| New file |
| | |
| | | /* |
| | | * CDDL HEADER START |
| | | * |
| | | * The contents of this file are subject to the terms of the |
| | | * Common Development and Distribution License, Version 1.0 only |
| | | * (the "License"). You may not use this file except in compliance |
| | | * with the License. |
| | | * |
| | | * You can obtain a copy of the license at |
| | | * trunk/opends/resource/legal-notices/OpenDS.LICENSE |
| | | * or https://OpenDS.dev.java.net/OpenDS.LICENSE. |
| | | * See the License for the specific language governing permissions |
| | | * and limitations under the License. |
| | | * |
| | | * When distributing Covered Code, include this CDDL HEADER in each |
| | | * file and include the License file at |
| | | * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable, |
| | | * add the following below this CDDL HEADER, with the fields enclosed |
| | | * 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(); |
| | | } |
| New file |
| | |
| | | /* |
| | | * CDDL HEADER START |
| | | * |
| | | * The contents of this file are subject to the terms of the |
| | | * Common Development and Distribution License, Version 1.0 only |
| | | * (the "License"). You may not use this file except in compliance |
| | | * with the License. |
| | | * |
| | | * You can obtain a copy of the license at |
| | | * trunk/opends/resource/legal-notices/OpenDS.LICENSE |
| | | * or https://OpenDS.dev.java.net/OpenDS.LICENSE. |
| | | * See the License for the specific language governing permissions |
| | | * and limitations under the License. |
| | | * |
| | | * When distributing Covered Code, include this CDDL HEADER in each |
| | | * file and include the License file at |
| | | * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable, |
| | | * add the following below this CDDL HEADER, with the fields enclosed |
| | | * 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; |
| | | } |
| | | } |
| New file |
| | |
| | | /* |
| | | * CDDL HEADER START |
| | | * |
| | | * The contents of this file are subject to the terms of the |
| | | * Common Development and Distribution License, Version 1.0 only |
| | | * (the "License"). You may not use this file except in compliance |
| | | * with the License. |
| | | * |
| | | * You can obtain a copy of the license at |
| | | * trunk/opends/resource/legal-notices/OpenDS.LICENSE |
| | | * or https://OpenDS.dev.java.net/OpenDS.LICENSE. |
| | | * See the License for the specific language governing permissions |
| | | * and limitations under the License. |
| | | * |
| | | * When distributing Covered Code, include this CDDL HEADER in each |
| | | * file and include the License file at |
| | | * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable, |
| | | * add the following below this CDDL HEADER, with the fields enclosed |
| | | * 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; |
| | | } |
| | | } |
| New file |
| | |
| | | /* |
| | | * CDDL HEADER START |
| | | * |
| | | * The contents of this file are subject to the terms of the |
| | | * Common Development and Distribution License, Version 1.0 only |
| | | * (the "License"). You may not use this file except in compliance |
| | | * with the License. |
| | | * |
| | | * You can obtain a copy of the license at |
| | | * trunk/opends/resource/legal-notices/OpenDS.LICENSE |
| | | * or https://OpenDS.dev.java.net/OpenDS.LICENSE. |
| | | * See the License for the specific language governing permissions |
| | | * and limitations under the License. |
| | | * |
| | | * When distributing Covered Code, include this CDDL HEADER in each |
| | | * file and include the License file at |
| | | * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable, |
| | | * add the following below this CDDL HEADER, with the fields enclosed |
| | | * 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("objectClass"); |
| | | * </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); |
| | | } |
| | | |
| | | } |
| New file |
| | |
| | | /* |
| | | * CDDL HEADER START |
| | | * |
| | | * The contents of this file are subject to the terms of the |
| | | * Common Development and Distribution License, Version 1.0 only |
| | | * (the "License"). You may not use this file except in compliance |
| | | * with the License. |
| | | * |
| | | * You can obtain a copy of the license at |
| | | * trunk/opends/resource/legal-notices/OpenDS.LICENSE |
| | | * or https://OpenDS.dev.java.net/OpenDS.LICENSE. |
| | | * See the License for the specific language governing permissions |
| | | * and limitations under the License. |
| | | * |
| | | * When distributing Covered Code, include this CDDL HEADER in each |
| | | * file and include the License file at |
| | | * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable, |
| | | * add the following below this CDDL HEADER, with the fields enclosed |
| | | * 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); |
| | | |
| | | } |
| New file |
| | |
| | | /* |
| | | * CDDL HEADER START |
| | | * |
| | | * The contents of this file are subject to the terms of the |
| | | * Common Development and Distribution License, Version 1.0 only |
| | | * (the "License"). You may not use this file except in compliance |
| | | * with the License. |
| | | * |
| | | * You can obtain a copy of the license at |
| | | * trunk/opends/resource/legal-notices/OpenDS.LICENSE |
| | | * or https://OpenDS.dev.java.net/OpenDS.LICENSE. |
| | | * See the License for the specific language governing permissions |
| | | * and limitations under the License. |
| | | * |
| | | * When distributing Covered Code, include this CDDL HEADER in each |
| | | * file and include the License file at |
| | | * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable, |
| | | * add the following below this CDDL HEADER, with the fields enclosed |
| | | * 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; |
| | | } |
| | | |
| | | } |
| New file |
| | |
| | | /* |
| | | * CDDL HEADER START |
| | | * |
| | | * The contents of this file are subject to the terms of the |
| | | * Common Development and Distribution License, Version 1.0 only |
| | | * (the "License"). You may not use this file except in compliance |
| | | * with the License. |
| | | * |
| | | * You can obtain a copy of the license at |
| | | * trunk/opends/resource/legal-notices/OpenDS.LICENSE |
| | | * or https://OpenDS.dev.java.net/OpenDS.LICENSE. |
| | | * See the License for the specific language governing permissions |
| | | * and limitations under the License. |
| | | * |
| | | * When distributing Covered Code, include this CDDL HEADER in each |
| | | * file and include the License file at |
| | | * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable, |
| | | * add the following below this CDDL HEADER, with the fields enclosed |
| | | * 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); |
| | | } |
| | | } |
| New file |
| | |
| | | /* |
| | | * CDDL HEADER START |
| | | * |
| | | * The contents of this file are subject to the terms of the |
| | | * Common Development and Distribution License, Version 1.0 only |
| | | * (the "License"). You may not use this file except in compliance |
| | | * with the License. |
| | | * |
| | | * You can obtain a copy of the license at |
| | | * trunk/opends/resource/legal-notices/OpenDS.LICENSE |
| | | * or https://OpenDS.dev.java.net/OpenDS.LICENSE. |
| | | * See the License for the specific language governing permissions |
| | | * and limitations under the License. |
| | | * |
| | | * When distributing Covered Code, include this CDDL HEADER in each |
| | | * file and include the License file at |
| | | * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable, |
| | | * add the following below this CDDL HEADER, with the fields enclosed |
| | | * 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; |
| | | } |
| | | } |
| New file |
| | |
| | | /* |
| | | * CDDL HEADER START |
| | | * |
| | | * The contents of this file are subject to the terms of the |
| | | * Common Development and Distribution License, Version 1.0 only |
| | | * (the "License"). You may not use this file except in compliance |
| | | * with the License. |
| | | * |
| | | * You can obtain a copy of the license at |
| | | * trunk/opends/resource/legal-notices/OpenDS.LICENSE |
| | | * or https://OpenDS.dev.java.net/OpenDS.LICENSE. |
| | | * See the License for the specific language governing permissions |
| | | * and limitations under the License. |
| | | * |
| | | * When distributing Covered Code, include this CDDL HEADER in each |
| | | * file and include the License file at |
| | | * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable, |
| | | * add the following below this CDDL HEADER, with the fields enclosed |
| | | * 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()); |
| | | } |
| | | } |
| New file |
| | |
| | | /* |
| | | * CDDL HEADER START |
| | | * |
| | | * The contents of this file are subject to the terms of the |
| | | * Common Development and Distribution License, Version 1.0 only |
| | | * (the "License"). You may not use this file except in compliance |
| | | * with the License. |
| | | * |
| | | * You can obtain a copy of the license at |
| | | * trunk/opends/resource/legal-notices/OpenDS.LICENSE |
| | | * or https://OpenDS.dev.java.net/OpenDS.LICENSE. |
| | | * See the License for the specific language governing permissions |
| | | * and limitations under the License. |
| | | * |
| | | * When distributing Covered Code, include this CDDL HEADER in each |
| | | * file and include the License file at |
| | | * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable, |
| | | * add the following below this CDDL HEADER, with the fields enclosed |
| | | * 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(); |
| | | } |
| | | |
| | | } |
| New file |
| | |
| | | /* |
| | | * CDDL HEADER START |
| | | * |
| | | * The contents of this file are subject to the terms of the |
| | | * Common Development and Distribution License, Version 1.0 only |
| | | * (the "License"). You may not use this file except in compliance |
| | | * with the License. |
| | | * |
| | | * You can obtain a copy of the license at |
| | | * trunk/opends/resource/legal-notices/OpenDS.LICENSE |
| | | * or https://OpenDS.dev.java.net/OpenDS.LICENSE. |
| | | * See the License for the specific language governing permissions |
| | | * and limitations under the License. |
| | | * |
| | | * When distributing Covered Code, include this CDDL HEADER in each |
| | | * file and include the License file at |
| | | * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable, |
| | | * add the following below this CDDL HEADER, with the fields enclosed |
| | | * 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(); |
| | | } |
| New file |
| | |
| | | /* |
| | | * CDDL HEADER START |
| | | * |
| | | * The contents of this file are subject to the terms of the |
| | | * Common Development and Distribution License, Version 1.0 only |
| | | * (the "License"). You may not use this file except in compliance |
| | | * with the License. |
| | | * |
| | | * You can obtain a copy of the license at |
| | | * trunk/opends/resource/legal-notices/OpenDS.LICENSE |
| | | * or https://OpenDS.dev.java.net/OpenDS.LICENSE. |
| | | * See the License for the specific language governing permissions |
| | | * and limitations under the License. |
| | | * |
| | | * When distributing Covered Code, include this CDDL HEADER in each |
| | | * file and include the License file at |
| | | * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable, |
| | | * add the following below this CDDL HEADER, with the fields enclosed |
| | | * 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); |
| | | } |
| New file |
| | |
| | | /* |
| | | * CDDL HEADER START |
| | | * |
| | | * The contents of this file are subject to the terms of the |
| | | * Common Development and Distribution License, Version 1.0 only |
| | | * (the "License"). You may not use this file except in compliance |
| | | * with the License. |
| | | * |
| | | * You can obtain a copy of the license at |
| | | * trunk/opends/resource/legal-notices/OpenDS.LICENSE |
| | | * or https://OpenDS.dev.java.net/OpenDS.LICENSE. |
| | | * See the License for the specific language governing permissions |
| | | * and limitations under the License. |
| | | * |
| | | * When distributing Covered Code, include this CDDL HEADER in each |
| | | * file and include the License file at |
| | | * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable, |
| | | * add the following below this CDDL HEADER, with the fields enclosed |
| | | * 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(); |
| | | } |
| | | } |
| New file |
| | |
| | | /* |
| | | * CDDL HEADER START |
| | | * |
| | | * The contents of this file are subject to the terms of the |
| | | * Common Development and Distribution License, Version 1.0 only |
| | | * (the "License"). You may not use this file except in compliance |
| | | * with the License. |
| | | * |
| | | * You can obtain a copy of the license at |
| | | * trunk/opends/resource/legal-notices/OpenDS.LICENSE |
| | | * or https://OpenDS.dev.java.net/OpenDS.LICENSE. |
| | | * See the License for the specific language governing permissions |
| | | * and limitations under the License. |
| | | * |
| | | * When distributing Covered Code, include this CDDL HEADER in each |
| | | * file and include the License file at |
| | | * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable, |
| | | * add the following below this CDDL HEADER, with the fields enclosed |
| | | * 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); |
| | | } |
| New file |
| | |
| | | /* |
| | | * CDDL HEADER START |
| | | * |
| | | * The contents of this file are subject to the terms of the |
| | | * Common Development and Distribution License, Version 1.0 only |
| | | * (the "License"). You may not use this file except in compliance |
| | | * with the License. |
| | | * |
| | | * You can obtain a copy of the license at |
| | | * trunk/opends/resource/legal-notices/OpenDS.LICENSE |
| | | * or https://OpenDS.dev.java.net/OpenDS.LICENSE. |
| | | * See the License for the specific language governing permissions |
| | | * and limitations under the License. |
| | | * |
| | | * When distributing Covered Code, include this CDDL HEADER in each |
| | | * file and include the License file at |
| | | * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable, |
| | | * add the following below this CDDL HEADER, with the fields enclosed |
| | | * 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; |
| | | } |
| | | } |
| New file |
| | |
| | | /* |
| | | * CDDL HEADER START |
| | | * |
| | | * The contents of this file are subject to the terms of the |
| | | * Common Development and Distribution License, Version 1.0 only |
| | | * (the "License"). You may not use this file except in compliance |
| | | * with the License. |
| | | * |
| | | * You can obtain a copy of the license at |
| | | * trunk/opends/resource/legal-notices/OpenDS.LICENSE |
| | | * or https://OpenDS.dev.java.net/OpenDS.LICENSE. |
| | | * See the License for the specific language governing permissions |
| | | * and limitations under the License. |
| | | * |
| | | * When distributing Covered Code, include this CDDL HEADER in each |
| | | * file and include the License file at |
| | | * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable, |
| | | * add the following below this CDDL HEADER, with the fields enclosed |
| | | * 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; |
| | | } |
| | | |
| | | } |
| New file |
| | |
| | | /* |
| | | * CDDL HEADER START |
| | | * |
| | | * The contents of this file are subject to the terms of the |
| | | * Common Development and Distribution License, Version 1.0 only |
| | | * (the "License"). You may not use this file except in compliance |
| | | * with the License. |
| | | * |
| | | * You can obtain a copy of the license at |
| | | * trunk/opends/resource/legal-notices/OpenDS.LICENSE |
| | | * or https://OpenDS.dev.java.net/OpenDS.LICENSE. |
| | | * See the License for the specific language governing permissions |
| | | * and limitations under the License. |
| | | * |
| | | * When distributing Covered Code, include this CDDL HEADER in each |
| | | * file and include the License file at |
| | | * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable, |
| | | * add the following below this CDDL HEADER, with the fields enclosed |
| | | * 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); |
| | | } |
| | | } |
| | | |
| | | } |
| New file |
| | |
| | | /* |
| | | * CDDL HEADER START |
| | | * |
| | | * The contents of this file are subject to the terms of the |
| | | * Common Development and Distribution License, Version 1.0 only |
| | | * (the "License"). You may not use this file except in compliance |
| | | * with the License. |
| | | * |
| | | * You can obtain a copy of the license at |
| | | * trunk/opends/resource/legal-notices/OpenDS.LICENSE |
| | | * or https://OpenDS.dev.java.net/OpenDS.LICENSE. |
| | | * See the License for the specific language governing permissions |
| | | * and limitations under the License. |
| | | * |
| | | * When distributing Covered Code, include this CDDL HEADER in each |
| | | * file and include the License file at |
| | | * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable, |
| | | * add the following below this CDDL HEADER, with the fields enclosed |
| | | * 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. |
| | | } |
| | | } |
| New file |
| | |
| | | /* |
| | | * CDDL HEADER START |
| | | * |
| | | * The contents of this file are subject to the terms of the |
| | | * Common Development and Distribution License, Version 1.0 only |
| | | * (the "License"). You may not use this file except in compliance |
| | | * with the License. |
| | | * |
| | | * You can obtain a copy of the license at |
| | | * trunk/opends/resource/legal-notices/OpenDS.LICENSE |
| | | * or https://OpenDS.dev.java.net/OpenDS.LICENSE. |
| | | * See the License for the specific language governing permissions |
| | | * and limitations under the License. |
| | | * |
| | | * When distributing Covered Code, include this CDDL HEADER in each |
| | | * file and include the License file at |
| | | * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable, |
| | | * add the following below this CDDL 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. |
| | | } |
| | | } |
| New file |
| | |
| | | /* |
| | | * CDDL HEADER START |
| | | * |
| | | * The contents of this file are subject to the terms of the |
| | | * Common Development and Distribution License, Version 1.0 only |
| | | * (the "License"). You may not use this file except in compliance |
| | | * with the License. |
| | | * |
| | | * You can obtain a copy of the license at |
| | | * trunk/opends/resource/legal-notices/OpenDS.LICENSE |
| | | * or https://OpenDS.dev.java.net/OpenDS.LICENSE. |
| | | * See the License for the specific language governing permissions |
| | | * and limitations under the License. |
| | | * |
| | | * When distributing Covered Code, include this CDDL HEADER in each |
| | | * file and include the License file at |
| | | * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable, |
| | | * add the following below this CDDL 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; |
| | | } |
| | | } |
| New file |
| | |
| | | /* |
| | | * CDDL HEADER START |
| | | * |
| | | * The contents of this file are subject to the terms of the |
| | | * Common Development and Distribution License, Version 1.0 only |
| | | * (the "License"). You may not use this file except in compliance |
| | | * with the License. |
| | | * |
| | | * You can obtain a copy of the license at |
| | | * trunk/opends/resource/legal-notices/OpenDS.LICENSE |
| | | * or https://OpenDS.dev.java.net/OpenDS.LICENSE. |
| | | * See the License for the specific language governing permissions |
| | | * and limitations under the License. |
| | | * |
| | | * When distributing Covered Code, include this CDDL HEADER in each |
| | | * file and include the License file at |
| | | * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable, |
| | | * add the following below this CDDL 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; |
| | | } |
| New file |
| | |
| | | /* |
| | | * CDDL HEADER START |
| | | * |
| | | * The contents of this file are subject to the terms of the |
| | | * Common Development and Distribution License, Version 1.0 only |
| | | * (the "License"). You may not use this file except in compliance |
| | | * with the License. |
| | | * |
| | | * You can obtain a copy of the license at |
| | | * trunk/opends/resource/legal-notices/OpenDS.LICENSE |
| | | * or https://OpenDS.dev.java.net/OpenDS.LICENSE. |
| | | * See the License for the specific language governing permissions |
| | | * and limitations under the License. |
| | | * |
| | | * When distributing Covered Code, include this CDDL HEADER in each |
| | | * file and include the License file at |
| | | * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable, |
| | | * add the following below this CDDL 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; |
| | | } |
| | | } |
| New file |
| | |
| | | /* |
| | | * CDDL HEADER START |
| | | * |
| | | * The contents of this file are subject to the terms of the |
| | | * Common Development and Distribution License, Version 1.0 only |
| | | * (the "License"). You may not use this file except in compliance |
| | | * with the License. |
| | | * |
| | | * You can obtain a copy of the license at |
| | | * trunk/opends/resource/legal-notices/OpenDS.LICENSE |
| | | * or https://OpenDS.dev.java.net/OpenDS.LICENSE. |
| | | * See the License for the specific language governing permissions |
| | | * and limitations under the License. |
| | | * |
| | | * When distributing Covered Code, include this CDDL HEADER in each |
| | | * file and include the License file at |
| | | * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable, |
| | | * add the following below this CDDL 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)); |
| | | } |
| | | } |
| | | } |
| New file |
| | |
| | | /* |
| | | * CDDL HEADER START |
| | | * |
| | | * The contents of this file are subject to the terms of the |
| | | * Common Development and Distribution License, Version 1.0 only |
| | | * (the "License"). You may not use this file except in compliance |
| | | * with the License. |
| | | * |
| | | * You can obtain a copy of the license at |
| | | * trunk/opends/resource/legal-notices/OpenDS.LICENSE |
| | | * or https://OpenDS.dev.java.net/OpenDS.LICENSE. |
| | | * See the License for the specific language governing permissions |
| | | * and limitations under the License. |
| | | * |
| | | * When distributing Covered Code, include this CDDL HEADER in each |
| | | * file and include the License file at |
| | | * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable, |
| | | * add the following below this CDDL 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; |
| | | } |
| 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 |