001/*
002 * Copyright 2011-2022 Ping Identity Corporation
003 * All Rights Reserved.
004 */
005/*
006 * Copyright 2011-2022 Ping Identity Corporation
007 *
008 * Licensed under the Apache License, Version 2.0 (the "License");
009 * you may not use this file except in compliance with the License.
010 * You may obtain a copy of the License at
011 *
012 *    http://www.apache.org/licenses/LICENSE-2.0
013 *
014 * Unless required by applicable law or agreed to in writing, software
015 * distributed under the License is distributed on an "AS IS" BASIS,
016 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
017 * See the License for the specific language governing permissions and
018 * limitations under the License.
019 */
020/*
021 * Copyright (C) 2011-2022 Ping Identity Corporation
022 *
023 * This program is free software; you can redistribute it and/or modify
024 * it under the terms of the GNU General Public License (GPLv2 only)
025 * or the terms of the GNU Lesser General Public License (LGPLv2.1 only)
026 * as published by the Free Software Foundation.
027 *
028 * This program is distributed in the hope that it will be useful,
029 * but WITHOUT ANY WARRANTY; without even the implied warranty of
030 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
031 * GNU General Public License for more details.
032 *
033 * You should have received a copy of the GNU General Public License
034 * along with this program; if not, see <http://www.gnu.org/licenses>.
035 */
036package com.unboundid.ldap.listener;
037
038
039
040import java.io.File;
041import java.io.OutputStream;
042import java.io.Serializable;
043import java.net.Socket;
044import java.util.ArrayList;
045import java.util.EnumSet;
046import java.util.Iterator;
047import java.util.LinkedHashMap;
048import java.util.List;
049import java.util.Map;
050import java.util.Set;
051import java.util.TreeMap;
052import java.util.logging.FileHandler;
053import java.util.logging.Level;
054import java.util.logging.StreamHandler;
055import javax.net.ssl.KeyManager;
056import javax.net.ssl.TrustManager;
057
058import com.unboundid.ldap.sdk.DN;
059import com.unboundid.ldap.sdk.LDAPException;
060import com.unboundid.ldap.sdk.OperationType;
061import com.unboundid.ldap.sdk.ResultCode;
062import com.unboundid.ldap.sdk.Version;
063import com.unboundid.ldap.sdk.schema.Schema;
064import com.unboundid.ldap.sdk.schema.SchemaValidator;
065import com.unboundid.util.CommandLineTool;
066import com.unboundid.util.CryptoHelper;
067import com.unboundid.util.Debug;
068import com.unboundid.util.MinimalLogFormatter;
069import com.unboundid.util.NotMutable;
070import com.unboundid.util.NotNull;
071import com.unboundid.util.Nullable;
072import com.unboundid.util.ObjectPair;
073import com.unboundid.util.StaticUtils;
074import com.unboundid.util.ThreadSafety;
075import com.unboundid.util.ThreadSafetyLevel;
076import com.unboundid.util.args.ArgumentException;
077import com.unboundid.util.args.ArgumentParser;
078import com.unboundid.util.args.BooleanArgument;
079import com.unboundid.util.args.DNArgument;
080import com.unboundid.util.args.IntegerArgument;
081import com.unboundid.util.args.FileArgument;
082import com.unboundid.util.args.StringArgument;
083import com.unboundid.util.ssl.KeyStoreKeyManager;
084import com.unboundid.util.ssl.SSLUtil;
085import com.unboundid.util.ssl.TrustAllTrustManager;
086import com.unboundid.util.ssl.TrustStoreTrustManager;
087import com.unboundid.util.ssl.cert.CertException;
088
089import static com.unboundid.ldap.listener.ListenerMessages.*;
090
091
092
093/**
094 * This class provides a command-line tool that can be used to run an instance
095 * of the in-memory directory server.  Instances of the server may also be
096 * created and controlled programmatically using the
097 * {@link InMemoryDirectoryServer} class.
098 * <BR><BR>
099 * The following command-line arguments may be used with this class:
100 * <UL>
101 *   <LI>"-b {baseDN}" or "--baseDN {baseDN}" -- specifies a base DN to use for
102 *       the server.  At least one base DN must be specified, and multiple
103 *       base DNs may be provided as separate arguments.</LI>
104 *   <LI>"-p {port}" or "--port {port}" -- specifies the port on which the
105 *       server should listen for client connections.  If this is not provided,
106 *       then a free port will be automatically chosen for use by the
107 *       server.</LI>
108 *   <LI>"-l {path}" or "--ldifFile {path}" -- specifies the path to an LDIF
109 *       file to use to initially populate the server.  If this is not provided,
110 *       then the server will initially be empty.  The LDIF file will not be
111 *       updated as operations are processed in the server.</LI>
112 *   <LI>"-D {bindDN}" or "--additionalBindDN {bindDN}" -- specifies an
113 *       additional DN that can be used to authenticate to the server, even if
114 *       there is no account for that user.  If this is provided, then the
115 *       --additionalBindPassword argument must also be given.</LI>
116 *   <LI>"-w {password}" or "--additionalBindPassword {password}" -- specifies
117 *       the password that should be used when attempting to bind as the user
118 *       specified with the "-additionalBindDN" argument.  If this is provided,
119 *       then the --additionalBindDN argument must also be given.</LI>
120 *   <LI>"-c {count}" or "--maxChangeLogEntries {count}" -- Indicates whether an
121 *       LDAP changelog should be enabled, and if so how many changelog records
122 *       should be maintained.  If this argument is not provided, or if it is
123 *       provided with a value of zero, then no changelog will be
124 *       maintained.</LI>
125 *   <LI>"-A" or "--accessLogToStandardOut" -- indicates that access log
126 *       information should be written to standard output.  This cannot be
127 *       provided in conjunction with the "--accessLogFile" argument.  If
128 *       neither argument is provided, then no access logging will be
129 *       performed</LI>
130 *   <LI>"-a {path}" or "--accessLogFile {path}" -- specifies the path to a file
131 *       that should be used as a server access log.  This cannot be provided in
132 *       conjunction with the "--accessLogToStandardOut" argument.  If neither
133 *       argument is provided, then no access logging will be performed</LI>
134 *   <LI>"---jsonAccessLogToStandardOut" -- indicates that JSON-formatted access
135 *       log information should be written to standard output.  This cannot be
136 *       provided in conjunction with the "--jsonAccessLogFile" argument.  If
137 *       neither argument is provided, then no JSON-formatted access logging
138 *       will be performed</LI>
139 *   <LI>"--jsonAccessLogFile {path}" -- specifies the path to a file that
140 *       should be used as a server access log with JSON-formatted messages.
141 *       This cannot be provided in conjunction with the
142 *       "--jsonAccessLogToStandardOut" argument.  If neither argument is
143 *       provided, then no JSON-formatted access logging will be performed</LI>
144 *   <LI>"--ldapDebugLogToStandardOut" -- Indicates that LDAP debug log
145 *       information should be written to standard output.  This cannot be
146 *       provided in conjunction with the "--ldapDebugLogFile" argument.  If
147 *       neither argument is provided, then no debug logging will be
148 *       performed.</LI>
149 *   <LI>"-d {path}" or "--ldapDebugLogFile {path}" -- specifies the path to a
150 *       file that should be used as a server LDAP debug log.  This cannot be
151 *       provided in conjunction with the "--ldapDebugLogToStandardOut"
152 *       argument.  If neither argument is provided, then no debug logging will
153 *       be performed.</LI>
154 *   <LI>"-s" or "--useDefaultSchema" -- Indicates that the server should use
155 *       the default standard schema provided as part of the LDAP SDK.  If
156 *       neither this argument nor the "--useSchemaFile" argument is provided,
157 *       then the server will not enforce schema compliance.</LI>
158 *   <LI>"-S {path}" or "--useSchemaFile {path}" -- specifies the path to a file
159 *       or directory containing schema definitions to use for the server.  If
160 *       neither this argument nor the "--useDefaultSchema" argument is
161 *       provided, then the server will not enforce schema compliance.  If
162 *       the specified path represents a file, then it must be an LDIF file
163 *       containing a valid LDAP subschema subentry.  If the path is a
164 *       directory, then its files will be processed in lexicographic order by
165 *       name.</LI>
166 *   <LI>"--doNotValidateSchemaDefinitions" -- indicates that the server should
167 *       not perform any validation for the custom schema provided using the
168 *       --useSchemaFile argument.  If this argument is not used and a custom
169 *       schema is configured, then the server will validate that schema and
170 *       report errors or warnings for any issues that it identifies with that
171 *       schema.</LI>
172 *   <LI>"--doNotGenerateOperationalAttributes" -- indicates that the server
173 *       should not maintain any operational attributes (including entryDN,
174 *       entryUUID, subschemaSubentry, creatorsName, createTimestamp,
175 *       modifiersName, and modifyTimestamp) in entries.</LI>
176 *   <LI>"-I {attr}" or "--equalityIndex {attr}" -- specifies that an equality
177 *       index should be maintained for the specified attribute.  The equality
178 *       index may be used to speed up certain kinds of searches, although it
179 *       will cause the server to consume more memory.</LI>
180 *   <LI>"-Z" or "--useSSL" -- indicates that the server should encrypt all
181 *       communication using SSL.  If this is provided, then the
182 *       "--keyStorePath" and "--keyStorePassword" arguments must also be
183 *       provided, and the "--useStartTLS" argument must not be provided.</LI>
184 *   <LI>"-q" or "--useStartTLS" -- indicates that the server should support the
185 *       use of the StartTLS extended request.  If this is provided, then the
186 *       "--keyStorePath" and "--keyStorePassword" arguments must also be
187 *       provided, and the "--useSSL" argument must not be provided.</LI>
188 *   <LI>"-K {path}" or "--keyStorePath {path}" -- specifies the path to the JKS
189 *       key store file that should be used to obtain the server certificate to
190 *       use for SSL communication.  If this argument is provided, then the
191 *       "--keyStorePassword" argument must also be provided, along with exactly
192 *       one of the "--useSSL" or "--useStartTLS" arguments.</LI>
193 *   <LI>"-W {password}" or "--keyStorePassword {password}" -- specifies the
194 *       password that should be used to access the contents of the SSL key
195 *       store.  If this argument is provided, then the "--keyStorePath"
196 *       argument must also be provided, along with exactly one of the
197 *       "--useSSL" or "--useStartTLS" arguments.</LI>
198 *   <LI>"--keyStoreType {type}" -- specifies the type of keystore represented
199 *       by the file specified by the keystore path.  If this argument is
200 *       provided, then the "--keyStorePath" argument must also be provided,
201 *       along with exactly one of the "--useSSL" or "--useStartTLS" arguments.
202 *       If this argument is not provided, then a default key store type of
203 *       "JKS" will be assumed.</LI>
204 *   <LI>"--generateSelfSignedCertificate" -- indicates that the server should
205 *       generate a self-signed certificate to use for SSL or StartTLS
206 *       communication.  If this argument is provided, then exactly one of the
207 *       "--useSSL" or "--useStartTLS" arguments must also be specified.</LI>
208 *   <LI>"-P {path}" or "--trustStorePath {path}" -- specifies the path to the
209 *       JKS trust store file that should be used to determine whether to trust
210 *       any SSL certificates that may be presented by the client.  If this
211 *       argument is provided, then exactly one of the "--useSSL" or
212 *       "--useStartTLS" arguments must also be provided.  If this argument is
213 *       not provided but SSL or StartTLS is to be used, then all client
214 *       certificates will be automatically trusted.</LI>
215 *   <LI>"-T {password}" or "--trustStorePassword {password}" -- specifies the
216 *       password that should be used to access the contents of the SSL trust
217 *       store.  If this argument is provided, then the "--trustStorePath"
218 *       argument must also be provided, along with exactly one of the
219 *       "--useSSL" or "--useStartTLS" arguments.  If an SSL trust store path
220 *       was provided without a trust store password, then the server will
221 *       attempt to use the trust store without a password.</LI>
222 *   <LI>"--trustStoreType {type}" -- specifies the type of trust store
223 *       represented by the file specified by the trust store path.  If this
224 *       argument is provided, then the "--trustStorePath" argument must also
225 *       be provided, along with exactly one of the "--useSSL" or
226 *       "--useStartTLS" arguments.  If this argument is not provided, then a
227 *       default trust store type of "JKS" will be assumed.</LI>
228 *   <LI>"--maxConcurrentConnections {num}" -- specifies the maximum number of
229 *       concurrent connections that the server will allow.</LI>
230 *   <LI>"--sizeLimit {num}" -- specifies the maximum number of entries that
231 *       the server will return for a single search operation.</LI>
232 *   <LI>"--passwordAttribute {attr}" -- specifies an attribute that will hold
233 *       user passwords.</LI>
234 *   <LI>"--defaultPasswordEncoding {scheme}" -- specifies the name of the
235 *       default scheme that the server will use to encode clear-text
236 *       passwords.  Allowed values include MD5, SMD5, SHA, SSHA, SHA256,
237 *       SSHA256, SHA384, SSHA384, SHA512, SSHA512, CLEAR, BASE64, and HEX.</LI>
238 *   <LI>"--allowedOperationType {type}" -- specifies a type of operation that
239 *       the server will allow.  Allowed values include add, bind, compare,
240 *       delete, extended, modify, modify-dn, and search.</LI>
241 *   <LI>"--authenticationRequiredOperationType {type}" -- specifies a type of
242 *       operation that the server will only allow for authenticated clients.
243 *       Allowed values include add, compare, delete, extended, modify,
244 *       modify-dn, and search.</LI>
245 *   <LI>"--vendorName {name}" -- specifies the vendor name value to appear in
246 *       the server root DSE.</LI>
247 *   <LI>"--vendorVersion {version}" -- specifies the vendor version value to
248 *       appear in the server root DSE.</LI>
249 * </UL>
250 */
251@NotMutable()
252@ThreadSafety(level=ThreadSafetyLevel.NOT_THREADSAFE)
253public final class InMemoryDirectoryServerTool
254       extends CommandLineTool
255       implements Serializable, LDAPListenerExceptionHandler
256{
257  /**
258   * The column at which long lines should be wrapped.
259   */
260  private static final int WRAP_COLUMN = StaticUtils.TERMINAL_WIDTH_COLUMNS - 1;
261
262
263
264  /**
265   * The SSL client authentication policy value that indicates that the server
266   * should not ask the client to present a certificate chain.
267   */
268  @NotNull private static final String SSL_CLIENT_AUTH_POLICY_PROHIBITED =
269       "prohibited";
270
271
272
273  /**
274   * The SSL client authentication policy value that indicates that the server
275   * should ask the client to present a certificate chain but will not require
276   * one.
277   */
278  @NotNull private static final String SSL_CLIENT_AUTH_POLICY_OPTIONAL =
279       "optional";
280
281
282
283  /**
284   * The SSL client authentication policy value that indicates that the server
285   * should require the client to present a certificate chain.
286   */
287  @NotNull private static final String SSL_CLIENT_AUTH_POLICY_REQUIRED =
288       "required";
289
290
291
292  /**
293   * The serial version UID for this serializable class.
294   */
295  private static final long serialVersionUID = 6484637038039050412L;
296
297
298
299  // The argument used to indicate that access log information should be written
300  // to standard output.
301  @Nullable private BooleanArgument accessLogToStandardOutArgument;
302
303  // Indicates that the should not maintain operational attributes in entries.
304  @Nullable private BooleanArgument doNotGenerateOperationalAttributesArgument;
305
306  // Indicates that the should not attempt to validate custom schema definitions
307  // provided by the useSchemaFile argument.
308  @Nullable private BooleanArgument doNotValidateSchemaDefinitionsArgument;
309
310  // The argument used to prevent the in-memory server from starting.  This is
311  // only intended to be used for internal testing purposes.
312  @Nullable private BooleanArgument dontStartArgument;
313
314  // The argument used to indicate that the server should generate a self-signed
315  // certificate for use in SSL or StartTLS negotiation.
316  @Nullable private BooleanArgument generateSelfSignedCertificateArgument;
317
318  // The argument used to indicate that JSON-formatted access log information
319  // should be written to standard output.
320  @Nullable private BooleanArgument jsonAccessLogToStandardOutArgument;
321
322  // The argument used to indicate that LDAP debug log information should be
323  // written to standard output.
324  @Nullable private BooleanArgument ldapDebugLogToStandardOutArgument;
325
326  // The argument used to indicate that the default standard schema should be
327  // used.
328  @Nullable private BooleanArgument useDefaultSchemaArgument;
329
330  // The argument used to indicate that the server should use SSL
331  @Nullable private BooleanArgument useSSLArgument;
332
333  // The argument used to indicate that the server should support the StartTLS
334  // extended operation
335  @Nullable private BooleanArgument useStartTLSArgument;
336
337  // The argument used to specify an additional bind DN to use for the server.
338  @Nullable private DNArgument additionalBindDNArgument;
339
340  // The argument used to specify the base DNs to use for the server.
341  @Nullable private DNArgument baseDNArgument;
342
343  // The argument used to specify the path to an access log file to which
344  // information should be written about operations processed by the server.
345  @Nullable private FileArgument accessLogFileArgument;
346
347  // The argument used to specify the code log file to use, if any.
348  @Nullable private FileArgument codeLogFile;
349
350  // The argument used to specify the path to an access log file to which
351  // JSON-formatted operation should be written about operations processed by
352  // the server.
353  @Nullable private FileArgument jsonAccessLogFileArgument;
354
355  // The argument used to specify the path to the SSL key store file.
356  @Nullable private FileArgument keyStorePathArgument;
357
358  // The argument used to specify the path to an LDAP debug log file to which
359  // information should be written about detailed LDAP communication performed
360  // by the server.
361  @Nullable private FileArgument ldapDebugLogFileArgument;
362
363  // The argument used to specify the path to an LDIF file with data to use to
364  // initially populate the server.
365  @Nullable private FileArgument ldifFileArgument;
366
367  // The argument used to specify the path to the SSL trust store file.
368  @Nullable private FileArgument trustStorePathArgument;
369
370  // The argument used to specify the path to a directory containing schema
371  // definitions.
372  @Nullable private FileArgument useSchemaFileArgument;
373
374  // The in-memory directory server instance that has been created by this tool.
375  @Nullable private InMemoryDirectoryServer directoryServer;
376
377  // The argument used to specify the maximum number of changelog entries that
378  // the server should maintain.
379  @Nullable private IntegerArgument maxChangeLogEntriesArgument;
380
381  // The argument used to specify the maximum number of concurrent connections.
382  @Nullable private IntegerArgument maxConcurrentConnectionsArgument;
383
384  // The argument used to specify the port on which the server should listen.
385  @Nullable private IntegerArgument portArgument;
386
387  // The argument used to specify the maximum search size limit.
388  @Nullable private IntegerArgument sizeLimitArgument;
389
390  // The argument used to specify the password for the additional bind DN.
391  @Nullable private StringArgument additionalBindPasswordArgument;
392
393  // The argument used to specify the types of allowed operations.
394  @Nullable private StringArgument allowedOperationTypeArgument;
395
396  // The argument used to specify the types of operations for which
397  // authentication is required.
398  @Nullable private StringArgument authenticationRequiredOperationTypeArgument;
399
400  // The argument used to specify the name of the default encoding scheme to use
401  // use for clear-text passwords.
402  @Nullable private StringArgument defaultPasswordEncodingArgument;
403
404  // The argument used to specify the attributes for which to maintain equality
405  // indexes.
406  @Nullable private StringArgument equalityIndexArgument;
407
408  // The argument used to specify the password to use to access the contents of
409  // the SSL key store
410  @Nullable private StringArgument keyStorePasswordArgument;
411
412  // The argument used to specify the key store type.
413  @Nullable private StringArgument keyStoreTypeArgument;
414
415  // The argument used to specify the password attribute types.
416  @Nullable private StringArgument passwordAttributeArgument;
417
418  // The argument used to specify the policy the server should use for TLS
419  // client authentication.
420  @Nullable private StringArgument sslClientAuthPolicy;
421
422  // The argument used to specify the password to use to access the contents of
423  // the SSL trust store
424  @Nullable private StringArgument trustStorePasswordArgument;
425
426  // The argument used to specify the trust store type.
427  @Nullable private StringArgument trustStoreTypeArgument;
428
429  // The argument used to specify the server vendor name.
430  @Nullable private StringArgument vendorNameArgument;
431
432  // The argument used to specify the server vendor version.
433  @Nullable private StringArgument vendorVersionArgument;
434
435
436
437  /**
438   * Parse the provided command line arguments and uses them to start the
439   * directory server.
440   *
441   * @param  args  The command line arguments provided to this program.
442   */
443  public static void main(@NotNull final String... args)
444  {
445    final ResultCode resultCode = main(args, System.out, System.err);
446    if (resultCode != ResultCode.SUCCESS)
447    {
448      System.exit(resultCode.intValue());
449    }
450  }
451
452
453
454  /**
455   * Parse the provided command line arguments and uses them to start the
456   * directory server.
457   *
458   * @param  outStream  The output stream to which standard out should be
459   *                    written.  It may be {@code null} if output should be
460   *                    suppressed.
461   * @param  errStream  The output stream to which standard error should be
462   *                    written.  It may be {@code null} if error messages
463   *                    should be suppressed.
464   * @param  args       The command line arguments provided to this program.
465   *
466   * @return  A result code indicating whether the processing was successful.
467   */
468  @NotNull()
469  public static ResultCode main(@NotNull final String[] args,
470                                @Nullable final OutputStream outStream,
471                                @Nullable final OutputStream errStream)
472  {
473    final InMemoryDirectoryServerTool tool =
474         new InMemoryDirectoryServerTool(outStream, errStream);
475    return tool.runTool(args);
476  }
477
478
479
480  /**
481   * Creates a new instance of this tool that use the provided output streams
482   * for standard output and standard error.
483   *
484   * @param  outStream  The output stream to use for standard output.  It may be
485   *                    {@code System.out} for the JVM's default standard output
486   *                    stream, {@code null} if no output should be generated,
487   *                    or a custom output stream if the output should be sent
488   *                    to an alternate location.
489   * @param  errStream  The output stream to use for standard error.  It may be
490   *                    {@code System.err} for the JVM's default standard error
491   *                    stream, {@code null} if no output should be generated,
492   *                    or a custom output stream if the output should be sent
493   *                    to an alternate location.
494   */
495  public InMemoryDirectoryServerTool(@Nullable final OutputStream outStream,
496                                     @Nullable final OutputStream errStream)
497  {
498    super(outStream, errStream);
499
500    directoryServer = null;
501    doNotGenerateOperationalAttributesArgument = null;
502    doNotValidateSchemaDefinitionsArgument = null;
503    dontStartArgument = null;
504    generateSelfSignedCertificateArgument = null;
505    useDefaultSchemaArgument = null;
506    useSSLArgument = null;
507    useStartTLSArgument = null;
508    additionalBindDNArgument = null;
509    baseDNArgument = null;
510    accessLogToStandardOutArgument = null;
511    accessLogFileArgument = null;
512    jsonAccessLogToStandardOutArgument = null;
513    jsonAccessLogFileArgument = null;
514    keyStorePathArgument = null;
515    ldapDebugLogToStandardOutArgument = null;
516    ldapDebugLogFileArgument = null;
517    ldifFileArgument = null;
518    trustStorePathArgument = null;
519    useSchemaFileArgument = null;
520    maxChangeLogEntriesArgument = null;
521    maxConcurrentConnectionsArgument = null;
522    portArgument = null;
523    sizeLimitArgument = null;
524    additionalBindPasswordArgument = null;
525    allowedOperationTypeArgument = null;
526    authenticationRequiredOperationTypeArgument = null;
527    defaultPasswordEncodingArgument = null;
528    equalityIndexArgument = null;
529    keyStorePasswordArgument = null;
530    keyStoreTypeArgument = null;
531    passwordAttributeArgument = null;
532    sslClientAuthPolicy = null;
533    trustStorePasswordArgument = null;
534    trustStoreTypeArgument = null;
535    vendorNameArgument = null;
536    vendorVersionArgument = null;
537  }
538
539
540
541  /**
542   * {@inheritDoc}
543   */
544  @Override()
545  @NotNull()
546  public String getToolName()
547  {
548    return "in-memory-directory-server";
549  }
550
551
552
553  /**
554   * {@inheritDoc}
555   */
556  @Override()
557  @NotNull()
558  public String getToolDescription()
559  {
560    return INFO_MEM_DS_TOOL_DESC.get(InMemoryDirectoryServer.class.getName());
561  }
562
563
564
565  /**
566   * Retrieves the version string for this tool.
567   *
568   * @return  The version string for this tool.
569   */
570  @Override()
571  @NotNull()
572  public String getToolVersion()
573  {
574    return Version.NUMERIC_VERSION_STRING;
575  }
576
577
578
579  /**
580   * {@inheritDoc}
581   */
582  @Override()
583  public void addToolArguments(@NotNull final ArgumentParser parser)
584         throws ArgumentException
585  {
586    portArgument = new IntegerArgument('p', "port", false, 1,
587         INFO_MEM_DS_TOOL_ARG_PLACEHOLDER_PORT.get(),
588         INFO_MEM_DS_TOOL_ARG_DESC_PORT.get(), 0, 65_535);
589    portArgument.setArgumentGroupName(
590         INFO_MEM_DS_TOOL_GROUP_CONNECTIVITY.get());
591    parser.addArgument(portArgument);
592
593    useSSLArgument = new BooleanArgument('Z', "useSSL",
594         INFO_MEM_DS_TOOL_ARG_DESC_USE_SSL.get());
595    useSSLArgument.setArgumentGroupName(
596         INFO_MEM_DS_TOOL_GROUP_CONNECTIVITY.get());
597    useSSLArgument.addLongIdentifier("use-ssl", true);
598    parser.addArgument(useSSLArgument);
599
600    useStartTLSArgument = new BooleanArgument('q', "useStartTLS",
601         INFO_MEM_DS_TOOL_ARG_DESC_USE_START_TLS.get());
602    useStartTLSArgument.setArgumentGroupName(
603         INFO_MEM_DS_TOOL_GROUP_CONNECTIVITY.get());
604    useStartTLSArgument.addLongIdentifier("use-starttls", true);
605    useStartTLSArgument.addLongIdentifier("use-start-tls", true);
606    parser.addArgument(useStartTLSArgument);
607
608    keyStorePathArgument = new FileArgument('K', "keyStorePath", false, 1,
609         INFO_MEM_DS_TOOL_ARG_PLACEHOLDER_PATH.get(),
610         INFO_MEM_DS_TOOL_ARG_DESC_KEY_STORE_PATH.get(), true, true, true,
611         false);
612    keyStorePathArgument.setArgumentGroupName(
613         INFO_MEM_DS_TOOL_GROUP_CONNECTIVITY.get());
614    keyStorePathArgument.addLongIdentifier("key-store-path", true);
615    parser.addArgument(keyStorePathArgument);
616
617    keyStorePasswordArgument = new StringArgument('W', "keyStorePassword",
618         false, 1, INFO_MEM_DS_TOOL_ARG_PLACEHOLDER_PASSWORD.get(),
619         INFO_MEM_DS_TOOL_ARG_DESC_KEY_STORE_PW.get());
620    keyStorePasswordArgument.setSensitive(true);
621    keyStorePasswordArgument.setArgumentGroupName(
622         INFO_MEM_DS_TOOL_GROUP_CONNECTIVITY.get());
623    keyStorePasswordArgument.addLongIdentifier("keyStorePIN", true);
624    keyStorePasswordArgument.addLongIdentifier("key-store-password", true);
625    keyStorePasswordArgument.addLongIdentifier("key-store-pin", true);
626    parser.addArgument(keyStorePasswordArgument);
627
628    keyStoreTypeArgument = new StringArgument(null, "keyStoreType",
629         false, 1, "{type}", INFO_MEM_DS_TOOL_ARG_DESC_KEY_STORE_TYPE.get(),
630         CryptoHelper.KEY_STORE_TYPE_JKS);
631    keyStoreTypeArgument.setArgumentGroupName(
632         INFO_MEM_DS_TOOL_GROUP_CONNECTIVITY.get());
633    keyStoreTypeArgument.addLongIdentifier("keyStoreFormat", true);
634    keyStoreTypeArgument.addLongIdentifier("key-store-type", true);
635    keyStoreTypeArgument.addLongIdentifier("key-store-format", true);
636    parser.addArgument(keyStoreTypeArgument);
637
638    generateSelfSignedCertificateArgument = new BooleanArgument(null,
639         "generateSelfSignedCertificate", 1,
640         INFO_MEM_DS_TOOL_ARG_DESC_SELF_SIGNED_CERT.get());
641    generateSelfSignedCertificateArgument.setArgumentGroupName(
642         INFO_MEM_DS_TOOL_GROUP_CONNECTIVITY.get());
643    generateSelfSignedCertificateArgument.addLongIdentifier(
644         "useSelfSignedCertificate", true);
645    generateSelfSignedCertificateArgument.addLongIdentifier(
646         "selfSignedCertificate", true);
647    generateSelfSignedCertificateArgument.addLongIdentifier(
648         "generate-self-signed-certificate", true);
649    generateSelfSignedCertificateArgument.addLongIdentifier(
650         "use-self-signed-certificate", true);
651    generateSelfSignedCertificateArgument.addLongIdentifier(
652         "self-signed-certificate", true);
653    parser.addArgument(generateSelfSignedCertificateArgument);
654
655    trustStorePathArgument = new FileArgument('P', "trustStorePath", false, 1,
656         INFO_MEM_DS_TOOL_ARG_PLACEHOLDER_PATH.get(),
657         INFO_MEM_DS_TOOL_ARG_DESC_TRUST_STORE_PATH.get(), true, true, true,
658         false);
659    trustStorePathArgument.setArgumentGroupName(
660         INFO_MEM_DS_TOOL_GROUP_CONNECTIVITY.get());
661    trustStorePathArgument.addLongIdentifier("trust-store-path", true);
662    parser.addArgument(trustStorePathArgument);
663
664    trustStorePasswordArgument = new StringArgument('T', "trustStorePassword",
665         false, 1, INFO_MEM_DS_TOOL_ARG_PLACEHOLDER_PASSWORD.get(),
666         INFO_MEM_DS_TOOL_ARG_DESC_TRUST_STORE_PW.get());
667    trustStorePasswordArgument.setSensitive(true);
668    trustStorePasswordArgument.setArgumentGroupName(
669         INFO_MEM_DS_TOOL_GROUP_CONNECTIVITY.get());
670    trustStorePasswordArgument.addLongIdentifier("trustStorePIN", true);
671    trustStorePasswordArgument.addLongIdentifier("trust-store-password", true);
672    trustStorePasswordArgument.addLongIdentifier("trust-store-pin", true);
673    parser.addArgument(trustStorePasswordArgument);
674
675    trustStoreTypeArgument = new StringArgument(null, "trustStoreType",
676         false, 1, "{type}", INFO_MEM_DS_TOOL_ARG_DESC_TRUST_STORE_TYPE.get(),
677         CryptoHelper.KEY_STORE_TYPE_JKS);
678    trustStoreTypeArgument.setArgumentGroupName(
679         INFO_MEM_DS_TOOL_GROUP_CONNECTIVITY.get());
680    trustStoreTypeArgument.addLongIdentifier("trustStoreFormat", true);
681    trustStoreTypeArgument.addLongIdentifier("trust-store-type", true);
682    trustStoreTypeArgument.addLongIdentifier("trust-store-format", true);
683    parser.addArgument(trustStoreTypeArgument);
684
685    sslClientAuthPolicy = new StringArgument(null, "sslClientAuthPolicy", false,
686         1, INFO_MEM_DS_TOOL_ARG_PLACEHOLDER_SSL_CLIENT_AUTH_POLICY.get(),
687         INFO_MEM_DS_TOOL_ARG_DESC_SSL_CLIENT_AUTH_POLICY.get(),
688         StaticUtils.setOf(
689              SSL_CLIENT_AUTH_POLICY_PROHIBITED,
690              SSL_CLIENT_AUTH_POLICY_OPTIONAL,
691              SSL_CLIENT_AUTH_POLICY_REQUIRED),
692         SSL_CLIENT_AUTH_POLICY_PROHIBITED);
693    sslClientAuthPolicy.addLongIdentifier("ssl-client-auth-policy", true);
694    sslClientAuthPolicy.addLongIdentifier("sslClientAuthenticationPolicy",
695         true);
696    sslClientAuthPolicy.addLongIdentifier("ssl-client-authentication-policy",
697         true);
698    sslClientAuthPolicy.addLongIdentifier("sslClientCertificatePolicy", true);
699    sslClientAuthPolicy.addLongIdentifier("ssl-client-certificate-policy",
700         true);
701    sslClientAuthPolicy.addLongIdentifier("sslClientCertPolicy", true);
702    sslClientAuthPolicy.addLongIdentifier("ssl-client-cert-policy", true);
703    sslClientAuthPolicy.setArgumentGroupName(
704         INFO_MEM_DS_TOOL_GROUP_CONNECTIVITY.get());
705    parser.addArgument(sslClientAuthPolicy);
706
707    maxConcurrentConnectionsArgument = new IntegerArgument(null,
708         "maxConcurrentConnections", false, 1, null,
709         INFO_MEM_DS_TOOL_ARG_DESC_MAX_CONNECTIONS.get(), 1,
710         Integer.MAX_VALUE, Integer.MAX_VALUE);
711    maxConcurrentConnectionsArgument.setArgumentGroupName(
712         INFO_MEM_DS_TOOL_GROUP_CONNECTIVITY.get());
713    maxConcurrentConnectionsArgument.addLongIdentifier(
714         "maximumConcurrentConnections", true);
715    maxConcurrentConnectionsArgument.addLongIdentifier(
716         "maxConnections", true);
717    maxConcurrentConnectionsArgument.addLongIdentifier(
718         "maximumConnections", true);
719    maxConcurrentConnectionsArgument.addLongIdentifier(
720         "max-concurrent-connections", true);
721    maxConcurrentConnectionsArgument.addLongIdentifier(
722         "maximum-concurrent-connections", true);
723    maxConcurrentConnectionsArgument.addLongIdentifier(
724         "max-connections", true);
725    maxConcurrentConnectionsArgument.addLongIdentifier(
726         "maximum-connections", true);
727    parser.addArgument(maxConcurrentConnectionsArgument);
728
729    dontStartArgument = new BooleanArgument(null, "dontStart",
730         INFO_MEM_DS_TOOL_ARG_DESC_DONT_START.get());
731    dontStartArgument.setArgumentGroupName(
732         INFO_MEM_DS_TOOL_GROUP_CONNECTIVITY.get());
733    dontStartArgument.setHidden(true);
734    dontStartArgument.addLongIdentifier("doNotStart", true);
735    dontStartArgument.addLongIdentifier("dont-start", true);
736    dontStartArgument.addLongIdentifier("do-not-start", true);
737    parser.addArgument(dontStartArgument);
738
739    baseDNArgument = new DNArgument('b', "baseDN", true, 0,
740         INFO_MEM_DS_TOOL_ARG_PLACEHOLDER_BASE_DN.get(),
741         INFO_MEM_DS_TOOL_ARG_DESC_BASE_DN.get());
742    baseDNArgument.setArgumentGroupName(INFO_MEM_DS_TOOL_GROUP_DATA.get());
743    baseDNArgument.addLongIdentifier("base-dn", true);
744    parser.addArgument(baseDNArgument);
745
746    ldifFileArgument = new FileArgument('l', "ldifFile", false, 1,
747         INFO_MEM_DS_TOOL_ARG_PLACEHOLDER_PATH.get(),
748         INFO_MEM_DS_TOOL_ARG_DESC_LDIF_FILE.get(), true, true, true, false);
749    ldifFileArgument.setArgumentGroupName(INFO_MEM_DS_TOOL_GROUP_DATA.get());
750    ldifFileArgument.addLongIdentifier("ldif-file", true);
751    parser.addArgument(ldifFileArgument);
752
753    additionalBindDNArgument = new DNArgument('D', "additionalBindDN", false, 1,
754         INFO_MEM_DS_TOOL_ARG_PLACEHOLDER_BIND_DN.get(),
755         INFO_MEM_DS_TOOL_ARG_DESC_ADDITIONAL_BIND_DN.get());
756    additionalBindDNArgument.setArgumentGroupName(
757         INFO_MEM_DS_TOOL_GROUP_DATA.get());
758    additionalBindDNArgument.addLongIdentifier("additional-bind-dn", true);
759    parser.addArgument(additionalBindDNArgument);
760
761    additionalBindPasswordArgument = new StringArgument('w',
762         "additionalBindPassword", false, 1,
763         INFO_MEM_DS_TOOL_ARG_PLACEHOLDER_PASSWORD.get(),
764         INFO_MEM_DS_TOOL_ARG_DESC_ADDITIONAL_BIND_PW.get());
765    additionalBindPasswordArgument.setSensitive(true);
766    additionalBindPasswordArgument.setArgumentGroupName(
767         INFO_MEM_DS_TOOL_GROUP_DATA.get());
768    additionalBindPasswordArgument.addLongIdentifier(
769         "additional-bind-password", true);
770    parser.addArgument(additionalBindPasswordArgument);
771
772    useDefaultSchemaArgument = new BooleanArgument('s', "useDefaultSchema",
773         INFO_MEM_DS_TOOL_ARG_DESC_USE_DEFAULT_SCHEMA.get());
774    useDefaultSchemaArgument.setArgumentGroupName(
775         INFO_MEM_DS_TOOL_GROUP_DATA.get());
776    useDefaultSchemaArgument.addLongIdentifier("use-default-schema", true);
777    parser.addArgument(useDefaultSchemaArgument);
778
779    useSchemaFileArgument = new FileArgument('S', "useSchemaFile", false, 0,
780         INFO_MEM_DS_TOOL_ARG_PLACEHOLDER_PATH.get(),
781         INFO_MEM_DS_TOOL_ARG_DESC_USE_SCHEMA_FILE.get(), true, true, false,
782         false);
783    useSchemaFileArgument.setArgumentGroupName(
784         INFO_MEM_DS_TOOL_GROUP_DATA.get());
785    useSchemaFileArgument.addLongIdentifier("use-schema-file", true);
786    parser.addArgument(useSchemaFileArgument);
787
788    doNotValidateSchemaDefinitionsArgument = new BooleanArgument(null,
789         "doNotValidateSchemaDefinitions", 1,
790         INFO_MEM_DS_TOOL_ARG_DESC_DO_NOT_VALIDATE_SCHEMA.get(
791              useSchemaFileArgument.getIdentifierString()));
792    doNotValidateSchemaDefinitionsArgument.setArgumentGroupName(
793         INFO_MEM_DS_TOOL_GROUP_DATA.get());
794    doNotValidateSchemaDefinitionsArgument.addLongIdentifier(
795         "do-not-validate-schema-definitions", true);
796    parser.addArgument(doNotValidateSchemaDefinitionsArgument);
797
798    doNotGenerateOperationalAttributesArgument = new BooleanArgument(null,
799         "doNotGenerateOperationalAttributes", 1,
800         INFO_MEM_DS_TOOL_ARG_DESC_DO_NOT_GENERATE_OP_ATTRS.get());
801    doNotGenerateOperationalAttributesArgument.setArgumentGroupName(
802         INFO_MEM_DS_TOOL_GROUP_DATA.get());
803    doNotGenerateOperationalAttributesArgument.addLongIdentifier(
804         "do-not-generate-operational-attributes");
805    parser.addArgument(doNotGenerateOperationalAttributesArgument);
806
807    equalityIndexArgument = new StringArgument('I', "equalityIndex", false, 0,
808         INFO_MEM_DS_TOOL_ARG_PLACEHOLDER_ATTR.get(),
809         INFO_MEM_DS_TOOL_ARG_DESC_EQ_INDEX.get());
810    equalityIndexArgument.setArgumentGroupName(
811         INFO_MEM_DS_TOOL_GROUP_DATA.get());
812    equalityIndexArgument.addLongIdentifier("equality-index", true);
813    parser.addArgument(equalityIndexArgument);
814
815    maxChangeLogEntriesArgument = new IntegerArgument('c',
816         "maxChangeLogEntries", false, 1,
817         INFO_MEM_DS_TOOL_ARG_PLACEHOLDER_COUNT.get(),
818         INFO_MEM_DS_TOOL_ARG_DESC_MAX_CHANGELOG_ENTRIES.get(), 0,
819         Integer.MAX_VALUE, 0);
820    maxChangeLogEntriesArgument.setArgumentGroupName(
821         INFO_MEM_DS_TOOL_GROUP_DATA.get());
822    maxChangeLogEntriesArgument.addLongIdentifier("max-changelog-entries",
823         true);
824    maxChangeLogEntriesArgument.addLongIdentifier("max-change-log-entries",
825         true);
826    parser.addArgument(maxChangeLogEntriesArgument);
827
828    sizeLimitArgument = new IntegerArgument(null, "sizeLimit", false, 1, null,
829         INFO_MEM_DS_TOOL_ARG_DESC_SIZE_LIMIT.get(), 1, Integer.MAX_VALUE,
830         Integer.MAX_VALUE);
831    sizeLimitArgument.setArgumentGroupName(INFO_MEM_DS_TOOL_GROUP_DATA.get());
832    sizeLimitArgument.addLongIdentifier("searchSizeLimit", true);
833    sizeLimitArgument.addLongIdentifier("size-limit", true);
834    sizeLimitArgument.addLongIdentifier("search-size-limit", true);
835    parser.addArgument(sizeLimitArgument);
836
837    passwordAttributeArgument = new StringArgument(null, "passwordAttribute",
838         false, 1, INFO_MEM_DS_TOOL_ARG_PLACEHOLDER_ATTR.get(),
839         INFO_MEM_DS_TOOL_ARG_DESC_PASSWORD_ATTRIBUTE.get(), "userPassword");
840    passwordAttributeArgument.setArgumentGroupName(
841         INFO_MEM_DS_TOOL_GROUP_DATA.get());
842    passwordAttributeArgument.addLongIdentifier("passwordAttributeType", true);
843    passwordAttributeArgument.addLongIdentifier("password-attribute", true);
844    passwordAttributeArgument.addLongIdentifier("password-attribute-type",
845         true);
846    parser.addArgument(passwordAttributeArgument);
847
848    final Set<String> allowedSchemes = StaticUtils.setOf("md5", "smd5", "sha",
849         "ssha", "sha256", "ssha256", "sha384", "ssha384", "sha512", "ssha512",
850         "clear", "base64", "hex");
851    defaultPasswordEncodingArgument = new StringArgument(null,
852         "defaultPasswordEncoding", false, 1,
853         INFO_MEM_DS_TOOL_ARG_PLACEHOLDER_SCHEME.get(),
854         INFO_MEM_DS_TOOL_ARG_DESC_DEFAULT_PASSWORD_ENCODING.get(),
855         allowedSchemes);
856    defaultPasswordEncodingArgument.setArgumentGroupName(
857         INFO_MEM_DS_TOOL_GROUP_DATA.get());
858    defaultPasswordEncodingArgument.addLongIdentifier(
859         "defaultPasswordEncodingScheme", true);
860    defaultPasswordEncodingArgument.addLongIdentifier(
861         "defaultPasswordStorageScheme", true);
862    defaultPasswordEncodingArgument.addLongIdentifier(
863         "defaultPasswordScheme", true);
864    defaultPasswordEncodingArgument.addLongIdentifier(
865         "default-password-encoding", true);
866    defaultPasswordEncodingArgument.addLongIdentifier(
867         "default-password-encoding-scheme", true);
868    defaultPasswordEncodingArgument.addLongIdentifier(
869         "default-password-storage-scheme", true);
870    defaultPasswordEncodingArgument.addLongIdentifier(
871         "default-password-scheme", true);
872    parser.addArgument(defaultPasswordEncodingArgument);
873
874    final Set<String> allowedOperationTypeAllowedValues = StaticUtils.setOf(
875         "add", "bind", "compare", "delete", "extended", "modify", "modify-dn",
876         "search");
877    allowedOperationTypeArgument = new StringArgument(null,
878         "allowedOperationType", false, 0,
879         INFO_MEM_DS_TOOL_ARG_PLACEHOLDER_TYPE.get(),
880         INFO_MEM_DS_TOOL_ARG_DESC_ALLOWED_OP_TYPE.get(),
881         allowedOperationTypeAllowedValues);
882    allowedOperationTypeArgument.setArgumentGroupName(
883         INFO_MEM_DS_TOOL_GROUP_DATA.get());
884    allowedOperationTypeArgument.addLongIdentifier("allowed-operation-type",
885         true);
886    parser.addArgument(allowedOperationTypeArgument);
887
888    final Set<String> authRequiredTypeAllowedValues = StaticUtils.setOf("add",
889         "compare", "delete", "extended", "modify", "modify-dn", "search");
890    authenticationRequiredOperationTypeArgument = new StringArgument(null,
891         "authenticationRequiredOperationType", false, 0,
892         INFO_MEM_DS_TOOL_ARG_PLACEHOLDER_TYPE.get(),
893         INFO_MEM_DS_TOOL_ARG_DESC_AUTH_REQUIRED_OP_TYPE.get(),
894         authRequiredTypeAllowedValues);
895    authenticationRequiredOperationTypeArgument.setArgumentGroupName(
896         INFO_MEM_DS_TOOL_GROUP_DATA.get());
897    authenticationRequiredOperationTypeArgument.addLongIdentifier(
898         "requiredAuthenticationOperationType", true);
899    authenticationRequiredOperationTypeArgument.addLongIdentifier(
900         "requireAuthenticationOperationType", true);
901    authenticationRequiredOperationTypeArgument.addLongIdentifier(
902         "authentication-required-operation-type", true);
903    authenticationRequiredOperationTypeArgument.addLongIdentifier(
904         "required-authentication-operation-type", true);
905    authenticationRequiredOperationTypeArgument.addLongIdentifier(
906         "require-authentication-operation-type", true);
907    parser.addArgument(authenticationRequiredOperationTypeArgument);
908
909    vendorNameArgument = new StringArgument(null, "vendorName", false, 1,
910         INFO_MEM_DS_TOOL_ARG_PLACEHOLDER_VALUE.get(),
911         INFO_MEM_DS_TOOL_ARG_DESC_VENDOR_NAME.get());
912    vendorNameArgument.setArgumentGroupName(INFO_MEM_DS_TOOL_GROUP_DATA.get());
913    vendorNameArgument.addLongIdentifier("vendor-name", true);
914    parser.addArgument(vendorNameArgument);
915
916    vendorVersionArgument = new StringArgument(null, "vendorVersion", false, 1,
917         INFO_MEM_DS_TOOL_ARG_PLACEHOLDER_VALUE.get(),
918         INFO_MEM_DS_TOOL_ARG_DESC_VENDOR_VERSION.get());
919    vendorVersionArgument.setArgumentGroupName(
920         INFO_MEM_DS_TOOL_GROUP_DATA.get());
921    vendorVersionArgument.addLongIdentifier("vendor-version", true);
922    parser.addArgument(vendorVersionArgument);
923
924    accessLogToStandardOutArgument = new BooleanArgument('A',
925         "accessLogToStandardOut",
926         INFO_MEM_DS_TOOL_ARG_DESC_ACCESS_LOG_TO_STDOUT.get());
927    accessLogToStandardOutArgument.setArgumentGroupName(
928         INFO_MEM_DS_TOOL_GROUP_LOGGING.get());
929    accessLogToStandardOutArgument.addLongIdentifier(
930         "access-log-to-standard-out", true);
931    parser.addArgument(accessLogToStandardOutArgument);
932
933    accessLogFileArgument = new FileArgument('a', "accessLogFile", false, 1,
934         INFO_MEM_DS_TOOL_ARG_PLACEHOLDER_PATH.get(),
935         INFO_MEM_DS_TOOL_ARG_DESC_ACCESS_LOG_FILE.get(), false, true, true,
936         false);
937    accessLogFileArgument.setArgumentGroupName(
938         INFO_MEM_DS_TOOL_GROUP_LOGGING.get());
939    accessLogFileArgument.addLongIdentifier("access-log-format", true);
940    parser.addArgument(accessLogFileArgument);
941
942    jsonAccessLogToStandardOutArgument = new BooleanArgument(null,
943         "jsonAccessLogToStandardOut",
944         INFO_MEM_DS_TOOL_ARG_DESC_JSON_ACCESS_LOG_TO_STDOUT.get());
945    jsonAccessLogToStandardOutArgument.setArgumentGroupName(
946         INFO_MEM_DS_TOOL_GROUP_LOGGING.get());
947    jsonAccessLogToStandardOutArgument.addLongIdentifier(
948         "json-access-log-to-standard-out", true);
949    parser.addArgument(jsonAccessLogToStandardOutArgument);
950
951    jsonAccessLogFileArgument = new FileArgument(null, "jsonAccessLogFile",
952         false, 1, INFO_MEM_DS_TOOL_ARG_PLACEHOLDER_PATH.get(),
953         INFO_MEM_DS_TOOL_ARG_DESC_JSON_ACCESS_LOG_FILE.get(), false, true,
954         true, false);
955    jsonAccessLogFileArgument.setArgumentGroupName(
956         INFO_MEM_DS_TOOL_GROUP_LOGGING.get());
957    jsonAccessLogFileArgument.addLongIdentifier("json-access-log-format", true);
958    parser.addArgument(jsonAccessLogFileArgument);
959
960    ldapDebugLogToStandardOutArgument = new BooleanArgument(null,
961         "ldapDebugLogToStandardOut",
962         INFO_MEM_DS_TOOL_ARG_DESC_LDAP_DEBUG_LOG_TO_STDOUT.get());
963    ldapDebugLogToStandardOutArgument.setArgumentGroupName(
964         INFO_MEM_DS_TOOL_GROUP_LOGGING.get());
965    ldapDebugLogToStandardOutArgument.addLongIdentifier(
966         "ldap-debug-log-to-standard-out", true);
967    parser.addArgument(ldapDebugLogToStandardOutArgument);
968
969    ldapDebugLogFileArgument = new FileArgument('d', "ldapDebugLogFile", false,
970         1, INFO_MEM_DS_TOOL_ARG_PLACEHOLDER_PATH.get(),
971         INFO_MEM_DS_TOOL_ARG_DESC_LDAP_DEBUG_LOG_FILE.get(), false, true, true,
972         false);
973    ldapDebugLogFileArgument.setArgumentGroupName(
974         INFO_MEM_DS_TOOL_GROUP_LOGGING.get());
975    ldapDebugLogFileArgument.addLongIdentifier("ldap-debug-log-file", true);
976    parser.addArgument(ldapDebugLogFileArgument);
977
978    codeLogFile = new FileArgument('C', "codeLogFile", false, 1, "{path}",
979         INFO_MEM_DS_TOOL_ARG_DESC_CODE_LOG_FILE.get(), false, true, true,
980         false);
981    codeLogFile.setArgumentGroupName(INFO_MEM_DS_TOOL_GROUP_LOGGING.get());
982    codeLogFile.addLongIdentifier("code-log-file", true);
983    parser.addArgument(codeLogFile);
984
985    parser.addExclusiveArgumentSet(useDefaultSchemaArgument,
986         useSchemaFileArgument);
987
988    parser.addDependentArgumentSet(doNotValidateSchemaDefinitionsArgument,
989         useSchemaFileArgument);
990
991    parser.addExclusiveArgumentSet(useSSLArgument, useStartTLSArgument);
992
993    parser.addExclusiveArgumentSet(keyStorePathArgument,
994         generateSelfSignedCertificateArgument);
995
996    parser.addExclusiveArgumentSet(accessLogToStandardOutArgument,
997         accessLogFileArgument);
998
999    parser.addExclusiveArgumentSet(jsonAccessLogToStandardOutArgument,
1000         jsonAccessLogFileArgument);
1001
1002    parser.addExclusiveArgumentSet(ldapDebugLogToStandardOutArgument,
1003         ldapDebugLogFileArgument);
1004
1005    parser.addDependentArgumentSet(additionalBindDNArgument,
1006         additionalBindPasswordArgument);
1007
1008    parser.addDependentArgumentSet(additionalBindPasswordArgument,
1009         additionalBindDNArgument);
1010
1011    parser.addDependentArgumentSet(useSSLArgument, keyStorePathArgument,
1012         generateSelfSignedCertificateArgument);
1013
1014    parser.addDependentArgumentSet(keyStorePathArgument,
1015         keyStorePasswordArgument);
1016
1017    parser.addDependentArgumentSet(keyStorePasswordArgument,
1018         keyStorePathArgument);
1019
1020    parser.addDependentArgumentSet(keyStoreTypeArgument,
1021         keyStorePathArgument);
1022
1023    parser.addDependentArgumentSet(useStartTLSArgument, keyStorePathArgument,
1024         generateSelfSignedCertificateArgument);
1025
1026    parser.addDependentArgumentSet(keyStorePathArgument, useSSLArgument,
1027         useStartTLSArgument);
1028
1029    parser.addDependentArgumentSet(generateSelfSignedCertificateArgument,
1030         useSSLArgument, useStartTLSArgument);
1031
1032    parser.addDependentArgumentSet(trustStorePathArgument, useSSLArgument,
1033         useStartTLSArgument);
1034
1035    parser.addDependentArgumentSet(trustStorePasswordArgument,
1036         trustStorePathArgument);
1037
1038    parser.addDependentArgumentSet(trustStoreTypeArgument,
1039         trustStorePathArgument);
1040  }
1041
1042
1043
1044  /**
1045   * {@inheritDoc}
1046   */
1047  @Override()
1048  public boolean supportsInteractiveMode()
1049  {
1050    return true;
1051  }
1052
1053
1054
1055  /**
1056   * {@inheritDoc}
1057   */
1058  @Override()
1059  public boolean defaultsToInteractiveMode()
1060  {
1061    return true;
1062  }
1063
1064
1065
1066  /**
1067   * Indicates whether this tool supports the use of a properties file for
1068   * specifying default values for arguments that aren't specified on the
1069   * command line.
1070   *
1071   * @return  {@code true} if this tool supports the use of a properties file
1072   *          for specifying default values for arguments that aren't specified
1073   *          on the command line, or {@code false} if not.
1074   */
1075  @Override()
1076  public boolean supportsPropertiesFile()
1077  {
1078    return true;
1079  }
1080
1081
1082
1083  /**
1084   * {@inheritDoc}
1085   */
1086  @Override()
1087  @NotNull()
1088  public ResultCode doToolProcessing()
1089  {
1090    // Create a base configuration.
1091    final InMemoryDirectoryServerConfig serverConfig;
1092    try
1093    {
1094      serverConfig = getConfig();
1095    }
1096    catch (final LDAPException le)
1097    {
1098      Debug.debugException(le);
1099      wrapErr(0, WRAP_COLUMN,
1100           ERR_MEM_DS_TOOL_ERROR_INITIALIZING_CONFIG.get(le.getMessage()));
1101      return le.getResultCode();
1102    }
1103
1104
1105    // Create the server instance using the provided configuration, but don't
1106    // start it yet.
1107    try
1108    {
1109      directoryServer = new InMemoryDirectoryServer(serverConfig);
1110    }
1111    catch (final LDAPException le)
1112    {
1113      Debug.debugException(le);
1114      wrapErr(0, WRAP_COLUMN,
1115           ERR_MEM_DS_TOOL_ERROR_CREATING_SERVER_INSTANCE.get(le.getMessage()));
1116      return le.getResultCode();
1117    }
1118
1119
1120    // If an LDIF file was provided, then use it to populate the server.
1121    if (ldifFileArgument.isPresent())
1122    {
1123      final File ldifFile = ldifFileArgument.getValue();
1124      try
1125      {
1126        final int numEntries = directoryServer.importFromLDIF(true,
1127             ldifFile.getAbsolutePath());
1128        wrapOut(0, WRAP_COLUMN,
1129             INFO_MEM_DS_TOOL_ADDED_ENTRIES_FROM_LDIF.get(numEntries,
1130                  ldifFile.getAbsolutePath()));
1131      }
1132      catch (final LDAPException le)
1133      {
1134        Debug.debugException(le);
1135        wrapErr(0, WRAP_COLUMN,
1136             ERR_MEM_DS_TOOL_ERROR_POPULATING_SERVER_INSTANCE.get(
1137                  ldifFile.getAbsolutePath(), le.getMessage()));
1138        return le.getResultCode();
1139      }
1140    }
1141
1142
1143    // Start the server.
1144    try
1145    {
1146      if (! dontStartArgument.isPresent())
1147      {
1148        directoryServer.startListening();
1149        wrapOut(0, WRAP_COLUMN,
1150             INFO_MEM_DS_TOOL_LISTENING.get(directoryServer.getListenPort()));
1151      }
1152    }
1153    catch (final Exception e)
1154    {
1155      Debug.debugException(e);
1156      wrapErr(0, WRAP_COLUMN,
1157           ERR_MEM_DS_TOOL_ERROR_STARTING_SERVER.get(
1158                StaticUtils.getExceptionMessage(e)));
1159      return ResultCode.LOCAL_ERROR;
1160    }
1161
1162    return ResultCode.SUCCESS;
1163  }
1164
1165
1166
1167  /**
1168   * Creates a server configuration based on information provided with
1169   * command line arguments.
1170   *
1171   * @return  The configuration that was created.
1172   *
1173   * @throws  LDAPException  If a problem is encountered while creating the
1174   *                         configuration.
1175   */
1176  @NotNull()
1177  private InMemoryDirectoryServerConfig getConfig()
1178          throws LDAPException
1179  {
1180    final List<DN> dnList = baseDNArgument.getValues();
1181    final DN[] baseDNs = new DN[dnList.size()];
1182    dnList.toArray(baseDNs);
1183
1184    final InMemoryDirectoryServerConfig serverConfig =
1185         new InMemoryDirectoryServerConfig(baseDNs);
1186
1187
1188    // If a listen port was specified, then update the configuration to use it.
1189    int listenPort = 0;
1190    if (portArgument.isPresent())
1191    {
1192      listenPort = portArgument.getValue();
1193    }
1194
1195
1196    // If schema should be used, then get it.
1197    if (useDefaultSchemaArgument.isPresent())
1198    {
1199      serverConfig.setSchema(Schema.getDefaultStandardSchema());
1200    }
1201    else if (useSchemaFileArgument.isPresent())
1202    {
1203      final Map<String,File> schemaFiles = new TreeMap<>();
1204      for (final File f : useSchemaFileArgument.getValues())
1205      {
1206        if (f.exists())
1207        {
1208          if (f.isFile())
1209          {
1210            schemaFiles.put(f.getName(), f);
1211          }
1212          else
1213          {
1214            for (final File subFile : f.listFiles())
1215            {
1216              if (subFile.isFile())
1217              {
1218                schemaFiles.put(subFile.getName(), subFile);
1219              }
1220            }
1221          }
1222        }
1223        else
1224        {
1225          throw new LDAPException(ResultCode.PARAM_ERROR,
1226               ERR_MEM_DS_TOOL_NO_SUCH_SCHEMA_FILE.get(f.getAbsolutePath()));
1227        }
1228      }
1229
1230      if (! doNotValidateSchemaDefinitionsArgument.isPresent())
1231      {
1232        Schema schema = null;
1233        final List<String> errorMessages = new ArrayList<>();
1234        final SchemaValidator schemaValidator = new SchemaValidator();
1235        for (final File schemaFile : schemaFiles.values())
1236        {
1237          schema = schemaValidator.validateSchema(schemaFile, schema,
1238               errorMessages);
1239        }
1240
1241        if (! errorMessages.isEmpty())
1242        {
1243          wrapErr(0, WRAP_COLUMN,
1244               WARN_MEM_DS_TOOL_SCHEMA_ISSUES_IDENTIFIED.get());
1245          for (final String message : errorMessages)
1246          {
1247            err();
1248            final List<String> wrappedLines = StaticUtils.wrapLine(message,
1249                 (WRAP_COLUMN - 2));
1250            final Iterator<String> iterator = wrappedLines.iterator();
1251            err("* " + iterator.next());
1252            while (iterator.hasNext())
1253            {
1254              err("  " + iterator.next());
1255            }
1256          }
1257          err();
1258          wrapErr(0, WRAP_COLUMN,
1259               WARN_MEM_DS_TOOL_WILL_CONTINUE_WITH_SCHEMA.get(
1260                    doNotValidateSchemaDefinitionsArgument.
1261                         getIdentifierString()));
1262          err();
1263        }
1264      }
1265
1266      try
1267      {
1268        serverConfig.setSchema(Schema.getSchema(
1269             new ArrayList<File>(schemaFiles.values())));
1270      }
1271      catch (final Exception e)
1272      {
1273        Debug.debugException(e);
1274
1275        final StringBuilder fileList = new StringBuilder();
1276        final Iterator<File> fileIterator = schemaFiles.values().iterator();
1277        while (fileIterator.hasNext())
1278        {
1279          fileList.append(fileIterator.next().getAbsolutePath());
1280          if (fileIterator.hasNext())
1281          {
1282            fileList.append(", ");
1283          }
1284        }
1285
1286        throw new LDAPException(ResultCode.LOCAL_ERROR,
1287             ERR_MEM_DS_TOOL_ERROR_READING_SCHEMA.get(
1288                  fileList, StaticUtils.getExceptionMessage(e)),
1289             e);
1290      }
1291    }
1292    else
1293    {
1294      serverConfig.setSchema(null);
1295    }
1296
1297
1298    // If an additional bind DN and password are provided, then include them in
1299    // the configuration.
1300    if (additionalBindDNArgument.isPresent())
1301    {
1302      serverConfig.addAdditionalBindCredentials(
1303           additionalBindDNArgument.getValue().toString(),
1304           additionalBindPasswordArgument.getValue());
1305    }
1306
1307
1308    // If a maximum number of changelog entries was specified, then update the
1309    // configuration with that.
1310    if (maxChangeLogEntriesArgument.isPresent())
1311    {
1312      serverConfig.setMaxChangeLogEntries(
1313           maxChangeLogEntriesArgument.getValue());
1314    }
1315
1316
1317    // If a maximum number of concurrent connections was specified, then update
1318    // the configuration with that.
1319    if (maxConcurrentConnectionsArgument.isPresent())
1320    {
1321      serverConfig.setMaxConnections(
1322           maxConcurrentConnectionsArgument.getValue());
1323    }
1324
1325
1326    // If a size limit was specified, then update the configuration with that.
1327    if (sizeLimitArgument.isPresent())
1328    {
1329      serverConfig.setMaxSizeLimit(sizeLimitArgument.getValue());
1330    }
1331
1332
1333    // If the password argument was specified, then set the password arguments.
1334    if (passwordAttributeArgument.isPresent())
1335    {
1336      serverConfig.setPasswordAttributes(passwordAttributeArgument.getValues());
1337    }
1338
1339
1340    // Configure password encodings for the server.
1341    final LinkedHashMap<String,InMemoryPasswordEncoder> passwordEncoders =
1342         new LinkedHashMap<>(10);
1343    addUnsaltedEncoder("MD5", "MD5", passwordEncoders);
1344    addUnsaltedEncoder("SHA", "SHA-1", passwordEncoders);
1345    addUnsaltedEncoder("SHA1", "SHA-1", passwordEncoders);
1346    addUnsaltedEncoder("SHA-1", "SHA-1", passwordEncoders);
1347    addUnsaltedEncoder("SHA256", "SHA-256", passwordEncoders);
1348    addUnsaltedEncoder("SHA-256", "SHA-256", passwordEncoders);
1349    addUnsaltedEncoder("SHA384", "SHA-384", passwordEncoders);
1350    addUnsaltedEncoder("SHA-384", "SHA-384", passwordEncoders);
1351    addUnsaltedEncoder("SHA512", "SHA-512", passwordEncoders);
1352    addUnsaltedEncoder("SHA-512", "SHA-512", passwordEncoders);
1353    addSaltedEncoder("SMD5", "MD5", passwordEncoders);
1354    addSaltedEncoder("SSHA", "SHA-1", passwordEncoders);
1355    addSaltedEncoder("SSHA1", "SHA-1", passwordEncoders);
1356    addSaltedEncoder("SSHA-1", "SHA-1", passwordEncoders);
1357    addSaltedEncoder("SSHA256", "SHA-256", passwordEncoders);
1358    addSaltedEncoder("SSHA-256", "SHA-256", passwordEncoders);
1359    addSaltedEncoder("SSHA384", "SHA-384", passwordEncoders);
1360    addSaltedEncoder("SSHA-384", "SHA-384", passwordEncoders);
1361    addSaltedEncoder("SSHA512", "SHA-512", passwordEncoders);
1362    addSaltedEncoder("SSHA-512", "SHA-512", passwordEncoders);
1363    addClearEncoder("CLEAR", null, passwordEncoders);
1364    addClearEncoder("BASE64",
1365         Base64PasswordEncoderOutputFormatter.getInstance(), passwordEncoders);
1366    addClearEncoder("HEX",
1367         HexPasswordEncoderOutputFormatter.getLowercaseInstance(),
1368         passwordEncoders);
1369
1370    final InMemoryPasswordEncoder primaryEncoder;
1371    if (defaultPasswordEncodingArgument.isPresent())
1372    {
1373      primaryEncoder = passwordEncoders.remove(
1374           StaticUtils.toLowerCase(defaultPasswordEncodingArgument.getValue()));
1375      if (primaryEncoder == null)
1376      {
1377        throw new LDAPException(ResultCode.PARAM_ERROR,
1378             ERR_MEM_DS_TOOL_UNAVAILABLE_PW_ENCODING.get(
1379                  defaultPasswordEncodingArgument.getValue(),
1380                  String.valueOf(passwordEncoders.keySet())));
1381      }
1382    }
1383    else
1384    {
1385      primaryEncoder = null;
1386    }
1387
1388    serverConfig.setPasswordEncoders(primaryEncoder,
1389         passwordEncoders.values());
1390
1391
1392    // Configure the allowed operation types.
1393    if (allowedOperationTypeArgument.isPresent())
1394    {
1395      final EnumSet<OperationType> operationTypes =
1396           EnumSet.noneOf(OperationType.class);
1397      for (final String operationTypeName :
1398           allowedOperationTypeArgument.getValues())
1399      {
1400        final OperationType name = OperationType.forName(operationTypeName);
1401        if (name == null)
1402        {
1403          throw new LDAPException(ResultCode.PARAM_ERROR,
1404               ERR_MEM_DS_TOOL_UNSUPPORTED_ALLOWED_OP_TYPE.get(name));
1405        }
1406        else
1407        {
1408          switch (name)
1409          {
1410            case ADD:
1411            case BIND:
1412            case COMPARE:
1413            case DELETE:
1414            case EXTENDED:
1415            case MODIFY:
1416            case MODIFY_DN:
1417            case SEARCH:
1418              operationTypes.add(name);
1419              break;
1420            case ABANDON:
1421            case UNBIND:
1422            default:
1423              throw new LDAPException(ResultCode.PARAM_ERROR,
1424                   ERR_MEM_DS_TOOL_UNSUPPORTED_ALLOWED_OP_TYPE.get(name));
1425          }
1426        }
1427      }
1428
1429      serverConfig.setAllowedOperationTypes(operationTypes);
1430    }
1431
1432
1433    // Configure the authentication required operation types.
1434    if (authenticationRequiredOperationTypeArgument.isPresent())
1435    {
1436      final EnumSet<OperationType> operationTypes =
1437           EnumSet.noneOf(OperationType.class);
1438      for (final String operationTypeName :
1439           authenticationRequiredOperationTypeArgument.getValues())
1440      {
1441        final OperationType name = OperationType.forName(operationTypeName);
1442        if (name == null)
1443        {
1444          throw new LDAPException(ResultCode.PARAM_ERROR,
1445               ERR_MEM_DS_TOOL_UNSUPPORTED_AUTH_REQUIRED_OP_TYPE.get(name));
1446        }
1447        else
1448        {
1449          switch (name)
1450          {
1451            case ADD:
1452            case COMPARE:
1453            case DELETE:
1454            case EXTENDED:
1455            case MODIFY:
1456            case MODIFY_DN:
1457            case SEARCH:
1458              operationTypes.add(name);
1459              break;
1460            case ABANDON:
1461            case UNBIND:
1462            default:
1463              throw new LDAPException(ResultCode.PARAM_ERROR,
1464                   ERR_MEM_DS_TOOL_UNSUPPORTED_AUTH_REQUIRED_OP_TYPE.get(name));
1465          }
1466        }
1467      }
1468
1469      serverConfig.setAuthenticationRequiredOperationTypes(operationTypes);
1470    }
1471
1472
1473    // If an access log file was specified, then create the appropriate log
1474    // handler.
1475    if (accessLogToStandardOutArgument.isPresent())
1476    {
1477      final StreamHandler handler = new StreamHandler(System.out,
1478           new MinimalLogFormatter(null, false, false, true));
1479      StaticUtils.setLogHandlerLevel(handler, Level.INFO);
1480      serverConfig.setAccessLogHandler(handler);
1481    }
1482    else if (accessLogFileArgument.isPresent())
1483    {
1484      final File logFile = accessLogFileArgument.getValue();
1485      try
1486      {
1487        final FileHandler handler =
1488             new FileHandler(logFile.getAbsolutePath(), true);
1489        StaticUtils.setLogHandlerLevel(handler, Level.INFO);
1490        handler.setFormatter(new MinimalLogFormatter(null, false, false,
1491             true));
1492        serverConfig.setAccessLogHandler(handler);
1493      }
1494      catch (final Exception e)
1495      {
1496        Debug.debugException(e);
1497        throw new LDAPException(ResultCode.LOCAL_ERROR,
1498             ERR_MEM_DS_TOOL_ERROR_CREATING_LOG_HANDLER.get(
1499                  logFile.getAbsolutePath(),
1500                  StaticUtils.getExceptionMessage(e)),
1501             e);
1502      }
1503    }
1504
1505
1506    // If a JSON-formatted access log file was specified, then create the
1507    // appropriate log handler.
1508    if (jsonAccessLogToStandardOutArgument.isPresent())
1509    {
1510      final StreamHandler handler = new StreamHandler(System.out,
1511           new MinimalLogFormatter(null, false, false, true));
1512      StaticUtils.setLogHandlerLevel(handler, Level.INFO);
1513      serverConfig.setJSONAccessLogHandler(handler);
1514    }
1515    else if (jsonAccessLogFileArgument.isPresent())
1516    {
1517      final File logFile = jsonAccessLogFileArgument.getValue();
1518      try
1519      {
1520        final FileHandler handler =
1521             new FileHandler(logFile.getAbsolutePath(), true);
1522        StaticUtils.setLogHandlerLevel(handler, Level.INFO);
1523        handler.setFormatter(new MinimalLogFormatter(null, false, false,
1524             true));
1525        serverConfig.setJSONAccessLogHandler(handler);
1526      }
1527      catch (final Exception e)
1528      {
1529        Debug.debugException(e);
1530        throw new LDAPException(ResultCode.LOCAL_ERROR,
1531             ERR_MEM_DS_TOOL_ERROR_CREATING_LOG_HANDLER.get(
1532                  logFile.getAbsolutePath(),
1533                  StaticUtils.getExceptionMessage(e)),
1534             e);
1535      }
1536    }
1537
1538
1539    // If an LDAP debug log file was specified, then create the appropriate log
1540    // handler.
1541    if (ldapDebugLogToStandardOutArgument.isPresent())
1542    {
1543      final StreamHandler handler = new StreamHandler(System.out,
1544           new MinimalLogFormatter(null, false, false, true));
1545      StaticUtils.setLogHandlerLevel(handler, Level.INFO);
1546      serverConfig.setLDAPDebugLogHandler(handler);
1547    }
1548    else if (ldapDebugLogFileArgument.isPresent())
1549    {
1550      final File logFile = ldapDebugLogFileArgument.getValue();
1551      try
1552      {
1553        final FileHandler handler =
1554             new FileHandler(logFile.getAbsolutePath(), true);
1555        StaticUtils.setLogHandlerLevel(handler, Level.INFO);
1556        handler.setFormatter(new MinimalLogFormatter(null, false, false,
1557             true));
1558        serverConfig.setLDAPDebugLogHandler(handler);
1559      }
1560      catch (final Exception e)
1561      {
1562        Debug.debugException(e);
1563        throw new LDAPException(ResultCode.LOCAL_ERROR,
1564             ERR_MEM_DS_TOOL_ERROR_CREATING_LOG_HANDLER.get(
1565                  logFile.getAbsolutePath(),
1566                  StaticUtils.getExceptionMessage(e)),
1567             e);
1568      }
1569    }
1570
1571
1572    // If a code log file was specified, then update the configuration
1573    // accordingly.
1574    if (codeLogFile.isPresent())
1575    {
1576      serverConfig.setCodeLogDetails(codeLogFile.getValue().getAbsolutePath(),
1577           true);
1578    }
1579
1580
1581    // If SSL is to be used, then create the corresponding socket factories.
1582    if (useSSLArgument.isPresent() || useStartTLSArgument.isPresent())
1583    {
1584      final File keyStorePath;
1585      final char[] keyStorePIN;
1586      final String keyStoreType;
1587      if (keyStorePathArgument.isPresent())
1588      {
1589        keyStorePath = keyStorePathArgument.getValue();
1590        keyStorePIN = keyStorePasswordArgument.getValue().toCharArray();
1591        keyStoreType = keyStoreTypeArgument.getValue();
1592      }
1593      else
1594      {
1595        try
1596        {
1597          keyStoreType = CryptoHelper.KEY_STORE_TYPE_JKS;
1598          final ObjectPair<File,char[]> keyStoreInfo =
1599               SelfSignedCertificateGenerator.
1600                    generateTemporarySelfSignedCertificate(
1601                         getToolName(), keyStoreType);
1602          keyStorePath = keyStoreInfo.getFirst();
1603          keyStorePIN = keyStoreInfo.getSecond();
1604        }
1605        catch (final CertException e)
1606        {
1607          Debug.debugException(e);
1608          throw new LDAPException(ResultCode.LOCAL_ERROR, e.getMessage(), e);
1609        }
1610      }
1611
1612
1613      try
1614      {
1615        final KeyManager keyManager = new KeyStoreKeyManager(keyStorePath,
1616             keyStorePIN, keyStoreType, null, true);
1617
1618        final TrustManager trustManager;
1619        if (trustStorePathArgument.isPresent())
1620        {
1621          final char[] password;
1622          if (trustStorePasswordArgument.isPresent())
1623          {
1624            password = trustStorePasswordArgument.getValue().toCharArray();
1625          }
1626          else
1627          {
1628            password = null;
1629          }
1630
1631          trustManager = new TrustStoreTrustManager(
1632               trustStorePathArgument.getValue(), password,
1633               trustStoreTypeArgument.getValue(), true);
1634        }
1635        else
1636        {
1637          trustManager = new TrustAllTrustManager();
1638        }
1639
1640        final SSLUtil serverSSLUtil = new SSLUtil(keyManager, trustManager);
1641
1642        final boolean requestCertificate;
1643        final boolean requireCertificate;
1644        final String clientAuthPolicy = sslClientAuthPolicy.getValue();
1645        if (clientAuthPolicy.equalsIgnoreCase(
1646             SSL_CLIENT_AUTH_POLICY_OPTIONAL))
1647        {
1648          requestCertificate = true;
1649          requireCertificate = false;
1650        }
1651        else if (clientAuthPolicy.equalsIgnoreCase(
1652             SSL_CLIENT_AUTH_POLICY_REQUIRED))
1653        {
1654          requestCertificate = true;
1655          requireCertificate = true;
1656        }
1657        else
1658        {
1659          requestCertificate = false;
1660          requireCertificate = false;
1661        }
1662
1663        if (useSSLArgument.isPresent())
1664        {
1665          final SSLUtil clientSSLUtil = new SSLUtil(new TrustAllTrustManager());
1666          serverConfig.setListenerConfigs(
1667               InMemoryListenerConfig.createLDAPSConfig("LDAPS", null,
1668                    listenPort, serverSSLUtil.createSSLServerSocketFactory(),
1669                    clientSSLUtil.createSSLSocketFactory(),
1670                    requestCertificate, requireCertificate));
1671        }
1672        else
1673        {
1674          serverConfig.setListenerConfigs(
1675               InMemoryListenerConfig.createLDAPConfig("LDAP+StartTLS", null,
1676                    listenPort, serverSSLUtil.createSSLSocketFactory(),
1677                    requestCertificate, requireCertificate));
1678        }
1679      }
1680      catch (final Exception e)
1681      {
1682        Debug.debugException(e);
1683        throw new LDAPException(ResultCode.LOCAL_ERROR,
1684             ERR_MEM_DS_TOOL_ERROR_INITIALIZING_SSL.get(
1685                  StaticUtils.getExceptionMessage(e)),
1686             e);
1687      }
1688    }
1689    else
1690    {
1691      serverConfig.setListenerConfigs(InMemoryListenerConfig.createLDAPConfig(
1692           "LDAP", listenPort));
1693    }
1694
1695
1696    // If vendor name and/or vendor version values were provided, then configure
1697    // them for use.
1698    if (vendorNameArgument.isPresent())
1699    {
1700      serverConfig.setVendorName(vendorNameArgument.getValue());
1701    }
1702
1703    if (vendorVersionArgument.isPresent())
1704    {
1705      serverConfig.setVendorVersion(vendorVersionArgument.getValue());
1706    }
1707
1708
1709    // If equality indexing is to be performed, then configure it.
1710    if (equalityIndexArgument.isPresent())
1711    {
1712      serverConfig.setEqualityIndexAttributes(
1713           equalityIndexArgument.getValues());
1714    }
1715
1716
1717    // Update the configuration to indicate whether to generate operational
1718    // attributes.
1719    serverConfig.setGenerateOperationalAttributes(
1720         ! doNotGenerateOperationalAttributesArgument.isPresent());
1721
1722
1723    return serverConfig;
1724  }
1725
1726
1727
1728  /**
1729   * Updates the map with an unsalted password encoder with the provided
1730   * information.
1731   *
1732   * @param  schemeName       The name to use to identify the scheme, without
1733   *                          the curly braces.
1734   * @param  digestAlgorithm  The name of the message digest algorithm to use
1735   *                          for the password encoder.
1736   * @param  encoderMap       The map to which the encoder will bea added.
1737   */
1738  private static void addUnsaltedEncoder(@NotNull final String schemeName,
1739               @NotNull final String digestAlgorithm,
1740               @NotNull final Map<String,InMemoryPasswordEncoder> encoderMap)
1741  {
1742    try
1743    {
1744      final UnsaltedMessageDigestInMemoryPasswordEncoder encoder =
1745           new UnsaltedMessageDigestInMemoryPasswordEncoder(
1746                '{' + schemeName + '}',
1747                Base64PasswordEncoderOutputFormatter.getInstance(),
1748                CryptoHelper.getMessageDigest(digestAlgorithm));
1749      encoderMap.put(StaticUtils.toLowerCase(schemeName), encoder);
1750    }
1751    catch (final Exception e)
1752    {
1753      Debug.debugException(e);
1754    }
1755  }
1756
1757
1758
1759  /**
1760   * Updates the map with a salted password encoder with the provided
1761   * information.
1762   *
1763   * @param  schemeName       The name to use to identify the scheme, without
1764   *                          the curly braces.
1765   * @param  digestAlgorithm  The name of the message digest algorithm to use
1766   *                          for the password encoder.
1767   * @param  encoderMap       The map to which the encoder will bea added.
1768   */
1769  private static void addSaltedEncoder(@NotNull final String schemeName,
1770               @NotNull final String digestAlgorithm,
1771               @NotNull final Map<String,InMemoryPasswordEncoder> encoderMap)
1772  {
1773    try
1774    {
1775      final SaltedMessageDigestInMemoryPasswordEncoder encoder =
1776           new SaltedMessageDigestInMemoryPasswordEncoder(
1777                '{' + schemeName + '}',
1778                Base64PasswordEncoderOutputFormatter.getInstance(),
1779                CryptoHelper.getMessageDigest(digestAlgorithm), 8, true, true);
1780      encoderMap.put(StaticUtils.toLowerCase(schemeName), encoder);
1781    }
1782    catch (final Exception e)
1783    {
1784      Debug.debugException(e);
1785    }
1786  }
1787
1788
1789
1790  /**
1791   * Updates the map with a clear-text password encoder with the provided
1792   * information.
1793   *
1794   * @param  schemeName       The name to use to identify the scheme, without
1795   *                          the curly braces.
1796   * @param  outputFormatter  The output formatter to use.  It may be
1797   *                          {@code null} if the output should remain in the
1798   *                          clear.
1799   * @param  encoderMap       The map to which the encoder will bea added.
1800   */
1801  private static void addClearEncoder(@NotNull final String schemeName,
1802               @Nullable final PasswordEncoderOutputFormatter outputFormatter,
1803               @NotNull final Map<String,InMemoryPasswordEncoder> encoderMap)
1804  {
1805    final ClearInMemoryPasswordEncoder encoder =
1806         new ClearInMemoryPasswordEncoder('{' + schemeName + '}',
1807              outputFormatter);
1808    encoderMap.put(StaticUtils.toLowerCase(schemeName), encoder);
1809  }
1810
1811
1812
1813  /**
1814   * {@inheritDoc}
1815   */
1816  @Override()
1817  @NotNull()
1818  public LinkedHashMap<String[],String> getExampleUsages()
1819  {
1820    final LinkedHashMap<String[],String> exampleUsages =
1821         new LinkedHashMap<>(StaticUtils.computeMapCapacity(2));
1822
1823    final String[] example1Args =
1824    {
1825      "--baseDN", "dc=example,dc=com"
1826    };
1827    exampleUsages.put(example1Args, INFO_MEM_DS_TOOL_EXAMPLE_1.get());
1828
1829    final String[] example2Args =
1830    {
1831      "--baseDN", "dc=example,dc=com",
1832      "--port", "1389",
1833      "--ldifFile", "test.ldif",
1834      "--accessLogFile", "access.log",
1835      "--useDefaultSchema"
1836    };
1837    exampleUsages.put(example2Args, INFO_MEM_DS_TOOL_EXAMPLE_2.get());
1838
1839    return exampleUsages;
1840  }
1841
1842
1843
1844  /**
1845   * Retrieves the in-memory directory server instance that has been created by
1846   * this tool.  It will only be valid after the {@link #doToolProcessing()}
1847   * method has been called.
1848   *
1849   * @return  The in-memory directory server instance that has been created by
1850   *          this tool, or {@code null} if the directory server instance has
1851   *          not been successfully created.
1852   */
1853  @Nullable()
1854  public InMemoryDirectoryServer getDirectoryServer()
1855  {
1856    return directoryServer;
1857  }
1858
1859
1860
1861  /**
1862   * {@inheritDoc}
1863   */
1864  @Override()
1865  public void connectionCreationFailure(@Nullable final Socket socket,
1866                                        @NotNull final Throwable cause)
1867  {
1868    wrapErr(0, WRAP_COLUMN,
1869         ERR_MEM_DS_TOOL_ERROR_ACCEPTING_CONNECTION.get(
1870              StaticUtils.getExceptionMessage(cause)));
1871  }
1872
1873
1874
1875  /**
1876   * {@inheritDoc}
1877   */
1878  @Override()
1879  public void connectionTerminated(
1880                   @NotNull final LDAPListenerClientConnection connection,
1881                   @NotNull final LDAPException cause)
1882  {
1883    wrapErr(0, WRAP_COLUMN,
1884         ERR_MEM_DS_TOOL_CONNECTION_TERMINATED_BY_EXCEPTION.get(
1885              StaticUtils.getExceptionMessage(cause)));
1886  }
1887}