001/*
002 * Copyright 2010-2020 Ping Identity Corporation
003 * All Rights Reserved.
004 */
005/*
006 * Copyright 2010-2020 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) 2010-2020 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.sdk.unboundidds;
037
038
039
040import java.io.OutputStream;
041import java.io.PrintStream;
042import java.lang.reflect.Constructor;
043import java.util.Arrays;
044import java.util.List;
045
046import com.unboundid.ldap.listener.InMemoryDirectoryServerTool;
047import com.unboundid.ldap.sdk.LDAPException;
048import com.unboundid.ldap.sdk.ResultCode;
049import com.unboundid.ldap.sdk.Version;
050import com.unboundid.ldap.sdk.examples.AuthRate;
051import com.unboundid.ldap.sdk.examples.Base64Tool;
052import com.unboundid.ldap.sdk.examples.IdentifyReferencesToMissingEntries;
053import com.unboundid.ldap.sdk.examples.IdentifyUniqueAttributeConflicts;
054import com.unboundid.ldap.sdk.examples.IndentLDAPFilter;
055import com.unboundid.ldap.sdk.examples.LDAPDebugger;
056import com.unboundid.ldap.sdk.examples.ModRate;
057import com.unboundid.ldap.sdk.examples.SearchRate;
058import com.unboundid.ldap.sdk.examples.SearchAndModRate;
059import com.unboundid.ldap.sdk.examples.TestLDAPSDKPerformance;
060import com.unboundid.ldap.sdk.examples.ValidateLDIF;
061import com.unboundid.ldap.sdk.persist.GenerateSchemaFromSource;
062import com.unboundid.ldap.sdk.persist.GenerateSourceFromSchema;
063import com.unboundid.ldap.sdk.schema.ValidateLDAPSchema;
064import com.unboundid.ldap.sdk.transformations.TransformLDIF;
065import com.unboundid.ldap.sdk.unboundidds.examples.DumpDNs;
066import com.unboundid.ldap.sdk.unboundidds.examples.SubtreeAccessibility;
067import com.unboundid.ldap.sdk.unboundidds.examples.SummarizeAccessLog;
068import com.unboundid.ldap.sdk.unboundidds.tools.CollectSupportData;
069import com.unboundid.ldap.sdk.unboundidds.tools.GenerateTOTPSharedSecret;
070import com.unboundid.ldap.sdk.unboundidds.tools.LDAPCompare;
071import com.unboundid.ldap.sdk.unboundidds.tools.LDAPDelete;
072import com.unboundid.ldap.sdk.unboundidds.tools.LDAPModify;
073import com.unboundid.ldap.sdk.unboundidds.tools.LDAPPasswordModify;
074import com.unboundid.ldap.sdk.unboundidds.tools.LDAPSearch;
075import com.unboundid.ldap.sdk.unboundidds.tools.ManageAccount;
076import com.unboundid.ldap.sdk.unboundidds.tools.SplitLDIF;
077import com.unboundid.ldif.LDIFDiff;
078import com.unboundid.ldif.LDIFModify;
079import com.unboundid.ldif.LDIFSearch;
080import com.unboundid.util.CommandLineTool;
081import com.unboundid.util.Debug;
082import com.unboundid.util.NotNull;
083import com.unboundid.util.Nullable;
084import com.unboundid.util.StaticUtils;
085import com.unboundid.util.ThreadSafety;
086import com.unboundid.util.ThreadSafetyLevel;
087import com.unboundid.util.ssl.TLSCipherSuiteSelector;
088import com.unboundid.util.ssl.cert.ManageCertificates;
089
090import static com.unboundid.ldap.sdk.unboundidds.UnboundIDDSMessages.*;
091
092
093
094/**
095 * This class provides an entry point that may be used to launch other tools
096 * provided as part of the LDAP SDK.  This is primarily a convenience for
097 * someone who just has the jar file and none of the scripts, since you can run
098 * "<CODE>java -jar unboundid-ldapsdk.jar {tool-name} {tool-args}</CODE>"
099 * in order to invoke any of the example tools.  Running just
100 * "<CODE>java -jar unboundid-ldapsdk.jar</CODE>" will display version
101 * information about the LDAP SDK.
102 * <BR>
103 * <BLOCKQUOTE>
104 *   <B>NOTE:</B>  This class, and other classes within the
105 *   {@code com.unboundid.ldap.sdk.unboundidds} package structure, are only
106 *   supported for use against Ping Identity, UnboundID, and
107 *   Nokia/Alcatel-Lucent 8661 server products.  These classes provide support
108 *   for proprietary functionality or for external specifications that are not
109 *   considered stable or mature enough to be guaranteed to work in an
110 *   interoperable way with other types of LDAP servers.
111 * </BLOCKQUOTE>
112 * <BR>
113 * The tool names are case-insensitive.  Supported tool names include:
114 * <UL>
115 *   <LI>authrate -- Launch the {@link AuthRate} tool.</LI>
116 *   <LI>base64 -- Launch the {@link Base64Tool} tool.</LI>
117 *   <LI>collect-support-data -- Launch the
118 *       {@link CollectSupportData} tool.</LI>
119 *   <LI>deliver-one-time-password -- Launch the
120 *       {@link DeliverOneTimePassword} tool.</LI>
121 *   <LI>deliver-password-reset-token -- Launch the
122 *       {@link DeliverPasswordResetToken} tool.</LI>
123 *   <LI>dump-dns -- Launch the {@link DumpDNs} tool.</LI>
124 *   <LI>generate-schema-from-source -- Launch the
125 *       {@link GenerateSchemaFromSource} tool.</LI>
126 *   <LI>generate-source-from-schema -- Launch the
127 *       {@link GenerateSourceFromSchema} tool.</LI>
128 *   <LI>generate-totp-shared-secret -- Launch the
129 *       {@link GenerateTOTPSharedSecret} tool.</LI>
130 *   <LI>identify-references-to-missing-entries -- Launch the
131 *       {@link IdentifyReferencesToMissingEntries} tool.</LI>
132 *   <LI>identify-unique-attribute-conflicts -- Launch the
133 *       {@link IdentifyUniqueAttributeConflicts} tool.</LI>
134 *   <LI>indent-ldap-filter -- Launch the {@link IndentLDAPFilter} tool.</LI>
135 *   <LI>in-memory-directory-server -- Launch the
136 *       {@link InMemoryDirectoryServerTool} tool.</LI>
137 *   <LI>ldapcompare -- Launch the {@link LDAPCompare} tool.</LI>
138 *   <LI>ldapdelete -- Launch the {@link LDAPDelete} tool.</LI>
139 *   <LI>ldapmodify -- Launch the {@link LDAPModify} tool.</LI>
140 *   <LI>ldappasswordmodify -- Launch the {@link LDAPPasswordModify} tool.</LI>
141 *   <LI>ldapsearch -- Launch the {@link LDAPSearch} tool.</LI>
142 *   <LI>ldap-debugger -- Launch the {@link LDAPDebugger} tool.</LI>
143 *   <LI>ldifmodify -- Launch the {@link LDIFModify} tool.</LI>
144 *   <LI>ldifsearch -- Launch the {@link LDIFSearch} tool.</LI>
145 *   <LI>ldif-diff -- Launch the {@link LDIFDiff} tool.</LI>
146 *   <LI>manage-account -- Launch the {@link ManageAccount} tool.</LI>
147 *   <LI>manage-certificates -- Launch the {@link ManageCertificates} tool.</LI>
148 *   <LI>modrate -- Launch the {@link ModRate} tool.</LI>
149 *   <LI>move-subtree -- Launch the {@link MoveSubtree} tool.</LI>
150 *   <LI>register-yubikey-otp-device -- Launch the
151 *       {@link RegisterYubiKeyOTPDevice} tool.</LI>
152 *   <LI>searchrate -- Launch the {@link SearchRate} tool.</LI>
153 *   <LI>search-and-mod-rate -- Launch the {@link SearchAndModRate} tool.</LI>
154 *   <LI>split-ldif -- Launch the {@link SplitLDIF} tool.</LI>
155 *   <LI>subtree-accessibility -- Launch the {@link SubtreeAccessibility}
156 *       tool.</LI>
157 *   <LI>summarize-access-log -- Launch the {@link SummarizeAccessLog}
158 *       tool.</LI>
159 *   <LI>test-ldap-sdk-performance -- Launch the {@link TLSCipherSuiteSelector}
160 *       tool.</LI>
161 *   <LI>tls-cipher-suite-selector -- Launch the {@link TLSCipherSuiteSelector}
162 *       tool.</LI>
163 *   <LI>transform-ldif -- Launch the {@link TransformLDIF} tool.</LI>
164 *   <LI>validate-ldap-schema -- Launch the {@link ValidateLDAPSchema}
165 *       tool.</LI>
166 *   <LI>validate-ldif -- Launch the {@link ValidateLDIF} tool.</LI>
167 *   <LI>version -- Display version information for the LDAP SDK.</LI>
168 * </UL>
169 */
170@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE)
171public final class Launcher
172{
173  /**
174   * Prevent this utility class from being instantiated.
175   */
176  private Launcher()
177  {
178    // No implementation required.
179  }
180
181
182
183  /**
184   * Parses the command-line arguments and performs any appropriate processing
185   * for this program.
186   *
187   * @param  args  The command-line arguments provided to this program.
188   */
189  public static void main(@NotNull final String... args)
190  {
191    main(System.out, System.err, args);
192  }
193
194
195
196  /**
197   * Parses the command-line arguments and performs any appropriate processing
198   * for this program.
199   *
200   * @param  outStream  The output stream to which standard out should be
201   *                    written.  It may be {@code null} if output should be
202   *                    suppressed.
203   * @param  errStream  The output stream to which standard error should be
204   *                    written.  It may be {@code null} if error messages
205   *                    should be suppressed.
206   * @param  args       The command-line arguments provided to this program.
207   *
208   * @return  A result code with information about the status of processing.
209   */
210  @NotNull()
211  public static ResultCode main(@Nullable final OutputStream outStream,
212                                @Nullable final OutputStream errStream,
213                                @NotNull final String... args)
214  {
215    if ((args == null) || (args.length == 0) ||
216        args[0].equalsIgnoreCase("version"))
217    {
218      if (outStream != null)
219      {
220        final PrintStream out = new PrintStream(outStream);
221        for (final String line : Version.getVersionLines())
222        {
223          out.println(line);
224        }
225      }
226
227      return ResultCode.SUCCESS;
228    }
229
230    final String firstArg = StaticUtils.toLowerCase(args[0]);
231    final String[] remainingArgs = new String[args.length - 1];
232    System.arraycopy(args, 1, remainingArgs, 0, remainingArgs.length);
233
234    if (firstArg.equals("authrate"))
235    {
236      return AuthRate.main(remainingArgs, outStream, errStream);
237    }
238    else if (firstArg.equals("base64"))
239    {
240      return Base64Tool.main(System.in, outStream, errStream, remainingArgs);
241    }
242    else if (firstArg.equals("collect-support-data"))
243    {
244      return CollectSupportData.main(outStream, errStream, remainingArgs);
245    }
246    else if (firstArg.equals("deliver-one-time-password"))
247    {
248      return DeliverOneTimePassword.main(remainingArgs, outStream, errStream);
249    }
250    else if (firstArg.equals("deliver-password-reset-token"))
251    {
252      return DeliverPasswordResetToken.main(remainingArgs, outStream,
253           errStream);
254    }
255    else if (firstArg.equals("dump-dns"))
256    {
257      return DumpDNs.main(remainingArgs, outStream, errStream);
258    }
259    else if (firstArg.equals("identify-references-to-missing-entries"))
260    {
261      return IdentifyReferencesToMissingEntries.main(remainingArgs, outStream,
262           errStream);
263    }
264    else if (firstArg.equals("identify-unique-attribute-conflicts"))
265    {
266      return IdentifyUniqueAttributeConflicts.main(remainingArgs, outStream,
267           errStream);
268    }
269    else if (firstArg.equals("in-memory-directory-server"))
270    {
271      return InMemoryDirectoryServerTool.main(remainingArgs, outStream,
272           errStream);
273    }
274    else if (firstArg.equals("indent-ldap-filter"))
275    {
276      return IndentLDAPFilter.main(outStream, errStream, remainingArgs);
277    }
278    else if (firstArg.equals("generate-schema-from-source"))
279    {
280      return GenerateSchemaFromSource.main(remainingArgs, outStream, errStream);
281    }
282    else if (firstArg.equals("generate-source-from-schema"))
283    {
284      return GenerateSourceFromSchema.main(remainingArgs, outStream, errStream);
285    }
286    else if (firstArg.equals("generate-totp-shared-secret"))
287    {
288      return GenerateTOTPSharedSecret.main(outStream, errStream, remainingArgs);
289    }
290    else if (firstArg.equals("ldapcompare"))
291    {
292      return LDAPCompare.main(outStream, errStream, remainingArgs);
293    }
294    else if (firstArg.equals("ldapdelete"))
295    {
296      return LDAPDelete.main(System.in, outStream, errStream, remainingArgs);
297    }
298    else if (firstArg.equals("ldapmodify"))
299    {
300      return LDAPModify.main(System.in, outStream, errStream, remainingArgs);
301    }
302    else if (firstArg.equals("ldappasswordmodify"))
303    {
304      return LDAPPasswordModify.main(outStream, errStream, remainingArgs);
305    }
306    else if (firstArg.equals("ldapsearch"))
307    {
308      return LDAPSearch.main(outStream, errStream, remainingArgs);
309    }
310    else if (firstArg.equals("ldap-debugger"))
311    {
312      return LDAPDebugger.main(remainingArgs, outStream, errStream);
313    }
314    else if (firstArg.equals("ldifmodify"))
315    {
316      return LDIFModify.main(outStream, errStream, remainingArgs);
317    }
318    else if (firstArg.equals("ldifsearch"))
319    {
320      return LDIFSearch.main(outStream, errStream, remainingArgs);
321    }
322    else if (firstArg.equals("ldif-diff"))
323    {
324      return LDIFDiff.main(outStream, errStream, remainingArgs);
325    }
326    else if (firstArg.equals("manage-account"))
327    {
328      return ManageAccount.main(outStream, errStream, remainingArgs);
329    }
330    else if (firstArg.equals("manage-certificates"))
331    {
332      return ManageCertificates.main(System.in, outStream, errStream,
333           remainingArgs);
334    }
335    else if (firstArg.equals("modrate"))
336    {
337      return ModRate.main(remainingArgs, outStream, errStream);
338    }
339    else if (firstArg.equals("move-subtree"))
340    {
341      return MoveSubtree.main(remainingArgs, outStream, errStream);
342    }
343    else if (firstArg.equals("register-yubikey-otp-device"))
344    {
345      return RegisterYubiKeyOTPDevice.main(remainingArgs, outStream, errStream);
346    }
347    else if (firstArg.equals("searchrate"))
348    {
349      return SearchRate.main(remainingArgs, outStream, errStream);
350    }
351    else if (firstArg.equals("search-and-mod-rate"))
352    {
353      return SearchAndModRate.main(remainingArgs, outStream, errStream);
354    }
355    else if (firstArg.equals("split-ldif"))
356    {
357      return SplitLDIF.main(outStream, errStream, remainingArgs);
358    }
359    else if (firstArg.equals("subtree-accessibility"))
360    {
361      return SubtreeAccessibility.main(remainingArgs, outStream, errStream);
362    }
363    else if (firstArg.equals("summarize-access-log"))
364    {
365      return SummarizeAccessLog.main(remainingArgs, outStream, errStream);
366    }
367    else if (firstArg.equals("test-ldap-sdk-performance"))
368    {
369      return TestLDAPSDKPerformance.main(outStream, errStream, remainingArgs);
370    }
371    else if (firstArg.equals("tls-cipher-suite-selector"))
372    {
373      return TLSCipherSuiteSelector.main(outStream, errStream, remainingArgs);
374    }
375    else if (firstArg.equals("transform-ldif"))
376    {
377      return TransformLDIF.main(outStream, errStream, remainingArgs);
378    }
379    else if (firstArg.equals("validate-ldap-schema"))
380    {
381      return ValidateLDAPSchema.main(outStream, errStream, remainingArgs);
382    }
383    else if (firstArg.equals("validate-ldif"))
384    {
385      return ValidateLDIF.main(remainingArgs, outStream, errStream);
386    }
387    else
388    {
389      if (errStream != null)
390      {
391        final PrintStream err = new PrintStream(errStream);
392        err.println("Unrecognized tool name '" + args[0] + '\'');
393        err.println("Supported tool names include:");
394        err.println("     authrate");
395        err.println("     base64");
396        err.println("     collect-support-data");
397        err.println("     deliver-one-time-password");
398        err.println("     deliver-password-reset-token");
399        err.println("     dump-dns");
400        err.println("     generate-schema-from-source");
401        err.println("     generate-source-from-schema");
402        err.println("     generate-totp-shared-secret");
403        err.println("     identify-references-to-missing-entries");
404        err.println("     identify-unique-attribute-conflicts");
405        err.println("     indent-ldap-filter");
406        err.println("     in-memory-directory-server");
407        err.println("     ldapcompare");
408        err.println("     ldapdelete");
409        err.println("     ldapmodify");
410        err.println("     ldappasswordmodify");
411        err.println("     ldapsearch");
412        err.println("     ldap-debugger");
413        err.println("     ldifmodify");
414        err.println("     ldifsearch");
415        err.println("     ldif-diff");
416        err.println("     manage-account");
417        err.println("     manage-certificates");
418        err.println("     modrate");
419        err.println("     move-subtree");
420        err.println("     register-yubikey-otp-device");
421        err.println("     searchrate");
422        err.println("     search-and-mod-rate");
423        err.println("     split-ldif");
424        err.println("     subtree-accessibility");
425        err.println("     summarize-access-log");
426        err.println("     test-ldap-sdk-performance");
427        err.println("     tls-cipher-suite-selector");
428        err.println("     transform-ldif");
429        err.println("     validate-ldap-schema");
430        err.println("     validate-ldif");
431        err.println("     version");
432      }
433
434      return ResultCode.PARAM_ERROR;
435    }
436  }
437
438
439
440  /**
441   * Retrieves a list of all of the classes that provide the implementations for
442   * all of the command-line tools included with the LDAP SDK.
443   *
444   * @return  A list of all of the classes that provide  the implementations for
445   *          all of the command-line tools included with the LDAP SDK.
446   */
447  @NotNull()
448  public static List<Class<? extends CommandLineTool>> getToolClasses()
449  {
450    return Arrays.asList(
451         AuthRate.class,
452         Base64Tool.class,
453         CollectSupportData.class,
454         DeliverOneTimePassword.class,
455         DeliverPasswordResetToken.class,
456         DumpDNs.class,
457         GenerateSchemaFromSource.class,
458         GenerateSourceFromSchema.class,
459         GenerateTOTPSharedSecret.class,
460         IdentifyReferencesToMissingEntries.class,
461         IdentifyUniqueAttributeConflicts.class,
462         IndentLDAPFilter.class,
463         InMemoryDirectoryServerTool.class,
464         LDAPCompare.class,
465         LDAPDebugger.class,
466         LDAPDelete.class,
467         LDAPModify.class,
468         LDAPPasswordModify.class,
469         LDAPSearch.class,
470         LDIFDiff.class,
471         LDIFModify.class,
472         LDIFSearch.class,
473         ManageAccount.class,
474         ManageCertificates.class,
475         ModRate.class,
476         MoveSubtree.class,
477         RegisterYubiKeyOTPDevice.class,
478         SearchAndModRate.class,
479         SearchRate.class,
480         SplitLDIF.class,
481         SubtreeAccessibility.class,
482         SummarizeAccessLog.class,
483         TestLDAPSDKPerformance.class,
484         TLSCipherSuiteSelector.class,
485         TransformLDIF.class,
486         ValidateLDAPSchema.class,
487         ValidateLDIF.class);
488  }
489
490
491
492  /**
493   * Retrieves an instance of the specified type of command-line tool with the
494   * given output and error streams.  The tool class must provide a two-argument
495   * constructor in which the first argument is a possibly-{@code null}
496   * {@code OutputStream} to use for standard output, and the second argument is
497   * a possibly-{@code null} {@code OutputStream} to use for standard error.
498   *
499   * @param  toolClass  The class that provides the implementation for the
500   *                    desired command-line tool.
501   * @param  outStream  The output stream to which standard out should be
502   *                    written.  It may be {@code null} if output should be
503   *                    suppressed.
504   * @param  errStream  The output stream to which standard error should be
505   *                    written.  It may be {@code null} if error messages
506   *                    should be suppressed.
507   *
508   * @return  An instance of the specified command-line tool.
509   *
510   * @throws  LDAPException  If a problem occurs while attempting to create an
511   *                         instance of the requested tool.
512   */
513  @NotNull()
514  public static CommandLineTool getToolInstance(
515                     @NotNull final Class<?> toolClass,
516                     @Nullable final OutputStream outStream,
517                     @Nullable final OutputStream errStream)
518         throws LDAPException
519  {
520    if (! CommandLineTool.class.isAssignableFrom(toolClass))
521    {
522      throw new LDAPException(ResultCode.PARAM_ERROR,
523           ERR_LAUNCHER_CLASS_NOT_COMMAND_LINE_TOOL.get(toolClass.getName(),
524                CommandLineTool.class.getName()));
525    }
526
527    final Constructor<?> constructor;
528    try
529    {
530      constructor = toolClass.getConstructor(OutputStream.class,
531           OutputStream.class);
532    }
533    catch (final Exception e)
534    {
535      Debug.debugException(e);
536      throw new LDAPException(ResultCode.PARAM_ERROR,
537           ERR_LAUNCHER_TOOL_CLASS_MISSING_EXPECTED_CONSTRUCTOR.get(
538                toolClass.getName()),
539           e);
540    }
541
542
543    try
544    {
545      return (CommandLineTool) constructor.newInstance(outStream, errStream);
546    }
547    catch (final Exception e)
548    {
549      Debug.debugException(e);
550      throw new LDAPException(ResultCode.LOCAL_ERROR,
551           ERR_LAUNCHER_ERROR_INVOKING_CONSTRUCTOR.get(toolClass.getName(),
552                StaticUtils.getExceptionMessage(e)),
553           e);
554    }
555  }
556}