001/*
002 * Copyright 2011-2025 Ping Identity Corporation
003 * All Rights Reserved.
004 */
005/*
006 * Copyright 2011-2025 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-2025 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  protected boolean supportsDebugLogging()
1088  {
1089    return true;
1090  }
1091
1092
1093
1094  /**
1095   * {@inheritDoc}
1096   */
1097  @Override()
1098  @NotNull()
1099  public ResultCode doToolProcessing()
1100  {
1101    // Create a base configuration.
1102    final InMemoryDirectoryServerConfig serverConfig;
1103    try
1104    {
1105      serverConfig = getConfig();
1106    }
1107    catch (final LDAPException le)
1108    {
1109      Debug.debugException(le);
1110      wrapErr(0, WRAP_COLUMN,
1111           ERR_MEM_DS_TOOL_ERROR_INITIALIZING_CONFIG.get(le.getMessage()));
1112      return le.getResultCode();
1113    }
1114
1115
1116    // Create the server instance using the provided configuration, but don't
1117    // start it yet.
1118    try
1119    {
1120      directoryServer = new InMemoryDirectoryServer(serverConfig);
1121    }
1122    catch (final LDAPException le)
1123    {
1124      Debug.debugException(le);
1125      wrapErr(0, WRAP_COLUMN,
1126           ERR_MEM_DS_TOOL_ERROR_CREATING_SERVER_INSTANCE.get(le.getMessage()));
1127      return le.getResultCode();
1128    }
1129
1130
1131    // If an LDIF file was provided, then use it to populate the server.
1132    if (ldifFileArgument.isPresent())
1133    {
1134      final File ldifFile = ldifFileArgument.getValue();
1135      try
1136      {
1137        final int numEntries = directoryServer.importFromLDIF(true,
1138             ldifFile.getAbsolutePath());
1139        wrapOut(0, WRAP_COLUMN,
1140             INFO_MEM_DS_TOOL_ADDED_ENTRIES_FROM_LDIF.get(numEntries,
1141                  ldifFile.getAbsolutePath()));
1142      }
1143      catch (final LDAPException le)
1144      {
1145        Debug.debugException(le);
1146        wrapErr(0, WRAP_COLUMN,
1147             ERR_MEM_DS_TOOL_ERROR_POPULATING_SERVER_INSTANCE.get(
1148                  ldifFile.getAbsolutePath(), le.getMessage()));
1149        return le.getResultCode();
1150      }
1151    }
1152
1153
1154    // Start the server.
1155    try
1156    {
1157      if (! dontStartArgument.isPresent())
1158      {
1159        directoryServer.startListening();
1160        wrapOut(0, WRAP_COLUMN,
1161             INFO_MEM_DS_TOOL_LISTENING.get(directoryServer.getListenPort()));
1162      }
1163    }
1164    catch (final Exception e)
1165    {
1166      Debug.debugException(e);
1167      wrapErr(0, WRAP_COLUMN,
1168           ERR_MEM_DS_TOOL_ERROR_STARTING_SERVER.get(
1169                StaticUtils.getExceptionMessage(e)));
1170      return ResultCode.LOCAL_ERROR;
1171    }
1172
1173    return ResultCode.SUCCESS;
1174  }
1175
1176
1177
1178  /**
1179   * Creates a server configuration based on information provided with
1180   * command line arguments.
1181   *
1182   * @return  The configuration that was created.
1183   *
1184   * @throws  LDAPException  If a problem is encountered while creating the
1185   *                         configuration.
1186   */
1187  @NotNull()
1188  private InMemoryDirectoryServerConfig getConfig()
1189          throws LDAPException
1190  {
1191    final List<DN> dnList = baseDNArgument.getValues();
1192    final DN[] baseDNs = new DN[dnList.size()];
1193    dnList.toArray(baseDNs);
1194
1195    final InMemoryDirectoryServerConfig serverConfig =
1196         new InMemoryDirectoryServerConfig(baseDNs);
1197
1198
1199    // If a listen port was specified, then update the configuration to use it.
1200    int listenPort = 0;
1201    if (portArgument.isPresent())
1202    {
1203      listenPort = portArgument.getValue();
1204    }
1205
1206
1207    // If schema should be used, then get it.
1208    if (useDefaultSchemaArgument.isPresent())
1209    {
1210      serverConfig.setSchema(Schema.getDefaultStandardSchema());
1211    }
1212    else if (useSchemaFileArgument.isPresent())
1213    {
1214      final Map<String,File> schemaFiles = new TreeMap<>();
1215      for (final File f : useSchemaFileArgument.getValues())
1216      {
1217        if (f.exists())
1218        {
1219          if (f.isFile())
1220          {
1221            schemaFiles.put(f.getName(), f);
1222          }
1223          else
1224          {
1225            for (final File subFile : f.listFiles())
1226            {
1227              if (subFile.isFile())
1228              {
1229                schemaFiles.put(subFile.getName(), subFile);
1230              }
1231            }
1232          }
1233        }
1234        else
1235        {
1236          throw new LDAPException(ResultCode.PARAM_ERROR,
1237               ERR_MEM_DS_TOOL_NO_SUCH_SCHEMA_FILE.get(f.getAbsolutePath()));
1238        }
1239      }
1240
1241      if (! doNotValidateSchemaDefinitionsArgument.isPresent())
1242      {
1243        Schema schema = null;
1244        final List<String> errorMessages = new ArrayList<>();
1245        final SchemaValidator schemaValidator = new SchemaValidator();
1246        for (final File schemaFile : schemaFiles.values())
1247        {
1248          schema = schemaValidator.validateSchema(schemaFile, schema,
1249               errorMessages);
1250        }
1251
1252        if (! errorMessages.isEmpty())
1253        {
1254          wrapErr(0, WRAP_COLUMN,
1255               WARN_MEM_DS_TOOL_SCHEMA_ISSUES_IDENTIFIED.get());
1256          for (final String message : errorMessages)
1257          {
1258            err();
1259            final List<String> wrappedLines = StaticUtils.wrapLine(message,
1260                 (WRAP_COLUMN - 2));
1261            final Iterator<String> iterator = wrappedLines.iterator();
1262            err("* " + iterator.next());
1263            while (iterator.hasNext())
1264            {
1265              err("  " + iterator.next());
1266            }
1267          }
1268          err();
1269          wrapErr(0, WRAP_COLUMN,
1270               WARN_MEM_DS_TOOL_WILL_CONTINUE_WITH_SCHEMA.get(
1271                    doNotValidateSchemaDefinitionsArgument.
1272                         getIdentifierString()));
1273          err();
1274        }
1275      }
1276
1277      try
1278      {
1279        serverConfig.setSchema(Schema.getSchema(
1280             new ArrayList<File>(schemaFiles.values())));
1281      }
1282      catch (final Exception e)
1283      {
1284        Debug.debugException(e);
1285
1286        final StringBuilder fileList = new StringBuilder();
1287        final Iterator<File> fileIterator = schemaFiles.values().iterator();
1288        while (fileIterator.hasNext())
1289        {
1290          fileList.append(fileIterator.next().getAbsolutePath());
1291          if (fileIterator.hasNext())
1292          {
1293            fileList.append(", ");
1294          }
1295        }
1296
1297        throw new LDAPException(ResultCode.LOCAL_ERROR,
1298             ERR_MEM_DS_TOOL_ERROR_READING_SCHEMA.get(
1299                  fileList, StaticUtils.getExceptionMessage(e)),
1300             e);
1301      }
1302    }
1303    else
1304    {
1305      serverConfig.setSchema(null);
1306    }
1307
1308
1309    // If an additional bind DN and password are provided, then include them in
1310    // the configuration.
1311    if (additionalBindDNArgument.isPresent())
1312    {
1313      serverConfig.addAdditionalBindCredentials(
1314           additionalBindDNArgument.getValue().toString(),
1315           additionalBindPasswordArgument.getValue());
1316    }
1317
1318
1319    // If a maximum number of changelog entries was specified, then update the
1320    // configuration with that.
1321    if (maxChangeLogEntriesArgument.isPresent())
1322    {
1323      serverConfig.setMaxChangeLogEntries(
1324           maxChangeLogEntriesArgument.getValue());
1325    }
1326
1327
1328    // If a maximum number of concurrent connections was specified, then update
1329    // the configuration with that.
1330    if (maxConcurrentConnectionsArgument.isPresent())
1331    {
1332      serverConfig.setMaxConnections(
1333           maxConcurrentConnectionsArgument.getValue());
1334    }
1335
1336
1337    // If a size limit was specified, then update the configuration with that.
1338    if (sizeLimitArgument.isPresent())
1339    {
1340      serverConfig.setMaxSizeLimit(sizeLimitArgument.getValue());
1341    }
1342
1343
1344    // If the password argument was specified, then set the password arguments.
1345    if (passwordAttributeArgument.isPresent())
1346    {
1347      serverConfig.setPasswordAttributes(passwordAttributeArgument.getValues());
1348    }
1349
1350
1351    // Configure password encodings for the server.
1352    final LinkedHashMap<String,InMemoryPasswordEncoder> passwordEncoders =
1353         new LinkedHashMap<>(10);
1354    addUnsaltedEncoder("MD5", "MD5", passwordEncoders);
1355    addUnsaltedEncoder("SHA", "SHA-1", passwordEncoders);
1356    addUnsaltedEncoder("SHA1", "SHA-1", passwordEncoders);
1357    addUnsaltedEncoder("SHA-1", "SHA-1", passwordEncoders);
1358    addUnsaltedEncoder("SHA256", "SHA-256", passwordEncoders);
1359    addUnsaltedEncoder("SHA-256", "SHA-256", passwordEncoders);
1360    addUnsaltedEncoder("SHA384", "SHA-384", passwordEncoders);
1361    addUnsaltedEncoder("SHA-384", "SHA-384", passwordEncoders);
1362    addUnsaltedEncoder("SHA512", "SHA-512", passwordEncoders);
1363    addUnsaltedEncoder("SHA-512", "SHA-512", passwordEncoders);
1364    addSaltedEncoder("SMD5", "MD5", passwordEncoders);
1365    addSaltedEncoder("SSHA", "SHA-1", passwordEncoders);
1366    addSaltedEncoder("SSHA1", "SHA-1", passwordEncoders);
1367    addSaltedEncoder("SSHA-1", "SHA-1", passwordEncoders);
1368    addSaltedEncoder("SSHA256", "SHA-256", passwordEncoders);
1369    addSaltedEncoder("SSHA-256", "SHA-256", passwordEncoders);
1370    addSaltedEncoder("SSHA384", "SHA-384", passwordEncoders);
1371    addSaltedEncoder("SSHA-384", "SHA-384", passwordEncoders);
1372    addSaltedEncoder("SSHA512", "SHA-512", passwordEncoders);
1373    addSaltedEncoder("SSHA-512", "SHA-512", passwordEncoders);
1374    addClearEncoder("CLEAR", null, passwordEncoders);
1375    addClearEncoder("BASE64",
1376         Base64PasswordEncoderOutputFormatter.getInstance(), passwordEncoders);
1377    addClearEncoder("HEX",
1378         HexPasswordEncoderOutputFormatter.getLowercaseInstance(),
1379         passwordEncoders);
1380
1381    final InMemoryPasswordEncoder primaryEncoder;
1382    if (defaultPasswordEncodingArgument.isPresent())
1383    {
1384      primaryEncoder = passwordEncoders.remove(
1385           StaticUtils.toLowerCase(defaultPasswordEncodingArgument.getValue()));
1386      if (primaryEncoder == null)
1387      {
1388        throw new LDAPException(ResultCode.PARAM_ERROR,
1389             ERR_MEM_DS_TOOL_UNAVAILABLE_PW_ENCODING.get(
1390                  defaultPasswordEncodingArgument.getValue(),
1391                  String.valueOf(passwordEncoders.keySet())));
1392      }
1393    }
1394    else
1395    {
1396      primaryEncoder = null;
1397    }
1398
1399    serverConfig.setPasswordEncoders(primaryEncoder,
1400         passwordEncoders.values());
1401
1402
1403    // Configure the allowed operation types.
1404    if (allowedOperationTypeArgument.isPresent())
1405    {
1406      final EnumSet<OperationType> operationTypes =
1407           EnumSet.noneOf(OperationType.class);
1408      for (final String operationTypeName :
1409           allowedOperationTypeArgument.getValues())
1410      {
1411        final OperationType name = OperationType.forName(operationTypeName);
1412        if (name == null)
1413        {
1414          throw new LDAPException(ResultCode.PARAM_ERROR,
1415               ERR_MEM_DS_TOOL_UNSUPPORTED_ALLOWED_OP_TYPE.get(name));
1416        }
1417        else
1418        {
1419          switch (name)
1420          {
1421            case ADD:
1422            case BIND:
1423            case COMPARE:
1424            case DELETE:
1425            case EXTENDED:
1426            case MODIFY:
1427            case MODIFY_DN:
1428            case SEARCH:
1429              operationTypes.add(name);
1430              break;
1431            case ABANDON:
1432            case UNBIND:
1433            default:
1434              throw new LDAPException(ResultCode.PARAM_ERROR,
1435                   ERR_MEM_DS_TOOL_UNSUPPORTED_ALLOWED_OP_TYPE.get(name));
1436          }
1437        }
1438      }
1439
1440      serverConfig.setAllowedOperationTypes(operationTypes);
1441    }
1442
1443
1444    // Configure the authentication required operation types.
1445    if (authenticationRequiredOperationTypeArgument.isPresent())
1446    {
1447      final EnumSet<OperationType> operationTypes =
1448           EnumSet.noneOf(OperationType.class);
1449      for (final String operationTypeName :
1450           authenticationRequiredOperationTypeArgument.getValues())
1451      {
1452        final OperationType name = OperationType.forName(operationTypeName);
1453        if (name == null)
1454        {
1455          throw new LDAPException(ResultCode.PARAM_ERROR,
1456               ERR_MEM_DS_TOOL_UNSUPPORTED_AUTH_REQUIRED_OP_TYPE.get(name));
1457        }
1458        else
1459        {
1460          switch (name)
1461          {
1462            case ADD:
1463            case COMPARE:
1464            case DELETE:
1465            case EXTENDED:
1466            case MODIFY:
1467            case MODIFY_DN:
1468            case SEARCH:
1469              operationTypes.add(name);
1470              break;
1471            case ABANDON:
1472            case UNBIND:
1473            default:
1474              throw new LDAPException(ResultCode.PARAM_ERROR,
1475                   ERR_MEM_DS_TOOL_UNSUPPORTED_AUTH_REQUIRED_OP_TYPE.get(name));
1476          }
1477        }
1478      }
1479
1480      serverConfig.setAuthenticationRequiredOperationTypes(operationTypes);
1481    }
1482
1483
1484    // If an access log file was specified, then create the appropriate log
1485    // handler.
1486    if (accessLogToStandardOutArgument.isPresent())
1487    {
1488      final StreamHandler handler = new StreamHandler(System.out,
1489           new MinimalLogFormatter(null, false, false, true));
1490      StaticUtils.setLogHandlerLevel(handler, Level.INFO);
1491      serverConfig.setAccessLogHandler(handler);
1492    }
1493    else if (accessLogFileArgument.isPresent())
1494    {
1495      final File logFile = accessLogFileArgument.getValue();
1496      try
1497      {
1498        final FileHandler handler =
1499             new FileHandler(logFile.getAbsolutePath(), true);
1500        StaticUtils.setLogHandlerLevel(handler, Level.INFO);
1501        handler.setFormatter(new MinimalLogFormatter(null, false, false,
1502             true));
1503        serverConfig.setAccessLogHandler(handler);
1504      }
1505      catch (final Exception e)
1506      {
1507        Debug.debugException(e);
1508        throw new LDAPException(ResultCode.LOCAL_ERROR,
1509             ERR_MEM_DS_TOOL_ERROR_CREATING_LOG_HANDLER.get(
1510                  logFile.getAbsolutePath(),
1511                  StaticUtils.getExceptionMessage(e)),
1512             e);
1513      }
1514    }
1515
1516
1517    // If a JSON-formatted access log file was specified, then create the
1518    // appropriate log handler.
1519    if (jsonAccessLogToStandardOutArgument.isPresent())
1520    {
1521      final StreamHandler handler = new StreamHandler(System.out,
1522           new MinimalLogFormatter(null, false, false, true));
1523      StaticUtils.setLogHandlerLevel(handler, Level.INFO);
1524      serverConfig.setJSONAccessLogHandler(handler);
1525    }
1526    else if (jsonAccessLogFileArgument.isPresent())
1527    {
1528      final File logFile = jsonAccessLogFileArgument.getValue();
1529      try
1530      {
1531        final FileHandler handler =
1532             new FileHandler(logFile.getAbsolutePath(), true);
1533        StaticUtils.setLogHandlerLevel(handler, Level.INFO);
1534        handler.setFormatter(new MinimalLogFormatter(null, false, false,
1535             true));
1536        serverConfig.setJSONAccessLogHandler(handler);
1537      }
1538      catch (final Exception e)
1539      {
1540        Debug.debugException(e);
1541        throw new LDAPException(ResultCode.LOCAL_ERROR,
1542             ERR_MEM_DS_TOOL_ERROR_CREATING_LOG_HANDLER.get(
1543                  logFile.getAbsolutePath(),
1544                  StaticUtils.getExceptionMessage(e)),
1545             e);
1546      }
1547    }
1548
1549
1550    // If an LDAP debug log file was specified, then create the appropriate log
1551    // handler.
1552    if (ldapDebugLogToStandardOutArgument.isPresent())
1553    {
1554      final StreamHandler handler = new StreamHandler(System.out,
1555           new MinimalLogFormatter(null, false, false, true));
1556      StaticUtils.setLogHandlerLevel(handler, Level.INFO);
1557      serverConfig.setLDAPDebugLogHandler(handler);
1558    }
1559    else if (ldapDebugLogFileArgument.isPresent())
1560    {
1561      final File logFile = ldapDebugLogFileArgument.getValue();
1562      try
1563      {
1564        final FileHandler handler =
1565             new FileHandler(logFile.getAbsolutePath(), true);
1566        StaticUtils.setLogHandlerLevel(handler, Level.INFO);
1567        handler.setFormatter(new MinimalLogFormatter(null, false, false,
1568             true));
1569        serverConfig.setLDAPDebugLogHandler(handler);
1570      }
1571      catch (final Exception e)
1572      {
1573        Debug.debugException(e);
1574        throw new LDAPException(ResultCode.LOCAL_ERROR,
1575             ERR_MEM_DS_TOOL_ERROR_CREATING_LOG_HANDLER.get(
1576                  logFile.getAbsolutePath(),
1577                  StaticUtils.getExceptionMessage(e)),
1578             e);
1579      }
1580    }
1581
1582
1583    // If a code log file was specified, then update the configuration
1584    // accordingly.
1585    if (codeLogFile.isPresent())
1586    {
1587      serverConfig.setCodeLogDetails(codeLogFile.getValue().getAbsolutePath(),
1588           true);
1589    }
1590
1591
1592    // If SSL is to be used, then create the corresponding socket factories.
1593    if (useSSLArgument.isPresent() || useStartTLSArgument.isPresent())
1594    {
1595      final File keyStorePath;
1596      final char[] keyStorePIN;
1597      final String keyStoreType;
1598      if (keyStorePathArgument.isPresent())
1599      {
1600        keyStorePath = keyStorePathArgument.getValue();
1601        keyStorePIN = keyStorePasswordArgument.getValue().toCharArray();
1602        keyStoreType = keyStoreTypeArgument.getValue();
1603      }
1604      else
1605      {
1606        try
1607        {
1608          keyStoreType = CryptoHelper.KEY_STORE_TYPE_JKS;
1609          final ObjectPair<File,char[]> keyStoreInfo =
1610               SelfSignedCertificateGenerator.
1611                    generateTemporarySelfSignedCertificate(
1612                         getToolName(), keyStoreType);
1613          keyStorePath = keyStoreInfo.getFirst();
1614          keyStorePIN = keyStoreInfo.getSecond();
1615        }
1616        catch (final CertException e)
1617        {
1618          Debug.debugException(e);
1619          throw new LDAPException(ResultCode.LOCAL_ERROR, e.getMessage(), e);
1620        }
1621      }
1622
1623
1624      try
1625      {
1626        final KeyManager keyManager = new KeyStoreKeyManager(keyStorePath,
1627             keyStorePIN, keyStoreType, null, true);
1628
1629        final TrustManager trustManager;
1630        if (trustStorePathArgument.isPresent())
1631        {
1632          final char[] password;
1633          if (trustStorePasswordArgument.isPresent())
1634          {
1635            password = trustStorePasswordArgument.getValue().toCharArray();
1636          }
1637          else
1638          {
1639            password = null;
1640          }
1641
1642          trustManager = new TrustStoreTrustManager(
1643               trustStorePathArgument.getValue(), password,
1644               trustStoreTypeArgument.getValue(), true);
1645        }
1646        else
1647        {
1648          trustManager = new TrustAllTrustManager();
1649        }
1650
1651        final SSLUtil serverSSLUtil = new SSLUtil(keyManager, trustManager);
1652
1653        final boolean requestCertificate;
1654        final boolean requireCertificate;
1655        final String clientAuthPolicy = sslClientAuthPolicy.getValue();
1656        if (clientAuthPolicy.equalsIgnoreCase(
1657             SSL_CLIENT_AUTH_POLICY_OPTIONAL))
1658        {
1659          requestCertificate = true;
1660          requireCertificate = false;
1661        }
1662        else if (clientAuthPolicy.equalsIgnoreCase(
1663             SSL_CLIENT_AUTH_POLICY_REQUIRED))
1664        {
1665          requestCertificate = true;
1666          requireCertificate = true;
1667        }
1668        else
1669        {
1670          requestCertificate = false;
1671          requireCertificate = false;
1672        }
1673
1674        if (useSSLArgument.isPresent())
1675        {
1676          final SSLUtil clientSSLUtil = new SSLUtil(new TrustAllTrustManager());
1677          serverConfig.setListenerConfigs(
1678               InMemoryListenerConfig.createLDAPSConfig("LDAPS", null,
1679                    listenPort, serverSSLUtil.createSSLServerSocketFactory(),
1680                    clientSSLUtil.createSSLSocketFactory(),
1681                    requestCertificate, requireCertificate));
1682        }
1683        else
1684        {
1685          serverConfig.setListenerConfigs(
1686               InMemoryListenerConfig.createLDAPConfig("LDAP+StartTLS", null,
1687                    listenPort, serverSSLUtil.createSSLSocketFactory(),
1688                    requestCertificate, requireCertificate));
1689        }
1690      }
1691      catch (final Exception e)
1692      {
1693        Debug.debugException(e);
1694        throw new LDAPException(ResultCode.LOCAL_ERROR,
1695             ERR_MEM_DS_TOOL_ERROR_INITIALIZING_SSL.get(
1696                  StaticUtils.getExceptionMessage(e)),
1697             e);
1698      }
1699    }
1700    else
1701    {
1702      serverConfig.setListenerConfigs(InMemoryListenerConfig.createLDAPConfig(
1703           "LDAP", listenPort));
1704    }
1705
1706
1707    // If vendor name and/or vendor version values were provided, then configure
1708    // them for use.
1709    if (vendorNameArgument.isPresent())
1710    {
1711      serverConfig.setVendorName(vendorNameArgument.getValue());
1712    }
1713
1714    if (vendorVersionArgument.isPresent())
1715    {
1716      serverConfig.setVendorVersion(vendorVersionArgument.getValue());
1717    }
1718
1719
1720    // If equality indexing is to be performed, then configure it.
1721    if (equalityIndexArgument.isPresent())
1722    {
1723      serverConfig.setEqualityIndexAttributes(
1724           equalityIndexArgument.getValues());
1725    }
1726
1727
1728    // Update the configuration to indicate whether to generate operational
1729    // attributes.
1730    serverConfig.setGenerateOperationalAttributes(
1731         ! doNotGenerateOperationalAttributesArgument.isPresent());
1732
1733
1734    return serverConfig;
1735  }
1736
1737
1738
1739  /**
1740   * Updates the map with an unsalted password encoder with the provided
1741   * information.
1742   *
1743   * @param  schemeName       The name to use to identify the scheme, without
1744   *                          the curly braces.
1745   * @param  digestAlgorithm  The name of the message digest algorithm to use
1746   *                          for the password encoder.
1747   * @param  encoderMap       The map to which the encoder will bea added.
1748   */
1749  private static void addUnsaltedEncoder(@NotNull final String schemeName,
1750               @NotNull final String digestAlgorithm,
1751               @NotNull final Map<String,InMemoryPasswordEncoder> encoderMap)
1752  {
1753    try
1754    {
1755      final UnsaltedMessageDigestInMemoryPasswordEncoder encoder =
1756           new UnsaltedMessageDigestInMemoryPasswordEncoder(
1757                '{' + schemeName + '}',
1758                Base64PasswordEncoderOutputFormatter.getInstance(),
1759                CryptoHelper.getMessageDigest(digestAlgorithm));
1760      encoderMap.put(StaticUtils.toLowerCase(schemeName), encoder);
1761    }
1762    catch (final Exception e)
1763    {
1764      Debug.debugException(e);
1765    }
1766  }
1767
1768
1769
1770  /**
1771   * Updates the map with a salted password encoder with the provided
1772   * information.
1773   *
1774   * @param  schemeName       The name to use to identify the scheme, without
1775   *                          the curly braces.
1776   * @param  digestAlgorithm  The name of the message digest algorithm to use
1777   *                          for the password encoder.
1778   * @param  encoderMap       The map to which the encoder will bea added.
1779   */
1780  private static void addSaltedEncoder(@NotNull final String schemeName,
1781               @NotNull final String digestAlgorithm,
1782               @NotNull final Map<String,InMemoryPasswordEncoder> encoderMap)
1783  {
1784    try
1785    {
1786      final SaltedMessageDigestInMemoryPasswordEncoder encoder =
1787           new SaltedMessageDigestInMemoryPasswordEncoder(
1788                '{' + schemeName + '}',
1789                Base64PasswordEncoderOutputFormatter.getInstance(),
1790                CryptoHelper.getMessageDigest(digestAlgorithm), 8, true, true);
1791      encoderMap.put(StaticUtils.toLowerCase(schemeName), encoder);
1792    }
1793    catch (final Exception e)
1794    {
1795      Debug.debugException(e);
1796    }
1797  }
1798
1799
1800
1801  /**
1802   * Updates the map with a clear-text password encoder with the provided
1803   * information.
1804   *
1805   * @param  schemeName       The name to use to identify the scheme, without
1806   *                          the curly braces.
1807   * @param  outputFormatter  The output formatter to use.  It may be
1808   *                          {@code null} if the output should remain in the
1809   *                          clear.
1810   * @param  encoderMap       The map to which the encoder will bea added.
1811   */
1812  private static void addClearEncoder(@NotNull final String schemeName,
1813               @Nullable final PasswordEncoderOutputFormatter outputFormatter,
1814               @NotNull final Map<String,InMemoryPasswordEncoder> encoderMap)
1815  {
1816    final ClearInMemoryPasswordEncoder encoder =
1817         new ClearInMemoryPasswordEncoder('{' + schemeName + '}',
1818              outputFormatter);
1819    encoderMap.put(StaticUtils.toLowerCase(schemeName), encoder);
1820  }
1821
1822
1823
1824  /**
1825   * {@inheritDoc}
1826   */
1827  @Override()
1828  @NotNull()
1829  public LinkedHashMap<String[],String> getExampleUsages()
1830  {
1831    final LinkedHashMap<String[],String> exampleUsages =
1832         new LinkedHashMap<>(StaticUtils.computeMapCapacity(2));
1833
1834    final String[] example1Args =
1835    {
1836      "--baseDN", "dc=example,dc=com"
1837    };
1838    exampleUsages.put(example1Args, INFO_MEM_DS_TOOL_EXAMPLE_1.get());
1839
1840    final String[] example2Args =
1841    {
1842      "--baseDN", "dc=example,dc=com",
1843      "--port", "1389",
1844      "--ldifFile", "test.ldif",
1845      "--accessLogFile", "access.log",
1846      "--useDefaultSchema"
1847    };
1848    exampleUsages.put(example2Args, INFO_MEM_DS_TOOL_EXAMPLE_2.get());
1849
1850    return exampleUsages;
1851  }
1852
1853
1854
1855  /**
1856   * Retrieves the in-memory directory server instance that has been created by
1857   * this tool.  It will only be valid after the {@link #doToolProcessing()}
1858   * method has been called.
1859   *
1860   * @return  The in-memory directory server instance that has been created by
1861   *          this tool, or {@code null} if the directory server instance has
1862   *          not been successfully created.
1863   */
1864  @Nullable()
1865  public InMemoryDirectoryServer getDirectoryServer()
1866  {
1867    return directoryServer;
1868  }
1869
1870
1871
1872  /**
1873   * {@inheritDoc}
1874   */
1875  @Override()
1876  public void connectionCreationFailure(@Nullable final Socket socket,
1877                                        @NotNull final Throwable cause)
1878  {
1879    wrapErr(0, WRAP_COLUMN,
1880         ERR_MEM_DS_TOOL_ERROR_ACCEPTING_CONNECTION.get(
1881              StaticUtils.getExceptionMessage(cause)));
1882  }
1883
1884
1885
1886  /**
1887   * {@inheritDoc}
1888   */
1889  @Override()
1890  public void connectionTerminated(
1891                   @NotNull final LDAPListenerClientConnection connection,
1892                   @NotNull final LDAPException cause)
1893  {
1894    wrapErr(0, WRAP_COLUMN,
1895         ERR_MEM_DS_TOOL_CONNECTION_TERMINATED_BY_EXCEPTION.get(
1896              StaticUtils.getExceptionMessage(cause)));
1897  }
1898}