/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at * trunk/opends/resource/legal-notices/OpenDS.LICENSE * or https://OpenDS.dev.java.net/OpenDS.LICENSE. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable, * add the following below this CDDL HEADER, with the fields enclosed * by brackets "[]" replaced with your own identifying information: * Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END * * * Copyright 2007-2009 Sun Microsystems, Inc. */ package org.opends.server.tools.dsconfig; import static org.opends.messages.DSConfigMessages.*; import static org.opends.messages.ToolMessages.*; import static org.opends.server.loggers.debug.DebugLogger.*; import static org.opends.server.tools.ToolConstants.*; import static org.opends.server.tools.dsconfig.ArgumentExceptionFactory.*; import static org.opends.server.util.StaticUtils.*; import java.io.BufferedWriter; import java.io.File; import java.io.FileWriter; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.Comparator; import java.util.HashMap; import java.util.Map; import java.util.Set; import java.util.SortedSet; import java.util.TreeMap; import java.util.TreeSet; import org.opends.messages.Message; import org.opends.quicksetup.util.Utils; import org.opends.server.admin.AttributeTypePropertyDefinition; import org.opends.server.admin.ClassLoaderProvider; import org.opends.server.admin.ClassPropertyDefinition; import org.opends.server.admin.InstantiableRelationDefinition; import org.opends.server.admin.RelationDefinition; import org.opends.server.admin.SetRelationDefinition; import org.opends.server.admin.Tag; import org.opends.server.admin.client.ManagedObjectDecodingException; import org.opends.server.admin.client.MissingMandatoryPropertiesException; import org.opends.server.admin.client.OperationRejectedException; import org.opends.server.loggers.debug.DebugTracer; import org.opends.server.tools.ClientException; import org.opends.server.types.DebugLogLevel; import org.opends.server.types.InitializationException; import org.opends.server.util.EmbeddedUtils; import org.opends.server.util.ServerConstants; import org.opends.server.util.StaticUtils; import org.opends.server.util.args.ArgumentException; import org.opends.server.util.args.BooleanArgument; import org.opends.server.util.args.StringArgument; import org.opends.server.util.args.SubCommand; import org.opends.server.util.args.SubCommandArgumentParser; import org.opends.server.util.args.ArgumentGroup; import org.opends.server.util.cli.CLIException; import org.opends.server.util.cli.CommandBuilder; import org.opends.server.util.cli.ConsoleApplication; import org.opends.server.util.cli.Menu; import org.opends.server.util.cli.MenuBuilder; import org.opends.server.util.cli.MenuCallback; import org.opends.server.util.cli.MenuResult; import org.opends.server.util.cli.OutputStreamConsoleApplication; /** * This class provides a command-line tool which enables * administrators to configure the Directory Server. */ public final class DSConfig extends ConsoleApplication { /** * A menu call-back which runs a sub-command interactively. */ private class SubCommandHandlerMenuCallback implements MenuCallback { // The sub-command handler. private final SubCommandHandler handler; /** * Creates a new sub-command handler call-back. * * @param handler * The sub-command handler. */ public SubCommandHandlerMenuCallback(SubCommandHandler handler) { this.handler = handler; } /** * {@inheritDoc} */ public MenuResult invoke(ConsoleApplication app) throws CLIException { try { MenuResult 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.getExitCode()); } } } /** * The interactive mode sub-menu implementation. */ private class SubMenuCallback implements MenuCallback { // The menu. private final Menu menu; /** * 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) { Message ufn = rd.getUserFriendlyName(); Message ufpn = null; if (rd instanceof InstantiableRelationDefinition) { InstantiableRelationDefinition ir = (InstantiableRelationDefinition) rd; ufpn = ir.getUserFriendlyPluralName(); } else if (rd instanceof SetRelationDefinition) { SetRelationDefinition sr = (SetRelationDefinition) rd; ufpn = sr.getUserFriendlyPluralName(); } MenuBuilder builder = new MenuBuilder(app); builder.setTitle(INFO_DSCFG_HEADING_COMPONENT_MENU_TITLE.get(ufn)); builder.setPrompt(INFO_DSCFG_HEADING_COMPONENT_MENU_PROMPT.get()); if (lh != null) { SubCommandHandlerMenuCallback callback = new SubCommandHandlerMenuCallback(lh); if (ufpn != null) { builder.addNumberedOption( INFO_DSCFG_OPTION_COMPONENT_MENU_LIST_PLURAL.get(ufpn), callback); } else { builder .addNumberedOption(INFO_DSCFG_OPTION_COMPONENT_MENU_LIST_SINGULAR .get(ufn), callback); } } if (ch != null) { SubCommandHandlerMenuCallback callback = new SubCommandHandlerMenuCallback(ch); builder.addNumberedOption(INFO_DSCFG_OPTION_COMPONENT_MENU_CREATE .get(ufn), callback); } if (sh != null) { SubCommandHandlerMenuCallback callback = new SubCommandHandlerMenuCallback(sh); if (ufpn != null) { builder .addNumberedOption(INFO_DSCFG_OPTION_COMPONENT_MENU_MODIFY_PLURAL .get(ufn), callback); } else { builder.addNumberedOption( INFO_DSCFG_OPTION_COMPONENT_MENU_MODIFY_SINGULAR.get(ufn), callback); } } if (dh != null) { SubCommandHandlerMenuCallback callback = new SubCommandHandlerMenuCallback(dh); builder.addNumberedOption(INFO_DSCFG_OPTION_COMPONENT_MENU_DELETE .get(ufn), callback); } builder.addBackOption(true); builder.addQuitOption(); this.menu = builder.toMenu(); } /** * {@inheritDoc} */ public final MenuResult invoke(ConsoleApplication app) throws CLIException { try { app.println(); app.println(); MenuResult result = menu.run(); if (result.isCancel()) { return MenuResult.again(); } return result; } catch (CLIException 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"; /** * The value for the long option advanced. */ private static final String OPTION_DSCFG_LONG_ADVANCED = "advanced"; /** * The value for the short option advanced. */ private static final Character OPTION_DSCFG_SHORT_ADVANCED = null; /** * The tracer object for the debug logger. */ private static final DebugTracer TRACER = getTracer(); // This CLI is always using the administration connector with SSL private static final boolean alwaysSSL = true; /** * 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, true, System.out, System.err); if (exitCode != 0) { 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 initializeServer * Indicates whether to perform basic initialization (which * should not be done if the tool is running in the same * JVM as the server). * @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, boolean initializeServer, OutputStream outStream, OutputStream errStream) { DSConfig app = new DSConfig(System.in, outStream, errStream, new LDAPManagementContextFactory(alwaysSSL)); // Only initialize the client environment when run as a standalone // application. if (initializeServer) { try { app.initializeClientEnvironment(); } catch (InitializationException e) { // TODO: is this ok as an error message? app.println(e.getMessageObject()); return 1; } } // Run the application. return app.run(args); } // The argument which should be used to request advanced mode. private BooleanArgument advancedModeArgument; // Flag indicating whether or not the application environment has // already been initialized. private boolean environmentInitialized = false; // The factory which the application should use to retrieve its // management context. private final ManagementContextFactory factory; // 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 handlers = new HashMap(); // Indicates whether or not a sub-command was provided. private boolean hasSubCommand = true; // 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; // The boolean that is used to know if data must be appended to the file // containing equivalent non-interactive commands. private boolean alreadyWroteEquivalentCommand; /** * Creates a new dsconfig application instance. * * @param in * The application input stream. * @param out * The application output stream. * @param err * The application error stream. * @param factory * The factory which this application instance should use * for obtaining management contexts. */ private DSConfig(InputStream in, OutputStream out, OutputStream err, ManagementContextFactory factory) { super(in, out, err); this.parser = new SubCommandArgumentParser(this.getClass().getName(), INFO_CONFIGDS_TOOL_DESCRIPTION.get(), false); this.factory = factory; } /** * Initializes core APIs for use when dsconfig will be run as a * standalone application. * * @throws InitializationException * If the core APIs could not be initialized. */ private void initializeClientEnvironment() throws InitializationException { if (environmentInitialized == false) { EmbeddedUtils.initializeForClientUse(); // Bootstrap definition classes. ClassLoaderProvider.getInstance().enable(); // Switch off class name validation in client. ClassPropertyDefinition.setAllowClassValidation(false); // Switch off attribute type name validation in client. AttributeTypePropertyDefinition.setCheckSchema(false); environmentInitialized = true; } } /** * {@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(Message 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() throws ArgumentException { if (globalArgumentsInitialized == false) { verboseArgument = new BooleanArgument("verbose", 'v', "verbose", INFO_DESCRIPTION_VERBOSE.get()); quietArgument = new BooleanArgument( OPTION_LONG_QUIET, OPTION_SHORT_QUIET, OPTION_LONG_QUIET, INFO_DESCRIPTION_QUIET.get()); quietArgument.setPropertyName(OPTION_LONG_QUIET); scriptFriendlyArgument = new BooleanArgument("script-friendly", OPTION_SHORT_SCRIPT_FRIENDLY, OPTION_LONG_SCRIPT_FRIENDLY, INFO_DESCRIPTION_SCRIPT_FRIENDLY.get()); scriptFriendlyArgument.setPropertyName(OPTION_LONG_SCRIPT_FRIENDLY); noPromptArgument = new BooleanArgument( OPTION_LONG_NO_PROMPT, OPTION_SHORT_NO_PROMPT, OPTION_LONG_NO_PROMPT, INFO_DESCRIPTION_NO_PROMPT.get()); advancedModeArgument = new BooleanArgument(OPTION_DSCFG_LONG_ADVANCED, OPTION_DSCFG_SHORT_ADVANCED, OPTION_DSCFG_LONG_ADVANCED, INFO_DSCFG_DESCRIPTION_ADVANCED.get()); advancedModeArgument.setPropertyName(OPTION_DSCFG_LONG_ADVANCED); showUsageArgument = new BooleanArgument("showUsage", OPTION_SHORT_HELP, OPTION_LONG_HELP, INFO_DSCFG_DESCRIPTION_SHOW_GROUP_USAGE_SUMMARY .get()); displayEquivalentArgument = new BooleanArgument( OPTION_DSCFG_LONG_DISPLAY_EQUIVALENT, null, OPTION_DSCFG_LONG_DISPLAY_EQUIVALENT, INFO_DSCFG_DESCRIPTION_DISPLAY_EQUIVALENT.get()); advancedModeArgument.setPropertyName( OPTION_DSCFG_LONG_DISPLAY_EQUIVALENT); 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_DESCRIPTION_CONFIG_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(displayEquivalentArgument); parser.addGlobalArgument(equivalentCommandFileArgument); parser.addGlobalArgument(propertiesFileArgument); parser.setFilePropertiesArgument(propertiesFileArgument); parser.addGlobalArgument(noPropertiesFileArgument); parser.setNoPropertiesFileArgument(noPropertiesFileArgument); // Register any global arguments required by the management // context factory. factory.registerGlobalArguments(parser); 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); Comparator c = new Comparator() { public int compare(SubCommand o1, SubCommand o2) { return o1.getName().compareTo(o2.getName()); } }; Map> groups = new TreeMap>(); SortedSet allSubCommands = new TreeSet(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 group = groups.get(tag); if (group == null) { group = new TreeSet(c); groups.put(tag, group); } group.add(sc); } } // Register the usage arguments. for (Map.Entry> group : groups.entrySet()) { Tag tag = group.getKey(); SortedSet 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(); initializeSubCommands(); } catch (ArgumentException e) { Message message = ERR_CANNOT_INITIALIZE_ARGS.get(e.getMessage()); println(message); return 1; } // Parse the command-line arguments provided to this program. try { parser.parseArguments(args); } catch (ArgumentException ae) { Message message = ERR_ERROR_PARSING_ARGS.get(ae.getMessage()); displayMessageAndUsageReference(message); return 1; } // If the usage/version argument was provided, then we don't need // to do anything else. if (parser.usageOrVersionDisplayed()) { return 0; } // Check for conflicting arguments. if (quietArgument.isPresent() && verboseArgument.isPresent()) { Message message = ERR_TOOL_CONFLICTING_ARGS.get(quietArgument .getLongIdentifier(), verboseArgument.getLongIdentifier()); displayMessageAndUsageReference(message); return 1; } if (quietArgument.isPresent() && !noPromptArgument.isPresent()) { Message message = ERR_DSCFG_ERROR_QUIET_AND_INTERACTIVE_INCOMPATIBLE.get( quietArgument.getLongIdentifier(), noPromptArgument .getLongIdentifier()); displayMessageAndUsageReference(message); return 1; } if (scriptFriendlyArgument.isPresent() && verboseArgument.isPresent()) { Message message = ERR_TOOL_CONFLICTING_ARGS.get(scriptFriendlyArgument .getLongIdentifier(), verboseArgument.getLongIdentifier()); displayMessageAndUsageReference(message); return 1; } if (noPropertiesFileArgument.isPresent() && propertiesFileArgument.isPresent()) { Message message = ERR_TOOL_CONFLICTING_ARGS.get( noPropertiesFileArgument.getLongIdentifier(), propertiesFileArgument.getLongIdentifier()); displayMessageAndUsageReference(message); return 1; } // Check that we can write on the provided path where we write the // equivalent non-interactive commands. if (equivalentCommandFileArgument.isPresent()) { String file = equivalentCommandFileArgument.getValue(); if (!Utils.canWrite(file)) { println(ERR_DSCFG_CANNOT_WRITE_EQUIVALENT_COMMAND_LINE_FILE.get(file)); return 1; } else { File f = new File(file); if (f.isDirectory()) { println(ERR_DSCFG_EQUIVALENT_COMMAND_LINE_FILE_DIRECTORY.get(file)); return 1; } } } // Make sure that management context's arguments are valid. try { factory.validateGlobalArguments(); } catch (ArgumentException e) { println(e.getMessageObject()); return 1; } int retCode = 0; if (parser.getSubCommand() == null) { hasSubCommand = false; if (isInteractive()) { // Top-level interactive mode. retCode = runInteractiveMode(); } else { Message message = ERR_ERROR_PARSING_ARGS .get(ERR_DSCFG_ERROR_MISSING_SUBCOMMAND.get()); displayMessageAndUsageReference(message); retCode = 1; } } else { hasSubCommand = true; // Retrieve the sub-command implementation and run it. SubCommandHandler handler = handlers.get(parser.getSubCommand()); retCode = runSubCommand(handler); } try { // Close the Management context ==> an LDAP UNBIND is sent factory.close(); } catch (Exception e) { // Nothing to report in this case } return retCode; } // Run the top-level interactive console. private int runInteractiveMode() { // In interactive mode, redirect all output to stdout. ConsoleApplication app = new OutputStreamConsoleApplication(this); // Build menu structure. Comparator> c = new Comparator>() { public int compare(RelationDefinition rd1, RelationDefinition rd2) { String s1 = rd1.getUserFriendlyName().toString(); String s2 = rd2.getUserFriendlyName().toString(); return s1.compareToIgnoreCase(s2); } }; Set> relations; Map, CreateSubCommandHandler> createHandlers; Map, DeleteSubCommandHandler> deleteHandlers; Map, ListSubCommandHandler> listHandlers; Map, GetPropSubCommandHandler> getPropHandlers; Map, SetPropSubCommandHandler> setPropHandlers; relations = new TreeSet>(c); createHandlers = new HashMap, CreateSubCommandHandler>(); deleteHandlers = new HashMap, DeleteSubCommandHandler>(); listHandlers = new HashMap, ListSubCommandHandler>(); getPropHandlers = new HashMap, GetPropSubCommandHandler>(); setPropHandlers = new HashMap, SetPropSubCommandHandler>(); for (CreateSubCommandHandler ch : handlerFactory .getCreateSubCommandHandlers()) { relations.add(ch.getRelationDefinition()); createHandlers.put(ch.getRelationDefinition(), ch); } for (DeleteSubCommandHandler dh : handlerFactory .getDeleteSubCommandHandlers()) { relations.add(dh.getRelationDefinition()); deleteHandlers.put(dh.getRelationDefinition(), dh); } for (ListSubCommandHandler lh : handlerFactory.getListSubCommandHandlers()) { relations.add(lh.getRelationDefinition()); listHandlers.put(lh.getRelationDefinition(), lh); } for (GetPropSubCommandHandler gh : handlerFactory .getGetPropSubCommandHandlers()) { relations.add(gh.getRelationDefinition()); getPropHandlers.put(gh.getRelationDefinition(), gh); } for (SetPropSubCommandHandler sh : handlerFactory .getSetPropSubCommandHandlers()) { relations.add(sh.getRelationDefinition()); setPropHandlers.put(sh.getRelationDefinition(), sh); } // Main menu. MenuBuilder builder = new MenuBuilder(app); builder.setTitle(INFO_DSCFG_HEADING_MAIN_MENU_TITLE.get()); builder.setPrompt(INFO_DSCFG_HEADING_MAIN_MENU_PROMPT.get()); builder.setMultipleColumnThreshold(0); for (RelationDefinition rd : relations) { MenuCallback callback = new SubMenuCallback(app, rd, createHandlers.get(rd), deleteHandlers.get(rd), listHandlers.get(rd), setPropHandlers.get(rd)); builder.addNumberedOption(rd.getUserFriendlyName(), callback); } builder.addQuitOption(); Menu menu = builder.toMenu(); try { // Force retrieval of management context. factory.getManagementContext(app); } catch (ArgumentException e) { app.println(e.getMessageObject()); return 1; } catch (ClientException e) { app.println(e.getMessageObject()); return 1; } try { app.println(); app.println(); MenuResult result = menu.run(); if (result.isQuit()) { return 0; } else { return result.getValue(); } } catch (CLIException e) { app.println(e.getMessageObject()); return 1; } } // Run the provided sub-command handler. private int runSubCommand(SubCommandHandler handler) { try { MenuResult result = handler.run(this, factory); if (result.isSuccess()) { if (isInteractive()) { println(); println(INFO_DSCFG_NON_INTERACTIVE.get( getCommandBuilder(handler).toString())); } return result.getValue(); } else { // User must have quit. return 1; } } catch (ArgumentException e) { println(e.getMessageObject()); return 1; } catch (CLIException e) { println(e.getMessageObject()); return 1; } catch (ClientException e) { Throwable cause = e.getCause(); if (cause instanceof ManagedObjectDecodingException) { ManagedObjectDecodingException de = (ManagedObjectDecodingException) cause; println(); displayManagedObjectDecodingException(this, de); println(); } else if (cause instanceof MissingMandatoryPropertiesException) { MissingMandatoryPropertiesException mmpe = (MissingMandatoryPropertiesException) cause; println(); displayMissingMandatoryPropertyException(this, mmpe); println(); } else if (cause instanceof OperationRejectedException) { OperationRejectedException ore = (OperationRejectedException) cause; println(); displayOperationRejectedException(this, ore); println(); } else { // Just display the default message. println(e.getMessageObject()); } return 1; } catch (Exception e) { if (debugEnabled()) { TRACER.debugCaught(DebugLogLevel.ERROR, e); } println(Message.raw(StaticUtils.stackTraceToString(e))); return 1; } } /** * Updates the command builder with the global options: script friendly, * verbose, etc. for a given subcommand. It also adds systematically the * no-prompt option. * @param handler the subcommand handler. */ private CommandBuilder getCommandBuilder(SubCommandHandler handler) { String commandName = System.getProperty(ServerConstants.PROPERTY_SCRIPT_NAME); if (commandName == null) { commandName = "dsconfig"; } CommandBuilder commandBuilder = new CommandBuilder(commandName, handler.getSubCommand().getName()); commandBuilder.append(handler.getCommandBuilder()); 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; } /** * Creates a command builder with the global options: script friendly, * verbose, etc. for a given subcommand name. It also adds systematically the * no-prompt option. * @param subcommandName the subcommand name. * @return the command builder that has been created with the specified * subcommandName. */ CommandBuilder getCommandBuilder(String subcommandName) { String commandName = System.getProperty(ServerConstants.PROPERTY_SCRIPT_NAME); if (commandName == null) { commandName = "dsconfig"; } CommandBuilder commandBuilder = new CommandBuilder(commandName, subcommandName); 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. Currently it simply writes the content of the CommandBuilder * to the standard output, but if we provide an option to write the content * to a file only the implementation of this method must be changed. * @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.toString())); } if (equivalentCommandFileArgument.isPresent()) { // Write to the file. boolean append = alreadyWroteEquivalentCommand; String file = equivalentCommandFileArgument.getValue(); try { BufferedWriter writer = new BufferedWriter(new FileWriter(file, append)); writer.write(commandBuilder.toString()); writer.newLine(); writer.flush(); writer.close(); } catch (IOException ioe) { println(ERR_DSCFG_ERROR_WRITING_EQUIVALENT_COMMAND_LINE.get(file, ioe.toString())); } alreadyWroteEquivalentCommand = true; } } }