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