All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.unboundid.ldap.sdk.unboundidds.controls.MatchingEntryCountResponseControl Maven / Gradle / Ivy

/*
 * Copyright 2014-2019 Ping Identity Corporation
 * All Rights Reserved.
 */
/*
 * Copyright (C) 2015-2019 Ping Identity Corporation
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License (GPLv2 only)
 * or the terms of the GNU Lesser General Public License (LGPLv2.1 only)
 * as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, see .
 */
package com.unboundid.ldap.sdk.unboundidds.controls;



import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;

import com.unboundid.asn1.ASN1Boolean;
import com.unboundid.asn1.ASN1Element;
import com.unboundid.asn1.ASN1Integer;
import com.unboundid.asn1.ASN1Null;
import com.unboundid.asn1.ASN1OctetString;
import com.unboundid.asn1.ASN1Sequence;
import com.unboundid.ldap.sdk.Control;
import com.unboundid.ldap.sdk.DecodeableControl;
import com.unboundid.ldap.sdk.LDAPException;
import com.unboundid.ldap.sdk.ResultCode;
import com.unboundid.ldap.sdk.SearchResult;
import com.unboundid.util.Debug;
import com.unboundid.util.NotMutable;
import com.unboundid.util.StaticUtils;
import com.unboundid.util.ThreadSafety;
import com.unboundid.util.ThreadSafetyLevel;
import com.unboundid.util.Validator;

import static com.unboundid.ldap.sdk.unboundidds.controls.ControlMessages.*;



/**
 * This class provides a response control that may be used to provide
 * information about the number of entries that match a given set of search
 * criteria.  The control will be included in the search result done message
 * for any successful search operation in which the request contained a matching
 * entry count request control.
 * 
*
* NOTE: This class, and other classes within the * {@code com.unboundid.ldap.sdk.unboundidds} package structure, are only * supported for use against Ping Identity, UnboundID, and * Nokia/Alcatel-Lucent 8661 server products. These classes provide support * for proprietary functionality or for external specifications that are not * considered stable or mature enough to be guaranteed to work in an * interoperable way with other types of LDAP servers. *
*
* The matching entry count response control has an OID of * "1.3.6.1.4.1.30221.2.5.37", a criticality of false, and a value with the * following encoding: *
 *   MatchingEntryCountResponse ::= SEQUENCE {
 *        entryCount        CHOICE {
 *             examinedCount       [0] INTEGER,
 *             unexaminedCount     [1] INTEGER,
 *             upperBound          [2] INTEGER,
 *             unknown             [3] NULL,
 *             ... }
 *        debugInfo         [0] SEQUENCE OF OCTET STRING OPTIONAL,
 *        searchIndexed     [1] BOOLEAN DEFAULT TRUE,
 *        ... }
 * 
* * @see MatchingEntryCountRequestControl */ @NotMutable() @ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE) public final class MatchingEntryCountResponseControl extends Control implements DecodeableControl { /** * The OID (1.3.6.1.4.1.30221.2.5.37) for the matching entry count response * control. */ public static final String MATCHING_ENTRY_COUNT_RESPONSE_OID = "1.3.6.1.4.1.30221.2.5.37"; /** * The BER type for the element used to hold the list of debug messages. */ private static final byte TYPE_DEBUG_INFO = (byte) 0xA0; /** * The BER type for the element used to indicate whether the search criteria * is at least partially indexed. */ private static final byte TYPE_SEARCH_INDEXED = (byte) 0x81; /** * The serial version UID for this serializable class. */ private static final long serialVersionUID = -5488025806310455564L; // Indicates whether the search criteria is considered at least partially // indexed by the server. private final boolean searchIndexed; // The count value for this matching entry count response control. private final int countValue; // A list of messages providing debug information about the processing // performed by the server. private final List debugInfo; // The count type for this matching entry count response control. private final MatchingEntryCountType countType; /** * Creates a new empty control instance that is intended to be used only for * decoding controls via the {@code DecodeableControl} interface. */ MatchingEntryCountResponseControl() { searchIndexed = false; countType = null; countValue = -1; debugInfo = null; } /** * Creates a new matching entry count response control with the provided * information. * * @param countType The matching entry count type. It must not be * {@code null}. * @param countValue The matching entry count value. It must be greater * than or equal to zero for a count type of either * {@code EXAMINED_COUNT} or {@code UNEXAMINED_COUNT}. * It must be greater than zero for a count type of * {@code UPPER_BOUND}. It must be -1 for a count type * of {@code UNKNOWN}. * @param searchIndexed Indicates whether the search criteria is considered * at least partially indexed and could be processed * more efficiently than examining all entries with a * full database scan. * @param debugInfo An optional list of messages providing debug * information about the processing performed by the * server. It may be {@code null} or empty if no debug * messages should be included. */ private MatchingEntryCountResponseControl( final MatchingEntryCountType countType, final int countValue, final boolean searchIndexed, final Collection debugInfo) { super(MATCHING_ENTRY_COUNT_RESPONSE_OID, false, encodeValue(countType, countValue, searchIndexed, debugInfo)); this.countType = countType; this.countValue = countValue; this.searchIndexed = searchIndexed; if (debugInfo == null) { this.debugInfo = Collections.emptyList(); } else { this.debugInfo = Collections.unmodifiableList(new ArrayList<>(debugInfo)); } } /** * Creates a new matching entry count response control decoded from the given * generic control contents. * * @param oid The OID for the control. * @param isCritical Indicates whether this control should be marked * critical. * @param value The encoded value for the control. * * @throws LDAPException If a problem occurs while attempting to decode the * generic control as a matching entry count response * control. */ public MatchingEntryCountResponseControl(final String oid, final boolean isCritical, final ASN1OctetString value) throws LDAPException { super(oid, isCritical, value); if (value == null) { throw new LDAPException(ResultCode.DECODING_ERROR, ERR_MATCHING_ENTRY_COUNT_RESPONSE_MISSING_VALUE.get()); } try { final ASN1Element[] elements = ASN1Sequence.decodeAsSequence(value.getValue()).elements(); countType = MatchingEntryCountType.valueOf(elements[0].getType()); if (countType == null) { throw new LDAPException(ResultCode.DECODING_ERROR, ERR_MATCHING_ENTRY_COUNT_RESPONSE_INVALID_COUNT_TYPE.get( StaticUtils.toHex(elements[0].getType()))); } switch (countType) { case EXAMINED_COUNT: case UNEXAMINED_COUNT: countValue = ASN1Integer.decodeAsInteger(elements[0]).intValue(); if (countValue < 0) { throw new LDAPException(ResultCode.DECODING_ERROR, ERR_MATCHING_ENTRY_COUNT_RESPONSE_NEGATIVE_EXACT_COUNT.get()); } break; case UPPER_BOUND: countValue = ASN1Integer.decodeAsInteger(elements[0]).intValue(); if (countValue <= 0) { throw new LDAPException(ResultCode.DECODING_ERROR, ERR_MATCHING_ENTRY_COUNT_RESPONSE_NON_POSITIVE_UPPER_BOUND. get()); } break; case UNKNOWN: default: countValue = -1; break; } boolean isIndexed = (countType != MatchingEntryCountType.UNKNOWN); List debugMessages = Collections.emptyList(); for (int i=1; i < elements.length; i++) { switch (elements[i].getType()) { case TYPE_DEBUG_INFO: final ASN1Element[] debugElements = ASN1Sequence.decodeAsSequence(elements[i]).elements(); debugMessages = new ArrayList<>(debugElements.length); for (final ASN1Element e : debugElements) { debugMessages.add( ASN1OctetString.decodeAsOctetString(e).stringValue()); } break; case TYPE_SEARCH_INDEXED: isIndexed = ASN1Boolean.decodeAsBoolean(elements[i]).booleanValue(); break; default: throw new LDAPException(ResultCode.DECODING_ERROR, ERR_MATCHING_ENTRY_COUNT_RESPONSE_UNKNOWN_ELEMENT_TYPE.get( StaticUtils.toHex(elements[i].getType()))); } } searchIndexed = isIndexed; debugInfo = Collections.unmodifiableList(debugMessages); } catch (final LDAPException le) { Debug.debugException(le); throw le; } catch (final Exception e) { Debug.debugException(e); throw new LDAPException(ResultCode.DECODING_ERROR, ERR_GET_BACKEND_SET_ID_RESPONSE_CANNOT_DECODE.get( StaticUtils.getExceptionMessage(e)), e); } } /** * Creates a new matching entry count response control for the case in which * the exact number of matching entries is known. * * @param count The exact number of entries matching the associated * search criteria. It must be greater than or equal to * zero. * @param examined Indicates whether the server examined the entries to * exclude those entries that would not be returned to the * client in a normal search with the same criteria. * @param debugInfo An optional list of messages providing debug information * about the processing performed by the server. It may be * {@code null} or empty if no debug messages should be * included. * * @return The matching entry count response control that was created. */ public static MatchingEntryCountResponseControl createExactCountResponse( final int count, final boolean examined, final Collection debugInfo) { return createExactCountResponse(count, examined, true, debugInfo); } /** * Creates a new matching entry count response control for the case in which * the exact number of matching entries is known. * * @param count The exact number of entries matching the associated * search criteria. It must be greater than or equal * to zero. * @param examined Indicates whether the server examined the entries to * exclude those entries that would not be returned to * the client in a normal search with the same * criteria. * @param searchIndexed Indicates whether the search criteria is considered * at least partially indexed and could be processed * more efficiently than examining all entries with a * full database scan. * @param debugInfo An optional list of messages providing debug * information about the processing performed by the * server. It may be {@code null} or empty if no debug * messages should be included. * * @return The matching entry count response control that was created. */ public static MatchingEntryCountResponseControl createExactCountResponse( final int count, final boolean examined, final boolean searchIndexed, final Collection debugInfo) { Validator.ensureTrue(count >= 0); final MatchingEntryCountType countType; if (examined) { countType = MatchingEntryCountType.EXAMINED_COUNT; } else { countType = MatchingEntryCountType.UNEXAMINED_COUNT; } return new MatchingEntryCountResponseControl(countType, count, searchIndexed, debugInfo); } /** * Creates a new matching entry count response control for the case in which * the exact number of matching entries is not known, but the server was able * to determine an upper bound on the number of matching entries. This upper * bound count may include entries that do not match the search filter, that * are outside the scope of the search, and/or that match the search criteria * but would not have been returned to the client in a normal search with the * same criteria. * * @param upperBound The upper bound on the number of entries that match the * associated search criteria. It must be greater than * zero. * @param debugInfo An optional list of messages providing debug * information about the processing performed by the * server. It may be {@code null} or empty if no debug * messages should be included. * * @return The matching entry count response control that was created. */ public static MatchingEntryCountResponseControl createUpperBoundResponse( final int upperBound, final Collection debugInfo) { return createUpperBoundResponse(upperBound, true, debugInfo); } /** * Creates a new matching entry count response control for the case in which * the exact number of matching entries is not known, but the server was able * to determine an upper bound on the number of matching entries. This upper * bound count may include entries that do not match the search filter, that * are outside the scope of the search, and/or that match the search criteria * but would not have been returned to the client in a normal search with the * same criteria. * * @param upperBound The upper bound on the number of entries that match * the associated search criteria. It must be greater * than zero. * @param searchIndexed Indicates whether the search criteria is considered * at least partially indexed and could be processed * more efficiently than examining all entries with a * full database scan. * @param debugInfo An optional list of messages providing debug * information about the processing performed by the * server. It may be {@code null} or empty if no debug * messages should be included. * * @return The matching entry count response control that was created. */ public static MatchingEntryCountResponseControl createUpperBoundResponse( final int upperBound, final boolean searchIndexed, final Collection debugInfo) { Validator.ensureTrue(upperBound > 0); return new MatchingEntryCountResponseControl( MatchingEntryCountType.UPPER_BOUND, upperBound, searchIndexed, debugInfo); } /** * Creates a new matching entry count response control for the case in which * the server was unable to make any meaningful determination about the number * of entries matching the search criteria. * * @param debugInfo An optional list of messages providing debug information * about the processing performed by the server. It may be * {@code null} or empty if no debug messages should be * included. * * @return The matching entry count response control that was created. */ public static MatchingEntryCountResponseControl createUnknownCountResponse( final Collection debugInfo) { return new MatchingEntryCountResponseControl(MatchingEntryCountType.UNKNOWN, -1, false, debugInfo); } /** * Encodes a control value with the provided information. * * @param countType The matching entry count type. It must not be * {@code null}. * @param countValue The matching entry count value. It must be greater * than or equal to zero for a count type of either * {@code EXAMINED_COUNT} or {@code UNEXAMINED_COUNT}. * It must be greater than zero for a count type of * {@code UPPER_BOUND}. It must be -1 for a count type * of {@code UNKNOWN}. * @param searchIndexed Indicates whether the search criteria is considered * at least partially indexed and could be processed * more efficiently than examining all entries with a * full database scan. * @param debugInfo An optional list of messages providing debug * information about the processing performed by the * server. It may be {@code null} or empty if no debug * messages should be included. * * @return The encoded control value. */ private static ASN1OctetString encodeValue( final MatchingEntryCountType countType, final int countValue, final boolean searchIndexed, final Collection debugInfo) { final ArrayList elements = new ArrayList<>(3); switch (countType) { case EXAMINED_COUNT: case UNEXAMINED_COUNT: case UPPER_BOUND: elements.add(new ASN1Integer(countType.getBERType(), countValue)); break; case UNKNOWN: elements.add(new ASN1Null(countType.getBERType())); break; } if (debugInfo != null) { final ArrayList debugElements = new ArrayList<>(debugInfo.size()); for (final String s : debugInfo) { debugElements.add(new ASN1OctetString(s)); } elements.add(new ASN1Sequence(TYPE_DEBUG_INFO, debugElements)); } if (! searchIndexed) { elements.add(new ASN1Boolean(TYPE_SEARCH_INDEXED, searchIndexed)); } return new ASN1OctetString(new ASN1Sequence(elements).encode()); } /** * Retrieves the matching entry count type for the response control. * * @return The matching entry count type for the response control. */ public MatchingEntryCountType getCountType() { return countType; } /** * Retrieves the matching entry count value for the response control. For a * count type of {@code EXAMINED_COUNT} or {@code UNEXAMINED_COUNT}, this is * the exact number of matching entries. For a count type of * {@code UPPER_BOUND}, this is the maximum number of entries that may match * the search criteria, but it may also include entries that do not match the * criteria. For a count type of {@code UNKNOWN}, this will always be -1. * * @return The exact count or upper bound of the number of entries in the * server that may match the search criteria, or -1 if the server * could not determine the number of matching entries. */ public int getCountValue() { return countValue; } /** * Indicates whether the server considers the search criteria to be indexed * and therefore it could be processed more efficiently than examining all * entries with a full database scan. * * @return {@code true} if the server considers the search criteria to be * indexed, or {@code false} if not. */ public boolean searchIndexed() { return searchIndexed; } /** * Retrieves a list of messages with debug information about the processing * performed by the server in the course of obtaining the matching entry * count. These messages are intended to be human-readable rather than * machine-parsable. * * @return A list of messages with debug information about the processing * performed by the server in the course of obtaining the matching * entry count, or an empty list if no debug messages were provided. */ public List getDebugInfo() { return debugInfo; } /** * {@inheritDoc} */ @Override() public MatchingEntryCountResponseControl decodeControl(final String oid, final boolean isCritical, final ASN1OctetString value) throws LDAPException { return new MatchingEntryCountResponseControl(oid, isCritical, value); } /** * Extracts a matching entry count response control from the provided search * result. * * @param result The search result from which to retrieve the matching entry * count response control. * * @return The matching entry count response control contained in the * provided result, or {@code null} if the result did not contain a * matching entry count response control. * * @throws LDAPException If a problem is encountered while attempting to * decode the matching entry count response control * contained in the provided result. */ public static MatchingEntryCountResponseControl get(final SearchResult result) throws LDAPException { final Control c = result.getResponseControl(MATCHING_ENTRY_COUNT_RESPONSE_OID); if (c == null) { return null; } if (c instanceof MatchingEntryCountResponseControl) { return (MatchingEntryCountResponseControl) c; } else { return new MatchingEntryCountResponseControl(c.getOID(), c.isCritical(), c.getValue()); } } /** * {@inheritDoc} */ @Override() public String getControlName() { return INFO_CONTROL_NAME_MATCHING_ENTRY_COUNT_RESPONSE.get(); } /** * {@inheritDoc} */ @Override() public void toString(final StringBuilder buffer) { buffer.append("MatchingEntryCountResponseControl(countType='"); buffer.append(countType.name()); buffer.append('\''); switch (countType) { case EXAMINED_COUNT: case UNEXAMINED_COUNT: buffer.append(", count="); buffer.append(countValue); break; case UPPER_BOUND: buffer.append(", upperBound="); buffer.append(countValue); break; } buffer.append(", searchIndexed="); buffer.append(searchIndexed); if (! debugInfo.isEmpty()) { buffer.append(", debugInfo={"); final Iterator iterator = debugInfo.iterator(); while (iterator.hasNext()) { buffer.append('\''); buffer.append(iterator.next()); buffer.append('\''); if (iterator.hasNext()) { buffer.append(", "); } } buffer.append('}'); } buffer.append(')'); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy