Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*
* Copyright 2017 UnboundID Corp.
* All Rights Reserved.
*/
/*
* Copyright (C) 2017 UnboundID Corp.
*
* 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.tools;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.EnumSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.StringTokenizer;
import java.util.concurrent.atomic.AtomicLong;
import com.unboundid.asn1.ASN1OctetString;
import com.unboundid.ldap.sdk.Control;
import com.unboundid.ldap.sdk.DN;
import com.unboundid.ldap.sdk.DereferencePolicy;
import com.unboundid.ldap.sdk.ExtendedResult;
import com.unboundid.ldap.sdk.Filter;
import com.unboundid.ldap.sdk.LDAPConnectionOptions;
import com.unboundid.ldap.sdk.LDAPConnection;
import com.unboundid.ldap.sdk.LDAPConnectionPool;
import com.unboundid.ldap.sdk.LDAPException;
import com.unboundid.ldap.sdk.LDAPResult;
import com.unboundid.ldap.sdk.LDAPSearchException;
import com.unboundid.ldap.sdk.LDAPURL;
import com.unboundid.ldap.sdk.ResultCode;
import com.unboundid.ldap.sdk.SearchRequest;
import com.unboundid.ldap.sdk.SearchResult;
import com.unboundid.ldap.sdk.SearchScope;
import com.unboundid.ldap.sdk.UnsolicitedNotificationHandler;
import com.unboundid.ldap.sdk.Version;
import com.unboundid.ldap.sdk.controls.AssertionRequestControl;
import com.unboundid.ldap.sdk.controls.AuthorizationIdentityRequestControl;
import com.unboundid.ldap.sdk.controls.ManageDsaITRequestControl;
import com.unboundid.ldap.sdk.controls.MatchedValuesFilter;
import com.unboundid.ldap.sdk.controls.MatchedValuesRequestControl;
import com.unboundid.ldap.sdk.controls.PersistentSearchChangeType;
import com.unboundid.ldap.sdk.controls.PersistentSearchRequestControl;
import com.unboundid.ldap.sdk.controls.ProxiedAuthorizationV1RequestControl;
import com.unboundid.ldap.sdk.controls.ProxiedAuthorizationV2RequestControl;
import com.unboundid.ldap.sdk.controls.ServerSideSortRequestControl;
import com.unboundid.ldap.sdk.controls.SimplePagedResultsControl;
import com.unboundid.ldap.sdk.controls.SortKey;
import com.unboundid.ldap.sdk.controls.SubentriesRequestControl;
import com.unboundid.ldap.sdk.controls.VirtualListViewRequestControl;
import com.unboundid.ldap.sdk.persist.PersistUtils;
import com.unboundid.ldap.sdk.transformations.EntryTransformation;
import com.unboundid.ldap.sdk.transformations.ExcludeAttributeTransformation;
import com.unboundid.ldap.sdk.transformations.MoveSubtreeTransformation;
import com.unboundid.ldap.sdk.transformations.RedactAttributeTransformation;
import com.unboundid.ldap.sdk.transformations.RenameAttributeTransformation;
import com.unboundid.ldap.sdk.transformations.ScrambleAttributeTransformation;
import com.unboundid.ldap.sdk.unboundidds.controls.AccountUsableRequestControl;
import com.unboundid.ldap.sdk.unboundidds.controls.ExcludeBranchRequestControl;
import com.unboundid.ldap.sdk.unboundidds.controls.
GetAuthorizationEntryRequestControl;
import com.unboundid.ldap.sdk.unboundidds.controls.
GetEffectiveRightsRequestControl;
import com.unboundid.ldap.sdk.unboundidds.controls.
GetUserResourceLimitsRequestControl;
import com.unboundid.ldap.sdk.unboundidds.controls.JoinBaseDN;
import com.unboundid.ldap.sdk.unboundidds.controls.JoinRequestControl;
import com.unboundid.ldap.sdk.unboundidds.controls.JoinRequestValue;
import com.unboundid.ldap.sdk.unboundidds.controls.JoinRule;
import com.unboundid.ldap.sdk.unboundidds.controls.
MatchingEntryCountRequestControl;
import com.unboundid.ldap.sdk.unboundidds.controls.
OperationPurposeRequestControl;
import com.unboundid.ldap.sdk.unboundidds.controls.PasswordPolicyRequestControl;
import com.unboundid.ldap.sdk.unboundidds.controls.
RealAttributesOnlyRequestControl;
import com.unboundid.ldap.sdk.unboundidds.controls.
ReturnConflictEntriesRequestControl;
import com.unboundid.ldap.sdk.unboundidds.controls.
SoftDeletedEntryAccessRequestControl;
import com.unboundid.ldap.sdk.unboundidds.controls.
SuppressOperationalAttributeUpdateRequestControl;
import com.unboundid.ldap.sdk.unboundidds.controls.SuppressType;
import com.unboundid.ldap.sdk.unboundidds.controls.
VirtualAttributesOnlyRequestControl;
import com.unboundid.ldap.sdk.unboundidds.extensions.
StartAdministrativeSessionExtendedRequest;
import com.unboundid.ldap.sdk.unboundidds.extensions.
StartAdministrativeSessionPostConnectProcessor;
import com.unboundid.ldif.LDIFWriter;
import com.unboundid.util.Debug;
import com.unboundid.util.FilterFileReader;
import com.unboundid.util.FixedRateBarrier;
import com.unboundid.util.LDAPCommandLineTool;
import com.unboundid.util.OutputFormat;
import com.unboundid.util.StaticUtils;
import com.unboundid.util.TeeOutputStream;
import com.unboundid.util.ThreadSafety;
import com.unboundid.util.ThreadSafetyLevel;
import com.unboundid.util.args.ArgumentException;
import com.unboundid.util.args.ArgumentParser;
import com.unboundid.util.args.BooleanArgument;
import com.unboundid.util.args.ControlArgument;
import com.unboundid.util.args.DNArgument;
import com.unboundid.util.args.FileArgument;
import com.unboundid.util.args.FilterArgument;
import com.unboundid.util.args.IntegerArgument;
import com.unboundid.util.args.ScopeArgument;
import com.unboundid.util.args.StringArgument;
import static com.unboundid.ldap.sdk.unboundidds.tools.ToolMessages.*;
/**
* This class provides an implementation of an LDAP command-line tool that may
* be used to issue searches to a directory server. Matching entries will be
* output in the LDAP data interchange format (LDIF), to standard output and/or
* to a specified file. This is a much more full-featured tool than the
* {@link com.unboundid.ldap.sdk.examples.LDAPSearch} tool, and includes a
* number of features only available in the Commercial Edition of the LDAP SDK.
*
*
* NOTE: This class is part of the Commercial Edition of the UnboundID
* LDAP SDK for Java. It is not available for use in applications that
* include only the Standard Edition of the LDAP SDK, and is not supported for
* use in conjunction with non-UnboundID products.
*
*/
@ThreadSafety(level=ThreadSafetyLevel.NOT_THREADSAFE)
public final class LDAPSearch
extends LDAPCommandLineTool
implements UnsolicitedNotificationHandler
{
/**
* The column at which to wrap long lines.
*/
private static int WRAP_COLUMN = StaticUtils.TERMINAL_WIDTH_COLUMNS - 1;
// The set of arguments supported by this program.
private BooleanArgument accountUsable = null;
private BooleanArgument authorizationIdentity = null;
private BooleanArgument continueOnError = null;
private BooleanArgument countEntries = null;
private BooleanArgument dontWrap = null;
private BooleanArgument dryRun = null;
private BooleanArgument followReferrals = null;
private BooleanArgument hideRedactedValueCount = null;
private BooleanArgument getUserResourceLimits = null;
private BooleanArgument includeReplicationConflictEntries = null;
private BooleanArgument includeSubentries = null;
private BooleanArgument joinRequireMatch = null;
private BooleanArgument manageDsaIT = null;
private BooleanArgument realAttributesOnly = null;
private BooleanArgument retryFailedOperations = null;
private BooleanArgument separateOutputFilePerSearch = null;
private BooleanArgument suppressBase64EncodedValueComments = null;
private BooleanArgument teeResultsToStandardOut = null;
private BooleanArgument useAdministrativeSession = null;
private BooleanArgument usePasswordPolicyControl = null;
private BooleanArgument terse = null;
private BooleanArgument typesOnly = null;
private BooleanArgument verbose = null;
private BooleanArgument virtualAttributesOnly = null;
private ControlArgument bindControl = null;
private ControlArgument searchControl = null;
private DNArgument baseDN = null;
private DNArgument excludeBranch = null;
private DNArgument moveSubtreeFrom = null;
private DNArgument moveSubtreeTo = null;
private DNArgument proxyV1As = null;
private FileArgument filterFile = null;
private FileArgument ldapURLFile = null;
private FileArgument outputFile = null;
private FilterArgument assertionFilter = null;
private FilterArgument filter = null;
private FilterArgument joinFilter = null;
private FilterArgument matchedValuesFilter = null;
private IntegerArgument joinSizeLimit = null;
private IntegerArgument ratePerSecond = null;
private IntegerArgument scrambleRandomSeed = null;
private IntegerArgument simplePageSize = null;
private IntegerArgument sizeLimit = null;
private IntegerArgument timeLimitSeconds = null;
private IntegerArgument wrapColumn = null;
private ScopeArgument joinScope = null;
private ScopeArgument scope = null;
private StringArgument dereferencePolicy = null;
private StringArgument excludeAttribute = null;
private StringArgument getAuthorizationEntryAttribute = null;
private StringArgument getEffectiveRightsAttribute = null;
private StringArgument getEffectiveRightsAuthzID = null;
private StringArgument includeSoftDeletedEntries = null;
private StringArgument joinBaseDN = null;
private StringArgument joinRequestedAttribute = null;
private StringArgument joinRule = null;
private StringArgument matchingEntryCountControl = null;
private StringArgument operationPurpose = null;
private StringArgument outputFormat = null;
private StringArgument persistentSearch = null;
private StringArgument proxyAs = null;
private StringArgument redactAttribute = null;
private StringArgument renameAttributeFrom = null;
private StringArgument renameAttributeTo = null;
private StringArgument requestedAttribute = null;
private StringArgument scrambleAttribute = null;
private StringArgument scrambleJSONField = null;
private StringArgument sortOrder = null;
private StringArgument suppressOperationalAttributeUpdates = null;
private StringArgument virtualListView = null;
// The argument parser used by this tool.
private volatile ArgumentParser parser = null;
// Controls that should be sent to the server but need special validation.
private volatile JoinRequestControl joinRequestControl = null;
private volatile MatchedValuesRequestControl
matchedValuesRequestControl = null;
private volatile MatchingEntryCountRequestControl
matchingEntryCountRequestControl = null;
private volatile PersistentSearchRequestControl
persistentSearchRequestControl = null;
private volatile ServerSideSortRequestControl sortRequestControl = null;
private volatile VirtualListViewRequestControl vlvRequestControl = null;
// Other values decoded from arguments.
private volatile DereferencePolicy derefPolicy = null;
// The print streams used for standard output and error.
private final AtomicLong outputFileCounter = new AtomicLong(1);
private volatile PrintStream errStream = null;
private volatile PrintStream outStream = null;
// The output handler for this tool.
private volatile LDAPSearchOutputHandler outputHandler =
new LDIFLDAPSearchOutputHandler(this, WRAP_COLUMN);
// The list of entry transformations to apply.
private volatile List entryTransformations = null;
/**
* Runs this tool with the provided command-line arguments. It will use the
* JVM-default streams for standard input, output, and error.
*
* @param args The command-line arguments to provide to this program.
*/
public static void main(final String... args)
{
final ResultCode resultCode = main(System.out, System.err, args);
if (resultCode != ResultCode.SUCCESS)
{
System.exit(Math.min(resultCode.intValue(), 255));
}
}
/**
* Runs this tool with the provided streams and command-line arguments.
*
* @param out The output stream to use for standard output. If this is
* {@code null}, then standard output will be suppressed.
* @param err The output stream to use for standard error. If this is
* {@code null}, then standard error will be suppressed.
* @param args The command-line arguments provided to this program.
*
* @return The result code obtained when running the tool. Any result code
* other than {@link ResultCode#SUCCESS} indicates an error.
*/
public static ResultCode main(final OutputStream out, final OutputStream err,
final String... args)
{
final LDAPSearch tool = new LDAPSearch(out, err);
return tool.runTool(args);
}
/**
* Creates a new instance of this tool with the provided streams.
*
* @param out The output stream to use for standard output. If this is
* {@code null}, then standard output will be suppressed.
* @param err The output stream to use for standard error. If this is
* {@code null}, then standard error will be suppressed.
*/
public LDAPSearch(final OutputStream out, final OutputStream err)
{
super(out, err);
}
/**
* {@inheritDoc}
*/
@Override()
public String getToolName()
{
return "ldapsearch";
}
/**
* {@inheritDoc}
*/
@Override()
public String getToolDescription()
{
return INFO_LDAPSEARCH_TOOL_DESCRIPTION.get();
}
/**
* {@inheritDoc}
*/
@Override()
public String getToolVersion()
{
return Version.NUMERIC_VERSION_STRING;
}
/**
* {@inheritDoc}
*/
@Override()
public int getMinTrailingArguments()
{
return 0;
}
/**
* {@inheritDoc}
*/
@Override()
public int getMaxTrailingArguments()
{
return -1;
}
/**
* {@inheritDoc}
*/
@Override()
public String getTrailingArgumentsPlaceholder()
{
return INFO_LDAPSEARCH_TRAILING_ARGS_PLACEHOLDER.get();
}
/**
* {@inheritDoc}
*/
@Override()
public boolean supportsInteractiveMode()
{
return true;
}
/**
* {@inheritDoc}
*/
@Override()
public boolean defaultsToInteractiveMode()
{
return true;
}
/**
* {@inheritDoc}
*/
@Override()
public boolean supportsPropertiesFile()
{
return true;
}
/**
* {@inheritDoc}
*/
@Override()
protected boolean defaultToPromptForBindPassword()
{
return true;
}
/**
* {@inheritDoc}
*/
@Override()
protected boolean includeAlternateLongIdentifiers()
{
return true;
}
/**
* {@inheritDoc}
*/
@Override()
public void addNonLDAPArguments(final ArgumentParser parser)
throws ArgumentException
{
this.parser = parser;
baseDN = new DNArgument('b', "baseDN", false, 1, null,
INFO_LDAPSEARCH_ARG_DESCRIPTION_BASE_DN.get());
baseDN.addLongIdentifier("base-dn");
baseDN.setArgumentGroupName(INFO_LDAPSEARCH_ARG_GROUP_OPS.get());
parser.addArgument(baseDN);
scope = new ScopeArgument('s', "scope", false, null,
INFO_LDAPSEARCH_ARG_DESCRIPTION_SCOPE.get(), SearchScope.SUB);
scope.addLongIdentifier("searchScope");
scope.addLongIdentifier("search-scope");
scope.setArgumentGroupName(INFO_LDAPSEARCH_ARG_GROUP_OPS.get());
parser.addArgument(scope);
sizeLimit = new IntegerArgument('z', "sizeLimit", false, 1, null,
INFO_LDAPSEARCH_ARG_DESCRIPTION_SIZE_LIMIT.get(), 0,
Integer.MAX_VALUE, 0);
sizeLimit.addLongIdentifier("size-limit");
sizeLimit.setArgumentGroupName(INFO_LDAPSEARCH_ARG_GROUP_OPS.get());
parser.addArgument(sizeLimit);
timeLimitSeconds = new IntegerArgument('l', "timeLimitSeconds", false, 1,
null, INFO_LDAPSEARCH_ARG_DESCRIPTION_TIME_LIMIT.get(), 0,
Integer.MAX_VALUE, 0);
timeLimitSeconds.addLongIdentifier("timeLimit");
timeLimitSeconds.addLongIdentifier("time-limit-seconds");
timeLimitSeconds.addLongIdentifier("time-limit");
timeLimitSeconds.setArgumentGroupName(INFO_LDAPSEARCH_ARG_GROUP_OPS.get());
parser.addArgument(timeLimitSeconds);
final LinkedHashSet derefAllowedValues =
new LinkedHashSet(4);
derefAllowedValues.add("never");
derefAllowedValues.add("always");
derefAllowedValues.add("search");
derefAllowedValues.add("find");
dereferencePolicy = new StringArgument('a', "dereferencePolicy", false, 1,
"{never|always|search|find}",
INFO_LDAPSEARCH_ARG_DESCRIPTION_DEREFERENCE_POLICY.get(),
derefAllowedValues, "never");
dereferencePolicy.addLongIdentifier("dereference-policy");
dereferencePolicy.setArgumentGroupName(
INFO_LDAPSEARCH_ARG_GROUP_OPS.get());
parser.addArgument(dereferencePolicy);
typesOnly = new BooleanArgument('A', "typesOnly", 1,
INFO_LDAPSEARCH_ARG_DESCRIPTION_TYPES_ONLY.get());
typesOnly.addLongIdentifier("types-only");
typesOnly.setArgumentGroupName(INFO_LDAPSEARCH_ARG_GROUP_OPS.get());
parser.addArgument(typesOnly);
requestedAttribute = new StringArgument(null, "requestedAttribute", false,
0, INFO_PLACEHOLDER_ATTR.get(),
INFO_LDAPSEARCH_ARG_DESCRIPTION_REQUESTED_ATTR.get());
requestedAttribute.addLongIdentifier("requested-attribute");
requestedAttribute.setArgumentGroupName(
INFO_LDAPSEARCH_ARG_GROUP_OPS.get());
parser.addArgument(requestedAttribute);
filter = new FilterArgument(null, "filter", false, 0,
INFO_PLACEHOLDER_FILTER.get(),
INFO_LDAPSEARCH_ARG_DESCRIPTION_FILTER.get());
filter.setArgumentGroupName(INFO_LDAPSEARCH_ARG_GROUP_OPS.get());
parser.addArgument(filter);
filterFile = new FileArgument('f', "filterFile", false, 0, null,
INFO_LDAPSEARCH_ARG_DESCRIPTION_FILTER_FILE.get(), true, true,
true, false);
filterFile.addLongIdentifier("filename");
filterFile.addLongIdentifier("filter-file");
filterFile.setArgumentGroupName(INFO_LDAPSEARCH_ARG_GROUP_OPS.get());
parser.addArgument(filterFile);
ldapURLFile = new FileArgument(null, "ldapURLFile", false, 0, null,
INFO_LDAPSEARCH_ARG_DESCRIPTION_LDAP_URL_FILE.get(), true, true,
true, false);
ldapURLFile.addLongIdentifier("ldap-url-file");
ldapURLFile.setArgumentGroupName(INFO_LDAPSEARCH_ARG_GROUP_OPS.get());
parser.addArgument(ldapURLFile);
followReferrals = new BooleanArgument(null, "followReferrals", 1,
INFO_LDAPSEARCH_ARG_DESCRIPTION_FOLLOW_REFERRALS.get());
followReferrals.addLongIdentifier("follow-referrals");
followReferrals.setArgumentGroupName(INFO_LDAPSEARCH_ARG_GROUP_OPS.get());
parser.addArgument(followReferrals);
retryFailedOperations = new BooleanArgument(null, "retryFailedOperations",
1, INFO_LDAPSEARCH_ARG_DESCRIPTION_RETRY_FAILED_OPERATIONS.get());
retryFailedOperations.addLongIdentifier("retry-failed-operations");
retryFailedOperations.setArgumentGroupName(
INFO_LDAPSEARCH_ARG_GROUP_OPS.get());
parser.addArgument(retryFailedOperations);
continueOnError = new BooleanArgument('c', "continueOnError", 1,
INFO_LDAPSEARCH_ARG_DESCRIPTION_CONTINUE_ON_ERROR.get());
continueOnError.addLongIdentifier("continue-on-error");
continueOnError.setArgumentGroupName(INFO_LDAPSEARCH_ARG_GROUP_OPS.get());
parser.addArgument(continueOnError);
ratePerSecond = new IntegerArgument('r', "ratePerSecond", false, 1,
INFO_PLACEHOLDER_NUM.get(),
INFO_LDAPSEARCH_ARG_DESCRIPTION_RATE_PER_SECOND.get(), 1,
Integer.MAX_VALUE);
ratePerSecond.addLongIdentifier("rate-per-second");
ratePerSecond.setArgumentGroupName(INFO_LDAPSEARCH_ARG_GROUP_OPS.get());
parser.addArgument(ratePerSecond);
useAdministrativeSession = new BooleanArgument(null,
"useAdministrativeSession", 1,
INFO_LDAPSEARCH_ARG_DESCRIPTION_USE_ADMIN_SESSION.get());
useAdministrativeSession.addLongIdentifier("use-administrative-session");
useAdministrativeSession.setArgumentGroupName(
INFO_LDAPSEARCH_ARG_GROUP_OPS.get());
parser.addArgument(useAdministrativeSession);
dryRun = new BooleanArgument('n', "dryRun", 1,
INFO_LDAPSEARCH_ARG_DESCRIPTION_DRY_RUN.get());
dryRun.addLongIdentifier("dry-run");
dryRun.setArgumentGroupName(INFO_LDAPSEARCH_ARG_GROUP_OPS.get());
parser.addArgument(dryRun);
wrapColumn = new IntegerArgument(null, "wrapColumn", false, 1, null,
INFO_LDAPSEARCH_ARG_DESCRIPTION_WRAP_COLUMN.get(), 0,
Integer.MAX_VALUE);
wrapColumn.addLongIdentifier("wrap-column");
wrapColumn.setArgumentGroupName(INFO_LDAPSEARCH_ARG_GROUP_DATA.get());
parser.addArgument(wrapColumn);
dontWrap = new BooleanArgument(null, "dontWrap", 1,
INFO_LDAPSEARCH_ARG_DESCRIPTION_DONT_WRAP.get());
dontWrap.addLongIdentifier("doNotWrap");
dontWrap.addLongIdentifier("dont-wrap");
dontWrap.addLongIdentifier("do-not-wrap");
dontWrap.setArgumentGroupName(INFO_LDAPSEARCH_ARG_GROUP_DATA.get());
parser.addArgument(dontWrap);
suppressBase64EncodedValueComments = new BooleanArgument(null,
"suppressBase64EncodedValueComments", 1,
INFO_LDAPSEARCH_ARG_DESCRIPTION_SUPPRESS_BASE64_COMMENTS.get());
suppressBase64EncodedValueComments.addLongIdentifier(
"suppress-base64-encoded-value-comments");
suppressBase64EncodedValueComments.setArgumentGroupName(
INFO_LDAPSEARCH_ARG_GROUP_DATA.get());
parser.addArgument(suppressBase64EncodedValueComments);
countEntries = new BooleanArgument(null, "countEntries", 1,
INFO_LDAPSEARCH_ARG_DESCRIPTION_COUNT_ENTRIES.get());
countEntries.addLongIdentifier("count-entries");
countEntries.setArgumentGroupName(INFO_LDAPSEARCH_ARG_GROUP_OPS.get());
countEntries.setHidden(true);
parser.addArgument(countEntries);
outputFile = new FileArgument(null, "outputFile", false, 1, null,
INFO_LDAPSEARCH_ARG_DESCRIPTION_OUTPUT_FILE.get(), false, true, true,
false);
outputFile.addLongIdentifier("output-file");
outputFile.setArgumentGroupName(INFO_LDAPSEARCH_ARG_GROUP_DATA.get());
parser.addArgument(outputFile);
separateOutputFilePerSearch = new BooleanArgument(null,
"separateOutputFilePerSearch", 1,
INFO_LDAPSEARCH_ARG_DESCRIPTION_SEPARATE_OUTPUT_FILES.get());
separateOutputFilePerSearch.addLongIdentifier(
"separate-output-file-per-search");
separateOutputFilePerSearch.setArgumentGroupName(
INFO_LDAPSEARCH_ARG_GROUP_DATA.get());
parser.addArgument(separateOutputFilePerSearch);
teeResultsToStandardOut = new BooleanArgument(null,
"teeResultsToStandardOut", 1,
INFO_LDAPSEARCH_ARG_DESCRIPTION_TEE.get("outputFile"));
teeResultsToStandardOut.addLongIdentifier(
"tee-results-to-standard-out");
teeResultsToStandardOut.setArgumentGroupName(
INFO_LDAPSEARCH_ARG_GROUP_DATA.get());
parser.addArgument(teeResultsToStandardOut);
final LinkedHashSet outputFormatAllowedValues =
new LinkedHashSet(4);
outputFormatAllowedValues.add("ldif");
outputFormatAllowedValues.add("json");
outputFormatAllowedValues.add("csv");
outputFormatAllowedValues.add("tab-delimited");
outputFormat = new StringArgument(null, "outputFormat", false, 1,
"{ldif|json|csv|tab-delimited}",
INFO_LDAPSEARCH_ARG_DESCRIPTION_OUTPUT_FORMAT.get(
requestedAttribute.getIdentifierString(),
ldapURLFile.getIdentifierString()),
outputFormatAllowedValues, "ldif");
outputFormat.addLongIdentifier("output-format");
outputFormat.setArgumentGroupName(INFO_LDAPSEARCH_ARG_GROUP_DATA.get());
parser.addArgument(outputFormat);
terse = new BooleanArgument(null, "terse", 1,
INFO_LDAPSEARCH_ARG_DESCRIPTION_TERSE.get());
terse.setArgumentGroupName(INFO_LDAPSEARCH_ARG_GROUP_DATA.get());
parser.addArgument(terse);
verbose = new BooleanArgument('v', "verbose", 1,
INFO_LDAPSEARCH_ARG_DESCRIPTION_VERBOSE.get());
verbose.setArgumentGroupName(INFO_LDAPSEARCH_ARG_GROUP_DATA.get());
parser.addArgument(verbose);
bindControl = new ControlArgument(null, "bindControl", false, 0, null,
INFO_LDAPSEARCH_ARG_DESCRIPTION_BIND_CONTROL.get());
bindControl.addLongIdentifier("bind-control");
bindControl.setArgumentGroupName(
INFO_LDAPSEARCH_ARG_GROUP_CONTROLS.get());
parser.addArgument(bindControl);
searchControl = new ControlArgument('J', "control", false, 0, null,
INFO_LDAPSEARCH_ARG_DESCRIPTION_SEARCH_CONTROL.get());
searchControl.addLongIdentifier("searchControl");
searchControl.addLongIdentifier("search-control");
searchControl.setArgumentGroupName(
INFO_LDAPSEARCH_ARG_GROUP_CONTROLS.get());
parser.addArgument(searchControl);
authorizationIdentity = new BooleanArgument('E', "authorizationIdentity",
1, INFO_LDAPSEARCH_ARG_DESCRIPTION_AUTHZ_IDENTITY.get());
authorizationIdentity.addLongIdentifier("reportAuthzID");
authorizationIdentity.addLongIdentifier("authorization-identity");
authorizationIdentity.addLongIdentifier("report-authzid");
authorizationIdentity.setArgumentGroupName(
INFO_LDAPSEARCH_ARG_GROUP_CONTROLS.get());
parser.addArgument(authorizationIdentity);
assertionFilter = new FilterArgument(null, "assertionFilter", false, 1,
INFO_PLACEHOLDER_FILTER.get(),
INFO_LDAPSEARCH_ARG_DESCRIPTION_ASSERTION_FILTER.get());
assertionFilter.addLongIdentifier("assertion-filter");
assertionFilter.setArgumentGroupName(
INFO_LDAPSEARCH_ARG_GROUP_CONTROLS.get());
parser.addArgument(assertionFilter);
getAuthorizationEntryAttribute = new StringArgument(null,
"getAuthorizationEntryAttribute", false, 0,
INFO_PLACEHOLDER_ATTR.get(),
INFO_LDAPSEARCH_ARG_DESCRIPTION_GET_AUTHZ_ENTRY_ATTR.get());
getAuthorizationEntryAttribute.addLongIdentifier(
"get-authorization-entry-attribute");
getAuthorizationEntryAttribute.setArgumentGroupName(
INFO_LDAPSEARCH_ARG_GROUP_CONTROLS.get());
parser.addArgument(getAuthorizationEntryAttribute);
getUserResourceLimits = new BooleanArgument(null, "getUserResourceLimits",
1, INFO_LDAPSEARCH_ARG_DESCRIPTION_GET_USER_RESOURCE_LIMITS.get());
getUserResourceLimits.addLongIdentifier("get-user-resource-limits");
getUserResourceLimits.setArgumentGroupName(
INFO_LDAPSEARCH_ARG_GROUP_CONTROLS.get());
parser.addArgument(getUserResourceLimits);
accountUsable = new BooleanArgument(null, "accountUsable", 1,
INFO_LDAPSEARCH_ARG_DESCRIPTION_ACCOUNT_USABLE.get());
accountUsable.addLongIdentifier("account-usable");
accountUsable.setArgumentGroupName(
INFO_LDAPSEARCH_ARG_GROUP_CONTROLS.get());
parser.addArgument(accountUsable);
excludeBranch = new DNArgument(null, "excludeBranch", false, 0, null,
INFO_LDAPSEARCH_ARG_DESCRIPTION_EXCLUDE_BRANCH.get());
excludeBranch.addLongIdentifier("exclude-branch");
excludeBranch.setArgumentGroupName(
INFO_LDAPSEARCH_ARG_GROUP_CONTROLS.get());
parser.addArgument(excludeBranch);
getEffectiveRightsAuthzID = new StringArgument('g',
"getEffectiveRightsAuthzID", false, 1,
INFO_PLACEHOLDER_AUTHZID.get(),
INFO_LDAPSEARCH_ARG_DESCRIPTION_GET_EFFECTIVE_RIGHTS_AUTHZID.get(
"getEffectiveRightsAttribute"));
getEffectiveRightsAuthzID.addLongIdentifier(
"get-effective-rights-authzid");
getEffectiveRightsAuthzID.setArgumentGroupName(
INFO_LDAPSEARCH_ARG_GROUP_CONTROLS.get());
parser.addArgument(getEffectiveRightsAuthzID);
getEffectiveRightsAttribute = new StringArgument('e',
"getEffectiveRightsAttribute", false, 0,
INFO_PLACEHOLDER_ATTR.get(),
INFO_LDAPSEARCH_ARG_DESCRIPTION_GET_EFFECTIVE_RIGHTS_ATTR.get());
getEffectiveRightsAttribute.addLongIdentifier(
"get-effective-rights-attribute");
getEffectiveRightsAttribute.setArgumentGroupName(
INFO_LDAPSEARCH_ARG_GROUP_CONTROLS.get());
parser.addArgument(getEffectiveRightsAttribute);
includeReplicationConflictEntries = new BooleanArgument(null,
"includeReplicationConflictEntries", 1,
INFO_LDAPSEARCH_ARG_DESCRIPTION_INCLUDE_REPL_CONFLICTS.get());
includeReplicationConflictEntries.addLongIdentifier(
"include-replication-conflict-entries");
includeReplicationConflictEntries.setArgumentGroupName(
INFO_LDAPSEARCH_ARG_GROUP_CONTROLS.get());
parser.addArgument(includeReplicationConflictEntries);
final LinkedHashSet softDeleteAllowedValues =
new LinkedHashSet(3);
softDeleteAllowedValues.add("with-non-deleted-entries");
softDeleteAllowedValues.add("without-non-deleted-entries");
softDeleteAllowedValues.add("deleted-entries-in-undeleted-form");
includeSoftDeletedEntries = new StringArgument(null,
"includeSoftDeletedEntries", false, 1,
"{with-non-deleted-entries|without-non-deleted-entries|" +
"deleted-entries-in-undeleted-form}",
INFO_LDAPSEARCH_ARG_DESCRIPTION_INCLUDE_SOFT_DELETED.get(),
softDeleteAllowedValues);
includeSoftDeletedEntries.addLongIdentifier(
"include-soft-deleted-entries");
includeSoftDeletedEntries.setArgumentGroupName(
INFO_LDAPSEARCH_ARG_GROUP_CONTROLS.get());
parser.addArgument(includeSoftDeletedEntries);
includeSubentries = new BooleanArgument(null, "includeSubentries", 1,
INFO_LDAPSEARCH_ARG_DESCRIPTION_INCLUDE_SUBENTRIES.get());
includeSubentries.addLongIdentifier("includeLDAPSubentries");
includeSubentries.addLongIdentifier("include-subentries");
includeSubentries.addLongIdentifier("include-ldap-subentries");
includeSubentries.setArgumentGroupName(
INFO_LDAPSEARCH_ARG_GROUP_CONTROLS.get());
parser.addArgument(includeSubentries);
joinRule = new StringArgument(null, "joinRule", false, 1,
"{dn:sourceAttr|reverse-dn:targetAttr|equals:sourceAttr:targetAttr|" +
"contains:sourceAttr:targetAttr }",
INFO_LDAPSEARCH_ARG_DESCRIPTION_JOIN_RULE.get());
joinRule.addLongIdentifier("join-rule");
joinRule.setArgumentGroupName(INFO_LDAPSEARCH_ARG_GROUP_CONTROLS.get());
parser.addArgument(joinRule);
joinBaseDN = new StringArgument(null, "joinBaseDN", false, 1,
"{search-base|source-entry-dn|{dn}}",
INFO_LDAPSEARCH_ARG_DESCRIPTION_JOIN_BASE_DN.get());
joinBaseDN.addLongIdentifier("join-base-dn");
joinBaseDN.setArgumentGroupName(INFO_LDAPSEARCH_ARG_GROUP_CONTROLS.get());
parser.addArgument(joinBaseDN);
joinScope = new ScopeArgument(null, "joinScope", false, null,
INFO_LDAPSEARCH_ARG_DESCRIPTION_JOIN_SCOPE.get());
joinScope.addLongIdentifier("join-scope");
joinScope.setArgumentGroupName(INFO_LDAPSEARCH_ARG_GROUP_CONTROLS.get());
parser.addArgument(joinScope);
joinSizeLimit = new IntegerArgument(null, "joinSizeLimit", false, 1,
INFO_PLACEHOLDER_NUM.get(),
INFO_LDAPSEARCH_ARG_DESCRIPTION_JOIN_SIZE_LIMIT.get(), 0,
Integer.MAX_VALUE);
joinSizeLimit.addLongIdentifier("join-size-limit");
joinSizeLimit.setArgumentGroupName(
INFO_LDAPSEARCH_ARG_GROUP_CONTROLS.get());
parser.addArgument(joinSizeLimit);
joinFilter = new FilterArgument(null, "joinFilter", false, 1, null,
INFO_LDAPSEARCH_ARG_DESCRIPTION_JOIN_FILTER.get());
joinFilter.addLongIdentifier("join-filter");
joinFilter.setArgumentGroupName(INFO_LDAPSEARCH_ARG_GROUP_CONTROLS.get());
parser.addArgument(joinFilter);
joinRequestedAttribute = new StringArgument(null, "joinRequestedAttribute",
false, 0, INFO_PLACEHOLDER_ATTR.get(),
INFO_LDAPSEARCH_ARG_DESCRIPTION_JOIN_ATTR.get());
joinRequestedAttribute.addLongIdentifier("join-requested-attribute");
joinRequestedAttribute.setArgumentGroupName(
INFO_LDAPSEARCH_ARG_GROUP_CONTROLS.get());
parser.addArgument(joinRequestedAttribute);
joinRequireMatch = new BooleanArgument(null, "joinRequireMatch", 1,
INFO_LDAPSEARCH_ARG_DESCRIPTION_JOIN_REQUIRE_MATCH.get());
joinRequireMatch.addLongIdentifier("join-require-match");
joinRequireMatch.setArgumentGroupName(
INFO_LDAPSEARCH_ARG_GROUP_CONTROLS.get());
parser.addArgument(joinRequireMatch);
manageDsaIT = new BooleanArgument(null, "manageDsaIT", 1,
INFO_LDAPSEARCH_ARG_DESCRIPTION_MANAGE_DSA_IT.get());
manageDsaIT.addLongIdentifier("manage-dsa-it");
manageDsaIT.setArgumentGroupName(
INFO_LDAPSEARCH_ARG_GROUP_CONTROLS.get());
parser.addArgument(manageDsaIT);
matchedValuesFilter = new FilterArgument(null, "matchedValuesFilter",
false, 0, INFO_PLACEHOLDER_FILTER.get(),
INFO_LDAPSEARCH_ARG_DESCRIPTION_MATCHED_VALUES_FILTER.get());
matchedValuesFilter.addLongIdentifier("matched-values-filter");
matchedValuesFilter.setArgumentGroupName(
INFO_LDAPSEARCH_ARG_GROUP_CONTROLS.get());
parser.addArgument(matchedValuesFilter);
matchingEntryCountControl = new StringArgument(null,
"matchingEntryCountControl", false, 1,
"{examineCount=NNN[:alwaysExamine][:allowUnindexed][:debug]}",
INFO_LDAPSEARCH_ARG_DESCRIPTION_MATCHING_ENTRY_COUNT_CONTROL.get());
matchingEntryCountControl.addLongIdentifier("matchingEntryCount");
matchingEntryCountControl.addLongIdentifier(
"matching-entry-count-control");
matchingEntryCountControl.addLongIdentifier("matching-entry-count");
matchingEntryCountControl.setArgumentGroupName(
INFO_LDAPSEARCH_ARG_GROUP_CONTROLS.get());
parser.addArgument(matchingEntryCountControl);
operationPurpose = new StringArgument(null, "operationPurpose", false, 1,
INFO_PLACEHOLDER_PURPOSE.get(),
INFO_LDAPSEARCH_ARG_DESCRIPTION_OPERATION_PURPOSE.get());
operationPurpose.addLongIdentifier("operation-purpose");
operationPurpose.setArgumentGroupName(
INFO_LDAPSEARCH_ARG_GROUP_CONTROLS.get());
parser.addArgument(operationPurpose);
persistentSearch = new StringArgument('C', "persistentSearch", false, 1,
"ps[:changetype[:changesonly[:entrychgcontrols]]]",
INFO_LDAPSEARCH_ARG_DESCRIPTION_PERSISTENT_SEARCH.get());
persistentSearch.addLongIdentifier("persistent-search");
persistentSearch.setArgumentGroupName(
INFO_LDAPSEARCH_ARG_GROUP_CONTROLS.get());
parser.addArgument(persistentSearch);
proxyAs = new StringArgument('Y', "proxyAs", false, 1,
INFO_PLACEHOLDER_AUTHZID.get(),
INFO_LDAPSEARCH_ARG_DESCRIPTION_PROXY_AS.get());
proxyAs.addLongIdentifier("proxy-as");
proxyAs.setArgumentGroupName(INFO_LDAPSEARCH_ARG_GROUP_CONTROLS.get());
parser.addArgument(proxyAs);
proxyV1As = new DNArgument(null, "proxyV1As", false, 1, null,
INFO_LDAPSEARCH_ARG_DESCRIPTION_PROXY_V1_AS.get());
proxyV1As.addLongIdentifier("proxy-v1-as");
proxyV1As.setArgumentGroupName(INFO_LDAPSEARCH_ARG_GROUP_CONTROLS.get());
parser.addArgument(proxyV1As);
final LinkedHashSet
suppressOperationalAttributeUpdatesAllowedValues =
new LinkedHashSet(4);
suppressOperationalAttributeUpdatesAllowedValues.add("last-access-time");
suppressOperationalAttributeUpdatesAllowedValues.add("last-login-time");
suppressOperationalAttributeUpdatesAllowedValues.add("last-login-ip");
suppressOperationalAttributeUpdatesAllowedValues.add("lastmod");
suppressOperationalAttributeUpdates = new StringArgument(null,
"suppressOperationalAttributeUpdates", false, -1,
INFO_PLACEHOLDER_ATTR.get(),
INFO_LDAPSEARCH_ARG_DESCRIPTION_SUPPRESS_OP_ATTR_UPDATES.get(),
suppressOperationalAttributeUpdatesAllowedValues);
suppressOperationalAttributeUpdates.addLongIdentifier(
"suppress-operational-attribute-updates");
suppressOperationalAttributeUpdates.setArgumentGroupName(
INFO_LDAPMODIFY_ARG_GROUP_CONTROLS.get());
parser.addArgument(suppressOperationalAttributeUpdates);
usePasswordPolicyControl = new BooleanArgument(null,
"usePasswordPolicyControl", 1,
INFO_LDAPSEARCH_ARG_DESCRIPTION_PASSWORD_POLICY.get());
usePasswordPolicyControl.addLongIdentifier("use-password-policy-control");
usePasswordPolicyControl.setArgumentGroupName(
INFO_LDAPSEARCH_ARG_GROUP_CONTROLS.get());
parser.addArgument(usePasswordPolicyControl);
realAttributesOnly = new BooleanArgument(null, "realAttributesOnly", 1,
INFO_LDAPSEARCH_ARG_DESCRIPTION_REAL_ATTRS_ONLY.get());
realAttributesOnly.addLongIdentifier("real-attributes-only");
realAttributesOnly.setArgumentGroupName(
INFO_LDAPSEARCH_ARG_GROUP_CONTROLS.get());
parser.addArgument(realAttributesOnly);
sortOrder = new StringArgument('S', "sortOrder", false, 1, null,
INFO_LDAPSEARCH_ARG_DESCRIPTION_SORT_ORDER.get());
sortOrder.addLongIdentifier("sort-order");
sortOrder.setArgumentGroupName(INFO_LDAPSEARCH_ARG_GROUP_CONTROLS.get());
parser.addArgument(sortOrder);
simplePageSize = new IntegerArgument(null, "simplePageSize", false, 1,
null, INFO_LDAPSEARCH_ARG_DESCRIPTION_PAGE_SIZE.get(), 1,
Integer.MAX_VALUE);
simplePageSize.addLongIdentifier("simple-page-size");
simplePageSize.setArgumentGroupName(
INFO_LDAPSEARCH_ARG_GROUP_CONTROLS.get());
parser.addArgument(simplePageSize);
virtualAttributesOnly = new BooleanArgument(null,
"virtualAttributesOnly", 1,
INFO_LDAPSEARCH_ARG_DESCRIPTION_VIRTUAL_ATTRS_ONLY.get());
virtualAttributesOnly.addLongIdentifier("virtual-attributes-only");
virtualAttributesOnly.setArgumentGroupName(
INFO_LDAPSEARCH_ARG_GROUP_CONTROLS.get());
parser.addArgument(virtualAttributesOnly);
virtualListView = new StringArgument('G', "virtualListView", false, 1,
"{before:after:index:count | before:after:value}",
INFO_LDAPSEARCH_ARG_DESCRIPTION_VLV.get("sortOrder"));
virtualListView.addLongIdentifier("vlv");
virtualListView.addLongIdentifier("virtual-list-view");
virtualListView.setArgumentGroupName(
INFO_LDAPSEARCH_ARG_GROUP_CONTROLS.get());
parser.addArgument(virtualListView);
excludeAttribute = new StringArgument(null, "excludeAttribute", false, 0,
INFO_PLACEHOLDER_ATTR.get(),
INFO_LDAPSEARCH_ARG_DESCRIPTION_EXCLUDE_ATTRIBUTE.get());
excludeAttribute.addLongIdentifier("exclude-attribute");
excludeAttribute.setArgumentGroupName(
INFO_LDAPSEARCH_ARG_GROUP_TRANSFORMATIONS.get());
parser.addArgument(excludeAttribute);
redactAttribute = new StringArgument(null, "redactAttribute", false, 0,
INFO_PLACEHOLDER_ATTR.get(),
INFO_LDAPSEARCH_ARG_DESCRIPTION_REDACT_ATTRIBUTE.get());
redactAttribute.addLongIdentifier("redact-attribute");
redactAttribute.setArgumentGroupName(
INFO_LDAPSEARCH_ARG_GROUP_TRANSFORMATIONS.get());
parser.addArgument(redactAttribute);
hideRedactedValueCount = new BooleanArgument(null, "hideRedactedValueCount",
1, INFO_LDAPSEARCH_ARG_DESCRIPTION_HIDE_REDACTED_VALUE_COUNT.get());
hideRedactedValueCount.addLongIdentifier("hide-redacted-value-count");
hideRedactedValueCount.setArgumentGroupName(
INFO_LDAPSEARCH_ARG_GROUP_TRANSFORMATIONS.get());
parser.addArgument(hideRedactedValueCount);
scrambleAttribute = new StringArgument(null, "scrambleAttribute", false, 0,
INFO_PLACEHOLDER_ATTR.get(),
INFO_LDAPSEARCH_ARG_DESCRIPTION_SCRAMBLE_ATTRIBUTE.get());
scrambleAttribute.addLongIdentifier("scramble-attribute");
scrambleAttribute.setArgumentGroupName(
INFO_LDAPSEARCH_ARG_GROUP_TRANSFORMATIONS.get());
parser.addArgument(scrambleAttribute);
scrambleJSONField = new StringArgument(null, "scrambleJSONField", false, 0,
INFO_PLACEHOLDER_FIELD_NAME.get(),
INFO_LDAPSEARCH_ARG_DESCRIPTION_SCRAMBLE_JSON_FIELD.get());
scrambleJSONField.addLongIdentifier("scramble-json-field");
scrambleJSONField.setArgumentGroupName(
INFO_LDAPSEARCH_ARG_GROUP_TRANSFORMATIONS.get());
parser.addArgument(scrambleJSONField);
scrambleRandomSeed = new IntegerArgument(null, "scrambleRandomSeed", false,
1, null, INFO_LDAPSEARCH_ARG_DESCRIPTION_SCRAMBLE_RANDOM_SEED.get());
scrambleRandomSeed.addLongIdentifier("scramble-random-seed");
scrambleRandomSeed.setArgumentGroupName(
INFO_LDAPSEARCH_ARG_GROUP_TRANSFORMATIONS.get());
parser.addArgument(scrambleRandomSeed);
renameAttributeFrom = new StringArgument(null, "renameAttributeFrom", false,
0, INFO_PLACEHOLDER_ATTR.get(),
INFO_LDAPSEARCH_ARG_DESCRIPTION_RENAME_ATTRIBUTE_FROM.get());
renameAttributeFrom.addLongIdentifier("rename-attribute-from");
renameAttributeFrom.setArgumentGroupName(
INFO_LDAPSEARCH_ARG_GROUP_TRANSFORMATIONS.get());
parser.addArgument(renameAttributeFrom);
renameAttributeTo = new StringArgument(null, "renameAttributeTo", false,
0, INFO_PLACEHOLDER_ATTR.get(),
INFO_LDAPSEARCH_ARG_DESCRIPTION_RENAME_ATTRIBUTE_TO.get());
renameAttributeTo.addLongIdentifier("rename-attribute-to");
renameAttributeTo.setArgumentGroupName(
INFO_LDAPSEARCH_ARG_GROUP_TRANSFORMATIONS.get());
parser.addArgument(renameAttributeTo);
moveSubtreeFrom = new DNArgument(null, "moveSubtreeFrom", false, 0,
INFO_PLACEHOLDER_ATTR.get(),
INFO_LDAPSEARCH_ARG_DESCRIPTION_MOVE_SUBTREE_FROM.get());
moveSubtreeFrom.addLongIdentifier("move-subtree-from");
moveSubtreeFrom.setArgumentGroupName(
INFO_LDAPSEARCH_ARG_GROUP_TRANSFORMATIONS.get());
parser.addArgument(moveSubtreeFrom);
moveSubtreeTo = new DNArgument(null, "moveSubtreeTo", false, 0,
INFO_PLACEHOLDER_ATTR.get(),
INFO_LDAPSEARCH_ARG_DESCRIPTION_MOVE_SUBTREE_TO.get());
moveSubtreeTo.addLongIdentifier("move-subtree-to");
moveSubtreeTo.setArgumentGroupName(
INFO_LDAPSEARCH_ARG_GROUP_TRANSFORMATIONS.get());
parser.addArgument(moveSubtreeTo);
// The "--scriptFriendly" argument is provided for compatibility with legacy
// ldapsearch tools, but is not actually used by this tool.
final BooleanArgument scriptFriendly = new BooleanArgument(null,
"scriptFriendly", 1,
INFO_LDAPSEARCH_ARG_DESCRIPTION_SCRIPT_FRIENDLY.get());
scriptFriendly.addLongIdentifier("script-friendly");
scriptFriendly.setHidden(true);
parser.addArgument(scriptFriendly);
// The "-V" / "--ldapVersion" argument is provided for compatibility with
// legacy ldapsearch tools, but is not actually used by this tool.
final IntegerArgument ldapVersion = new IntegerArgument('V', "ldapVersion",
false, 1, null, INFO_LDAPSEARCH_ARG_DESCRIPTION_LDAP_VERSION.get());
ldapVersion.addLongIdentifier("ldap-version");
ldapVersion.setHidden(true);
parser.addArgument(ldapVersion);
// The baseDN and ldapURLFile arguments can't be used together, but one of
// them must be present.
parser.addExclusiveArgumentSet(baseDN, ldapURLFile);
parser.addRequiredArgumentSet(baseDN, ldapURLFile);
// The scope and ldapURLFile arguments can't be used together.
parser.addExclusiveArgumentSet(scope, ldapURLFile);
// The requestedAttribute and ldapURLFile arguments can't be used together.
parser.addExclusiveArgumentSet(requestedAttribute, ldapURLFile);
// The filter and ldapURLFile arguments can't be used together.
parser.addExclusiveArgumentSet(filter, ldapURLFile);
// The filterFile and ldapURLFile arguments can't be used together.
parser.addExclusiveArgumentSet(filterFile, ldapURLFile);
// The followReferrals and manageDsaIT arguments can't be used together.
parser.addExclusiveArgumentSet(followReferrals, manageDsaIT);
// The persistent search argument can't be used with either the filterFile
// or ldapURLFile arguments.
parser.addExclusiveArgumentSet(persistentSearch, filterFile);
parser.addExclusiveArgumentSet(persistentSearch, ldapURLFile);
// The realAttributesOnly and virtualAttributesOnly arguments can't be used
// together.
parser.addExclusiveArgumentSet(realAttributesOnly, virtualAttributesOnly);
// The simplePageSize and virtualListView arguments can't be used together.
parser.addExclusiveArgumentSet(simplePageSize, virtualListView);
// The terse and verbose arguments can't be used together.
parser.addExclusiveArgumentSet(terse, verbose);
// The getEffectiveRightsAttribute argument requires the
// getEffectiveRightsAuthzID argument.
parser.addDependentArgumentSet(getEffectiveRightsAttribute,
getEffectiveRightsAuthzID);
// The virtualListView argument requires the sortOrder argument.
parser.addDependentArgumentSet(virtualListView, sortOrder);
// The separateOutputFilePerSearch argument requires the outputFile
// argument. It also requires either the filter, filterFile or ldapURLFile
// argument.
parser.addDependentArgumentSet(separateOutputFilePerSearch, outputFile);
parser.addDependentArgumentSet(separateOutputFilePerSearch, filter,
filterFile, ldapURLFile);
// The teeResultsToStandardOut argument requires the outputFile argument.
parser.addDependentArgumentSet(teeResultsToStandardOut, outputFile);
// The wrapColumn and dontWrap arguments must not be used together.
parser.addExclusiveArgumentSet(wrapColumn, dontWrap);
// All arguments that specifically pertain to join processing can only be
// used if the joinRule argument is provided.
parser.addDependentArgumentSet(joinBaseDN, joinRule);
parser.addDependentArgumentSet(joinScope, joinRule);
parser.addDependentArgumentSet(joinSizeLimit, joinRule);
parser.addDependentArgumentSet(joinFilter, joinRule);
parser.addDependentArgumentSet(joinRequestedAttribute, joinRule);
parser.addDependentArgumentSet(joinRequireMatch, joinRule);
// The countEntries argument must not be used in conjunction with the
// filter, filterFile, LDAPURLFile, or persistentSearch arguments.
parser.addExclusiveArgumentSet(countEntries, filter);
parser.addExclusiveArgumentSet(countEntries, filterFile);
parser.addExclusiveArgumentSet(countEntries, ldapURLFile);
parser.addExclusiveArgumentSet(countEntries, persistentSearch);
// The hideRedactedValueCount argument requires the redactAttribute
// argument.
parser.addDependentArgumentSet(hideRedactedValueCount, redactAttribute);
// The scrambleJSONField and scrambleRandomSeed arguments require the
// scrambleAttribute argument.
parser.addDependentArgumentSet(scrambleJSONField, scrambleAttribute);
parser.addDependentArgumentSet(scrambleRandomSeed, scrambleAttribute);
// The renameAttributeFrom and renameAttributeTo arguments must be provided
// together.
parser.addDependentArgumentSet(renameAttributeFrom, renameAttributeTo);
parser.addDependentArgumentSet(renameAttributeTo, renameAttributeFrom);
// The moveSubtreeFrom and moveSubtreeTo arguments must be provided
// together.
parser.addDependentArgumentSet(moveSubtreeFrom, moveSubtreeTo);
parser.addDependentArgumentSet(moveSubtreeTo, moveSubtreeFrom);
}
/**
* {@inheritDoc}
*/
@Override()
protected List getBindControls()
{
final ArrayList bindControls = new ArrayList(10);
if (bindControl.isPresent())
{
bindControls.addAll(bindControl.getValues());
}
if (authorizationIdentity.isPresent())
{
bindControls.add(new AuthorizationIdentityRequestControl(false));
}
if (getAuthorizationEntryAttribute.isPresent())
{
bindControls.add(new GetAuthorizationEntryRequestControl(true, true,
getAuthorizationEntryAttribute.getValues()));
}
if (getUserResourceLimits.isPresent())
{
bindControls.add(new GetUserResourceLimitsRequestControl());
}
if (usePasswordPolicyControl.isPresent())
{
bindControls.add(new PasswordPolicyRequestControl());
}
if (suppressOperationalAttributeUpdates.isPresent())
{
final EnumSet suppressTypes =
EnumSet.noneOf(SuppressType.class);
for (final String s : suppressOperationalAttributeUpdates.getValues())
{
if (s.equalsIgnoreCase("last-access-time"))
{
suppressTypes.add(SuppressType.LAST_ACCESS_TIME);
}
else if (s.equalsIgnoreCase("last-login-time"))
{
suppressTypes.add(SuppressType.LAST_LOGIN_TIME);
}
else if (s.equalsIgnoreCase("last-login-ip"))
{
suppressTypes.add(SuppressType.LAST_LOGIN_IP);
}
}
bindControls.add(new SuppressOperationalAttributeUpdateRequestControl(
suppressTypes));
}
return bindControls;
}
/**
* {@inheritDoc}
*/
@Override()
protected boolean supportsMultipleServers()
{
// We will support providing information about multiple servers. This tool
// will not communicate with multiple servers concurrently, but it can
// accept information about multiple servers in the event that multiple
// searches are to be performed and a server goes down in the middle of
// those searches. In this case, we can resume processing on a
// newly-created connection, possibly to a different server.
return true;
}
/**
* {@inheritDoc}
*/
@Override()
public void doExtendedNonLDAPArgumentValidation()
throws ArgumentException
{
// If wrapColumn was provided, then use its value. Otherwise, if dontWrap
// was provided, then use that.
if (wrapColumn.isPresent())
{
final int wc = wrapColumn.getValue();
if (wc <= 0)
{
WRAP_COLUMN = Integer.MAX_VALUE;
}
else
{
WRAP_COLUMN = wc;
}
}
else if (dontWrap.isPresent())
{
WRAP_COLUMN = Integer.MAX_VALUE;
}
// If the ldapURLFile argument was provided, then there must not be any
// trailing arguments.
final List trailingArgs = parser.getTrailingArguments();
if (ldapURLFile.isPresent())
{
if (! trailingArgs.isEmpty())
{
throw new ArgumentException(
ERR_LDAPSEARCH_TRAILING_ARGS_WITH_URL_FILE.get(
ldapURLFile.getIdentifierString()));
}
}
// If the filter or filterFile argument was provided, then there may
// optionally be trailing arguments, but the first trailing argument must
// not be a filter.
if (filter.isPresent() || filterFile.isPresent())
{
if (! trailingArgs.isEmpty())
{
try
{
Filter.create(trailingArgs.get(0));
throw new ArgumentException(
ERR_LDAPSEARCH_TRAILING_FILTER_WITH_FILTER_FILE.get(
filterFile.getIdentifierString()));
}
catch (final LDAPException le)
{
// This is the normal condition. Not even worth debugging the
// exception.
}
}
}
// If none of the ldapURLFile, filter, or filterFile arguments was provided,
// then there must be at least one trailing argument, and the first trailing
// argument must be a valid search filter.
if (! (ldapURLFile.isPresent() || filter.isPresent() ||
filterFile.isPresent()))
{
if (trailingArgs.isEmpty())
{
throw new ArgumentException(ERR_LDAPSEARCH_NO_TRAILING_ARGS.get(
filterFile.getIdentifierString(),
ldapURLFile.getIdentifierString()));
}
try
{
Filter.create(trailingArgs.get(0));
}
catch (final Exception e)
{
Debug.debugException(e);
throw new ArgumentException(
ERR_LDAPSEARCH_FIRST_TRAILING_ARG_NOT_FILTER.get(
trailingArgs.get(0)),
e);
}
}
// There should never be a case in which a trailing argument starts with a
// dash, and it's probably an attempt to use a named argument but that was
// inadvertently put after the filter. Warn about the problem, but don't
// fail.
for (final String s : trailingArgs)
{
if (s.startsWith("-"))
{
commentToErr(WARN_LDAPSEARCH_TRAILING_ARG_STARTS_WITH_DASH.get(s));
break;
}
}
// If any matched values filters are specified, then validate them and
// pre-create the matched values request control.
if (matchedValuesFilter.isPresent())
{
final List filterList = matchedValuesFilter.getValues();
final MatchedValuesFilter[] matchedValuesFilters =
new MatchedValuesFilter[filterList.size()];
for (int i=0; i < matchedValuesFilters.length; i++)
{
try
{
matchedValuesFilters[i] =
MatchedValuesFilter.create(filterList.get(i));
}
catch (final Exception e)
{
Debug.debugException(e);
throw new ArgumentException(
ERR_LDAPSEARCH_INVALID_MATCHED_VALUES_FILTER.get(
filterList.get(i).toString()),
e);
}
}
matchedValuesRequestControl =
new MatchedValuesRequestControl(true, matchedValuesFilters);
}
// If we should use the matching entry count request control, then validate
// the argument value and pre-create the control.
if (matchingEntryCountControl.isPresent())
{
boolean allowUnindexed = false;
boolean alwaysExamine = false;
boolean debug = false;
Integer examineCount = null;
try
{
for (final String element :
matchingEntryCountControl.getValue().toLowerCase().split(":"))
{
if (element.startsWith("examinecount="))
{
examineCount = Integer.parseInt(element.substring(13));
}
else if (element.equals("allowunindexed"))
{
allowUnindexed = true;
}
else if (element.equals("alwaysexamine"))
{
alwaysExamine = true;
}
else if (element.equals("debug"))
{
debug = true;
}
else
{
throw new ArgumentException(
ERR_LDAPSEARCH_MATCHING_ENTRY_COUNT_INVALID_VALUE.get(
matchingEntryCountControl.getIdentifierString()));
}
}
}
catch (final ArgumentException ae)
{
Debug.debugException(ae);
throw ae;
}
catch (final Exception e)
{
Debug.debugException(e);
throw new ArgumentException(
ERR_LDAPSEARCH_MATCHING_ENTRY_COUNT_INVALID_VALUE.get(
matchingEntryCountControl.getIdentifierString()),
e);
}
if (examineCount == null)
{
throw new ArgumentException(
ERR_LDAPSEARCH_MATCHING_ENTRY_COUNT_INVALID_VALUE.get(
matchingEntryCountControl.getIdentifierString()));
}
matchingEntryCountRequestControl = new MatchingEntryCountRequestControl(
true, examineCount, alwaysExamine, allowUnindexed, debug);
}
// If we should use the persistent search request control, then validate
// the argument value and pre-create the control.
if (persistentSearch.isPresent())
{
boolean changesOnly = true;
boolean returnECs = true;
EnumSet changeTypes =
EnumSet.allOf(PersistentSearchChangeType.class);
try
{
final String[] elements =
persistentSearch.getValue().toLowerCase().split(":");
if (elements.length == 0)
{
throw new ArgumentException(
ERR_LDAPSEARCH_PERSISTENT_SEARCH_INVALID_VALUE.get(
persistentSearch.getIdentifierString()));
}
final String header = StaticUtils.toLowerCase(elements[0]);
if (! (header.equals("ps") || header.equals("persist") ||
header.equals("persistent") || header.equals("psearch") ||
header.equals("persistentsearch")))
{
throw new ArgumentException(
ERR_LDAPSEARCH_PERSISTENT_SEARCH_INVALID_VALUE.get(
persistentSearch.getIdentifierString()));
}
if (elements.length > 1)
{
final String ctString = StaticUtils.toLowerCase(elements[1]);
if (ctString.equals("any"))
{
changeTypes = EnumSet.allOf(PersistentSearchChangeType.class);
}
else
{
changeTypes.clear();
for (final String t : ctString.split(","))
{
if (t.equals("add"))
{
changeTypes.add(PersistentSearchChangeType.ADD);
}
else if (t.equals("del") || t.equals("delete"))
{
changeTypes.add(PersistentSearchChangeType.DELETE);
}
else if (t.equals("mod") || t.equals("modify"))
{
changeTypes.add(PersistentSearchChangeType.MODIFY);
}
else if (t.equals("moddn") || t.equals("modrdn") ||
t.equals("modifydn") || t.equals("modifyrdn"))
{
changeTypes.add(PersistentSearchChangeType.MODIFY_DN);
}
else
{
throw new ArgumentException(
ERR_LDAPSEARCH_PERSISTENT_SEARCH_INVALID_VALUE.get(
persistentSearch.getIdentifierString()));
}
}
}
}
if (elements.length > 2)
{
if (elements[2].equalsIgnoreCase("true") || elements[2].equals("1"))
{
changesOnly = true;
}
else if (elements[2].equalsIgnoreCase("false") ||
elements[2].equals("0"))
{
changesOnly = false;
}
else
{
throw new ArgumentException(
ERR_LDAPSEARCH_PERSISTENT_SEARCH_INVALID_VALUE.get(
persistentSearch.getIdentifierString()));
}
}
if (elements.length > 3)
{
if (elements[3].equalsIgnoreCase("true") || elements[3].equals("1"))
{
returnECs = true;
}
else if (elements[3].equalsIgnoreCase("false") ||
elements[3].equals("0"))
{
returnECs = false;
}
else
{
throw new ArgumentException(
ERR_LDAPSEARCH_PERSISTENT_SEARCH_INVALID_VALUE.get(
persistentSearch.getIdentifierString()));
}
}
}
catch (final ArgumentException ae)
{
Debug.debugException(ae);
throw ae;
}
catch (final Exception e)
{
Debug.debugException(e);
throw new ArgumentException(
ERR_LDAPSEARCH_PERSISTENT_SEARCH_INVALID_VALUE.get(
persistentSearch.getIdentifierString()),
e);
}
persistentSearchRequestControl = new PersistentSearchRequestControl(
changeTypes, changesOnly, returnECs, true);
}
// If we should use the server-side sort request control, then validate the
// sort order and pre-create the control.
if (sortOrder.isPresent())
{
final ArrayList sortKeyList = new ArrayList(5);
final StringTokenizer tokenizer =
new StringTokenizer(sortOrder.getValue(), ", ");
while (tokenizer.hasMoreTokens())
{
final String token = tokenizer.nextToken();
final boolean ascending;
String attributeName;
if (token.startsWith("-"))
{
ascending = false;
attributeName = token.substring(1);
}
else if (token.startsWith("+"))
{
ascending = true;
attributeName = token.substring(1);
}
else
{
ascending = true;
attributeName = token;
}
final String matchingRuleID;
final int colonPos = attributeName.indexOf(':');
if (colonPos >= 0)
{
matchingRuleID = attributeName.substring(colonPos+1);
attributeName = attributeName.substring(0, colonPos);
}
else
{
matchingRuleID = null;
}
final StringBuilder invalidReason = new StringBuilder();
if (! PersistUtils.isValidLDAPName(attributeName, false, invalidReason))
{
throw new ArgumentException(
ERR_LDAPSEARCH_SORT_ORDER_INVALID_VALUE.get(
sortOrder.getIdentifierString()));
}
sortKeyList.add(
new SortKey(attributeName, matchingRuleID, (! ascending)));
}
if (sortKeyList.isEmpty())
{
throw new ArgumentException(
ERR_LDAPSEARCH_SORT_ORDER_INVALID_VALUE.get(
sortOrder.getIdentifierString()));
}
final SortKey[] sortKeyArray = new SortKey[sortKeyList.size()];
sortKeyList.toArray(sortKeyArray);
sortRequestControl = new ServerSideSortRequestControl(sortKeyArray);
}
// If we should use the virtual list view request control, then validate the
// argument value and pre-create the control.
if (virtualListView.isPresent())
{
try
{
final String[] elements = virtualListView.getValue().split(":");
if (elements.length == 4)
{
vlvRequestControl = new VirtualListViewRequestControl(
Integer.parseInt(elements[2]), Integer.parseInt(elements[0]),
Integer.parseInt(elements[1]), Integer.parseInt(elements[3]),
null);
}
else if (elements.length == 3)
{
vlvRequestControl = new VirtualListViewRequestControl(elements[2],
Integer.parseInt(elements[0]), Integer.parseInt(elements[1]),
null);
}
else
{
throw new ArgumentException(
ERR_LDAPSEARCH_VLV_INVALID_VALUE.get(
virtualListView.getIdentifierString()));
}
}
catch (final ArgumentException ae)
{
Debug.debugException(ae);
throw ae;
}
catch (final Exception e)
{
Debug.debugException(e);
throw new ArgumentException(
ERR_LDAPSEARCH_VLV_INVALID_VALUE.get(
virtualListView.getIdentifierString()),
e);
}
}
if (joinRule.isPresent())
{
final JoinRule rule;
try
{
final String[] elements = joinRule.getValue().toLowerCase().split(":");
final String ruleName = StaticUtils.toLowerCase(elements[0]);
if (ruleName.equals("dn"))
{
rule = JoinRule.createDNJoin(elements[1]);
}
else if (ruleName.equals("reverse-dn") || ruleName.equals("reversedn"))
{
rule = JoinRule.createReverseDNJoin(elements[1]);
}
else if (ruleName.equals("equals") || ruleName.equals("equality"))
{
rule = JoinRule.createEqualityJoin(elements[1], elements[2], false);
}
else if (ruleName.equals("contains") || ruleName.equals("substring"))
{
rule = JoinRule.createContainsJoin(elements[1], elements[2], false);
}
else
{
throw new ArgumentException(
ERR_LDAPSEARCH_JOIN_RULE_INVALID_VALUE.get(
joinRule.getIdentifierString()));
}
}
catch (final ArgumentException ae)
{
Debug.debugException(ae);
throw ae;
}
catch (final Exception e)
{
Debug.debugException(e);
throw new ArgumentException(
ERR_LDAPSEARCH_JOIN_RULE_INVALID_VALUE.get(
joinRule.getIdentifierString()),
e);
}
final JoinBaseDN joinBase;
if (joinBaseDN.isPresent())
{
final String s = StaticUtils.toLowerCase(joinBaseDN.getValue());
if (s.equals("search-base") || s.equals("search-base-dn"))
{
joinBase = JoinBaseDN.createUseSearchBaseDN();
}
else if (s.equals("source-entry-dn") || s.equals("source-dn"))
{
joinBase = JoinBaseDN.createUseSourceEntryDN();
}
else
{
try
{
final DN dn = new DN(joinBaseDN.getValue());
joinBase = JoinBaseDN.createUseCustomBaseDN(joinBaseDN.getValue());
}
catch (final Exception e)
{
Debug.debugException(e);
throw new ArgumentException(
ERR_LDAPSEARCH_JOIN_BASE_DN_INVALID_VALUE.get(
joinBaseDN.getIdentifierString()),
e);
}
}
}
else
{
joinBase = JoinBaseDN.createUseSearchBaseDN();
}
final String[] joinAttrs;
if (joinRequestedAttribute.isPresent())
{
final List valueList = joinRequestedAttribute.getValues();
joinAttrs = new String[valueList.size()];
valueList.toArray(joinAttrs);
}
else
{
joinAttrs = null;
}
joinRequestControl = new JoinRequestControl(new JoinRequestValue(rule,
joinBase, joinScope.getValue(), DereferencePolicy.NEVER,
joinSizeLimit.getValue(), joinFilter.getValue(), joinAttrs,
joinRequireMatch.isPresent(), null));
}
// Parse the dereference policy.
final String derefStr =
StaticUtils.toLowerCase(dereferencePolicy.getValue());
if (derefStr.equals("always"))
{
derefPolicy = DereferencePolicy.ALWAYS;
}
else if (derefStr.equals("search"))
{
derefPolicy = DereferencePolicy.SEARCHING;
}
else if (derefStr.equals("find"))
{
derefPolicy = DereferencePolicy.FINDING;
}
else
{
derefPolicy = DereferencePolicy.NEVER;
}
// See if any entry transformations need to be applied.
final ArrayList transformations =
new ArrayList(5);
if (excludeAttribute.isPresent())
{
transformations.add(new ExcludeAttributeTransformation(null,
excludeAttribute.getValues()));
}
if (redactAttribute.isPresent())
{
transformations.add(new RedactAttributeTransformation(null, true,
(! hideRedactedValueCount.isPresent()),
redactAttribute.getValues()));
}
if (scrambleAttribute.isPresent())
{
final Long randomSeed;
if (scrambleRandomSeed.isPresent())
{
randomSeed = scrambleRandomSeed.getValue().longValue();
}
else
{
randomSeed = null;
}
transformations.add(new ScrambleAttributeTransformation(null, randomSeed,
true, scrambleAttribute.getValues(), scrambleJSONField.getValues()));
}
if (renameAttributeFrom.isPresent())
{
if (renameAttributeFrom.getNumOccurrences() !=
renameAttributeTo.getNumOccurrences())
{
throw new ArgumentException(
ERR_LDAPSEARCH_RENAME_ATTRIBUTE_MISMATCH.get());
}
final Iterator sourceIterator =
renameAttributeFrom.getValues().iterator();
final Iterator targetIterator =
renameAttributeTo.getValues().iterator();
while (sourceIterator.hasNext())
{
transformations.add(new RenameAttributeTransformation(null,
sourceIterator.next(), targetIterator.next(), true));
}
}
if (moveSubtreeFrom.isPresent())
{
if (moveSubtreeFrom.getNumOccurrences() !=
moveSubtreeTo.getNumOccurrences())
{
throw new ArgumentException(ERR_LDAPSEARCH_MOVE_SUBTREE_MISMATCH.get());
}
final Iterator sourceIterator =
moveSubtreeFrom.getValues().iterator();
final Iterator targetIterator = moveSubtreeTo.getValues().iterator();
while (sourceIterator.hasNext())
{
transformations.add(new MoveSubtreeTransformation(sourceIterator.next(),
targetIterator.next()));
}
}
if (! transformations.isEmpty())
{
entryTransformations = transformations;
}
// Create the output handler.
final String outputFormatStr =
StaticUtils.toLowerCase(outputFormat.getValue());
if (outputFormatStr.equals("json"))
{
outputHandler = new JSONLDAPSearchOutputHandler(this);
}
else if (outputFormatStr.equals("csv") ||
outputFormatStr.equals("tab-delimited"))
{
// These output formats cannot be used with the --ldapURLFile argument.
if (ldapURLFile.isPresent())
{
throw new ArgumentException(
ERR_LDAPSEARCH_OUTPUT_FORMAT_NOT_SUPPORTED_WITH_URLS.get(
outputFormat.getValue(), ldapURLFile.getIdentifierString()));
}
// These output formats require the requested attributes to be specified
// via the --requestedAttribute argument rather than as unnamed trailing
// arguments.
final List requestedAttributes = requestedAttribute.getValues();
if ((requestedAttributes == null) || requestedAttributes.isEmpty())
{
throw new ArgumentException(
ERR_LDAPSEARCH_OUTPUT_FORMAT_REQUIRES_REQUESTED_ATTR_ARG.get(
outputFormat.getValue(),
requestedAttribute.getIdentifierString()));
}
switch (trailingArgs.size())
{
case 0:
// This is fine.
break;
case 1:
// Make sure that the trailing argument is a filter rather than a
// requested attribute. It's sufficient to ensure that neither the
// filter nor filterFile argument was provided.
if (filter.isPresent() || filterFile.isPresent())
{
throw new ArgumentException(
ERR_LDAPSEARCH_OUTPUT_FORMAT_REQUIRES_REQUESTED_ATTR_ARG.get(
outputFormat.getValue(),
requestedAttribute.getIdentifierString()));
}
break;
default:
throw new ArgumentException(
ERR_LDAPSEARCH_OUTPUT_FORMAT_REQUIRES_REQUESTED_ATTR_ARG.get(
outputFormat.getValue(),
requestedAttribute.getIdentifierString()));
}
outputHandler = new ColumnFormatterLDAPSearchOutputHandler(this,
(outputFormatStr.equals("csv")
? OutputFormat.CSV
: OutputFormat.TAB_DELIMITED_TEXT),
requestedAttributes, WRAP_COLUMN);
}
else
{
outputHandler = new LDIFLDAPSearchOutputHandler(this, WRAP_COLUMN);
}
}
/**
* {@inheritDoc}
*/
@Override()
public LDAPConnectionOptions getConnectionOptions()
{
final LDAPConnectionOptions options = new LDAPConnectionOptions();
options.setUseSynchronousMode(true);
options.setFollowReferrals(followReferrals.isPresent());
options.setUnsolicitedNotificationHandler(this);
return options;
}
/**
* {@inheritDoc}
*/
@Override()
public ResultCode doToolProcessing()
{
// If we should use an output file, then set that up now. Otherwise, write
// the header to standard output.
if (outputFile.isPresent())
{
if (! separateOutputFilePerSearch.isPresent())
{
try
{
final FileOutputStream fos =
new FileOutputStream(outputFile.getValue());
if (teeResultsToStandardOut.isPresent())
{
outStream = new PrintStream(new TeeOutputStream(fos, getOut()));
}
else
{
outStream = new PrintStream(fos);
}
errStream = outStream;
}
catch (final Exception e)
{
Debug.debugException(e);
wrapErr(0, WRAP_COLUMN, ERR_LDAPSEARCH_CANNOT_OPEN_OUTPUT_FILE.get(
outputFile.getValue().getAbsolutePath(),
StaticUtils.getExceptionMessage(e)));
return ResultCode.LOCAL_ERROR;
}
outputHandler.formatHeader();
}
}
else
{
outputHandler.formatHeader();
}
// Examine the arguments to determine the sets of controls to use for each
// type of request.
final List searchControls = getSearchControls();
// If appropriate, ensure that any search result entries that include
// base64-encoded attribute values will also include comments that attempt
// to provide a human-readable representation of that value.
final boolean originalCommentAboutBase64EncodedValues =
LDIFWriter.commentAboutBase64EncodedValues();
LDIFWriter.setCommentAboutBase64EncodedValues(
! suppressBase64EncodedValueComments.isPresent());
LDAPConnectionPool pool = null;
try
{
// Create a connection pool that will be used to communicate with the
// directory server.
if (! dryRun.isPresent())
{
try
{
final StartAdministrativeSessionPostConnectProcessor p;
if (useAdministrativeSession.isPresent())
{
p = new StartAdministrativeSessionPostConnectProcessor(
new StartAdministrativeSessionExtendedRequest(getToolName(),
true));
}
else
{
p = null;
}
pool = getConnectionPool(1, 1, 0, p, null, true,
new ReportBindResultLDAPConnectionPoolHealthCheck(this, true,
false));
}
catch (final LDAPException le)
{
// This shouldn't happen since the pool won't throw an exception if an
// attempt to create an initial connection fails.
Debug.debugException(le);
commentToErr(ERR_LDAPSEARCH_CANNOT_CREATE_CONNECTION_POOL.get(
StaticUtils.getExceptionMessage(le)));
return le.getResultCode();
}
if (retryFailedOperations.isPresent())
{
pool.setRetryFailedOperationsDueToInvalidConnections(true);
}
}
// If appropriate, create a rate limiter.
final FixedRateBarrier rateLimiter;
if (ratePerSecond.isPresent())
{
rateLimiter = new FixedRateBarrier(1000L, ratePerSecond.getValue());
}
else
{
rateLimiter = null;
}
// If one or more LDAP URL files are provided, then construct search
// requests from those URLs.
if (ldapURLFile.isPresent())
{
return searchWithLDAPURLs(pool, rateLimiter, searchControls);
}
// Get the set of requested attributes, as a combination of the
// requestedAttribute argument values and any trailing arguments.
final ArrayList attrList = new ArrayList(10);
if (requestedAttribute.isPresent())
{
attrList.addAll(requestedAttribute.getValues());
}
final List trailingArgs = parser.getTrailingArguments();
if (! trailingArgs.isEmpty())
{
final Iterator trailingArgIterator = trailingArgs.iterator();
if (! (filter.isPresent() || filterFile.isPresent()))
{
trailingArgIterator.next();
}
while (trailingArgIterator.hasNext())
{
attrList.add(trailingArgIterator.next());
}
}
final String[] attributes = new String[attrList.size()];
attrList.toArray(attributes);
// If either or both the filter or filterFile arguments are provided, then
// use them to get the filters to process. Otherwise, the first trailing
// argument should be a filter.
ResultCode resultCode = ResultCode.SUCCESS;
if (filter.isPresent() || filterFile.isPresent())
{
if (filter.isPresent())
{
for (final Filter f : filter.getValues())
{
final ResultCode rc = searchWithFilter(pool, f, attributes,
rateLimiter, searchControls);
if (rc != ResultCode.SUCCESS)
{
if (resultCode == ResultCode.SUCCESS)
{
resultCode = rc;
}
if (! continueOnError.isPresent())
{
return resultCode;
}
}
}
}
if (filterFile.isPresent())
{
final ResultCode rc = searchWithFilterFile(pool, attributes,
rateLimiter, searchControls);
if (rc != ResultCode.SUCCESS)
{
if (resultCode == ResultCode.SUCCESS)
{
resultCode = rc;
}
if (! continueOnError.isPresent())
{
return resultCode;
}
}
}
}
else
{
final Filter f;
try
{
final String filterStr =
parser.getTrailingArguments().iterator().next();
f = Filter.create(filterStr);
}
catch (final LDAPException le)
{
// This should never happen.
Debug.debugException(le);
displayResult(le.toLDAPResult());
return le.getResultCode();
}
resultCode =
searchWithFilter(pool, f, attributes, rateLimiter, searchControls);
}
return resultCode;
}
finally
{
if (pool != null)
{
try
{
pool.close();
}
catch (final Exception e)
{
Debug.debugException(e);
}
}
if (outStream != null)
{
try
{
outStream.close();
outStream = null;
}
catch (final Exception e)
{
Debug.debugException(e);
}
}
if (errStream != null)
{
try
{
errStream.close();
errStream = null;
}
catch (final Exception e)
{
Debug.debugException(e);
}
}
LDIFWriter.setCommentAboutBase64EncodedValues(
originalCommentAboutBase64EncodedValues);
}
}
/**
* Processes a set of searches using LDAP URLs read from one or more files.
*
* @param pool The connection pool to use to communicate with the
* directory server.
* @param rateLimiter An optional fixed-rate barrier that can be used for
* request rate limiting.
* @param searchControls The set of controls to include in search requests.
*
* @return A result code indicating the result of the processing.
*/
private ResultCode searchWithLDAPURLs(final LDAPConnectionPool pool,
final FixedRateBarrier rateLimiter,
final List searchControls)
{
ResultCode resultCode = ResultCode.SUCCESS;
for (final File f : ldapURLFile.getValues())
{
BufferedReader reader = null;
try
{
reader = new BufferedReader(new FileReader(f));
while (true)
{
final String line = reader.readLine();
if (line == null)
{
break;
}
if ((line.length() == 0) || line.startsWith("#"))
{
continue;
}
final LDAPURL url;
try
{
url = new LDAPURL(line);
}
catch (final LDAPException le)
{
Debug.debugException(le);
commentToErr(ERR_LDAPSEARCH_MALFORMED_LDAP_URL.get(
f.getAbsolutePath(), line));
if (resultCode == ResultCode.SUCCESS)
{
resultCode = le.getResultCode();
}
if (continueOnError.isPresent())
{
continue;
}
else
{
return resultCode;
}
}
final SearchRequest searchRequest = new SearchRequest(
new LDAPSearchListener(outputHandler, entryTransformations),
url.getBaseDN().toString(), scope.getValue(), derefPolicy,
sizeLimit.getValue(), timeLimitSeconds.getValue(),
typesOnly.isPresent(), url.getFilter(), url.getAttributes());
final ResultCode rc =
doSearch(pool, searchRequest, rateLimiter, searchControls);
if (rc != ResultCode.SUCCESS)
{
if (resultCode == ResultCode.SUCCESS)
{
resultCode = rc;
}
if (! continueOnError.isPresent())
{
return resultCode;
}
}
}
}
catch (final IOException ioe)
{
commentToErr(ERR_LDAPSEARCH_CANNOT_READ_LDAP_URL_FILE.get(
f.getAbsolutePath(), StaticUtils.getExceptionMessage(ioe)));
return ResultCode.LOCAL_ERROR;
}
finally
{
if (reader != null)
{
try
{
reader.close();
}
catch (final Exception e)
{
Debug.debugException(e);
}
}
}
}
return resultCode;
}
/**
* Processes a set of searches using filters read from one or more files.
*
* @param pool The connection pool to use to communicate with the
* directory server.
* @param attributes The set of attributes to request that the server
* include in matching entries.
* @param rateLimiter An optional fixed-rate barrier that can be used for
* request rate limiting.
* @param searchControls The set of controls to include in search requests.
*
* @return A result code indicating the result of the processing.
*/
private ResultCode searchWithFilterFile(final LDAPConnectionPool pool,
final String[] attributes,
final FixedRateBarrier rateLimiter,
final List searchControls)
{
ResultCode resultCode = ResultCode.SUCCESS;
for (final File f : filterFile.getValues())
{
FilterFileReader reader = null;
try
{
reader = new FilterFileReader(f);
while (true)
{
final Filter searchFilter;
try
{
searchFilter = reader.readFilter();
}
catch (final LDAPException le)
{
Debug.debugException(le);
commentToErr(ERR_LDAPSEARCH_MALFORMED_FILTER.get(
f.getAbsolutePath(), le.getMessage()));
if (resultCode == ResultCode.SUCCESS)
{
resultCode = le.getResultCode();
}
if (continueOnError.isPresent())
{
continue;
}
else
{
return resultCode;
}
}
if (searchFilter == null)
{
break;
}
final ResultCode rc = searchWithFilter(pool, searchFilter, attributes,
rateLimiter, searchControls);
if (rc != ResultCode.SUCCESS)
{
if (resultCode == ResultCode.SUCCESS)
{
resultCode = rc;
}
if (! continueOnError.isPresent())
{
return resultCode;
}
}
}
}
catch (final IOException ioe)
{
Debug.debugException(ioe);
commentToErr(ERR_LDAPSEARCH_CANNOT_READ_FILTER_FILE.get(
f.getAbsolutePath(), StaticUtils.getExceptionMessage(ioe)));
return ResultCode.LOCAL_ERROR;
}
finally
{
if (reader != null)
{
try
{
reader.close();
}
catch (final Exception e)
{
Debug.debugException(e);
}
}
}
}
return resultCode;
}
/**
* Processes a search using the provided filter.
*
* @param pool The connection pool to use to communicate with the
* directory server.
* @param filter The filter to use for the search.
* @param attributes The set of attributes to request that the server
* include in matching entries.
* @param rateLimiter An optional fixed-rate barrier that can be used for
* request rate limiting.
* @param searchControls The set of controls to include in search requests.
*
* @return A result code indicating the result of the processing.
*/
private ResultCode searchWithFilter(final LDAPConnectionPool pool,
final Filter filter,
final String[] attributes,
final FixedRateBarrier rateLimiter,
final List searchControls)
{
final SearchRequest searchRequest = new SearchRequest(
new LDAPSearchListener(outputHandler, entryTransformations),
baseDN.getStringValue(), scope.getValue(), derefPolicy,
sizeLimit.getValue(), timeLimitSeconds.getValue(),
typesOnly.isPresent(), filter, attributes);
return doSearch(pool, searchRequest, rateLimiter, searchControls);
}
/**
* Processes a search with the provided information.
*
* @param pool The connection pool to use to communicate with the
* directory server.
* @param searchRequest The search request to process.
* @param rateLimiter An optional fixed-rate barrier that can be used for
* request rate limiting.
* @param searchControls The set of controls to include in search requests.
*
* @return A result code indicating the result of the processing.
*/
private ResultCode doSearch(final LDAPConnectionPool pool,
final SearchRequest searchRequest,
final FixedRateBarrier rateLimiter,
final List searchControls)
{
if (separateOutputFilePerSearch.isPresent())
{
try
{
final String path = outputFile.getValue().getAbsolutePath() + '.' +
outputFileCounter.getAndIncrement();
final FileOutputStream fos = new FileOutputStream(path);
if (teeResultsToStandardOut.isPresent())
{
outStream = new PrintStream(new TeeOutputStream(fos, getOut()));
}
else
{
outStream = new PrintStream(fos);
}
errStream = outStream;
}
catch (final Exception e)
{
Debug.debugException(e);
wrapErr(0, WRAP_COLUMN, ERR_LDAPSEARCH_CANNOT_OPEN_OUTPUT_FILE.get(
outputFile.getValue().getAbsolutePath(),
StaticUtils.getExceptionMessage(e)));
return ResultCode.LOCAL_ERROR;
}
outputHandler.formatHeader();
}
try
{
if (rateLimiter != null)
{
rateLimiter.await();
}
ASN1OctetString pagedResultsCookie = null;
boolean multiplePages = false;
long totalEntries = 0;
long totalReferences = 0;
SearchResult searchResult;
try
{
while (true)
{
searchRequest.setControls(searchControls);
if (simplePageSize.isPresent())
{
searchRequest.addControl(new SimplePagedResultsControl(
simplePageSize.getValue(), pagedResultsCookie));
}
if (dryRun.isPresent())
{
searchResult = new SearchResult(-1, ResultCode.SUCCESS,
INFO_LDAPSEARCH_DRY_RUN_REQUEST_NOT_SENT.get(
dryRun.getIdentifierString(),
String.valueOf(searchRequest)),
null, null, 0, 0, null);
break;
}
else
{
if (! terse.isPresent())
{
if (verbose.isPresent() || persistentSearch.isPresent() ||
filterFile.isPresent() || ldapURLFile.isPresent() ||
(filter.isPresent() && (filter.getNumOccurrences() > 1)))
{
commentToOut(INFO_LDAPSEARCH_SENDING_SEARCH_REQUEST.get(
String.valueOf(searchRequest)));
}
}
searchResult = pool.search(searchRequest);
}
if (searchResult.getEntryCount() > 0)
{
totalEntries += searchResult.getEntryCount();
}
if (searchResult.getReferenceCount() > 0)
{
totalReferences += searchResult.getReferenceCount();
}
if (simplePageSize.isPresent())
{
final SimplePagedResultsControl pagedResultsControl;
try
{
pagedResultsControl = SimplePagedResultsControl.get(searchResult);
if (pagedResultsControl == null)
{
throw new LDAPSearchException(new SearchResult(
searchResult.getMessageID(), ResultCode.CONTROL_NOT_FOUND,
ERR_LDAPSEARCH_MISSING_PAGED_RESULTS_RESPONSE_CONTROL.
get(),
searchResult.getMatchedDN(),
searchResult.getReferralURLs(),
searchResult.getSearchEntries(),
searchResult.getSearchReferences(),
searchResult.getEntryCount(),
searchResult.getReferenceCount(),
searchResult.getResponseControls()));
}
if (pagedResultsControl.moreResultsToReturn())
{
if (verbose.isPresent())
{
commentToOut(
INFO_LDAPSEARCH_INTERMEDIATE_PAGED_SEARCH_RESULT.get());
displayResult(searchResult);
}
multiplePages = true;
pagedResultsCookie = pagedResultsControl.getCookie();
}
else
{
break;
}
}
catch (final LDAPException le)
{
Debug.debugException(le);
throw new LDAPSearchException(new SearchResult(
searchResult.getMessageID(), ResultCode.CONTROL_NOT_FOUND,
ERR_LDAPSEARCH_CANNOT_DECODE_PAGED_RESULTS_RESPONSE_CONTROL.
get(StaticUtils.getExceptionMessage(le)),
searchResult.getMatchedDN(), searchResult.getReferralURLs(),
searchResult.getSearchEntries(),
searchResult.getSearchReferences(),
searchResult.getEntryCount(),
searchResult.getReferenceCount(),
searchResult.getResponseControls()));
}
}
else
{
break;
}
}
}
catch (final LDAPSearchException lse)
{
Debug.debugException(lse);
searchResult = lse.toLDAPResult();
if (searchResult.getEntryCount() > 0)
{
totalEntries += searchResult.getEntryCount();
}
if (searchResult.getReferenceCount() > 0)
{
totalReferences += searchResult.getReferenceCount();
}
}
displayResult(searchResult);
if (multiplePages && (! terse.isPresent()))
{
commentToOut(INFO_LDAPSEARCH_TOTAL_SEARCH_ENTRIES.get(totalEntries));
if (totalReferences > 0)
{
commentToOut(INFO_LDAPSEARCH_TOTAL_SEARCH_REFERENCES.get(
totalReferences));
}
}
if (countEntries.isPresent())
{
return ResultCode.valueOf((int) Math.min(totalEntries, 255));
}
else
{
return searchResult.getResultCode();
}
}
finally
{
if (separateOutputFilePerSearch.isPresent())
{
try
{
outStream.close();
}
catch (final Exception e)
{
Debug.debugException(e);
}
outStream = null;
errStream = null;
}
}
}
/**
* Retrieves a list of the controls that should be used when processing search
* operations.
*
* @return A list of the controls that should be used when processing search
* operations.
*/
private List getSearchControls()
{
final ArrayList controls = new ArrayList(10);
if (searchControl.isPresent())
{
controls.addAll(searchControl.getValues());
}
if (joinRequestControl != null)
{
controls.add(joinRequestControl);
}
if (matchedValuesRequestControl != null)
{
controls.add(matchedValuesRequestControl);
}
if (matchingEntryCountRequestControl != null)
{
controls.add(matchingEntryCountRequestControl);
}
if (persistentSearchRequestControl != null)
{
controls.add(persistentSearchRequestControl);
}
if (sortRequestControl != null)
{
controls.add(sortRequestControl);
}
if (vlvRequestControl != null)
{
controls.add(vlvRequestControl);
}
if (accountUsable.isPresent())
{
controls.add(new AccountUsableRequestControl(true));
}
if (includeReplicationConflictEntries.isPresent())
{
controls.add(new ReturnConflictEntriesRequestControl(true));
}
if (includeSoftDeletedEntries.isPresent())
{
final String valueStr =
StaticUtils.toLowerCase(includeSoftDeletedEntries.getValue());
if (valueStr.equals("with-non-deleted-entries"))
{
controls.add(new SoftDeletedEntryAccessRequestControl(true, true,
false));
}
else if (valueStr.equals("without-non-deleted-entries"))
{
controls.add(new SoftDeletedEntryAccessRequestControl(true, false,
false));
}
else
{
controls.add(new SoftDeletedEntryAccessRequestControl(true, false,
true));
}
}
if (includeSubentries.isPresent())
{
controls.add(new SubentriesRequestControl(true));
}
if (manageDsaIT.isPresent())
{
controls.add(new ManageDsaITRequestControl(true));
}
if (realAttributesOnly.isPresent())
{
controls.add(new RealAttributesOnlyRequestControl(true));
}
if (virtualAttributesOnly.isPresent())
{
controls.add(new VirtualAttributesOnlyRequestControl(true));
}
if (excludeBranch.isPresent())
{
final ArrayList dns =
new ArrayList(excludeBranch.getValues().size());
for (final DN dn : excludeBranch.getValues())
{
dns.add(dn.toString());
}
controls.add(new ExcludeBranchRequestControl(true, dns));
}
if (assertionFilter.isPresent())
{
controls.add(new AssertionRequestControl(
assertionFilter.getValue(), true));
}
if (getEffectiveRightsAuthzID.isPresent())
{
final String[] attributes;
if (getEffectiveRightsAttribute.isPresent())
{
attributes = new String[getEffectiveRightsAttribute.getValues().size()];
for (int i=0; i < attributes.length; i++)
{
attributes[i] = getEffectiveRightsAttribute.getValues().get(i);
}
}
else
{
attributes = StaticUtils.NO_STRINGS;
}
controls.add(new GetEffectiveRightsRequestControl(true,
getEffectiveRightsAuthzID.getValue(), attributes));
}
if (operationPurpose.isPresent())
{
controls.add(new OperationPurposeRequestControl(true, "ldapsearch",
Version.NUMERIC_VERSION_STRING, "LDAPSearch.getSearchControls",
operationPurpose.getValue()));
}
if (proxyAs.isPresent())
{
controls.add(new ProxiedAuthorizationV2RequestControl(
proxyAs.getValue()));
}
if (proxyV1As.isPresent())
{
controls.add(new ProxiedAuthorizationV1RequestControl(
proxyV1As.getValue()));
}
if (suppressOperationalAttributeUpdates.isPresent())
{
final EnumSet suppressTypes =
EnumSet.noneOf(SuppressType.class);
for (final String s : suppressOperationalAttributeUpdates.getValues())
{
if (s.equalsIgnoreCase("last-access-time"))
{
suppressTypes.add(SuppressType.LAST_ACCESS_TIME);
}
else if (s.equalsIgnoreCase("last-login-time"))
{
suppressTypes.add(SuppressType.LAST_LOGIN_TIME);
}
else if (s.equalsIgnoreCase("last-login-ip"))
{
suppressTypes.add(SuppressType.LAST_LOGIN_IP);
}
}
controls.add(new SuppressOperationalAttributeUpdateRequestControl(
suppressTypes));
}
return controls;
}
/**
* Displays information about the provided result, including special
* processing for a number of supported response controls.
*
* @param result The result to examine.
*/
void displayResult(final LDAPResult result)
{
outputHandler.formatResult(result);
}
/**
* Writes the provided message to the output stream.
*
* @param message The message to be written.
*/
void writeOut(final String message)
{
if (outStream == null)
{
out(message);
}
else
{
outStream.println(message);
}
}
/**
* Writes the provided message to the error stream.
*
* @param message The message to be written.
*/
void writeErr(final String message)
{
if (errStream == null)
{
err(message);
}
else
{
errStream.println(message);
}
}
/**
* Writes a line-wrapped, commented version of the provided message to
* standard output.
*
* @param message The message to be written.
*/
private void commentToOut(final String message)
{
if (terse.isPresent())
{
return;
}
for (final String line : StaticUtils.wrapLine(message, (WRAP_COLUMN - 2)))
{
writeOut("# " + line);
}
}
/**
* Writes a line-wrapped, commented version of the provided message to
* standard error.
*
* @param message The message to be written.
*/
private void commentToErr(final String message)
{
for (final String line : StaticUtils.wrapLine(message, (WRAP_COLUMN - 2)))
{
writeErr("# " + line);
}
}
/**
* Sets the output handler that should be used by this tool This is primarily
* intended for testing purposes.
*
* @param outputHandler The output handler that should be used by this tool.
*/
void setOutputHandler(final LDAPSearchOutputHandler outputHandler)
{
this.outputHandler = outputHandler;
}
/**
* {@inheritDoc}
*/
public void handleUnsolicitedNotification(final LDAPConnection connection,
final ExtendedResult notification)
{
outputHandler.formatUnsolicitedNotification(connection, notification);
}
/**
* {@inheritDoc}
*/
@Override()
public LinkedHashMap getExampleUsages()
{
final LinkedHashMap examples =
new LinkedHashMap(5);
String[] args =
{
"--hostname", "directory.example.com",
"--port", "389",
"--bindDN", "uid=jdoe,ou=People,dc=example,dc=com",
"--bindPassword", "password",
"--baseDN", "ou=People,dc=example,dc=com",
"--searchScope", "sub",
"(uid=jqpublic)",
"givenName",
"sn",
"mail"
};
examples.put(args, INFO_LDAPSEARCH_EXAMPLE_1.get());
args = new String[]
{
"--hostname", "directory.example.com",
"--port", "636",
"--useSSL",
"--saslOption", "mech=PLAIN",
"--saslOption", "authID=u:jdoe",
"--bindPasswordFile", "/path/to/password/file",
"--baseDN", "ou=People,dc=example,dc=com",
"--searchScope", "sub",
"--filterFile", "/path/to/filter/file",
"--outputFile", "/path/to/base/output/file",
"--separateOutputFilePerSearch",
"--requestedAttribute", "*",
"--requestedAttribute", "+"
};
examples.put(args, INFO_LDAPSEARCH_EXAMPLE_2.get());
args = new String[]
{
"--hostname", "directory.example.com",
"--port", "389",
"--useStartTLS",
"--trustStorePath", "/path/to/truststore/file",
"--baseDN", "",
"--searchScope", "base",
"--outputFile", "/path/to/output/file",
"--teeResultsToStandardOut",
"(objectClass=*)",
"*",
"+"
};
examples.put(args, INFO_LDAPSEARCH_EXAMPLE_3.get());
args = new String[]
{
"--hostname", "directory.example.com",
"--port", "389",
"--bindDN", "uid=admin,dc=example,dc=com",
"--baseDN", "dc=example,dc=com",
"--searchScope", "sub",
"--outputFile", "/path/to/output/file",
"--simplePageSize", "100",
"(objectClass=*)",
"*",
"+"
};
examples.put(args, INFO_LDAPSEARCH_EXAMPLE_4.get());
args = new String[]
{
"--hostname", "directory.example.com",
"--port", "389",
"--bindDN", "uid=admin,dc=example,dc=com",
"--baseDN", "dc=example,dc=com",
"--searchScope", "sub",
"(&(givenName=John)(sn=Doe))",
"debugsearchindex"
};
examples.put(args, INFO_LDAPSEARCH_EXAMPLE_5.get());
return examples;
}
}