View Javadoc

1   /*
2    JavaProgramImpl.java
3    Creation date : 3/06/2010
4    Copyright © Benjamin Croizet (graffity2199@yahoo.fr)
5   
6    This program is free software; you can redistribute it and/or
7    modify it under the terms of the GNU General Public License
8    or GNU Lesser General Public License as published by the
9    Free Software Foundation; either version 3 of the License,
10   or (at your option) any later version.
11  
12   This program is distributed in the hope that it will be useful,
13   but WITHOUT ANY WARRANTY; without even the implied warranty of
14   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15   GNU General Public License for more details.
16  
17   You should have received copies of the GNU General Public License
18   and GNU Lesser General Public License along with this program;
19   if not, write to the Free Software Foundation, Inc.,
20   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
21   http://www.fsf.org/licensing/licenses/gpl.html
22   http://www.gnu.org/licenses/lgpl.html
23   */
24  
25  package net.sourceforge.plantumldependency.commoncli.program.impl;
26  
27  import static java.util.logging.Level.FINE;
28  import static java.util.logging.Level.SEVERE;
29  import static java.util.logging.Logger.getLogger;
30  import static net.sourceforge.plantumldependency.common.constants.CharacterConstants.HYPHEN_CHAR;
31  import static net.sourceforge.plantumldependency.common.constants.CharacterConstants.LEFT_PARENTHESIS_CHAR;
32  import static net.sourceforge.plantumldependency.common.constants.CharacterConstants.LINE_CHAR;
33  import static net.sourceforge.plantumldependency.common.constants.CharacterConstants.RIGHT_PARENTHESIS_CHAR;
34  import static net.sourceforge.plantumldependency.common.constants.CharacterConstants.SPACE_CHAR;
35  import static net.sourceforge.plantumldependency.common.constants.CharacterConstants.TAB_CHAR;
36  import static net.sourceforge.plantumldependency.common.constants.log.ErrorConstants.UNEXPECTED_ERROR;
37  import static net.sourceforge.plantumldependency.common.utils.check.ParameterCheckerUtils.checkNull;
38  import static net.sourceforge.plantumldependency.common.utils.check.ParameterCheckerUtils.checkNullOrEmpty;
39  import static net.sourceforge.plantumldependency.common.utils.log.LogUtils.buildLogString;
40  import static net.sourceforge.plantumldependency.commoncli.constants.CommandLineConstants.EXAMPLES_OPTIONS_CMD;
41  import static net.sourceforge.plantumldependency.commoncli.constants.CommandLineConstants.JAVA_JAR_CMD;
42  import static net.sourceforge.plantumldependency.commoncli.constants.CommandLineConstants.KNOWN_BUGS_OR_LIMITATIONS_CMD;
43  import static net.sourceforge.plantumldependency.commoncli.constants.CommandLineConstants.MANDATORY_OPTIONS_CMD;
44  import static net.sourceforge.plantumldependency.commoncli.constants.CommandLineConstants.OPTIONAL_OPTIONS_CMD;
45  import static net.sourceforge.plantumldependency.commoncli.constants.CommandLineConstants.OPTIONS_CMD;
46  import static net.sourceforge.plantumldependency.commoncli.constants.CommandLineConstants.OPTION_STATUS_ACTIVE_SET;
47  import static net.sourceforge.plantumldependency.commoncli.constants.CommandLineConstants.OPTION_STATUS_MANDATORY_SET;
48  import static net.sourceforge.plantumldependency.commoncli.constants.CommandLineConstants.OPTION_STATUS_SET;
49  import static net.sourceforge.plantumldependency.commoncli.constants.CommandLineConstants.USAGE_CMD;
50  import static net.sourceforge.plantumldependency.commoncli.constants.log.ErrorConstants.COMMAND_LINE_NULL_ERROR;
51  import static net.sourceforge.plantumldependency.commoncli.constants.log.ErrorConstants.DUPLICATE_OPTION_NAME_ERROR;
52  import static net.sourceforge.plantumldependency.commoncli.constants.log.ErrorConstants.DUPLICATE_OPTION_PRIORITY_ERROR;
53  import static net.sourceforge.plantumldependency.commoncli.constants.log.ErrorConstants.FULL_USAGE_DESCRIPTION_NULL_ERROR;
54  import static net.sourceforge.plantumldependency.commoncli.constants.log.ErrorConstants.FULL_USAGE_EXAMPLES_NULL_ERROR;
55  import static net.sourceforge.plantumldependency.commoncli.constants.log.ErrorConstants.KNOWN_BUG_OR_LIMITATION_NULL_ERROR;
56  import static net.sourceforge.plantumldependency.commoncli.constants.log.ErrorConstants.MANDATORY_OPTIONS_NULL_ERROR;
57  import static net.sourceforge.plantumldependency.commoncli.constants.log.ErrorConstants.NO_OPTION_EXECUTIONS_ERROR;
58  import static net.sourceforge.plantumldependency.commoncli.constants.log.ErrorConstants.OPTIONAL_OPTION_NULL_ERROR;
59  import static net.sourceforge.plantumldependency.commoncli.constants.log.ErrorConstants.OPTIONS_NULL_ERROR;
60  import static net.sourceforge.plantumldependency.commoncli.constants.log.ErrorConstants.OPTION_NULL_ERROR;
61  import static net.sourceforge.plantumldependency.commoncli.constants.log.ErrorConstants.OPTION_STATUS_NULL_ERROR;
62  import static net.sourceforge.plantumldependency.commoncli.constants.log.ErrorConstants.OPTION_STATUS_SET_NULL_ERROR;
63  import static net.sourceforge.plantumldependency.commoncli.constants.log.ErrorConstants.PROGRAM_AUTHORS_NULL_ERROR;
64  import static net.sourceforge.plantumldependency.commoncli.constants.log.ErrorConstants.PROGRAM_JAR_NAME_NULL_ERROR;
65  import static net.sourceforge.plantumldependency.commoncli.constants.log.ErrorConstants.PROGRAM_LICENSES_NULL_ERROR;
66  import static net.sourceforge.plantumldependency.commoncli.constants.log.ErrorConstants.PROGRAM_NAME_NULL_ERROR;
67  import static net.sourceforge.plantumldependency.commoncli.constants.log.ErrorConstants.PROGRAM_TITLE_DESCRIPTION_NULL_ERROR;
68  import static net.sourceforge.plantumldependency.commoncli.constants.log.ErrorConstants.PROGRAM_URL_NULL_ERROR;
69  import static net.sourceforge.plantumldependency.commoncli.constants.log.ErrorConstants.PROGRAM_VERSION_NULL_ERROR;
70  import static net.sourceforge.plantumldependency.commoncli.constants.log.FineConstants.ANALYSING_COMMAND_LINE_FINE;
71  import static net.sourceforge.plantumldependency.commoncli.constants.log.FineConstants.NO_COMMAND_LINE_EXAMPLES_FINE;
72  import static net.sourceforge.plantumldependency.commoncli.constants.log.FineConstants.NO_KNOWN_BUGS_OR_LIMITATIONS_FINE;
73  import static net.sourceforge.plantumldependency.commoncli.constants.log.FineConstants.NO_MANDATORY_OPTIONS_FINE;
74  import static net.sourceforge.plantumldependency.commoncli.constants.log.FineConstants.NO_OPTIONAL_OPTIONS_FINE;
75  import static net.sourceforge.plantumldependency.commoncli.constants.log.FineConstants.OPTION_NOT_SPECIFIED_FINE;
76  import static net.sourceforge.plantumldependency.commoncli.option.status.OptionStatus.ACTIVE_OPTIONAL_OPTION_STATUS;
77  
78  import java.net.URL;
79  import java.util.ArrayList;
80  import java.util.List;
81  import java.util.Set;
82  import java.util.TreeSet;
83  import java.util.logging.Logger;
84  
85  import net.sourceforge.plantumldependency.commoncli.command.CommandLine;
86  import net.sourceforge.plantumldependency.commoncli.exception.CommandLineException;
87  import net.sourceforge.plantumldependency.commoncli.option.Option;
88  import net.sourceforge.plantumldependency.commoncli.option.execution.ExecutableOption;
89  import net.sourceforge.plantumldependency.commoncli.option.execution.OptionExecution;
90  import net.sourceforge.plantumldependency.commoncli.option.status.OptionStatus;
91  import net.sourceforge.plantumldependency.commoncli.program.JavaProgram;
92  import net.sourceforge.plantumldependency.commoncli.program.execution.JavaProgramExecution;
93  import net.sourceforge.plantumldependency.commoncli.program.execution.impl.JavaProgramExecutionImpl;
94  import net.sourceforge.plantumldependency.commoncli.program.version.ProgramVersion;
95  
96  /**
97   * The default implementation of the {@link JavaProgram} interface.
98   *
99   * @author Benjamin Croizet (<a href="mailto:graffity2199@yahoo.fr>graffity2199@yahoo.fr</a>)
100  * @since 1.3.0
101  * @version 1.3.0
102  */
103 public class JavaProgramImpl implements JavaProgram {
104 
105     /** The class logger. */
106     private static final transient Logger LOGGER = getLogger(JavaProgramImpl.class.getName());
107 
108     /** Serial version UID. */
109     private static final long serialVersionUID = 6320611334395831389L;
110 
111     /**
112      * This method finds all duplicate option names in a {@link Set} following the passed
113      * {@link Option}.
114      *
115      * @param option
116      *            the option to check names from, mustn't be <code>null</code>.
117      * @param optionsSet
118      *            the {@link Set} of all options to check duplicates, mustn't be <code>null</code>.
119      * @return the {@link Set} of all duplicate names found, return an empty set if no one is found.
120      * @since 1.3.0
121      */
122     private static Set < String > checkDuplicateOptionNames(final Option option, final Set < Option > optionsSet) {
123         checkNull(option, OPTION_NULL_ERROR);
124         checkNull(optionsSet, OPTIONS_NULL_ERROR);
125 
126         final Set < String > duplicateNames = new TreeSet < String >();
127         for (final Option opt : optionsSet) {
128             for (final String optionName : option.getAllNames()) {
129                 if (opt.getAllNames().contains(optionName)) {
130                     duplicateNames.add(optionName);
131                 }
132             }
133         }
134 
135         return duplicateNames;
136     }
137 
138     /**
139      * This method finds all duplicate option priorities in a {@link Set} following the passed
140      * {@link Option}.
141      *
142      * @param option
143      *            the option to check priorities from, mustn't be <code>null</code>.
144      * @param optionsSet
145      *            the {@link Set} of all options to check duplicates, mustn't be <code>null</code>.
146      * @return the {@link Set} of all duplicate priorities found, return an empty set if no one is
147      *         found.
148      * @since 1.3.0
149      */
150     private static Set < Integer > checkDuplicateOptionPriorities(final ExecutableOption option,
151             final Set < ExecutableOption > optionsSet) {
152         checkNull(option, OPTION_NULL_ERROR);
153         checkNull(optionsSet, OPTIONS_NULL_ERROR);
154 
155         final Set < Integer > duplicatePriorities = new TreeSet < Integer >();
156         for (final ExecutableOption opt : optionsSet) {
157             if (opt.getPriority() == option.getPriority()) {
158                 duplicatePriorities.add(opt.getPriority());
159             }
160         }
161 
162         return duplicatePriorities;
163     }
164 
165     /**
166      * Creates the {@link JavaProgramExecution} instance to execute the program.
167      *
168      * @param optionExecutions
169      *            the {@link Set} of all {@link OptionExecution} which will be executed by the
170      *            {@link JavaProgramExecution} instance.
171      * @return the {@link JavaProgramExecution} instance to execute the program
172      * @since 1.3.0
173      */
174     private static JavaProgramExecution createJavaProgramExecution(final Set < OptionExecution > optionExecutions) {
175         return new JavaProgramExecutionImpl(optionExecutions);
176     }
177 
178     /**
179      * Generates the program main usage description.
180      *
181      * @param fullJarName
182      *            the program jar name, mustn't be <code>null</code>.
183      * @param mandatoryOptions
184      *            the {@link Set} of all mandatory {@link Option}, mustn't be <code>null</code>.
185      * @param optionalOptions
186      *            the {@link Set} of all optional {@link Option}, mustn't be <code>null</code>.
187      * @return the {@link StringBuilder} containing the program main usage description.
188      * @since 1.3.0
189      */
190     private static StringBuilder generateMainUsageDescription(final String fullJarName,
191             final Set < Option > mandatoryOptions, final Set < Option > optionalOptions) {
192         checkNull(fullJarName, PROGRAM_JAR_NAME_NULL_ERROR);
193         checkNull(mandatoryOptions, MANDATORY_OPTIONS_NULL_ERROR);
194         checkNull(optionalOptions, OPTIONAL_OPTION_NULL_ERROR);
195 
196         final StringBuilder buffer = new StringBuilder(JAVA_JAR_CMD);
197 
198         buffer.append(fullJarName);
199         buffer.append(SPACE_CHAR);
200         for (final Option option : mandatoryOptions) {
201             buffer.append(option.getMainUsage());
202             buffer.append(SPACE_CHAR);
203         }
204 
205         if (optionalOptions.size() > 0) {
206             buffer.append(OPTIONS_CMD);
207         } else {
208             LOGGER.log(FINE, NO_OPTIONAL_OPTIONS_FINE);
209         }
210 
211         return buffer;
212     }
213 
214     /**
215      * Generates the program options full usage description.
216      *
217      * @param titleDescription
218      *            the program title description, mustn't be <code>null</code>.
219      * @param options
220      *            the {@link Set} of all program {@link Option}, mustn't be <code>null</code>.
221      * @return the {@link StringBuilder} containing the program options full usage description.
222      * @since 1.3.0
223      */
224     private static StringBuilder generateOptionsFullUsageDescription(final String titleDescription,
225             final Set < Option > options) {
226         checkNull(titleDescription, PROGRAM_TITLE_DESCRIPTION_NULL_ERROR);
227         checkNull(options, OPTIONS_NULL_ERROR);
228 
229         final StringBuilder buffer = new StringBuilder(LINE_CHAR);
230         buffer.append(titleDescription);
231 
232         for (final Option option : options) {
233             buffer.append(LINE_CHAR);
234             buffer.append(LINE_CHAR);
235             buffer.append(TAB_CHAR);
236             buffer.append(option.getFullUsage());
237         }
238 
239         return buffer;
240     }
241 
242     /** The program name. */
243     private String name;
244 
245     /** The {@link List} of all program license names. */
246     private List < String > licenseNames;
247 
248     /** The {@link List} of all program authors. */
249     private List < String > authors;
250 
251     /** The program version. */
252     private ProgramVersion version;
253 
254     /** The jar name. */
255     private String jarName;
256 
257     /** The {@link Set} of all program options. */
258     private Set < Option > allOptions;
259 
260     /** The program website URL. */
261     private URL url;
262 
263     /** The program full usage description. */
264     private StringBuilder fullUsageDescription;
265 
266     /** The {@link Set} of all program example command lines. */
267     private Set < CommandLine > fullUsageExamplesSet;
268 
269     /** The {@link Set} of all program known bugs or limitations. */
270     private Set < String > knownBugsOrLimitationsSet;
271 
272     /**
273      * Default constructor.
274      *
275      * @param programName
276      *            the program name, mustn't be <code>null</code>.
277      * @param programUrl
278      *            the program website URL, mustn't be <code>null</code>.
279      * @param fullJarName
280      *            the program jar name, mustn't be <code>null</code>.
281      * @param programLicenses
282      *            the {@link List} of all program license names, mustn't be <code>null</code>.
283      * @param programAuthors
284      *            the {@link List} of all program authors, mustn't be <code>null</code>.
285      * @param programVersion
286      *            the program version, mustn't be <code>null</code>.
287      * @since 1.3.0
288      */
289     public JavaProgramImpl(final String programName, final URL programUrl, final String fullJarName,
290             final List < String > programLicenses, final List < String > programAuthors,
291             final ProgramVersion programVersion) {
292         this(programName, programUrl, fullJarName, programLicenses, programAuthors, programVersion, new StringBuilder());
293     }
294 
295     /**
296      * Full constructor.
297      *
298      * @param programName
299      *            the program name, mustn't be <code>null</code>.
300      * @param programUrl
301      *            the program website URL, mustn't be <code>null</code>.
302      * @param fullJarName
303      *            the program jar name, mustn't be <code>null</code>.
304      * @param programLicenses
305      *            the {@link List} of all program license names, mustn't be <code>null</code>.
306      * @param programAuthors
307      *            the {@link List} of all program authors, mustn't be <code>null</code>.
308      * @param programVersion
309      *            the program version, mustn't be <code>null</code>.
310      * @param fullProgramDescription
311      *            the program full usage description, mustn't be <code>null</code>.
312      * @since 1.3.0
313      */
314     public JavaProgramImpl(final String programName, final URL programUrl, final String fullJarName,
315             final List < String > programLicenses, final List < String > programAuthors,
316             final ProgramVersion programVersion, final StringBuilder fullProgramDescription) {
317         setName(programName);
318         setUrl(programUrl);
319         setJarName(fullJarName);
320         setLicenseNames(programLicenses);
321         setVersion(programVersion);
322         setAuthors(programAuthors);
323         setFullUsageDescription(fullProgramDescription);
324         setAllOptions(new TreeSet < Option >());
325         setFullUsageExamplesSet(new TreeSet < CommandLine >());
326         setKnownBugsOrLimitationsSet(new TreeSet < String >());
327     }
328 
329     /**
330      * {@inheritDoc}
331      *
332      * @since 1.3.0
333      */
334     @Override
335     public void addExampleCommandLine(final CommandLine exampleCommandLine) throws CommandLineException {
336         checkNull(exampleCommandLine, COMMAND_LINE_NULL_ERROR);
337 
338         getFullUsageExamplesSet().add(exampleCommandLine);
339     }
340 
341     /**
342      * {@inheritDoc}
343      *
344      * @since 1.3.0
345      */
346     @Override
347     public void addKnownBugOrLimitation(final String bugOrLimitationDescription) throws CommandLineException {
348         checkNullOrEmpty(bugOrLimitationDescription, KNOWN_BUG_OR_LIMITATION_NULL_ERROR);
349         getKnownBugsOrLimitationsSet().add(bugOrLimitationDescription);
350     }
351 
352     /**
353      * {@inheritDoc}
354      *
355      * @since 1.3.0
356      */
357     @Override
358     public void addOption(final Option option) throws CommandLineException {
359         checkNull(option, OPTION_NULL_ERROR);
360 
361         final Set < String > duplicateNames = checkDuplicateOptionNames(option, getOriginalAllOptions());
362         if (duplicateNames.size() > 0) {
363             throw new CommandLineException(buildLogString(DUPLICATE_OPTION_NAME_ERROR, duplicateNames));
364         } else if (option instanceof ExecutableOption) {
365             final ExecutableOption executableOption = (ExecutableOption) option;
366             final Set < Integer > duplicatePriorities = checkDuplicateOptionPriorities(executableOption,
367                     getAllExecutableOptions());
368             if (duplicatePriorities.size() > 0) {
369                 throw new CommandLineException(buildLogString(DUPLICATE_OPTION_PRIORITY_ERROR, duplicatePriorities));
370             }
371             getOriginalAllOptions().add(option);
372         } else {
373             getOriginalAllOptions().add(option);
374         }
375     }
376 
377     /**
378      * {@inheritDoc}
379      *
380      * @since 1.3.0
381      */
382     @Override
383     public int compareTo(final JavaProgram o) {
384         return getName().compareTo(o.getName());
385     }
386 
387     /**
388      * {@inheritDoc}
389      *
390      * @since 1.3.0
391      */
392     @Override
393     public JavaProgram deepClone() {
394         JavaProgramImpl a = null;
395 
396         try {
397             a = (JavaProgramImpl) super.clone();
398             a.licenseNames = new ArrayList < String >(getLicenseNames());
399             a.authors = getAuthors();
400             a.version = getVersion().deepClone();
401             // FIXME Can't clone options because some of them have a reference to the JavaProgram
402             // instance
403             a.allOptions = getAllOptions();
404             a.fullUsageDescription = new StringBuilder(getFullUsageDescription());
405             a.fullUsageExamplesSet = new TreeSet < CommandLine >();
406             for (final CommandLine commandLine : getFullUsageExamplesSet()) {
407                 a.fullUsageExamplesSet.add(commandLine.deepClone());
408             }
409             a.knownBugsOrLimitationsSet = new TreeSet < String >(getKnownBugsOrLimitationsSet());
410         } catch (final CloneNotSupportedException cnse) {
411             LOGGER.log(SEVERE, UNEXPECTED_ERROR, cnse);
412         }
413 
414         return a;
415     }
416 
417     /**
418      * {@inheritDoc}
419      *
420      * @since 1.3.0
421      */
422     @Override
423     public boolean equals(final Object obj) {
424         if (this == obj) {
425             return true;
426         }
427         if (obj == null) {
428             return false;
429         }
430         if (getClass() != obj.getClass()) {
431             return false;
432         }
433         final JavaProgramImpl other = (JavaProgramImpl) obj;
434         if (name == null) {
435             if (other.name != null) {
436                 return false;
437             }
438         } else if (!name.equals(other.name)) {
439             return false;
440         }
441         return true;
442     }
443 
444     /**
445      * {@inheritDoc}
446      *
447      * @since 1.3.0
448      */
449     @Override
450     public Set < ExecutableOption > getAllExecutableOptions() {
451         return getAllExecutableOptions(OPTION_STATUS_SET);
452     }
453 
454     /**
455      * {@inheritDoc}
456      *
457      * @since 1.3.0
458      */
459     @Override
460     public Set < ExecutableOption > getAllExecutableOptions(final OptionStatus status) {
461         checkNull(status, OPTION_STATUS_NULL_ERROR);
462 
463         final Set < OptionStatus > statusSet = new TreeSet < OptionStatus >();
464         statusSet.add(status);
465         return getAllExecutableOptions(statusSet);
466     }
467 
468     /**
469      * {@inheritDoc}
470      *
471      * @since 1.3.0
472      */
473     @Override
474     public Set < ExecutableOption > getAllExecutableOptions(final Set < OptionStatus > statusSet) {
475         checkNull(statusSet, OPTION_STATUS_SET_NULL_ERROR);
476 
477         final Set < ExecutableOption > allExecutableOptions = new TreeSet < ExecutableOption >();
478         for (final Option option : getOriginalAllOptions()) {
479             if (option instanceof ExecutableOption && statusSet.contains(option.getStatus())) {
480                 allExecutableOptions.add((ExecutableOption) option);
481             }
482         }
483 
484         return allExecutableOptions;
485     }
486 
487     /**
488      * {@inheritDoc}
489      *
490      * @since 1.3.0
491      */
492     @Override
493     public Set < Option > getAllMandatoryOptions() {
494         return getAllOptions(OPTION_STATUS_MANDATORY_SET);
495     }
496 
497     /**
498      * {@inheritDoc}
499      *
500      * @since 1.3.0
501      */
502     @Override
503     public Set < Option > getAllOptionalActiveOptions() {
504         return getAllOptions(ACTIVE_OPTIONAL_OPTION_STATUS);
505     }
506 
507     /**
508      * {@inheritDoc}
509      *
510      * @since 1.3.0
511      */
512     @Override
513     public Set < Option > getAllOptions() {
514         return getAllOptions(OPTION_STATUS_SET);
515     }
516 
517     /**
518      * {@inheritDoc}
519      *
520      * @since 1.3.0
521      */
522     @Override
523     public Set < Option > getAllOptions(final OptionStatus status) {
524         checkNull(status, OPTION_STATUS_NULL_ERROR);
525 
526         final Set < OptionStatus > statusSet = new TreeSet < OptionStatus >();
527         statusSet.add(status);
528         return getAllOptions(statusSet);
529     }
530 
531     /**
532      * {@inheritDoc}
533      *
534      * @since 1.3.0
535      */
536     @Override
537     public Set < Option > getAllOptions(final Set < OptionStatus > statusSet) {
538         checkNull(statusSet, OPTION_STATUS_SET_NULL_ERROR);
539 
540         final Set < Option > options = new TreeSet < Option >();
541         for (final Option option : allOptions) {
542             if (statusSet.contains(option.getStatus())) {
543                 options.add(option);
544             }
545         }
546 
547         return options;
548     }
549 
550     /**
551      * {@inheritDoc}
552      *
553      * @since 1.3.0
554      */
555     @Override
556     public List < String > getAuthors() {
557         return new ArrayList < String >(authors);
558     }
559 
560     /**
561      * {@inheritDoc}
562      *
563      * @since 1.3.0
564      */
565     @Override
566     public StringBuilder getFullUsage() {
567         final StringBuilder buffer = new StringBuilder(getMainUsage());
568         buffer.append(LINE_CHAR);
569 
570         if (getAllMandatoryOptions().size() > 0) {
571             buffer.append(generateOptionsFullUsageDescription(MANDATORY_OPTIONS_CMD, getAllMandatoryOptions()));
572         } else {
573             LOGGER.log(FINE, NO_MANDATORY_OPTIONS_FINE);
574         }
575 
576         buffer.append(LINE_CHAR);
577 
578         if (getAllOptionalActiveOptions().size() > 0) {
579             buffer.append(generateOptionsFullUsageDescription(OPTIONAL_OPTIONS_CMD, getAllOptionalActiveOptions()));
580         } else {
581             LOGGER.log(FINE, NO_OPTIONAL_OPTIONS_FINE);
582         }
583 
584         buffer.append(LINE_CHAR);
585         buffer.append(LINE_CHAR);
586         buffer.append(getFullUsageExamples());
587 
588         buffer.append(LINE_CHAR);
589         buffer.append(LINE_CHAR);
590         buffer.append(getKnownBugsOrLimitations());
591 
592         return buffer;
593     }
594 
595     /**
596      * {@inheritDoc}
597      *
598      * @since 1.3.0
599      */
600     @Override
601     public StringBuilder getFullUsageDescription() {
602         return fullUsageDescription;
603     }
604 
605     /**
606      * {@inheritDoc}
607      *
608      * @since 1.3.0
609      */
610     @Override
611     public StringBuilder getFullUsageExamples() {
612         final StringBuilder buffer = new StringBuilder();
613 
614         if (getFullUsageExamplesSet().size() > 0) {
615             buffer.append(EXAMPLES_OPTIONS_CMD);
616             buffer.append(LINE_CHAR);
617 
618             for (final CommandLine commandLineExample : getFullUsageExamplesSet()) {
619                 buffer.append(LINE_CHAR);
620                 buffer.append(TAB_CHAR);
621                 buffer.append(JAVA_JAR_CMD);
622                 buffer.append(getJarName());
623                 buffer.append(SPACE_CHAR);
624                 buffer.append(commandLineExample.getCommandLineArgumentsAsString());
625             }
626 
627         } else {
628             LOGGER.log(FINE, NO_COMMAND_LINE_EXAMPLES_FINE);
629         }
630 
631         return buffer;
632     }
633 
634     /**
635      * Gets the value of <code>fullUsageExamplesSet</code>.
636      *
637      * @return the value of <code>fullUsageExamplesSet</code>.
638      * @see #setFullUsageExamplesSet(Set)
639      * @since 1.3.0
640      */
641     private Set < CommandLine > getFullUsageExamplesSet() {
642         return fullUsageExamplesSet;
643     }
644 
645     /**
646      * {@inheritDoc}
647      *
648      * @since 1.3.0
649      */
650     @Override
651     public String getJarName() {
652         return jarName;
653     }
654 
655     /**
656      * {@inheritDoc}
657      *
658      * @since 1.3.0
659      */
660     @Override
661     public StringBuilder getKnownBugsOrLimitations() {
662         final StringBuilder buffer = new StringBuilder();
663 
664         if (getKnownBugsOrLimitationsSet().size() > 0) {
665             buffer.append(KNOWN_BUGS_OR_LIMITATIONS_CMD);
666             buffer.append(LINE_CHAR);
667 
668             for (final String knownBugOrLimitation : getKnownBugsOrLimitationsSet()) {
669                 buffer.append(LINE_CHAR);
670                 buffer.append(TAB_CHAR);
671                 buffer.append(knownBugOrLimitation);
672             }
673 
674         } else {
675             LOGGER.log(FINE, NO_KNOWN_BUGS_OR_LIMITATIONS_FINE);
676         }
677 
678         return buffer;
679     }
680 
681     /**
682      * Gets the value of <code>knownBugsOrLimitationsSet</code>.
683      *
684      * @return the value of <code>knownBugsOrLimitationsSet</code>.
685      * @see #setKnownBugsOrLimitationsSet(Set)
686      * @since 1.3.0
687      */
688     private Set < String > getKnownBugsOrLimitationsSet() {
689         return knownBugsOrLimitationsSet;
690     }
691 
692     /**
693      * {@inheritDoc}
694      *
695      * @since 1.3.0
696      */
697     @Override
698     public List < String > getLicenseNames() {
699         return new ArrayList < String >(licenseNames);
700     }
701 
702     /**
703      * {@inheritDoc}
704      *
705      * @since 1.3.0
706      */
707     @Override
708     public StringBuilder getMainUsage() {
709         final StringBuilder buffer = new StringBuilder(getName());
710         if (getFullUsageDescription().length() != 0) {
711             buffer.append(SPACE_CHAR);
712             buffer.append(HYPHEN_CHAR);
713             buffer.append(SPACE_CHAR);
714             buffer.append(getFullUsageDescription());
715         }
716 
717         buffer.append(SPACE_CHAR);
718         buffer.append(LEFT_PARENTHESIS_CHAR);
719         buffer.append(getUrl());
720         buffer.append(RIGHT_PARENTHESIS_CHAR);
721 
722         buffer.append(LINE_CHAR);
723         buffer.append(LINE_CHAR);
724         buffer.append(USAGE_CMD);
725         buffer.append(LINE_CHAR);
726         buffer.append(TAB_CHAR);
727         buffer.append(generateMainUsageDescription(getJarName(), getAllMandatoryOptions(),
728                 getAllOptionalActiveOptions()));
729         return buffer;
730     }
731 
732     /**
733      * {@inheritDoc}
734      *
735      * @since 1.3.0
736      */
737     @Override
738     public String getName() {
739         return name;
740     }
741 
742     /**
743      * Gets the original <code>allOptions</code> attribute, without copying it.
744      *
745      * @return the value of <code>allOptions</code>.
746      * @see #getAllOptions()
747      * @since 1.3.0
748      */
749     private Set < Option > getOriginalAllOptions() {
750         return allOptions;
751     }
752 
753     /**
754      * {@inheritDoc}
755      *
756      * @since 1.3.0
757      */
758     @Override
759     public URL getUrl() {
760         return url;
761     }
762 
763     /**
764      * {@inheritDoc}
765      *
766      * @since 1.3.0
767      */
768     @Override
769     public ProgramVersion getVersion() {
770         return version;
771     }
772 
773     /**
774      * {@inheritDoc}
775      *
776      * @since 1.3.0
777      */
778     @Override
779     public int hashCode() {
780         final int prime = 31;
781         int result = 1;
782         result = prime * result + ((name == null) ? 0 : name.hashCode());
783         return result;
784     }
785 
786     /**
787      * {@inheritDoc}
788      *
789      * @since 1.3.0
790      */
791     @Override
792     public JavaProgramExecution parseCommandLine(final CommandLine commandLine) throws CommandLineException {
793         checkNull(commandLine, COMMAND_LINE_NULL_ERROR);
794 
795         LOGGER.log(FINE, buildLogString(ANALYSING_COMMAND_LINE_FINE, commandLine));
796 
797         JavaProgramExecution programExecution = null;
798 
799         final Set < OptionExecution > optionExecutions = new TreeSet < OptionExecution >();
800         for (final ExecutableOption executableOption : getAllExecutableOptions(OPTION_STATUS_ACTIVE_SET)) {
801             final OptionExecution optionExecution = executableOption.parseCommandLine(commandLine);
802             if (optionExecution == null) {
803                 LOGGER.log(FINE, buildLogString(OPTION_NOT_SPECIFIED_FINE, executableOption));
804             } else {
805                 optionExecutions.add(optionExecution);
806             }
807         }
808 
809         if (optionExecutions.size() > 0) {
810             programExecution = createJavaProgramExecution(optionExecutions);
811         } else {
812             throw new CommandLineException(NO_OPTION_EXECUTIONS_ERROR);
813         }
814 
815         return programExecution;
816     }
817 
818     /**
819      * Sets the value of <code>allOptions</code>.
820      *
821      * @param value
822      *            the <code>allOptions</code> to set, can be <code>null</code>.
823      * @see #getAllOptions()
824      * @since 1.3.0
825      */
826     private void setAllOptions(final Set < Option > value) {
827         checkNull(value, OPTIONS_NULL_ERROR);
828 
829         allOptions = value;
830     }
831 
832     /**
833      * Sets the value of <code>authors</code>.
834      *
835      * @param value
836      *            the <code>authors</code> to set, can be <code>null</code>.
837      * @see #getAuthors()
838      * @since 1.3.0
839      */
840     private void setAuthors(final List < String > value) {
841         checkNull(value, PROGRAM_AUTHORS_NULL_ERROR);
842 
843         authors = value;
844     }
845 
846     /**
847      * Sets the value of <code>fullUsageDescription</code>.
848      *
849      * @param value
850      *            the <code>fullUsageDescription</code> to set, can be <code>null</code>.
851      * @see #getFullUsageDescription()
852      * @since 1.3.0
853      */
854     private void setFullUsageDescription(final StringBuilder value) {
855         checkNull(value, FULL_USAGE_DESCRIPTION_NULL_ERROR);
856 
857         fullUsageDescription = value;
858     }
859 
860     /**
861      * Sets the value of <code>fullUsageExamplesSet</code>.
862      *
863      * @param value
864      *            the <code>fullUsageExamplesSet</code> to set, can be <code>null</code>.
865      * @see #getFullUsageExamplesSet()
866      * @since 1.3.0
867      */
868     private void setFullUsageExamplesSet(final Set < CommandLine > value) {
869         checkNull(value, FULL_USAGE_EXAMPLES_NULL_ERROR);
870 
871         fullUsageExamplesSet = value;
872     }
873 
874     /**
875      * Sets the value of <code>jarName</code>.
876      *
877      * @param value
878      *            the <code>jarName</code> to set, can be <code>null</code>.
879      * @see #getJarName()
880      * @since 1.3.0
881      */
882     private void setJarName(final String value) {
883         checkNull(value, PROGRAM_JAR_NAME_NULL_ERROR);
884 
885         jarName = value;
886     }
887 
888     /**
889      * Sets the value of <code>knownBugsOrLimitationsSet</code>.
890      *
891      * @param value
892      *            the <code>knownBugsOrLimitationsSet</code> to set, can be <code>null</code>.
893      * @see #getKnownBugsOrLimitationsSet()
894      * @since 1.3.0
895      */
896     private void setKnownBugsOrLimitationsSet(final Set < String > value) {
897         knownBugsOrLimitationsSet = value;
898     }
899 
900     /**
901      * Sets the value of <code>licenseNames</code>.
902      *
903      * @param value
904      *            the <code>licenseNames</code> to set, can be <code>null</code>.
905      * @see #getLicenseNames()
906      * @since 1.3.0
907      */
908     private void setLicenseNames(final List < String > value) {
909         checkNull(value, PROGRAM_LICENSES_NULL_ERROR);
910 
911         licenseNames = value;
912     }
913 
914     /**
915      * Sets the value of <code>name</code>.
916      *
917      * @param value
918      *            the <code>name</code> to set, can be <code>null</code>.
919      * @see #getName()
920      * @since 1.3.0
921      */
922     private void setName(final String value) {
923         checkNull(value, PROGRAM_NAME_NULL_ERROR);
924 
925         name = value;
926     }
927 
928     /**
929      * Sets the value of <code>url</code>.
930      *
931      * @param value
932      *            the <code>url</code> to set, can be <code>null</code>.
933      * @see #getUrl()
934      * @since 1.3.0
935      */
936     private void setUrl(final URL value) {
937         checkNull(value, PROGRAM_URL_NULL_ERROR);
938 
939         url = value;
940     }
941 
942     /**
943      * Sets the value of <code>version</code>.
944      *
945      * @param value
946      *            the <code>version</code> to set, can be <code>null</code>.
947      * @see #getVersion()
948      * @since 1.3.0
949      */
950     private void setVersion(final ProgramVersion value) {
951         checkNull(value, PROGRAM_VERSION_NULL_ERROR);
952 
953         version = value;
954     }
955 }