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