mirror of https://github.com/OpenIdentityPlatform/OpenDJ.git

Violette Roche-Montane
25.46.2014 56a730cb4c5473349dda9fecde648dd406ed6f35
Checkpoint for OPENDJ-1343 Migrate dsconfig
- Fixed checkstyle errors on DSConfig and LDAPManagementContextFactory.

2 files modified
2131 ■■■■ changed files
opendj-config/src/main/java/org/forgerock/opendj/config/dsconfig/DSConfig.java 1943 ●●●● patch | view | raw | blame | history
opendj-config/src/main/java/org/forgerock/opendj/config/dsconfig/LDAPManagementContextFactory.java 188 ●●●●● patch | view | raw | blame | history
opendj-config/src/main/java/org/forgerock/opendj/config/dsconfig/DSConfig.java
@@ -90,1094 +90,945 @@
import com.forgerock.opendj.cli.SubCommand;
import com.forgerock.opendj.cli.SubCommandArgumentParser;
/**
 * This class provides a command-line tool which enables
 * administrators to configure the Directory Server.
 * This class provides a command-line tool which enables administrators to configure the Directory Server.
 */
public final class DSConfig extends ConsoleApplication {
  /** The logger */
  private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass();
  /** The name of this tool. */
  final static String DSCONFIGTOOLNAME = "dsconfig";
    /** The logger. */
    private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass();
  /**
   * The name of a command-line script used to launch an administrative tool.
   */
  final static String PROPERTY_SCRIPT_NAME = "org.opends.server.scriptName";
  /**
   * A menu call-back which runs a sub-command interactively.
   */
  private class SubCommandHandlerMenuCallback implements MenuCallback<Integer> {
    /** The sub-command handler. */
    private final SubCommandHandler handler;
    /** The name of this tool. */
    final static String DSCONFIGTOOLNAME = "dsconfig";
    /**
     * Creates a new sub-command handler call-back.
     *
     * @param handler
     *          The sub-command handler.
     * The name of a command-line script used to launch an administrative tool.
     */
    public SubCommandHandlerMenuCallback(SubCommandHandler handler) {
      this.handler = handler;
    }
    /** {@inheritDoc} */
    @Override
    public MenuResult<Integer> invoke(ConsoleApplication app)
    throws ClientException {
      try {
        MenuResult<Integer> result = handler.run(app, factory);
        if (result.isQuit()) {
          return result;
        } else {
          if (result.isSuccess() && isInteractive() &&
              handler.isCommandBuilderUseful())
          {
            printCommandBuilder(getCommandBuilder(handler));
          }
          // Success or cancel.
          app.println();
          app.pressReturnToContinue();
          return MenuResult.again();
        }
      } catch (ArgumentException e) {
        app.println(e.getMessageObject());
        return MenuResult.success(1);
      } catch (ClientException e) {
        app.println(e.getMessageObject());
        return MenuResult.success(e.getReturnCode());
      }
    }
  }
  /** The interactive mode sub-menu implementation. */
  private class SubMenuCallback implements MenuCallback<Integer> {
    /** The menu. */
    private final Menu<Integer> menu;
    final static String PROPERTY_SCRIPT_NAME = "org.opends.server.scriptName";
    /**
     * Creates a new sub-menu implementation.
     *
     * @param app
     *          The console application.
     * @param rd
     *          The relation definition.
     * @param ch
     *          The optional create sub-command.
     * @param dh
     *          The optional delete sub-command.
     * @param lh
     *          The optional list sub-command.
     * @param sh
     *          The option set-prop sub-command.
     * A menu call-back which runs a sub-command interactively.
     */
    public SubMenuCallback(ConsoleApplication app, RelationDefinition<?, ?> rd,
        CreateSubCommandHandler<?, ?> ch, DeleteSubCommandHandler dh,
        ListSubCommandHandler lh, SetPropSubCommandHandler sh) {
      LocalizableMessage userFriendlyName = rd.getUserFriendlyName();
    private class SubCommandHandlerMenuCallback implements MenuCallback<Integer> {
      LocalizableMessage userFriendlyPluralName = null;
      if (rd instanceof InstantiableRelationDefinition<?,?>) {
        InstantiableRelationDefinition<?, ?> ir =
          (InstantiableRelationDefinition<?, ?>) rd;
        userFriendlyPluralName = ir.getUserFriendlyPluralName();
      } else if (rd instanceof SetRelationDefinition<?,?>) {
        SetRelationDefinition<?, ?> sr =
          (SetRelationDefinition<?, ?>) rd;
        userFriendlyPluralName = sr.getUserFriendlyPluralName();
      }
        /** The sub-command handler. */
        private final SubCommandHandler handler;
      final MenuBuilder<Integer> builder = new MenuBuilder<Integer>(app);
      builder.setTitle(INFO_DSCFG_HEADING_COMPONENT_MENU_TITLE
          .get(userFriendlyName));
      builder.setPrompt(INFO_DSCFG_HEADING_COMPONENT_MENU_PROMPT.get());
      if (lh != null) {
        final SubCommandHandlerMenuCallback callback =
          new SubCommandHandlerMenuCallback(lh);
        if (userFriendlyPluralName != null) {
          builder.addNumberedOption(
              INFO_DSCFG_OPTION_COMPONENT_MENU_LIST_PLURAL
                  .get(userFriendlyPluralName), callback);
        } else {
          builder
          .addNumberedOption(INFO_DSCFG_OPTION_COMPONENT_MENU_LIST_SINGULAR
              .get(userFriendlyName), callback);
        /**
         * Creates a new sub-command handler call-back.
         *
         * @param handler
         *            The sub-command handler.
         */
        public SubCommandHandlerMenuCallback(SubCommandHandler handler) {
            this.handler = handler;
        }
      }
      if (ch != null) {
        final SubCommandHandlerMenuCallback callback =
            new SubCommandHandlerMenuCallback(ch);
        builder.addNumberedOption(INFO_DSCFG_OPTION_COMPONENT_MENU_CREATE
            .get(userFriendlyName), callback);
      }
      if (sh != null) {
        final SubCommandHandlerMenuCallback callback =
            new SubCommandHandlerMenuCallback(sh);
        if (userFriendlyPluralName != null) {
          builder.addNumberedOption(
              INFO_DSCFG_OPTION_COMPONENT_MENU_MODIFY_PLURAL
                  .get(userFriendlyName), callback);
        } else {
          builder.addNumberedOption(
              INFO_DSCFG_OPTION_COMPONENT_MENU_MODIFY_SINGULAR
                  .get(userFriendlyName), callback);
        }
      }
      if (dh != null) {
        final SubCommandHandlerMenuCallback callback =
            new SubCommandHandlerMenuCallback(dh);
        builder.addNumberedOption(INFO_DSCFG_OPTION_COMPONENT_MENU_DELETE
            .get(userFriendlyName), callback);
      }
      builder.addBackOption(true);
      builder.addQuitOption();
      this.menu = builder.toMenu();
    }
    /** {@inheritDoc} */
    @Override
    public final MenuResult<Integer> invoke(ConsoleApplication app)
    throws ClientException {
      try {
        app.println();
        app.println();
        MenuResult<Integer> result = menu.run();
        if (result.isCancel()) {
          return MenuResult.again();
        }
        return result;
      } catch (ClientException e) {
        app.println(e.getMessageObject());
        return MenuResult.success(1);
      }
    }
  }
  /**
   * The type name which will be used for the most generic managed
   * object types when they are instantiable and intended for
   * customization only.
   */
  public static final String CUSTOM_TYPE = "custom";
  /**
   * The type name which will be used for the most generic managed
   * object types when they are instantiable and not intended for
   * customization.
   */
  public static final String GENERIC_TYPE = "generic";
  private long sessionStartTime;
  private boolean sessionStartTimePrinted = false;
  private int sessionEquivalentOperationNumber = 0;
  /**
   * Provides the command-line arguments to the main application for
   * processing.
   *
   * @param args
   *          The set of command-line arguments provided to this
   *          program.
   */
  public static void main(String[] args) {
    int exitCode = main(args, System.out, System.err);
    if (exitCode != ReturnCode.SUCCESS.get()) {
      System.exit(filterExitCode(exitCode));
    }
  }
  /**
   * Provides the command-line arguments to the main application for
   * processing and returns the exit code as an integer.
   *
   * @param args
   *          The set of command-line arguments provided to this
   *          program.
   * @param outStream
   *          The output stream for standard output.
   * @param errStream
   *          The output stream for standard error.
   * @return Zero to indicate that the program completed successfully,
   *         or non-zero to indicate that an error occurred.
   */
  public static int main(String[] args, OutputStream outStream,
      OutputStream errStream)
  {
    final DSConfig app = new DSConfig(System.in, outStream, errStream);
    app.sessionStartTime = System.currentTimeMillis();
    /*
     * FIXME: obtain path info from system properties.
     */
    if (!ConfigurationFramework.getInstance().isInitialized())
    {
      try
      {
        ConfigurationFramework.getInstance().initialize();
      }
      catch (ConfigException e)
      {
        app.println(e.getMessageObject());
        return ReturnCode.ERROR_INITIALIZING_SERVER.get();
      }
    }
    // Run the application.
    return app.run(args);
  }
  /** The argument which should be used to request advanced mode. */
  private BooleanArgument advancedModeArgument;
  /**
   * The factory which the application should use to retrieve its management
   * context.
   */
  private LDAPManagementContextFactory factory = null;
  /**
   * Flag indicating whether or not the global arguments have already been
   * initialized.
   */
  private boolean globalArgumentsInitialized = false;
  /** The sub-command handler factory. */
  private SubCommandHandlerFactory handlerFactory = null;
  /** Mapping of sub-commands to their implementations. */
  private final Map<SubCommand, SubCommandHandler> handlers =
    new HashMap<SubCommand, SubCommandHandler>();
  /** Indicates whether or not a sub-command was provided. */
  private boolean hasSubCommand = true;
  /** The argument which should be used to read dsconfig commands from a file. */
  private StringArgument batchFileArgument;
  /**
   * The argument which should be used to request non interactive behavior.
   */
  private BooleanArgument noPromptArgument;
  /**
   * The argument that the user must set to display the equivalent
   * non-interactive mode argument.
   */
  private BooleanArgument displayEquivalentArgument;
  /**
   * The argument that allows the user to dump the equivalent non-interactive
   * command to a file.
   */
  private StringArgument equivalentCommandFileArgument;
  /** The command-line argument parser. */
  private final SubCommandArgumentParser parser;
  /** The argument which should be used to request quiet output. */
  private BooleanArgument quietArgument;
  /** The argument which should be used to request script-friendly output. */
  private BooleanArgument scriptFriendlyArgument;
  /** The argument which should be used to request usage information. */
  private BooleanArgument showUsageArgument;
  /** The argument which should be used to request verbose output. */
  private BooleanArgument verboseArgument;
  /** The argument which should be used to indicate the properties file. */
  private StringArgument propertiesFileArgument;
  /**
   * The argument which should be used to indicate that we will not look for
   * properties file.
   */
  private BooleanArgument noPropertiesFileArgument;
  /**
   * Creates a new DSConfig application instance.
   *
   * @param in
   *          The application input stream.
   * @param out
   *          The application output stream.
   * @param err
   *          The application error stream.
   */
  private DSConfig(InputStream in, OutputStream out, OutputStream err) {
    super(new PrintStream(out), new PrintStream(err));
    this.parser = new SubCommandArgumentParser(getClass().getName(),
        INFO_DSCFG_TOOL_DESCRIPTION.get(), false);
  }
  /** {@inheritDoc} */
  @Override
  public boolean isAdvancedMode() {
    return advancedModeArgument.isPresent();
  }
  /** {@inheritDoc} */
  @Override
  public boolean isInteractive() {
    return !noPromptArgument.isPresent();
  }
  /** {@inheritDoc} */
  @Override
  public boolean isMenuDrivenMode() {
    return !hasSubCommand;
  }
  /** {@inheritDoc} */
  @Override
  public boolean isQuiet() {
    return quietArgument.isPresent();
  }
  /** {@inheritDoc} */
  @Override
  public boolean isScriptFriendly() {
    return scriptFriendlyArgument.isPresent();
  }
  /** {@inheritDoc} */
  @Override
  public boolean isVerbose() {
    return verboseArgument.isPresent();
  }
  /** Displays the provided message followed by a help usage reference. */
  private void displayMessageAndUsageReference(LocalizableMessage message) {
    println(message);
    println();
    println(parser.getHelpUsageReference());
  }
  /**
   * Registers the global arguments with the argument parser.
   *
   * @throws ArgumentException
   *           If a global argument could not be registered.
   */
  private void initializeGlobalArguments(String[] args)
  throws ArgumentException {
    if (!globalArgumentsInitialized) {
      verboseArgument = CommonArguments.getVerbose();
      quietArgument = CommonArguments.getQuiet();
      scriptFriendlyArgument = CommonArguments.getScriptFriendly();
      noPromptArgument = CommonArguments.getNoPrompt();
      advancedModeArgument = CommonArguments.getAdvancedMode();
      showUsageArgument = CommonArguments.getShowUsage();
      batchFileArgument = new StringArgument(OPTION_LONG_BATCH_FILE_PATH,
          OPTION_SHORT_BATCH_FILE_PATH, OPTION_LONG_BATCH_FILE_PATH,
          false, false, true, INFO_BATCH_FILE_PATH_PLACEHOLDER.get(),
          null, null,
          INFO_DESCRIPTION_BATCH_FILE_PATH.get());
      displayEquivalentArgument = new BooleanArgument(
          OPTION_LONG_DISPLAY_EQUIVALENT,
          null, OPTION_LONG_DISPLAY_EQUIVALENT,
          INFO_DSCFG_DESCRIPTION_DISPLAY_EQUIVALENT.get());
      equivalentCommandFileArgument = new StringArgument(
          OPTION_LONG_EQUIVALENT_COMMAND_FILE_PATH, null,
          OPTION_LONG_EQUIVALENT_COMMAND_FILE_PATH, false, false, true,
          INFO_PATH_PLACEHOLDER.get(), null, null,
          INFO_DSCFG_DESCRIPTION_EQUIVALENT_COMMAND_FILE_PATH.get());
      propertiesFileArgument = new StringArgument("propertiesFilePath",
          null, OPTION_LONG_PROP_FILE_PATH,
          false, false, true, INFO_PROP_FILE_PATH_PLACEHOLDER.get(), null, null,
          INFO_DESCRIPTION_PROP_FILE_PATH.get());
      noPropertiesFileArgument = new BooleanArgument(
          "noPropertiesFileArgument", null, OPTION_LONG_NO_PROP_FILE,
          INFO_DESCRIPTION_NO_PROP_FILE.get());
      // Register the global arguments.
      ArgumentGroup toolOptionsGroup = new ArgumentGroup(
          INFO_DSCFG_DESCRIPTION_OPTIONS_ARGS.get(), 2);
      parser.addGlobalArgument(advancedModeArgument, toolOptionsGroup);
      parser.addGlobalArgument(showUsageArgument);
      parser.setUsageArgument(showUsageArgument, getOutputStream());
      parser.addGlobalArgument(verboseArgument);
      parser.addGlobalArgument(quietArgument);
      parser.addGlobalArgument(scriptFriendlyArgument);
      parser.addGlobalArgument(noPromptArgument);
      parser.addGlobalArgument(batchFileArgument);
      parser.addGlobalArgument(displayEquivalentArgument);
      parser.addGlobalArgument(equivalentCommandFileArgument);
      parser.addGlobalArgument(propertiesFileArgument);
      parser.setFilePropertiesArgument(propertiesFileArgument);
      parser.addGlobalArgument(noPropertiesFileArgument);
      parser.setNoPropertiesFileArgument(noPropertiesFileArgument);
      globalArgumentsInitialized = true;
    }
  }
  /**
   * Registers the sub-commands with the argument parser. This method
   * uses the administration framework introspection APIs to determine
   * the overall structure of the command-line.
   *
   * @throws ArgumentException
   *           If a sub-command could not be created.
   */
  private void initializeSubCommands() throws ArgumentException {
    if (handlerFactory == null) {
      handlerFactory = new SubCommandHandlerFactory(parser);
      final Comparator<SubCommand> c = new Comparator<SubCommand>() {
        /** {@inheritDoc} */
        @Override
        public int compare(SubCommand o1, SubCommand o2) {
          return o1.getName().compareTo(o2.getName());
        public MenuResult<Integer> invoke(ConsoleApplication app) throws ClientException {
            try {
                MenuResult<Integer> result = handler.run(app, factory);
                if (result.isQuit()) {
                    return result;
                } else {
                    if (result.isSuccess() && isInteractive() && handler.isCommandBuilderUseful()) {
                        printCommandBuilder(getCommandBuilder(handler));
                    }
                    // Success or cancel.
                    app.println();
                    app.pressReturnToContinue();
                    return MenuResult.again();
                }
            } catch (ArgumentException e) {
                app.println(e.getMessageObject());
                return MenuResult.success(1);
            } catch (ClientException e) {
                app.println(e.getMessageObject());
                return MenuResult.success(e.getReturnCode());
            }
        }
      };
      Map<Tag, SortedSet<SubCommand>> groups =
        new TreeMap<Tag, SortedSet<SubCommand>>();
      SortedSet<SubCommand> allSubCommands = new TreeSet<SubCommand>(c);
      for (SubCommandHandler handler : handlerFactory
          .getAllSubCommandHandlers()) {
        SubCommand sc = handler.getSubCommand();
        handlers.put(sc, handler);
        allSubCommands.add(sc);
        // Add the sub-command to its groups.
        for (Tag tag : handler.getTags()) {
          SortedSet<SubCommand> group = groups.get(tag);
          if (group == null) {
            group = new TreeSet<SubCommand>(c);
            groups.put(tag, group);
          }
          group.add(sc);
        }
      }
      // Register the usage arguments.
      for (Map.Entry<Tag, SortedSet<SubCommand>> group : groups.entrySet()) {
        Tag tag = group.getKey();
        SortedSet<SubCommand> subCommands = group.getValue();
        String option = OPTION_LONG_HELP + "-" + tag.getName();
        String synopsis = tag.getSynopsis().toString().toLowerCase();
        BooleanArgument arg = new BooleanArgument(option, null, option,
            INFO_DSCFG_DESCRIPTION_SHOW_GROUP_USAGE.get(synopsis));
        parser.addGlobalArgument(arg);
        parser.setUsageGroupArgument(arg, subCommands);
      }
      // Register the --help-all argument.
      String option = OPTION_LONG_HELP + "-all";
      BooleanArgument arg = new BooleanArgument(option, null, option,
          INFO_DSCFG_DESCRIPTION_SHOW_GROUP_USAGE_ALL.get());
      parser.addGlobalArgument(arg);
      parser.setUsageGroupArgument(arg, allSubCommands);
    }
  }
  /**
   * Parses the provided command-line arguments and makes the
   * appropriate changes to the Directory Server configuration.
   *
   * @param args
   *          The command-line arguments provided to this program.
   * @return The exit code from the configuration processing. A
   *         nonzero value indicates that there was some kind of
   *         problem during the configuration processing.
   */
  private int run(String[] args) {
    // Register global arguments and sub-commands.
    try {
      initializeGlobalArguments(args);
      initializeSubCommands();
    } catch (ArgumentException e) {
      println(ERR_CANNOT_INITIALIZE_ARGS.get(e.getMessage()));
      return ReturnCode.ERROR_USER_DATA.get();
    }
    ConnectionFactoryProvider cfp = null;
    try
    {
      cfp =
          new ConnectionFactoryProvider(parser, this,
              CliConstants.DEFAULT_ROOT_USER_DN,
              CliConstants.DEFAULT_ADMINISTRATION_CONNECTOR_PORT, true, null);
      cfp.setIsAnAdminConnection();
    /** The interactive mode sub-menu implementation. */
    private class SubMenuCallback implements MenuCallback<Integer> {
      // Parse the command-line arguments provided to this program.
      parser.parseArguments(args);
      checkForConflictingArguments();
    }
    catch (ArgumentException ae)
    {
      displayMessageAndUsageReference(ERR_ERROR_PARSING_ARGS.get(ae
          .getMessage()));
      return ReturnCode.CONFLICTING_ARGS.get();
    }
        /** The menu. */
        private final Menu<Integer> menu;
    // If the usage/version argument was provided, then we don't need
    // to do anything else.
    if (parser.usageOrVersionDisplayed()) {
      return ReturnCode.SUCCESS.get();
    }
        /**
         * Creates a new sub-menu implementation.
         *
         * @param app
         *            The console application.
         * @param rd
         *            The relation definition.
         * @param ch
         *            The optional create sub-command.
         * @param dh
         *            The optional delete sub-command.
         * @param lh
         *            The optional list sub-command.
         * @param sh
         *            The option set-prop sub-command.
         */
        public SubMenuCallback(ConsoleApplication app, RelationDefinition<?, ?> rd, CreateSubCommandHandler<?, ?> ch,
                DeleteSubCommandHandler dh, ListSubCommandHandler lh, SetPropSubCommandHandler sh) {
            LocalizableMessage userFriendlyName = rd.getUserFriendlyName();
    // Check that we can write on the provided path where we write the
    // equivalent non-interactive commands.
    if (equivalentCommandFileArgument.isPresent())
    {
      final String file = equivalentCommandFileArgument.getValue();
      if (!canWrite(file))
      {
        println(ERR_DSCFG_CANNOT_WRITE_EQUIVALENT_COMMAND_LINE_FILE.get(file));
        return ReturnCode.ERROR_UNEXPECTED.get();
      }
      else
      {
        if (new File(file).isDirectory())
        {
          println(ERR_DSCFG_EQUIVALENT_COMMAND_LINE_FILE_DIRECTORY.get(file));
          return ReturnCode.ERROR_UNEXPECTED.get();
        }
      }
    }
    // Creates the management context factory which is based on the connection
    // provider factory and an authenticated connection factory.
    try
    {
      factory = new LDAPManagementContextFactory(cfp);
    }
    catch (ArgumentException e)
    {
      displayMessageAndUsageReference(ERR_ERROR_PARSING_ARGS
          .get(e.getMessage()));
      return ReturnCode.CONFLICTING_ARGS.get();
    }
            LocalizableMessage userFriendlyPluralName = null;
            if (rd instanceof InstantiableRelationDefinition<?, ?>) {
                InstantiableRelationDefinition<?, ?> ir = (InstantiableRelationDefinition<?, ?>) rd;
                userFriendlyPluralName = ir.getUserFriendlyPluralName();
            } else if (rd instanceof SetRelationDefinition<?, ?>) {
                SetRelationDefinition<?, ?> sr = (SetRelationDefinition<?, ?>) rd;
                userFriendlyPluralName = sr.getUserFriendlyPluralName();
            }
    // Checks the version - if upgrade required, the tool is unusable
    /*try
    {
      BuildVersion.checkVersionMismatch();
    }
    catch (ConfigException e)
    {
      println(e.getMessageObject());
      return ReturnCode.ERROR_USER_DATA.get();
    }*/
            final MenuBuilder<Integer> builder = new MenuBuilder<Integer>(app);
    // Handle batch file if any
    if (batchFileArgument.isPresent()) {
      handleBatchFile(args);
      // don't need to do anything else
      return ReturnCode.SUCCESS.get();
    }
            builder.setTitle(INFO_DSCFG_HEADING_COMPONENT_MENU_TITLE.get(userFriendlyName));
            builder.setPrompt(INFO_DSCFG_HEADING_COMPONENT_MENU_PROMPT.get());
    int retCode = 0;
    if (parser.getSubCommand() == null) {
      hasSubCommand = false;
            if (lh != null) {
                final SubCommandHandlerMenuCallback callback = new SubCommandHandlerMenuCallback(lh);
                if (userFriendlyPluralName != null) {
                    builder.addNumberedOption(INFO_DSCFG_OPTION_COMPONENT_MENU_LIST_PLURAL.get(userFriendlyPluralName),
                            callback);
                } else {
                    builder.addNumberedOption(INFO_DSCFG_OPTION_COMPONENT_MENU_LIST_SINGULAR.get(userFriendlyName),
                            callback);
                }
            }
      if (isInteractive()) {
        // Top-level interactive mode.
        retCode = runInteractiveMode();
      } else {
        LocalizableMessage message = ERR_ERROR_PARSING_ARGS
        .get(ERR_DSCFG_ERROR_MISSING_SUBCOMMAND.get());
        displayMessageAndUsageReference(message);
        retCode = ReturnCode.ERROR_USER_DATA.get();
      }
    } else {
      hasSubCommand = true;
            if (ch != null) {
                final SubCommandHandlerMenuCallback callback = new SubCommandHandlerMenuCallback(ch);
                builder.addNumberedOption(INFO_DSCFG_OPTION_COMPONENT_MENU_CREATE.get(userFriendlyName), callback);
            }
      // Retrieve the sub-command implementation and run it.
      SubCommandHandler handler = handlers.get(parser.getSubCommand());
      retCode = runSubCommand(handler);
    }
            if (sh != null) {
                final SubCommandHandlerMenuCallback callback = new SubCommandHandlerMenuCallback(sh);
                if (userFriendlyPluralName != null) {
                    builder.addNumberedOption(INFO_DSCFG_OPTION_COMPONENT_MENU_MODIFY_PLURAL.get(userFriendlyName),
                            callback);
                } else {
                    builder.addNumberedOption(INFO_DSCFG_OPTION_COMPONENT_MENU_MODIFY_SINGULAR.get(userFriendlyName),
                            callback);
                }
            }
    factory.close();
            if (dh != null) {
                final SubCommandHandlerMenuCallback callback = new SubCommandHandlerMenuCallback(dh);
                builder.addNumberedOption(INFO_DSCFG_OPTION_COMPONENT_MENU_DELETE.get(userFriendlyName), callback);
            }
    return retCode;
  }
            builder.addBackOption(true);
            builder.addQuitOption();
  private void checkForConflictingArguments() throws ArgumentException
  {
    if (quietArgument.isPresent() && verboseArgument.isPresent()) {
      final LocalizableMessage message = ERR_TOOL_CONFLICTING_ARGS.get(quietArgument
          .getLongIdentifier(), verboseArgument.getLongIdentifier());
      throw new ArgumentException(message);
    }
    if (batchFileArgument.isPresent() && !noPromptArgument.isPresent()) {
      final LocalizableMessage message =
          ERR_DSCFG_ERROR_QUIET_AND_INTERACTIVE_INCOMPATIBLE.get(
              batchFileArgument.getLongIdentifier(), noPromptArgument
                  .getLongIdentifier());
      throw new ArgumentException(message);
    }
    if (quietArgument.isPresent() && !noPromptArgument.isPresent()) {
      final LocalizableMessage message = ERR_DSCFG_ERROR_QUIET_AND_INTERACTIVE_INCOMPATIBLE.get(
          quietArgument.getLongIdentifier(), noPromptArgument
          .getLongIdentifier());
      throw new ArgumentException(message);
    }
    if (scriptFriendlyArgument.isPresent() && verboseArgument.isPresent()) {
      final LocalizableMessage message = ERR_TOOL_CONFLICTING_ARGS.get(scriptFriendlyArgument
          .getLongIdentifier(), verboseArgument.getLongIdentifier());
      throw new ArgumentException(message);
    }
    if (noPropertiesFileArgument.isPresent()
        && propertiesFileArgument.isPresent())
    {
      final LocalizableMessage message = ERR_TOOL_CONFLICTING_ARGS.get(
          noPropertiesFileArgument.getLongIdentifier(),
          propertiesFileArgument.getLongIdentifier());
      throw new ArgumentException(message);
    }
  }
  /** Run the top-level interactive console. */
  private int runInteractiveMode() {
    ConsoleApplication app = this;
    // Build menu structure.
    final Comparator<RelationDefinition<?, ?>> c =
      new Comparator<RelationDefinition<?, ?>>() {
      @Override
      public int compare(RelationDefinition<?, ?> rd1,
          RelationDefinition<?, ?> rd2) {
        final String s1 = rd1.getUserFriendlyName().toString();
        final String s2 = rd2.getUserFriendlyName().toString();
        return s1.compareToIgnoreCase(s2);
      }
    };
    final Set<RelationDefinition<?, ?>> relations =
        new TreeSet<RelationDefinition<?, ?>>(c);
    final Map<RelationDefinition<?, ?>, CreateSubCommandHandler<?, ?>> createHandlers =
        new HashMap<RelationDefinition<?, ?>, CreateSubCommandHandler<?, ?>>();
    final Map<RelationDefinition<?, ?>, DeleteSubCommandHandler> deleteHandlers =
        new HashMap<RelationDefinition<?, ?>, DeleteSubCommandHandler>();
    final Map<RelationDefinition<?, ?>, ListSubCommandHandler> listHandlers =
        new HashMap<RelationDefinition<?, ?>, ListSubCommandHandler>();
    final Map<RelationDefinition<?, ?>, GetPropSubCommandHandler> getPropHandlers =
        new HashMap<RelationDefinition<?, ?>, GetPropSubCommandHandler>();
    final Map<RelationDefinition<?, ?>, SetPropSubCommandHandler> setPropHandlers =
        new HashMap<RelationDefinition<?, ?>, SetPropSubCommandHandler>();
    for (final CreateSubCommandHandler<?, ?> ch : handlerFactory
        .getCreateSubCommandHandlers()) {
      relations.add(ch.getRelationDefinition());
      createHandlers.put(ch.getRelationDefinition(), ch);
    }
    for (final DeleteSubCommandHandler dh : handlerFactory
        .getDeleteSubCommandHandlers()) {
      relations.add(dh.getRelationDefinition());
      deleteHandlers.put(dh.getRelationDefinition(), dh);
    }
    for (final ListSubCommandHandler lh :
      handlerFactory.getListSubCommandHandlers()) {
      relations.add(lh.getRelationDefinition());
      listHandlers.put(lh.getRelationDefinition(), lh);
    }
    for (final GetPropSubCommandHandler gh : handlerFactory
        .getGetPropSubCommandHandlers()) {
      relations.add(gh.getRelationDefinition());
      getPropHandlers.put(gh.getRelationDefinition(), gh);
    }
    for (final SetPropSubCommandHandler sh : handlerFactory
        .getSetPropSubCommandHandlers()) {
      relations.add(sh.getRelationDefinition());
      setPropHandlers.put(sh.getRelationDefinition(), sh);
    }
    // Main menu.
    final MenuBuilder<Integer> builder = new MenuBuilder<Integer>(app);
    builder.setTitle(INFO_DSCFG_HEADING_MAIN_MENU_TITLE.get());
    builder.setPrompt(INFO_DSCFG_HEADING_MAIN_MENU_PROMPT.get());
    builder.setMultipleColumnThreshold(0);
    for (final RelationDefinition<?, ?> rd : relations) {
      final MenuCallback<Integer> callback = new SubMenuCallback(app, rd,
          createHandlers.get(rd), deleteHandlers.get(rd), listHandlers.get(rd),
          setPropHandlers.get(rd));
      builder.addNumberedOption(rd.getUserFriendlyName(), callback);
    }
    builder.addQuitOption();
    final Menu<Integer> menu = builder.toMenu();
    try {
      // Force retrieval of management context.
      factory.getManagementContext(app);
    } catch (ArgumentException e) {
      app.println(e.getMessageObject());
      return ReturnCode.ERROR_UNEXPECTED.get();
    } catch (ClientException e) {
      app.println(e.getMessageObject());
      return ReturnCode.ERROR_UNEXPECTED.get();
    }
    try {
      app.println();
      app.println();
      final MenuResult<Integer> result = menu.run();
      if (result.isQuit()) {
        return ReturnCode.SUCCESS.get();
      } else {
        return result.getValue();
      }
    } catch (ClientException e) {
      app.println(e.getMessageObject());
      return ReturnCode.ERROR_UNEXPECTED.get();
    }
  }
  /** Run the provided sub-command handler. */
  private int runSubCommand(SubCommandHandler handler) {
    try {
      final MenuResult<Integer> result = handler.run(this, factory);
      if (result.isSuccess()) {
        if (isInteractive() &&
            handler.isCommandBuilderUseful())
        {
          printCommandBuilder(getCommandBuilder(handler));
        }
        return result.getValue();
      } else {
        // User must have quit.
        return ReturnCode.ERROR_UNEXPECTED.get();
      }
    } catch (ArgumentException e) {
      println(e.getMessageObject());
      return ReturnCode.ERROR_UNEXPECTED.get();
    } catch (ClientException e) {
      Throwable cause = e.getCause();
      println();
      if (cause instanceof ManagedObjectDecodingException)
      {
        displayManagedObjectDecodingException(this,
            (ManagedObjectDecodingException) cause);
      }
      else if (cause instanceof MissingMandatoryPropertiesException)
      {
        displayMissingMandatoryPropertyException(this,
            (MissingMandatoryPropertiesException) cause);
      }
      else if (cause instanceof OperationRejectedException)
      {
        displayOperationRejectedException(this,
            (OperationRejectedException) cause);
      }
      else
      {
        // Just display the default message.
        println(e.getMessageObject());
      }
      println();
      return ReturnCode.ERROR_UNEXPECTED.get();
    } catch (Exception e) {
      println(LocalizableMessage.raw(stackTraceToSingleLineString(e, true)));
      return ReturnCode.ERROR_UNEXPECTED.get();
    }
  }
  /**
   * Updates the command builder with the global options: script friendly,
   * verbose, etc. for a given sub command. It also adds systematically the
   * no-prompt option.
   *
   * @param <T>
   *          SubCommand type.
   * @param subCommand
   *          The sub command handler or common.
   * @return <T> The builded command.
   */
  <T> CommandBuilder getCommandBuilder(final T subCommand)
  {
    String commandName = System.getProperty(PROPERTY_SCRIPT_NAME);
    if (commandName == null)
    {
      commandName = DSCONFIGTOOLNAME;
    }
    CommandBuilder commandBuilder = null;
    if (subCommand instanceof SubCommandHandler)
    {
      commandBuilder =
          new CommandBuilder(commandName, ((SubCommandHandler) subCommand)
              .getSubCommand().getName());
    }
    else
    {
      commandBuilder = new CommandBuilder(commandName, (String) subCommand);
    }
    if (factory != null && factory.getContextCommandBuilder() != null)
    {
      commandBuilder.append(factory.getContextCommandBuilder());
    }
    if (verboseArgument.isPresent())
    {
      commandBuilder.addArgument(verboseArgument);
    }
    if (scriptFriendlyArgument.isPresent())
    {
      commandBuilder.addArgument(scriptFriendlyArgument);
    }
    commandBuilder.addArgument(noPromptArgument);
    if (propertiesFileArgument.isPresent())
    {
      commandBuilder.addArgument(propertiesFileArgument);
    }
    if (noPropertiesFileArgument.isPresent())
    {
      commandBuilder.addArgument(noPropertiesFileArgument);
    }
    return commandBuilder;
  }
  /**
   * Prints the contents of a command builder.  This method has been created
   * since SetPropSubCommandHandler calls it.  All the logic of DSConfig is on
   * this method.  It writes the content of the CommandBuilder to the standard
   * output, or to a file depending on the options provided by the user.
   * @param commandBuilder the command builder to be printed.
   */
  void printCommandBuilder(CommandBuilder commandBuilder)
  {
    if (displayEquivalentArgument.isPresent())
    {
      println();
      // We assume that the app we are running is this one.
      println(INFO_DSCFG_NON_INTERACTIVE.get(commandBuilder));
    }
    if (equivalentCommandFileArgument.isPresent())
    {
      String file = equivalentCommandFileArgument.getValue();
      BufferedWriter writer = null;
      try
      {
        writer = new BufferedWriter(new FileWriter(file, true));
        if (!sessionStartTimePrinted)
        {
          writer.write(SHELL_COMMENT_SEPARATOR+getSessionStartTimeMessage());
          writer.newLine();
          sessionStartTimePrinted = true;
            this.menu = builder.toMenu();
        }
        sessionEquivalentOperationNumber++;
        writer.newLine();
        writer.write(SHELL_COMMENT_SEPARATOR+
            INFO_DSCFG_EQUIVALENT_COMMAND_LINE_SESSION_OPERATION_NUMBER.get(
                sessionEquivalentOperationNumber));
        writer.newLine();
        /** {@inheritDoc} */
        @Override
        public final MenuResult<Integer> invoke(ConsoleApplication app) throws ClientException {
            try {
                app.println();
                app.println();
        writer.write(SHELL_COMMENT_SEPARATOR+getCurrentOperationDateMessage());
        writer.newLine();
                MenuResult<Integer> result = menu.run();
        writer.write(commandBuilder.toString());
        writer.newLine();
        writer.newLine();
        writer.flush();
      }
      catch (IOException ioe)
      {
        println(ERR_DSCFG_ERROR_WRITING_EQUIVALENT_COMMAND_LINE.get(file, ioe));
      }
      finally
      {
        closeSilently(writer);
      }
    }
  }
  /**
   * Returns the message to be displayed in the file with the equivalent
   * command-line with information about when the session started.
   * @return  the message to be displayed in the file with the equivalent
   * command-line with information about when the session started.
   */
  private String getSessionStartTimeMessage()
  {
    String scriptName = System.getProperty(PROPERTY_SCRIPT_NAME);
    if (scriptName == null || scriptName.length() == 0)
    {
      scriptName = DSCONFIGTOOLNAME;
    }
    final String date = formatDateTimeStringForEquivalentCommand(
        new Date(sessionStartTime));
    return INFO_DSCFG_SESSION_START_TIME_MESSAGE.get(scriptName, date).
    toString();
  }
  private void handleBatchFile(String[] args) {
    BufferedReader bReader = null;
    try {
      // Build a list of initial arguments,
      // removing the batch file option + its value
      final List<String> initialArgs = new ArrayList<String>();
      Collections.addAll(initialArgs, args);
      int batchFileArgIndex = -1;
      for (final String elem : initialArgs) {
        if (elem.startsWith("-" + OPTION_SHORT_BATCH_FILE_PATH)
                || elem.contains(OPTION_LONG_BATCH_FILE_PATH)) {
          batchFileArgIndex = initialArgs.indexOf(elem);
          break;
                if (result.isCancel()) {
                    return MenuResult.again();
                }
                return result;
            } catch (ClientException e) {
                app.println(e.getMessageObject());
                return MenuResult.success(1);
            }
        }
      }
      if (batchFileArgIndex != -1) {
        // Remove both the batch file arg and its value
        initialArgs.remove(batchFileArgIndex);
        initialArgs.remove(batchFileArgIndex);
      }
      final String batchFilePath = batchFileArgument.getValue().trim();
      bReader =
              new BufferedReader(new FileReader(batchFilePath));
      String line;
      String command = "";
      // Split the CLI string into arguments array
      while ((line = bReader.readLine()) != null) {
         if ("".equals(line) || line.startsWith("#")) {
          // Empty line or comment
          continue;
    }
    /**
     * The type name which will be used for the most generic managed object types when they are instantiable and
     * intended for customization only.
     */
    public static final String CUSTOM_TYPE = "custom";
    /**
     * The type name which will be used for the most generic managed object types when they are instantiable and not
     * intended for customization.
     */
    public static final String GENERIC_TYPE = "generic";
    private long sessionStartTime;
    private boolean sessionStartTimePrinted = false;
    private int sessionEquivalentOperationNumber = 0;
    /**
     * Provides the command-line arguments to the main application for processing.
     *
     * @param args
     *            The set of command-line arguments provided to this program.
     */
    public static void main(String[] args) {
        int exitCode = main(args, System.out, System.err);
        if (exitCode != ReturnCode.SUCCESS.get()) {
            System.exit(filterExitCode(exitCode));
        }
       // command split in several line support
        if (line.endsWith("\\")) {
          // command is split into several lines
          command += line.substring(0, line.length() - 1);
          continue;
    }
    /**
     * Provides the command-line arguments to the main application for processing and returns the exit code as an
     * integer.
     *
     * @param args
     *            The set of command-line arguments provided to this program.
     * @param outStream
     *            The output stream for standard output.
     * @param errStream
     *            The output stream for standard error.
     * @return Zero to indicate that the program completed successfully, or non-zero to indicate that an error occurred.
     */
    public static int main(String[] args, OutputStream outStream, OutputStream errStream) {
        final DSConfig app = new DSConfig(System.in, outStream, errStream);
        app.sessionStartTime = System.currentTimeMillis();
        /*
         * FIXME: obtain path info from system properties.
         */
        if (!ConfigurationFramework.getInstance().isInitialized()) {
            try {
                ConfigurationFramework.getInstance().initialize();
            } catch (ConfigException e) {
                app.println(e.getMessageObject());
                return ReturnCode.ERROR_INITIALIZING_SERVER.get();
            }
        }
        // Run the application.
        return app.run(args);
    }
    /** The argument which should be used to request advanced mode. */
    private BooleanArgument advancedModeArgument;
    /**
     * The factory which the application should use to retrieve its management context.
     */
    private LDAPManagementContextFactory factory = null;
    /**
     * Flag indicating whether or not the global arguments have already been initialized.
     */
    private boolean globalArgumentsInitialized = false;
    /** The sub-command handler factory. */
    private SubCommandHandlerFactory handlerFactory = null;
    /** Mapping of sub-commands to their implementations. */
    private final Map<SubCommand, SubCommandHandler> handlers = new HashMap<SubCommand, SubCommandHandler>();
    /** Indicates whether or not a sub-command was provided. */
    private boolean hasSubCommand = true;
    /** The argument which should be used to read dsconfig commands from a file. */
    private StringArgument batchFileArgument;
    /**
     * The argument which should be used to request non interactive behavior.
     */
    private BooleanArgument noPromptArgument;
    /**
     * The argument that the user must set to display the equivalent non-interactive mode argument.
     */
    private BooleanArgument displayEquivalentArgument;
    /**
     * The argument that allows the user to dump the equivalent non-interactive command to a file.
     */
    private StringArgument equivalentCommandFileArgument;
    /** The command-line argument parser. */
    private final SubCommandArgumentParser parser;
    /** The argument which should be used to request quiet output. */
    private BooleanArgument quietArgument;
    /** The argument which should be used to request script-friendly output. */
    private BooleanArgument scriptFriendlyArgument;
    /** The argument which should be used to request usage information. */
    private BooleanArgument showUsageArgument;
    /** The argument which should be used to request verbose output. */
    private BooleanArgument verboseArgument;
    /** The argument which should be used to indicate the properties file. */
    private StringArgument propertiesFileArgument;
    /**
     * The argument which should be used to indicate that we will not look for properties file.
     */
    private BooleanArgument noPropertiesFileArgument;
    /**
     * Creates a new DSConfig application instance.
     *
     * @param in
     *            The application input stream.
     * @param out
     *            The application output stream.
     * @param err
     *            The application error stream.
     */
    private DSConfig(InputStream in, OutputStream out, OutputStream err) {
        super(new PrintStream(out), new PrintStream(err));
        this.parser = new SubCommandArgumentParser(getClass().getName(), INFO_DSCFG_TOOL_DESCRIPTION.get(), false);
    }
    /** {@inheritDoc} */
    @Override
    public boolean isAdvancedMode() {
        return advancedModeArgument.isPresent();
    }
    /** {@inheritDoc} */
    @Override
    public boolean isInteractive() {
        return !noPromptArgument.isPresent();
    }
    /** {@inheritDoc} */
    @Override
    public boolean isMenuDrivenMode() {
        return !hasSubCommand;
    }
    /** {@inheritDoc} */
    @Override
    public boolean isQuiet() {
        return quietArgument.isPresent();
    }
    /** {@inheritDoc} */
    @Override
    public boolean isScriptFriendly() {
        return scriptFriendlyArgument.isPresent();
    }
    /** {@inheritDoc} */
    @Override
    public boolean isVerbose() {
        return verboseArgument.isPresent();
    }
    /** Displays the provided message followed by a help usage reference. */
    private void displayMessageAndUsageReference(LocalizableMessage message) {
        println(message);
        println();
        println(parser.getHelpUsageReference());
    }
    /**
     * Registers the global arguments with the argument parser.
     *
     * @throws ArgumentException
     *             If a global argument could not be registered.
     */
    private void initializeGlobalArguments(String[] args) throws ArgumentException {
        if (!globalArgumentsInitialized) {
            verboseArgument = CommonArguments.getVerbose();
            quietArgument = CommonArguments.getQuiet();
            scriptFriendlyArgument = CommonArguments.getScriptFriendly();
            noPromptArgument = CommonArguments.getNoPrompt();
            advancedModeArgument = CommonArguments.getAdvancedMode();
            showUsageArgument = CommonArguments.getShowUsage();
            batchFileArgument = new StringArgument(OPTION_LONG_BATCH_FILE_PATH, OPTION_SHORT_BATCH_FILE_PATH,
                    OPTION_LONG_BATCH_FILE_PATH, false, false, true, INFO_BATCH_FILE_PATH_PLACEHOLDER.get(), null,
                    null, INFO_DESCRIPTION_BATCH_FILE_PATH.get());
            displayEquivalentArgument = new BooleanArgument(OPTION_LONG_DISPLAY_EQUIVALENT, null,
                    OPTION_LONG_DISPLAY_EQUIVALENT, INFO_DSCFG_DESCRIPTION_DISPLAY_EQUIVALENT.get());
            equivalentCommandFileArgument = new StringArgument(OPTION_LONG_EQUIVALENT_COMMAND_FILE_PATH, null,
                    OPTION_LONG_EQUIVALENT_COMMAND_FILE_PATH, false, false, true, INFO_PATH_PLACEHOLDER.get(), null,
                    null, INFO_DSCFG_DESCRIPTION_EQUIVALENT_COMMAND_FILE_PATH.get());
            propertiesFileArgument = new StringArgument("propertiesFilePath", null, OPTION_LONG_PROP_FILE_PATH, false,
                    false, true, INFO_PROP_FILE_PATH_PLACEHOLDER.get(), null, null,
                    INFO_DESCRIPTION_PROP_FILE_PATH.get());
            noPropertiesFileArgument = new BooleanArgument("noPropertiesFileArgument", null, OPTION_LONG_NO_PROP_FILE,
                    INFO_DESCRIPTION_NO_PROP_FILE.get());
            // Register the global arguments.
            ArgumentGroup toolOptionsGroup = new ArgumentGroup(INFO_DSCFG_DESCRIPTION_OPTIONS_ARGS.get(), 2);
            parser.addGlobalArgument(advancedModeArgument, toolOptionsGroup);
            parser.addGlobalArgument(showUsageArgument);
            parser.setUsageArgument(showUsageArgument, getOutputStream());
            parser.addGlobalArgument(verboseArgument);
            parser.addGlobalArgument(quietArgument);
            parser.addGlobalArgument(scriptFriendlyArgument);
            parser.addGlobalArgument(noPromptArgument);
            parser.addGlobalArgument(batchFileArgument);
            parser.addGlobalArgument(displayEquivalentArgument);
            parser.addGlobalArgument(equivalentCommandFileArgument);
            parser.addGlobalArgument(propertiesFileArgument);
            parser.setFilePropertiesArgument(propertiesFileArgument);
            parser.addGlobalArgument(noPropertiesFileArgument);
            parser.setNoPropertiesFileArgument(noPropertiesFileArgument);
            globalArgumentsInitialized = true;
        }
    }
    /**
     * Registers the sub-commands with the argument parser. This method uses the administration framework introspection
     * APIs to determine the overall structure of the command-line.
     *
     * @throws ArgumentException
     *             If a sub-command could not be created.
     */
    private void initializeSubCommands() throws ArgumentException {
        if (handlerFactory == null) {
            handlerFactory = new SubCommandHandlerFactory(parser);
            final Comparator<SubCommand> c = new Comparator<SubCommand>() {
                @Override
                public int compare(SubCommand o1, SubCommand o2) {
                    return o1.getName().compareTo(o2.getName());
                }
            };
            Map<Tag, SortedSet<SubCommand>> groups = new TreeMap<Tag, SortedSet<SubCommand>>();
            SortedSet<SubCommand> allSubCommands = new TreeSet<SubCommand>(c);
            for (SubCommandHandler handler : handlerFactory.getAllSubCommandHandlers()) {
                SubCommand sc = handler.getSubCommand();
                handlers.put(sc, handler);
                allSubCommands.add(sc);
                // Add the sub-command to its groups.
                for (Tag tag : handler.getTags()) {
                    SortedSet<SubCommand> group = groups.get(tag);
                    if (group == null) {
                        group = new TreeSet<SubCommand>(c);
                        groups.put(tag, group);
                    }
                    group.add(sc);
                }
            }
            // Register the usage arguments.
            for (Map.Entry<Tag, SortedSet<SubCommand>> group : groups.entrySet()) {
                Tag tag = group.getKey();
                SortedSet<SubCommand> subCommands = group.getValue();
                String option = OPTION_LONG_HELP + "-" + tag.getName();
                String synopsis = tag.getSynopsis().toString().toLowerCase();
                BooleanArgument arg = new BooleanArgument(option, null, option,
                        INFO_DSCFG_DESCRIPTION_SHOW_GROUP_USAGE.get(synopsis));
                parser.addGlobalArgument(arg);
                parser.setUsageGroupArgument(arg, subCommands);
            }
            // Register the --help-all argument.
            String option = OPTION_LONG_HELP + "-all";
            BooleanArgument arg = new BooleanArgument(option, null, option,
                    INFO_DSCFG_DESCRIPTION_SHOW_GROUP_USAGE_ALL.get());
            parser.addGlobalArgument(arg);
            parser.setUsageGroupArgument(arg, allSubCommands);
        }
    }
    /**
     * Parses the provided command-line arguments and makes the appropriate changes to the Directory Server
     * configuration.
     *
     * @param args
     *            The command-line arguments provided to this program.
     * @return The exit code from the configuration processing. A nonzero value indicates that there was some kind of
     *         problem during the configuration processing.
     */
    private int run(String[] args) {
        // Register global arguments and sub-commands.
        try {
            initializeGlobalArguments(args);
            initializeSubCommands();
        } catch (ArgumentException e) {
            println(ERR_CANNOT_INITIALIZE_ARGS.get(e.getMessage()));
            return ReturnCode.ERROR_USER_DATA.get();
        }
        ConnectionFactoryProvider cfp = null;
        try {
            cfp = new ConnectionFactoryProvider(parser, this, CliConstants.DEFAULT_ROOT_USER_DN,
                    CliConstants.DEFAULT_ADMINISTRATION_CONNECTOR_PORT, true, null);
            cfp.setIsAnAdminConnection();
            // Parse the command-line arguments provided to this program.
            parser.parseArguments(args);
            checkForConflictingArguments();
        } catch (ArgumentException ae) {
            displayMessageAndUsageReference(ERR_ERROR_PARSING_ARGS.get(ae.getMessage()));
            return ReturnCode.CONFLICTING_ARGS.get();
        }
        // If the usage/version argument was provided, then we don't need
        // to do anything else.
        if (parser.usageOrVersionDisplayed()) {
            return ReturnCode.SUCCESS.get();
        }
        // Check that we can write on the provided path where we write the
        // equivalent non-interactive commands.
        if (equivalentCommandFileArgument.isPresent()) {
            final String file = equivalentCommandFileArgument.getValue();
            if (!canWrite(file)) {
                println(ERR_DSCFG_CANNOT_WRITE_EQUIVALENT_COMMAND_LINE_FILE.get(file));
                return ReturnCode.ERROR_UNEXPECTED.get();
            } else {
                if (new File(file).isDirectory()) {
                    println(ERR_DSCFG_EQUIVALENT_COMMAND_LINE_FILE_DIRECTORY.get(file));
                    return ReturnCode.ERROR_UNEXPECTED.get();
                }
            }
        }
        // Creates the management context factory which is based on the connection
        // provider factory and an authenticated connection factory.
        try {
            factory = new LDAPManagementContextFactory(cfp);
        } catch (ArgumentException e) {
            displayMessageAndUsageReference(ERR_ERROR_PARSING_ARGS.get(e.getMessage()));
            return ReturnCode.CONFLICTING_ARGS.get();
        }
        // Checks the version - if upgrade required, the tool is unusable
        /*
         * try { BuildVersion.checkVersionMismatch(); } catch (ConfigException e) { println(e.getMessageObject());
         * return ReturnCode.ERROR_USER_DATA.get(); }
         */
        // Handle batch file if any
        if (batchFileArgument.isPresent()) {
            handleBatchFile(args);
            // don't need to do anything else
            return ReturnCode.SUCCESS.get();
        }
        int retCode = 0;
        if (parser.getSubCommand() == null) {
            hasSubCommand = false;
            if (isInteractive()) {
                // Top-level interactive mode.
                retCode = runInteractiveMode();
            } else {
                LocalizableMessage message = ERR_ERROR_PARSING_ARGS.get(ERR_DSCFG_ERROR_MISSING_SUBCOMMAND.get());
                displayMessageAndUsageReference(message);
                retCode = ReturnCode.ERROR_USER_DATA.get();
            }
        } else {
          command += line;
        }
        command = command.trim();
        // string between quotes support
        command = replaceSpacesInQuotes(command);
        String displayCommand = new String(command);
            hasSubCommand = true;
        // "\ " support
        command = command.replace("\\ ", "##");
        displayCommand = displayCommand.replace("\\ ", " ");
        String[] fileArguments = command.split("\\s+");
        // reset command
        command = "";
        for (int ii = 0; ii < fileArguments.length; ii++) {
          fileArguments[ii] = fileArguments[ii].replace("##", " ");
            // Retrieve the sub-command implementation and run it.
            SubCommandHandler handler = handlers.get(parser.getSubCommand());
            retCode = runSubCommand(handler);
        }
        errPrintln(LocalizableMessage.raw(displayCommand));
        factory.close();
        // Append initial arguments to the file line
        final List<String> allArguments = new ArrayList<String>();
        Collections.addAll(allArguments, fileArguments);
        allArguments.addAll(initialArgs);
        final String[] allArgsArray = allArguments.toArray(new String[]{});
        int exitCode = main(allArgsArray, getOutputStream(), getErrorStream());
        if (exitCode != ReturnCode.SUCCESS.get())
        {
          System.exit(filterExitCode(exitCode));
        }
        errPrintln();
      }
    } catch (IOException ex) {
      println(ERR_DSCFG_ERROR_READING_BATCH_FILE.get(ex));
    } finally {
      closeSilently(bReader);
        return retCode;
    }
  }
  /** Replace spaces in quotes by "\ ". */
  private String replaceSpacesInQuotes(final String line) {
    String newLine = "";
    boolean inQuotes = false;
    for (int ii = 0; ii < line.length(); ii++) {
      char ch = line.charAt(ii);
      if (ch == '\"' || ch == '\'') {
        inQuotes = !inQuotes;
        continue;
      }
      if (inQuotes && ch == ' ') {
        newLine += "\\ ";
      } else {
        newLine += ch;
      }
    private void checkForConflictingArguments() throws ArgumentException {
        if (quietArgument.isPresent() && verboseArgument.isPresent()) {
            final LocalizableMessage message = ERR_TOOL_CONFLICTING_ARGS.get(quietArgument.getLongIdentifier(),
                    verboseArgument.getLongIdentifier());
            throw new ArgumentException(message);
        }
        if (batchFileArgument.isPresent() && !noPromptArgument.isPresent()) {
            final LocalizableMessage message = ERR_DSCFG_ERROR_QUIET_AND_INTERACTIVE_INCOMPATIBLE.get(
                    batchFileArgument.getLongIdentifier(), noPromptArgument.getLongIdentifier());
            throw new ArgumentException(message);
        }
        if (quietArgument.isPresent() && !noPromptArgument.isPresent()) {
            final LocalizableMessage message = ERR_DSCFG_ERROR_QUIET_AND_INTERACTIVE_INCOMPATIBLE.get(
                    quietArgument.getLongIdentifier(), noPromptArgument.getLongIdentifier());
            throw new ArgumentException(message);
        }
        if (scriptFriendlyArgument.isPresent() && verboseArgument.isPresent()) {
            final LocalizableMessage message = ERR_TOOL_CONFLICTING_ARGS.get(
                    scriptFriendlyArgument.getLongIdentifier(), verboseArgument.getLongIdentifier());
            throw new ArgumentException(message);
        }
        if (noPropertiesFileArgument.isPresent() && propertiesFileArgument.isPresent()) {
            final LocalizableMessage message = ERR_TOOL_CONFLICTING_ARGS.get(
                    noPropertiesFileArgument.getLongIdentifier(), propertiesFileArgument.getLongIdentifier());
            throw new ArgumentException(message);
        }
    }
    return newLine;
  }
    /** Run the top-level interactive console. */
    private int runInteractiveMode() {
        ConsoleApplication app = this;
        // Build menu structure.
        final Comparator<RelationDefinition<?, ?>> c = new Comparator<RelationDefinition<?, ?>>() {
            @Override
            public int compare(RelationDefinition<?, ?> rd1, RelationDefinition<?, ?> rd2) {
                final String s1 = rd1.getUserFriendlyName().toString();
                final String s2 = rd2.getUserFriendlyName().toString();
                return s1.compareToIgnoreCase(s2);
            }
        };
        final Set<RelationDefinition<?, ?>> relations = new TreeSet<RelationDefinition<?, ?>>(c);
        final Map<RelationDefinition<?, ?>, CreateSubCommandHandler<?, ?>> createHandlers
            = new HashMap<RelationDefinition<?, ?>, CreateSubCommandHandler<?, ?>>();
        final Map<RelationDefinition<?, ?>, DeleteSubCommandHandler> deleteHandlers
            = new HashMap<RelationDefinition<?, ?>, DeleteSubCommandHandler>();
        final Map<RelationDefinition<?, ?>, ListSubCommandHandler> listHandlers
            = new HashMap<RelationDefinition<?, ?>, ListSubCommandHandler>();
        final Map<RelationDefinition<?, ?>, GetPropSubCommandHandler> getPropHandlers
            = new HashMap<RelationDefinition<?, ?>, GetPropSubCommandHandler>();
        final Map<RelationDefinition<?, ?>, SetPropSubCommandHandler> setPropHandlers
            = new HashMap<RelationDefinition<?, ?>, SetPropSubCommandHandler>();
        for (final CreateSubCommandHandler<?, ?> ch : handlerFactory.getCreateSubCommandHandlers()) {
            relations.add(ch.getRelationDefinition());
            createHandlers.put(ch.getRelationDefinition(), ch);
        }
        for (final DeleteSubCommandHandler dh : handlerFactory.getDeleteSubCommandHandlers()) {
            relations.add(dh.getRelationDefinition());
            deleteHandlers.put(dh.getRelationDefinition(), dh);
        }
        for (final ListSubCommandHandler lh : handlerFactory.getListSubCommandHandlers()) {
            relations.add(lh.getRelationDefinition());
            listHandlers.put(lh.getRelationDefinition(), lh);
        }
        for (final GetPropSubCommandHandler gh : handlerFactory.getGetPropSubCommandHandlers()) {
            relations.add(gh.getRelationDefinition());
            getPropHandlers.put(gh.getRelationDefinition(), gh);
        }
        for (final SetPropSubCommandHandler sh : handlerFactory.getSetPropSubCommandHandlers()) {
            relations.add(sh.getRelationDefinition());
            setPropHandlers.put(sh.getRelationDefinition(), sh);
        }
        // Main menu.
        final MenuBuilder<Integer> builder = new MenuBuilder<Integer>(app);
        builder.setTitle(INFO_DSCFG_HEADING_MAIN_MENU_TITLE.get());
        builder.setPrompt(INFO_DSCFG_HEADING_MAIN_MENU_PROMPT.get());
        builder.setMultipleColumnThreshold(0);
        for (final RelationDefinition<?, ?> rd : relations) {
            final MenuCallback<Integer> callback = new SubMenuCallback(app, rd, createHandlers.get(rd),
                    deleteHandlers.get(rd), listHandlers.get(rd), setPropHandlers.get(rd));
            builder.addNumberedOption(rd.getUserFriendlyName(), callback);
        }
        builder.addQuitOption();
        final Menu<Integer> menu = builder.toMenu();
        try {
            // Force retrieval of management context.
            factory.getManagementContext(app);
        } catch (ArgumentException e) {
            app.println(e.getMessageObject());
            return ReturnCode.ERROR_UNEXPECTED.get();
        } catch (ClientException e) {
            app.println(e.getMessageObject());
            return ReturnCode.ERROR_UNEXPECTED.get();
        }
        try {
            app.println();
            app.println();
            final MenuResult<Integer> result = menu.run();
            if (result.isQuit()) {
                return ReturnCode.SUCCESS.get();
            } else {
                return result.getValue();
            }
        } catch (ClientException e) {
            app.println(e.getMessageObject());
            return ReturnCode.ERROR_UNEXPECTED.get();
        }
    }
    /** Run the provided sub-command handler. */
    private int runSubCommand(SubCommandHandler handler) {
        try {
            final MenuResult<Integer> result = handler.run(this, factory);
            if (result.isSuccess()) {
                if (isInteractive() && handler.isCommandBuilderUseful()) {
                    printCommandBuilder(getCommandBuilder(handler));
                }
                return result.getValue();
            } else {
                // User must have quit.
                return ReturnCode.ERROR_UNEXPECTED.get();
            }
        } catch (ArgumentException e) {
            println(e.getMessageObject());
            return ReturnCode.ERROR_UNEXPECTED.get();
        } catch (ClientException e) {
            Throwable cause = e.getCause();
            println();
            if (cause instanceof ManagedObjectDecodingException) {
                displayManagedObjectDecodingException(this, (ManagedObjectDecodingException) cause);
            } else if (cause instanceof MissingMandatoryPropertiesException) {
                displayMissingMandatoryPropertyException(this, (MissingMandatoryPropertiesException) cause);
            } else if (cause instanceof OperationRejectedException) {
                displayOperationRejectedException(this, (OperationRejectedException) cause);
            } else {
                // Just display the default message.
                println(e.getMessageObject());
            }
            println();
            return ReturnCode.ERROR_UNEXPECTED.get();
        } catch (Exception e) {
            println(LocalizableMessage.raw(stackTraceToSingleLineString(e, true)));
            return ReturnCode.ERROR_UNEXPECTED.get();
        }
    }
    /**
     * Updates the command builder with the global options: script friendly, verbose, etc. for a given sub command. It
     * also adds systematically the no-prompt option.
     *
     * @param <T>
     *            SubCommand type.
     * @param subCommand
     *            The sub command handler or common.
     * @return <T> The builded command.
     */
    <T> CommandBuilder getCommandBuilder(final T subCommand) {
        String commandName = System.getProperty(PROPERTY_SCRIPT_NAME);
        if (commandName == null) {
            commandName = DSCONFIGTOOLNAME;
        }
        CommandBuilder commandBuilder = null;
        if (subCommand instanceof SubCommandHandler) {
            commandBuilder = new CommandBuilder(commandName,
                    ((SubCommandHandler) subCommand).getSubCommand().getName());
        } else {
            commandBuilder = new CommandBuilder(commandName, (String) subCommand);
        }
        if (factory != null && factory.getContextCommandBuilder() != null) {
            commandBuilder.append(factory.getContextCommandBuilder());
        }
        if (verboseArgument.isPresent()) {
            commandBuilder.addArgument(verboseArgument);
        }
        if (scriptFriendlyArgument.isPresent()) {
            commandBuilder.addArgument(scriptFriendlyArgument);
        }
        commandBuilder.addArgument(noPromptArgument);
        if (propertiesFileArgument.isPresent()) {
            commandBuilder.addArgument(propertiesFileArgument);
        }
        if (noPropertiesFileArgument.isPresent()) {
            commandBuilder.addArgument(noPropertiesFileArgument);
        }
        return commandBuilder;
    }
    /**
     * Prints the contents of a command builder. This method has been created since SetPropSubCommandHandler calls it.
     * All the logic of DSConfig is on this method. It writes the content of the CommandBuilder to the standard output,
     * or to a file depending on the options provided by the user.
     *
     * @param commandBuilder
     *            the command builder to be printed.
     */
    void printCommandBuilder(CommandBuilder commandBuilder) {
        if (displayEquivalentArgument.isPresent()) {
            println();
            // We assume that the app we are running is this one.
            println(INFO_DSCFG_NON_INTERACTIVE.get(commandBuilder));
        }
        if (equivalentCommandFileArgument.isPresent()) {
            String file = equivalentCommandFileArgument.getValue();
            BufferedWriter writer = null;
            try {
                writer = new BufferedWriter(new FileWriter(file, true));
                if (!sessionStartTimePrinted) {
                    writer.write(SHELL_COMMENT_SEPARATOR + getSessionStartTimeMessage());
                    writer.newLine();
                    sessionStartTimePrinted = true;
                }
                sessionEquivalentOperationNumber++;
                writer.newLine();
                writer.write(SHELL_COMMENT_SEPARATOR
                        + INFO_DSCFG_EQUIVALENT_COMMAND_LINE_SESSION_OPERATION_NUMBER
                                .get(sessionEquivalentOperationNumber));
                writer.newLine();
                writer.write(SHELL_COMMENT_SEPARATOR + getCurrentOperationDateMessage());
                writer.newLine();
                writer.write(commandBuilder.toString());
                writer.newLine();
                writer.newLine();
                writer.flush();
            } catch (IOException ioe) {
                println(ERR_DSCFG_ERROR_WRITING_EQUIVALENT_COMMAND_LINE.get(file, ioe));
            } finally {
                closeSilently(writer);
            }
        }
    }
    /**
     * Returns the message to be displayed in the file with the equivalent command-line with information about when the
     * session started.
     *
     * @return the message to be displayed in the file with the equivalent command-line with information about when the
     *         session started.
     */
    private String getSessionStartTimeMessage() {
        String scriptName = System.getProperty(PROPERTY_SCRIPT_NAME);
        if (scriptName == null || scriptName.length() == 0) {
            scriptName = DSCONFIGTOOLNAME;
        }
        final String date = formatDateTimeStringForEquivalentCommand(new Date(sessionStartTime));
        return INFO_DSCFG_SESSION_START_TIME_MESSAGE.get(scriptName, date).toString();
    }
    private void handleBatchFile(String[] args) {
        BufferedReader bReader = null;
        try {
            // Build a list of initial arguments,
            // removing the batch file option + its value
            final List<String> initialArgs = new ArrayList<String>();
            Collections.addAll(initialArgs, args);
            int batchFileArgIndex = -1;
            for (final String elem : initialArgs) {
                if (elem.startsWith("-" + OPTION_SHORT_BATCH_FILE_PATH) || elem.contains(OPTION_LONG_BATCH_FILE_PATH)) {
                    batchFileArgIndex = initialArgs.indexOf(elem);
                    break;
                }
            }
            if (batchFileArgIndex != -1) {
                // Remove both the batch file arg and its value
                initialArgs.remove(batchFileArgIndex);
                initialArgs.remove(batchFileArgIndex);
            }
            final String batchFilePath = batchFileArgument.getValue().trim();
            bReader = new BufferedReader(new FileReader(batchFilePath));
            String line;
            String command = "";
            // Split the CLI string into arguments array
            while ((line = bReader.readLine()) != null) {
                if ("".equals(line) || line.startsWith("#")) {
                    // Empty line or comment
                    continue;
                }
                // command split in several line support
                if (line.endsWith("\\")) {
                    // command is split into several lines
                    command += line.substring(0, line.length() - 1);
                    continue;
                } else {
                    command += line;
                }
                command = command.trim();
                // string between quotes support
                command = replaceSpacesInQuotes(command);
                String displayCommand = new String(command);
                // "\ " support
                command = command.replace("\\ ", "##");
                displayCommand = displayCommand.replace("\\ ", " ");
                String[] fileArguments = command.split("\\s+");
                // reset command
                command = "";
                for (int ii = 0; ii < fileArguments.length; ii++) {
                    fileArguments[ii] = fileArguments[ii].replace("##", " ");
                }
                errPrintln(LocalizableMessage.raw(displayCommand));
                // Append initial arguments to the file line
                final List<String> allArguments = new ArrayList<String>();
                Collections.addAll(allArguments, fileArguments);
                allArguments.addAll(initialArgs);
                final String[] allArgsArray = allArguments.toArray(new String[] {});
                int exitCode = main(allArgsArray, getOutputStream(), getErrorStream());
                if (exitCode != ReturnCode.SUCCESS.get()) {
                    System.exit(filterExitCode(exitCode));
                }
                errPrintln();
            }
        } catch (IOException ex) {
            println(ERR_DSCFG_ERROR_READING_BATCH_FILE.get(ex));
        } finally {
            closeSilently(bReader);
        }
    }
    /** Replace spaces in quotes by "\ ". */
    private String replaceSpacesInQuotes(final String line) {
        String newLine = "";
        boolean inQuotes = false;
        for (int ii = 0; ii < line.length(); ii++) {
            char ch = line.charAt(ii);
            if (ch == '\"' || ch == '\'') {
                inQuotes = !inQuotes;
                continue;
            }
            if (inQuotes && ch == ' ') {
                newLine += "\\ ";
            } else {
                newLine += ch;
            }
        }
        return newLine;
    }
}
opendj-config/src/main/java/org/forgerock/opendj/config/dsconfig/LDAPManagementContextFactory.java
@@ -50,118 +50,90 @@
/**
 * An LDAP management context factory for the DSConfig tool.
 */
public final class LDAPManagementContextFactory
{
public final class LDAPManagementContextFactory {
  /** The management context. */
  private ManagementContext context;
    /** The management context. */
    private ManagementContext context;
  /** The connection parameters command builder. */
  private CommandBuilder contextCommandBuilder;
    /** The connection parameters command builder. */
    private CommandBuilder contextCommandBuilder;
  /** The connection factory provider. */
  private final ConnectionFactoryProvider provider;
    /** The connection factory provider. */
    private final ConnectionFactoryProvider provider;
  /** The connection factory. */
  private final ConnectionFactory factory;
    /** The connection factory. */
    private final ConnectionFactory factory;
  /**
   * Creates a new LDAP management context factory based on an authenticated
   * connection factory.
   *
   * @param cfp
   *          The connection factory provider which should be used in this
   *          context.
   * @throws ArgumentException
   *           If an exception occurs when creating the authenticated connection
   *           factory linked to this context.
   */
  public LDAPManagementContextFactory(ConnectionFactoryProvider cfp) throws ArgumentException {
    this.provider = cfp;
    factory = cfp.getAuthenticatedConnectionFactory();
  }
  /**
   * Closes this management context.
   */
  public void close()
  {
    closeSilently(context);
  }
  /**
   * Returns the command builder that provides the equivalent arguments in
   * interactive mode to get the management context.
   *
   * @return the command builder that provides the equivalent arguments in
   *         interactive mode to get the management context.
   */
  public CommandBuilder getContextCommandBuilder()
  {
    return contextCommandBuilder;
  }
  /**
   * Gets the management context which sub-commands should use in
   * order to manage the directory server.
   *
   * @param app
   *          The console application instance.
   * @return Returns the management context which sub-commands should
   *         use in order to manage the directory server.
   * @throws ArgumentException
   *           If a management context related argument could not be
   *           parsed successfully.
   * @throws ClientException
   *           If the management context could not be created.
   */
  public ManagementContext getManagementContext(ConsoleApplication app)
      throws ArgumentException, ClientException
  {
    // Lazily create the LDAP management context.
    if (context == null)
    {
      Connection connection;
      final String hostName = provider.getHostname();
      final int port = provider.getPort();
      try
      {
        connection = factory.getConnection();
        BuildVersion.checkVersionMismatch(connection);
      }
      catch (ErrorResultException e)
      {
        if (e.getCause() instanceof SSLException)
        {
          throw new ClientException(ReturnCode.CLIENT_SIDE_CONNECT_ERROR,
              ERR_FAILED_TO_CONNECT_NOT_TRUSTED.get(hostName, String
                  .valueOf(port)));
        }
        else
        {
          throw new ClientException(ReturnCode.CLIENT_SIDE_CONNECT_ERROR,
              ERR_DSCFG_ERROR_LDAP_FAILED_TO_CONNECT.get(hostName, String
                  .valueOf(port)));
        }
      }
      catch (ConfigException e)
      {
        throw new ClientException(ReturnCode.ERROR_USER_DATA,e.getMessageObject());
      }
      catch (Exception ex)
      {
        throw new ClientException(ReturnCode.CLIENT_SIDE_CONNECT_ERROR,
            ERR_DSCFG_ERROR_LDAP_FAILED_TO_CONNECT.get(hostName, port));
      }
      finally
      {
        closeSilently(factory);
      }
      context =
          LDAPManagementContext.newManagementContext(connection, LDAPProfile
              .getInstance());
    /**
     * Creates a new LDAP management context factory based on an authenticated connection factory.
     *
     * @param cfp
     *            The connection factory provider which should be used in this context.
     * @throws ArgumentException
     *             If an exception occurs when creating the authenticated connection factory linked to this context.
     */
    public LDAPManagementContextFactory(ConnectionFactoryProvider cfp) throws ArgumentException {
        this.provider = cfp;
        factory = cfp.getAuthenticatedConnectionFactory();
    }
    return context;
  }
    /**
     * Closes this management context.
     */
    public void close() {
        closeSilently(context);
    }
    /**
     * Returns the command builder that provides the equivalent arguments in interactive mode to get the management
     * context.
     *
     * @return the command builder that provides the equivalent arguments in interactive mode to get the management
     *         context.
     */
    public CommandBuilder getContextCommandBuilder() {
        return contextCommandBuilder;
    }
    /**
     * Gets the management context which sub-commands should use in order to manage the directory server.
     *
     * @param app
     *            The console application instance.
     * @return Returns the management context which sub-commands should use in order to manage the directory server.
     * @throws ArgumentException
     *             If a management context related argument could not be parsed successfully.
     * @throws ClientException
     *             If the management context could not be created.
     */
    public ManagementContext getManagementContext(ConsoleApplication app) throws ArgumentException, ClientException {
        // Lazily create the LDAP management context.
        if (context == null) {
            Connection connection;
            final String hostName = provider.getHostname();
            final int port = provider.getPort();
            try {
                connection = factory.getConnection();
                BuildVersion.checkVersionMismatch(connection);
            } catch (ErrorResultException e) {
                if (e.getCause() instanceof SSLException) {
                    throw new ClientException(ReturnCode.CLIENT_SIDE_CONNECT_ERROR,
                            ERR_FAILED_TO_CONNECT_NOT_TRUSTED.get(hostName, String.valueOf(port)));
                } else {
                    throw new ClientException(ReturnCode.CLIENT_SIDE_CONNECT_ERROR,
                            ERR_DSCFG_ERROR_LDAP_FAILED_TO_CONNECT.get(hostName, String.valueOf(port)));
                }
            } catch (ConfigException e) {
                throw new ClientException(ReturnCode.ERROR_USER_DATA, e.getMessageObject());
            } catch (Exception ex) {
                throw new ClientException(ReturnCode.CLIENT_SIDE_CONNECT_ERROR,
                        ERR_DSCFG_ERROR_LDAP_FAILED_TO_CONNECT.get(hostName, port));
            } finally {
                closeSilently(factory);
            }
            context = LDAPManagementContext.newManagementContext(connection, LDAPProfile.getInstance());
        }
        return context;
    }
}