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