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