summaryrefslogtreecommitdiff
path: root/org.genivi.commonapi.console/src/org/genivi/commonapi/console/CommandExecuter.java
blob: a8a97d6c83df622ba97386ee818c3ab024a7e7fc (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
/* Copyright (C) 2013-2014 BMW Group
 * Author: Manfred Bathelt (manfred.bathelt@bmw.de)
 * Author: Juergen Gehring (juergen.gehring@bmw.de)
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
package org.genivi.commonapi.console;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.cli.AlreadySelectedException;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.HelpFormatter;
import org.apache.commons.cli.MissingArgumentException;
import org.apache.commons.cli.MissingOptionException;
import org.apache.commons.cli.Option;
import org.apache.commons.cli.OptionGroup;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException;
import org.apache.commons.cli.Parser;
import org.apache.commons.cli.PosixParser;
import org.apache.commons.cli.UnrecognizedOptionException;
import org.apache.commons.lang.WordUtils;
import org.eclipse.core.runtime.Assert;
import org.eclipse.core.runtime.IConfigurationElement;
import org.eclipse.core.runtime.IExtensionPoint;
import org.eclipse.core.runtime.IExtensionRegistry;
import org.eclipse.core.runtime.ISafeRunnable;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.SafeRunner;
import org.eclipse.core.runtime.Status;
import org.genivi.commonapi.console.internal.Application;

public enum CommandExecuter
{
    INSTANCE;

    private final String       COMMANDS_EXTENSION_POINT_ID                 = Application.PLUGIN_ID + ".commands";
    private final String       OPTIONS_EXTENSION_POINT_ID                  = Application.PLUGIN_ID + ".options";
    private final String       OPTION_GROUPS_EXTENSION_POINT_ID            = Application.PLUGIN_ID + ".optionGroups";

    private final String       COMMAND_ID_ATTRIBUTE_NAME                   = "id";
    private final String       COMMAND_NAME_ATTRIBUTE_NAME                 = "name";
    private final String       COMMAND_HANDLER_ATTRIBUTE_NAME              = "class";
    private final String       COMMAND_SYNTAX_ATTRIBUTE_NAME               = "syntax";

    private final String       OPTION_ID_ATTRIBUTE_NAME                    = "id";
    private final String       OPTION_SHORT_NAME_ATTRIBUTE_NAME            = "shortName";
    private final String       OPTION_LONG_NAME_ATTRIBUTE_NAME             = "longName";
    private final String       OPTION_DESCRIPTION_ATTRIBUTE_NAME           = "description";
    private final String       OPTION_REQUIRED_ATTRIBUTE_NAME              = "required";
    private final String       OPTION_ARG_COUNT_ATTRIBUTE_NAME             = "argCount";
    private final String       OPTION_ARG_NAME_ATTRIBUTE_NAME              = "argName";
    private final String       OPTION_HAS_OPTIONAL_ARG_ATTRIBUTE_NAME      = "hasOptionalArg";
    private final String       OPTION_VALUE_SEPARATOR_ATTRIBUTE_NAME       = "valueSeparator";

    private final String       OPTION_ID_OPTION_ID_ATTRIBUTE_NAME          = "optionId";

    private final String       OPTION_GROUP_ID_ATTRIBUTE_NAME              = "id";
    private final String       OPTION_GROUP_REQUIRED_ATTRIBUTE_NAME        = "required";

    private final String       OPTION_GROUP_OPTION_GROUP_ID_ATTRIBUTE_NAME = "optionGroupId";

    private final String       OPTIONS_CONFIGURATION_NAME                  = "options";
    private final String       HEADER_CONFIGURATION_NAME                   = "header";
    private final String       FOOTER_CONFIGURATION_NAME                   = "footer";
    private final String       OPTION_CONFIGURATION_NAME                   = "option";
    private final String       OPTION_ID_CONFIGURATION_NAME                = "optionId";
    private final String       OPTION_GROUP_CONFIGURATION_NAME             = "optionGroup";
    private final String       OPTION_GROUP_ID_CONFIGURATION_NAME          = "optionGroupId";

    private final String       ECLIPSE_LAUNCHER_PROPERTY_NAME              = "eclipse.launcher";

    private final String       ID_OPTION_DESCRIPTION                       = "%s of the desired console command";
    private final String       EXTENSION_POINT_PARSING_ERROR_MESSAGE       = "An error occured while parsing console command \"%s\"!";
    private final String       OPTION_ID_NOT_FOUND_MESSAGE                 = "The option ID \"%s\" could not be found!";
    private final String       OPTION_GROUP_ID_NOT_FOUND_MESSAGE           = "The option group ID \"%s\" could not be found!";
    private final String       NO_REQUIRED_OPTION_MESSAGE                  = "This console command needs to specify at least one required option!";
    private final String       HELP_NO_COMMANDS_TEXT_MESSAGE               = "No registered console commands available!";
    private final String       HELP_NAME_TEXT_MESSAGE                      = "Command: %s";
    private final String       HELP_ID_TEXT_MESSAGE                        = "%s: %s";
    private final String       HELP_WRONG_ID_MESSAGE                       = HELP_ID_TEXT_MESSAGE + "%nID does not match: %s";
    private final String       HELP_SEVERAL_COMMANDS_MESSAGE               = "Several console commands are compatible to this set of parameters. Add ID option to select the desired one.%n";
    private final String       EXECUTE_COMMAND_MESSAGE                     = "Excuting %s...%n" ;
    private final String       LAUNCHER_NAME;
    private final Option       ID_OPTION;

    public static final String SHORT_ID_OPTION                             = "ID";
    public static final String LONG_ID_OPTION                              = "COMMAND_ID";

    public static final int    DEFAULT_RETURN_VALUE                        = -1000;
    public static final int    CONSOLE_WIDTH                               = 80;

    private int                returnValue                                 = DEFAULT_RETURN_VALUE;

    private CommandExecuter()
    {
        String launcherName = System.getProperty(ECLIPSE_LAUNCHER_PROPERTY_NAME);
        LAUNCHER_NAME = (null != launcherName) ? new Path(launcherName).lastSegment() : Platform.getProduct().getName();

        ID_OPTION = new Option(SHORT_ID_OPTION, LONG_ID_OPTION, true, String.format(ID_OPTION_DESCRIPTION, SHORT_ID_OPTION));
        ID_OPTION.setRequired(true);
        ID_OPTION.setArgs(1);
        ID_OPTION.setOptionalArg(true);
    }

    public int executeCommand(String command)
    {
        Assert.isNotNull(command);

        String[] arguments = (command.length() > 0) ? (command.trim().split("\\s")) : (new String[0]);

        return executeCommand(arguments);
    }

    public int executeCommand(String[] arguments)
    {
        Assert.isNotNull(arguments);

        final List<ConsoleConfiguration> configurations = getParsedExtensionPointConfigurations();

        // Print message if there are no registered console commands.
        if (configurations.size() == 0)
        {
            println(HELP_NO_COMMANDS_TEXT_MESSAGE);

            return DEFAULT_RETURN_VALUE;
        }

        // Print help text if no option is available.
        if (arguments.length == 0)
        {
            printHelp(configurations);

            return DEFAULT_RETURN_VALUE;
        }

        // Find a suitable console configuration.
        final List<ConsoleConfiguration> perfectMatchingConfigurations = new ArrayList<ConsoleConfiguration>();
        final List<ConsoleConfiguration> partialMatchingConfigurations = new ArrayList<ConsoleConfiguration>();
        final List<ConsoleConfiguration> notMatchingConfigurations = new ArrayList<ConsoleConfiguration>();

        Parser parser = new PosixParser();

        for (ConsoleConfiguration configuration : configurations)
        {
            try
            {
                CommandLine commandLine = parser.parse(configuration.options, arguments);

                // Add ID option and ID information to configuration. Thus if there are several
                // perfect matches the printHelp method can print this information.
                configuration.options.addOption(ID_OPTION);
                configuration.message = String.format(HELP_ID_TEXT_MESSAGE, SHORT_ID_OPTION, configuration.id);
                configuration.commandLine = commandLine;
                perfectMatchingConfigurations.add(configuration);
            }
            catch (MissingOptionException | MissingArgumentException | AlreadySelectedException exception)
            {
                configuration.message = exception.getMessage();
                partialMatchingConfigurations.add(configuration);
            }
            catch (UnrecognizedOptionException exception)
            {
                // Check if the unrecognized option is the ID option.
                String unrecognizedOption = exception.getOption();

                if (unrecognizedOption.equals("-" + SHORT_ID_OPTION) || unrecognizedOption.equals("--" + LONG_ID_OPTION))
                {
                    try
                    {
                        // Add ID option to options object an parse arguments again.
                        CommandLine commandLine = parser.parse(configuration.options.addOption(ID_OPTION), arguments);
                        String idValue = commandLine.getOptionValue(SHORT_ID_OPTION);

                        // The correct console configuration is found if parsing did not throw an
                        // exception and the ID option equals extension point ID.
                        if (configuration.id.equals(idValue))
                        {
                            configuration.commandLine = commandLine;
                            perfectMatchingConfigurations.add(configuration);
                        }
                        else
                        {
                            configuration.message = String.format(HELP_WRONG_ID_MESSAGE, SHORT_ID_OPTION, configuration.id, idValue);
                            partialMatchingConfigurations.add(configuration);
                        }
                    }
                    catch (ParseException e)
                    {
                        configuration.message = e.getMessage();
                        notMatchingConfigurations.add(configuration);
                    }
                }
                else
                {
                    configuration.message = exception.getMessage();
                    notMatchingConfigurations.add(configuration);
                }
            }
            catch (ParseException exception)
            {
                configuration.message = exception.getMessage();
                notMatchingConfigurations.add(configuration);
            }
        }

        // Execute compatible command or print help text
        if (perfectMatchingConfigurations.size() == 1)
        {
            SafeRunner.run(new ISafeRunnable()
            {
                @Override
                public void run() throws Exception
                {
                    ConsoleConfiguration configuration = perfectMatchingConfigurations.get(0);

                    if (configurations.size() > 1)
                    {
                        println(EXECUTE_COMMAND_MESSAGE, configuration.name);
                    }

                    Object executable = configuration.commandConfiguration.createExecutableExtension(COMMAND_HANDLER_ATTRIBUTE_NAME);
                    ICommandLineHandler handler = (ICommandLineHandler) executable;

                    returnValue = handler.excute(configuration.commandLine);
                }

                @Override
                public void handleException(Throwable throwable)
                {
                    log(throwable);
                }
            });
        }
        else if (perfectMatchingConfigurations.size() > 1)
        {
            println(HELP_SEVERAL_COMMANDS_MESSAGE);
            printHelp(perfectMatchingConfigurations);
        }
        else if (partialMatchingConfigurations.size() > 0)
        {
            printHelp(partialMatchingConfigurations);
        }
        else
        {
            printHelp(notMatchingConfigurations);
        }

        return returnValue;
    }

    private void printHelp(List<ConsoleConfiguration> configurations)
    {
        for (ConsoleConfiguration configuration : configurations)
        {
            printHelp(configuration);
        }
    }

    private void printHelp(ConsoleConfiguration configuration)
    {
        println(HELP_NAME_TEXT_MESSAGE, configuration.name);

        if (null != configuration.message)
        {
            println(configuration.message);
        }

        boolean generateSyntax = true;
        String syntax = LAUNCHER_NAME;

        if (null != configuration.syntax && configuration.syntax.length() > 0)
        {
            syntax = syntax + " " + configuration.syntax;
            generateSyntax = false;
        }

        new HelpFormatter().printHelp(CONSOLE_WIDTH, syntax, configuration.header, configuration.options, configuration.footer,
                generateSyntax);

        System.out.println();
    }

    private void log(Throwable throwable)
    {
        IStatus status = new Status(Status.ERROR, Application.PLUGIN_ID, throwable.getMessage(), throwable);

        Platform.getLog(Platform.getBundle(Application.PLUGIN_ID)).log(status);
    }

    private List<ConsoleConfiguration> getParsedExtensionPointConfigurations()
    {
        List<ConsoleConfiguration> configurations = new ArrayList<ConsoleConfiguration>();

        // Parse extension point information
        IExtensionRegistry extensionRegistry = Platform.getExtensionRegistry();
        IExtensionPoint commandsExtensionPoint = extensionRegistry.getExtensionPoint(COMMANDS_EXTENSION_POINT_ID);

        if (null != commandsExtensionPoint)
        {
            Map<String, IConfigurationElement> referenceableOptionConfigurations = parseExtensionPoint(
                    extensionRegistry.getExtensionPoint(OPTIONS_EXTENSION_POINT_ID), OPTION_ID_ATTRIBUTE_NAME);
            Map<String, IConfigurationElement> referenceableOptionGroupConfigurations = parseExtensionPoint(
                    extensionRegistry.getExtensionPoint(OPTION_GROUPS_EXTENSION_POINT_ID), OPTION_GROUP_ID_ATTRIBUTE_NAME);

            for (IConfigurationElement commandConfiguration : commandsExtensionPoint.getConfigurationElements())
            {
                String id = commandConfiguration.getAttribute(COMMAND_ID_ATTRIBUTE_NAME);

                try
                {
                    Options options = new Options();

                    String name = commandConfiguration.getAttribute(COMMAND_NAME_ATTRIBUTE_NAME);
                    String syntax = commandConfiguration.getAttribute(COMMAND_SYNTAX_ATTRIBUTE_NAME);
                    String header = null;
                    String footer = null;

                    for (IConfigurationElement childConfiguration : commandConfiguration.getChildren())
                    {
                        switch (childConfiguration.getName())
                        {
                            case OPTIONS_CONFIGURATION_NAME:
                                for (IConfigurationElement optionConfiguration : childConfiguration.getChildren())
                                {
                                    Option option = getOptionByConfiguration(optionConfiguration, referenceableOptionConfigurations);
                                    OptionGroup optionGroup = getOptionGroupByConfiguration(optionConfiguration,
                                            referenceableOptionGroupConfigurations, referenceableOptionConfigurations);

                                    if (null != option)
                                    {
                                        options.addOption(option);
                                    }

                                    if (null != optionGroup)
                                    {
                                        options.addOptionGroup(optionGroup);
                                    }
                                }
                                break;

                            case HEADER_CONFIGURATION_NAME:
                                header = childConfiguration.getValue();
                                break;

                            case FOOTER_CONFIGURATION_NAME:
                                footer = childConfiguration.getValue();
                                break;
                        }
                    }

                    configurations.add(new ConsoleConfiguration(commandConfiguration, options, id, name, syntax, header, footer));
                }
                catch (Exception exception)
                {
                    String message = String.format(EXTENSION_POINT_PARSING_ERROR_MESSAGE + " " + exception.getMessage(), id);

                    log(new IllegalArgumentException(message, exception));
                }
            }
        }

        return configurations;
    }

    private Map<String, IConfigurationElement> parseExtensionPoint(IExtensionPoint extensionPoint, String keyAttributeName)
    {
        Map<String, IConfigurationElement> map = new HashMap<String, IConfigurationElement>();

        if (null != extensionPoint && null != keyAttributeName)
        {
            for (IConfigurationElement configurationElement : extensionPoint.getConfigurationElements())
            {
                map.put(configurationElement.getAttribute(keyAttributeName), configurationElement);
            }
        }

        return map;
    }

    private Option getOptionByConfiguration(IConfigurationElement optionConfiguration,
            Map<String, IConfigurationElement> referenceableOptionConfigurations)
    {
        switch (optionConfiguration.getName())
        {
            case OPTION_CONFIGURATION_NAME:
                return createOption(optionConfiguration);

            case OPTION_ID_CONFIGURATION_NAME:
                String referencedOptionId = optionConfiguration.getAttribute(OPTION_ID_OPTION_ID_ATTRIBUTE_NAME);
                IConfigurationElement referencedOptionConfiguration = referenceableOptionConfigurations.get(referencedOptionId);

                if (null == referencedOptionConfiguration)
                {
                    throw new IllegalArgumentException(String.format(OPTION_ID_NOT_FOUND_MESSAGE, referencedOptionId));
                }

                return createOption(referencedOptionConfiguration);

            default:
                return null;
        }
    }

    private OptionGroup getOptionGroupByConfiguration(IConfigurationElement optionConfiguration,
            Map<String, IConfigurationElement> referenceableOptionGroupConfigurations,
            Map<String, IConfigurationElement> referenceableOptionConfigurations)
    {
        switch (optionConfiguration.getName())
        {
            case OPTION_GROUP_CONFIGURATION_NAME:
                return createOptionGroup(optionConfiguration, referenceableOptionConfigurations);

            case OPTION_GROUP_ID_CONFIGURATION_NAME:
                String referencedOptionGroupId = optionConfiguration.getAttribute(OPTION_GROUP_OPTION_GROUP_ID_ATTRIBUTE_NAME);
                IConfigurationElement referencedOptionGroupConfiguration = referenceableOptionGroupConfigurations
                        .get(referencedOptionGroupId);

                if (null == referencedOptionGroupConfiguration)
                {
                    throw new IllegalArgumentException(String.format(OPTION_GROUP_ID_NOT_FOUND_MESSAGE, referencedOptionGroupId));
                }

                return createOptionGroup(referencedOptionGroupConfiguration, referenceableOptionConfigurations);

            default:
                return null;
        }
    }

    private Option createOption(IConfigurationElement optionConfiguration)
    {
        String shortName = optionConfiguration.getAttribute(OPTION_SHORT_NAME_ATTRIBUTE_NAME);
        String longName = optionConfiguration.getAttribute(OPTION_LONG_NAME_ATTRIBUTE_NAME);
        String description = optionConfiguration.getAttribute(OPTION_DESCRIPTION_ATTRIBUTE_NAME);
        String required = optionConfiguration.getAttribute(OPTION_REQUIRED_ATTRIBUTE_NAME);
        String argCount = optionConfiguration.getAttribute(OPTION_ARG_COUNT_ATTRIBUTE_NAME);
        String argName = optionConfiguration.getAttribute(OPTION_ARG_NAME_ATTRIBUTE_NAME);
        String hasOptionalArg = optionConfiguration.getAttribute(OPTION_HAS_OPTIONAL_ARG_ATTRIBUTE_NAME);
        String valueSeparator = optionConfiguration.getAttribute(OPTION_VALUE_SEPARATOR_ATTRIBUTE_NAME);

        Option option = new Option(shortName, description);
        option.setRequired(Boolean.parseBoolean(required));
        option.setArgs(Integer.parseInt(argCount));
        option.setOptionalArg(Boolean.parseBoolean(hasOptionalArg));

        if (null != longName)
        {
            option.setLongOpt(longName);
        }

        if (null != argName)
        {
            option.setArgName(argName);
        }

        if (null != valueSeparator)
        {
            option.setValueSeparator(valueSeparator.charAt(0));
        }

        return option;
    }

    private OptionGroup createOptionGroup(IConfigurationElement optionGroupConfiguration,
            Map<String, IConfigurationElement> referenceableOptionConfigurations)
    {
        String required = optionGroupConfiguration.getAttribute(OPTION_GROUP_REQUIRED_ATTRIBUTE_NAME);

        OptionGroup optionGroup = new OptionGroup();
        optionGroup.setRequired(Boolean.parseBoolean(required));

        for (IConfigurationElement optionConfiguration : optionGroupConfiguration.getChildren())
        {
            Option option = getOptionByConfiguration(optionConfiguration, referenceableOptionConfigurations);

            if (null != option)
            {
                optionGroup.addOption(option);
            }
        }

        return optionGroup;
    }

    private class ConsoleConfiguration
    {
        public final IConfigurationElement commandConfiguration;
        public final Options               options;
        public final String                id;
        public final String                name;
        public final String                syntax;
        public final String                header;
        public final String                footer;

        public CommandLine                 commandLine;
        public String                      message;

        public ConsoleConfiguration(IConfigurationElement commandConfiguration, Options options, String id, String name, String syntax,
                String header, String footer, CommandLine commandLine, String message)
        {
            this.commandConfiguration = commandConfiguration;
            this.options = options;
            this.id = id;
            this.name = name;
            this.syntax = syntax;
            this.header = header;
            this.footer = footer;
            this.commandLine = commandLine;
            this.message = message;
        }

        public ConsoleConfiguration(IConfigurationElement commandConfiguration, Options options, String id, String name, String syntax,
                String header, String footer)
        {
            this(commandConfiguration, options, id, name, syntax, header, footer, null, null);
        }
    }

    /**
     * Converts an instance the CommandLine Object into an array of strings.
     *
     * @param commandLine
     *            instance
     * @return Arguments split into string array
     */
    public static String[] getArguments(CommandLine commandLine)
    {
        return getArguments(commandLine, false);
    }

    /**
     * Converts an instance the CommandLine Object into an array of strings.
     *
     * @param commandLine
     *            instance
     * @param keepIdOption
     *            if true the returned array will contain the ID option if available
     * @return Arguments split into string array
     */
    public static String[] getArguments(CommandLine commandLine, boolean keepIdOption)
    {
        Assert.isNotNull(commandLine);

        List<String> argumentsList = new ArrayList<String>();

        Option[] options = commandLine.getOptions();

        if (null != options)
        {
            for (Option option : options)
            {
                String optionString = option.getOpt();

                if (keepIdOption == false && SHORT_ID_OPTION.equals(optionString))
                {
                    continue;
                }

                argumentsList.add("-" + optionString);

                String[] values = option.getValues();

                if (null != values)
                {
                    for (String value : values)
                    {
                        argumentsList.add(value);
                    }
                }
            }
        }

        return argumentsList.toArray(new String[argumentsList.size()]);
    }

    /**
     * Prints a message to the console and wraps the string to the same width as the outputs done by the command executer.
     *
     * @param message
     *            the message to print
     * @param arguments
     *            Arguments referenced by the format specifiers in the message string. If there are more arguments than format specifiers,
     *            the extra arguments are ignored. The number of arguments is variable and may be zero.
     */
    public static void println(String message, Object... arguments)
    {
        Assert.isNotNull(message);

        String formattedString = String.format(message, arguments);
        String newLineString = String.format("%n");

        // Split message into single line strings because the wrap method cannot handle multi-line messages.
        for (String line : formattedString.split(newLineString))
        {
            System.out.println(WordUtils.wrap(line, CONSOLE_WIDTH));
        }

        // A new-line character at the end gets lost because of the split method.
        if (formattedString.endsWith(newLineString))
        {
            System.out.println();
        }
    }
}