View Javadoc

1   /*
2    CommandLineImpl.java
3    Creation date : 11/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.command.impl;
26  
27  import static java.util.Arrays.asList;
28  import static java.util.logging.Level.FINE;
29  import static java.util.logging.Level.INFO;
30  import static java.util.logging.Level.SEVERE;
31  import static java.util.logging.Logger.getLogger;
32  import static net.sourceforge.plantumldependency.common.constants.CharacterConstants.SPACE_CHAR;
33  import static net.sourceforge.plantumldependency.common.constants.CommonConstants.BLANK_STRING;
34  import static net.sourceforge.plantumldependency.common.constants.CommonConstants.MINUS_ONE_RETURN_CODE;
35  import static net.sourceforge.plantumldependency.common.constants.log.ErrorConstants.UNEXPECTED_ERROR;
36  import static net.sourceforge.plantumldependency.common.utils.check.ParameterCheckerUtils.checkNull;
37  import static net.sourceforge.plantumldependency.common.utils.log.LogUtils.buildLogString;
38  import static net.sourceforge.plantumldependency.commoncli.constants.CommandLineConstants.OPTION_STATUS_ACTIVE_SET;
39  import static net.sourceforge.plantumldependency.commoncli.constants.log.ErrorConstants.ARGUMENT_NOT_FOUND_BUT_MANDATORY_ERROR;
40  import static net.sourceforge.plantumldependency.commoncli.constants.log.ErrorConstants.COMMAND_LINE_ARGUMENTS_NULL_ERROR;
41  import static net.sourceforge.plantumldependency.commoncli.constants.log.ErrorConstants.DUPLICATE_OPTION_ERROR;
42  import static net.sourceforge.plantumldependency.commoncli.constants.log.ErrorConstants.MANDATORY_OPTION_ERROR;
43  import static net.sourceforge.plantumldependency.commoncli.constants.log.ErrorConstants.OPTION_NULL_ERROR;
44  import static net.sourceforge.plantumldependency.commoncli.constants.log.FineConstants.NO_COMMAND_LINE_ARGUMENTS_FINE;
45  import static net.sourceforge.plantumldependency.commoncli.constants.log.FineConstants.OPTION_NOT_SPECIFIED_FINE;
46  import static net.sourceforge.plantumldependency.commoncli.constants.log.FineConstants.OPTION_SPECIFIED_FINE;
47  import static net.sourceforge.plantumldependency.commoncli.constants.log.FineConstants.SKIPPING_ARGUMENT_FINE;
48  import static net.sourceforge.plantumldependency.commoncli.constants.log.InfoConstants.ARGUMENT_NOT_SPECIFIED_INFO;
49  import static net.sourceforge.plantumldependency.commoncli.constants.log.InfoConstants.OPTION_SPECIFIED_INFO;
50  
51  import java.util.ArrayList;
52  import java.util.List;
53  import java.util.logging.Logger;
54  
55  import net.sourceforge.plantumldependency.commoncli.command.CommandLine;
56  import net.sourceforge.plantumldependency.commoncli.exception.CommandLineException;
57  import net.sourceforge.plantumldependency.commoncli.option.Option;
58  import net.sourceforge.plantumldependency.commoncli.option.OptionWithArgument;
59  
60  /**
61   * The default {@link CommandLine} implementation.
62   *
63   * @author Benjamin Croizet (<a href="mailto:graffity2199@yahoo.fr>graffity2199@yahoo.fr</a>)
64   * @since 1.3.0
65   * @version 1.3.0
66   */
67  public class CommandLineImpl implements CommandLine {
68  
69      /** Serial version UID. */
70      private static final long serialVersionUID = 8593066398749136948L;
71  
72      /** The class logger. */
73      private static final transient Logger LOGGER = getLogger(CommandLineImpl.class.getName());
74  
75      /** The {@link List} of {@link String} of all command line arguments. */
76      private List < String > commandLineArguments;
77  
78      /**
79       * Default constructor.
80       *
81       * @param args
82       *            the command line arguments as an array of {@link String}, mustn't be
83       *            <code>null</code>.
84       * @since 1.3.0
85       */
86      public CommandLineImpl(final String[] args) {
87          checkNull(args, COMMAND_LINE_ARGUMENTS_NULL_ERROR);
88  
89          commandLineArguments = new ArrayList < String >(asList(args));
90      }
91  
92      /**
93       * {@inheritDoc}
94       *
95       * @since 1.3.0
96       */
97      @Override
98      public int compareTo(final CommandLine o) {
99          return getCommandLineArgumentsAsString().toString().compareTo(o.getCommandLineArgumentsAsString().toString());
100     }
101 
102     /**
103      * {@inheritDoc}
104      *
105      * @since 1.3.0
106      */
107     @Override
108     public CommandLine deepClone() {
109         CommandLineImpl a = null;
110 
111         try {
112             a = (CommandLineImpl) super.clone();
113             a.commandLineArguments = new ArrayList < String >(getCommandLineArguments());
114         } catch (final CloneNotSupportedException cnse) {
115             LOGGER.log(SEVERE, UNEXPECTED_ERROR, cnse);
116         }
117 
118         return a;
119     }
120 
121     /**
122      * {@inheritDoc}
123      *
124      * @since 1.3.0
125      */
126     @Override
127     public boolean equals(final Object obj) {
128         if (this == obj) {
129             return true;
130         }
131         if (obj == null) {
132             return false;
133         }
134         if (getClass() != obj.getClass()) {
135             return false;
136         }
137         final CommandLineImpl other = (CommandLineImpl) obj;
138         if (commandLineArguments == null) {
139             if (other.commandLineArguments != null) {
140                 return false;
141             }
142         } else if (!commandLineArguments.equals(other.commandLineArguments)) {
143             return false;
144         }
145         return true;
146     }
147 
148     /**
149      * Find and returns the option index (in the arguments list) if specified on the command line.
150      *
151      * @param option
152      *            the option to look for, mustn't be <code>null</code>.
153      * @return the option index (in the arguments list) if specified on the command line, return
154      *         {@link net.sourceforge.plantumldependency.common.constants.CommonConstants#MINUS_ONE_RETURN_CODE}
155      *         if not specified.
156      * @throws CommandLineException
157      *             if any error occurs when finding the option index in the command line, for
158      *             instance when the option is specified several times in the command line.
159      * @since 1.3.0
160      */
161     private int findAndCheckOptionIndex(final Option option) throws CommandLineException {
162         checkNull(option, OPTION_NULL_ERROR);
163 
164         int optionIndex = MINUS_ONE_RETURN_CODE;
165 
166         for (int i = 0; i < getCommandLineArguments().size(); i++) {
167             final String currentArgument = getCommandLineArguments().get(i);
168             if (option.getAllNames().contains(currentArgument)) {
169                 if (optionIndex == MINUS_ONE_RETURN_CODE) {
170                     LOGGER.log(INFO, buildLogString(OPTION_SPECIFIED_INFO, option.getAllNames()));
171                     optionIndex = i;
172                 } else {
173                     throw new CommandLineException(buildLogString(DUPLICATE_OPTION_ERROR, option.getAllNames()));
174                 }
175             } else {
176                 LOGGER.log(FINE,
177                         buildLogString(SKIPPING_ARGUMENT_FINE, new String[] {currentArgument, option.getName()}));
178             }
179         }
180 
181         if (optionIndex == MINUS_ONE_RETURN_CODE) {
182             if (option.isMandatory()) {
183                 throw new CommandLineException(buildLogString(MANDATORY_OPTION_ERROR, option.getAllNames()));
184             } else {
185                 LOGGER.log(FINE, buildLogString(OPTION_NOT_SPECIFIED_FINE, option.getAllNames()));
186             }
187         } else {
188             LOGGER.log(FINE, buildLogString(OPTION_SPECIFIED_FINE, option.getAllNames()));
189         }
190 
191         return optionIndex;
192     }
193 
194     /**
195      * {@inheritDoc}
196      *
197      * @since 1.3.0
198      */
199     @Override
200     public String findOptionArgument(final OptionWithArgument < ? > option) throws CommandLineException {
201         checkNull(option, OPTION_NULL_ERROR);
202 
203         String argumentString = null;
204 
205         final int optionIndex = findAndCheckOptionIndex(option);
206         if (optionIndex == MINUS_ONE_RETURN_CODE) {
207             LOGGER.log(FINE, buildLogString(OPTION_NOT_SPECIFIED_FINE, option.getAllNames()));
208         } else {
209             final int argumentIndex = optionIndex + 1;
210             if (argumentIndex >= getCommandLineArguments().size()) {
211                 if (option.getOptionArgument().isMandatory()) {
212                     throw new CommandLineException(buildLogString(ARGUMENT_NOT_FOUND_BUT_MANDATORY_ERROR,
213                             option.getAllNames()));
214                 }
215                 LOGGER.log(INFO, buildLogString(ARGUMENT_NOT_SPECIFIED_INFO, option.getAllNames()));
216                 argumentString = BLANK_STRING;
217             } else {
218                 argumentString = getCommandLineArguments().get(argumentIndex);
219                 try {
220                     option.getOptionArgument().parseArgument(argumentString);
221                 } catch (final CommandLineException e) {
222                     if (option.getOptionArgument().isMandatory()) {
223                         throw new CommandLineException(buildLogString(ARGUMENT_NOT_FOUND_BUT_MANDATORY_ERROR,
224                                 option.getAllNames()), e);
225                     }
226                     LOGGER.log(INFO, buildLogString(ARGUMENT_NOT_SPECIFIED_INFO, option.getAllNames()));
227                     argumentString = BLANK_STRING;
228                 }
229             }
230         }
231 
232         return argumentString;
233     }
234 
235     /**
236      * {@inheritDoc}
237      *
238      * @since 1.3.0
239      */
240     @Override
241     public List < String > getCommandLineArguments() {
242         return commandLineArguments;
243     }
244 
245     /**
246      * {@inheritDoc}
247      *
248      * @since 1.3.0
249      */
250     @Override
251     public StringBuilder getCommandLineArgumentsAsString() {
252         final StringBuilder buffer = new StringBuilder();
253 
254         if (getCommandLineArguments().size() == 0) {
255             LOGGER.log(FINE, NO_COMMAND_LINE_ARGUMENTS_FINE);
256         } else {
257             for (int i = 0; i < getCommandLineArguments().size() - 1; i++) {
258                 final String argument = getCommandLineArguments().get(i);
259                 buffer.append(argument);
260                 buffer.append(SPACE_CHAR);
261             }
262 
263             buffer.append(getCommandLineArguments().get(getCommandLineArguments().size() - 1));
264         }
265 
266         return buffer;
267     }
268 
269     /**
270      * {@inheritDoc}
271      *
272      * @since 1.3.0
273      */
274     @Override
275     public int hashCode() {
276         final int prime = 31;
277         int result = 1;
278         result = prime * result + ((commandLineArguments == null) ? 0 : commandLineArguments.hashCode());
279         return result;
280     }
281 
282     /**
283      * {@inheritDoc}
284      *
285      * @since 1.3.0
286      */
287     @Override
288     public boolean isOptionActiveAndSpecified(final Option option) throws CommandLineException {
289         return OPTION_STATUS_ACTIVE_SET.contains(option.getStatus()) && isOptionSpecified(option);
290     }
291 
292     /**
293      * {@inheritDoc}
294      *
295      * @since 1.3.0
296      */
297     @Override
298     public boolean isOptionSpecified(final Option option) throws CommandLineException {
299         return findAndCheckOptionIndex(option) != MINUS_ONE_RETURN_CODE;
300     }
301 
302     /**
303      * {@inheritDoc}
304      *
305      * @since 1.3.0
306      */
307     @Override
308     public String toString() {
309         return getClass().getSimpleName() + " [commandLineArguments=" + commandLineArguments + "]";
310     }
311 }