001    /*
002     * Copyright 2011-2016 UnboundID Corp.
003     * All Rights Reserved.
004     */
005    /*
006     * Copyright (C) 2011-2016 UnboundID Corp.
007     *
008     * This program is free software; you can redistribute it and/or modify
009     * it under the terms of the GNU General Public License (GPLv2 only)
010     * or the terms of the GNU Lesser General Public License (LGPLv2.1 only)
011     * as published by the Free Software Foundation.
012     *
013     * This program is distributed in the hope that it will be useful,
014     * but WITHOUT ANY WARRANTY; without even the implied warranty of
015     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
016     * GNU General Public License for more details.
017     *
018     * You should have received a copy of the GNU General Public License
019     * along with this program; if not, see <http://www.gnu.org/licenses>.
020     */
021    package com.unboundid.util.args;
022    
023    
024    
025    import java.text.ParseException;
026    import java.util.ArrayList;
027    import java.util.Collections;
028    import java.util.List;
029    
030    import com.unboundid.util.Debug;
031    import com.unboundid.util.Mutable;
032    import com.unboundid.util.StaticUtils;
033    import com.unboundid.util.ThreadSafety;
034    import com.unboundid.util.ThreadSafetyLevel;
035    
036    import static com.unboundid.util.args.ArgsMessages.*;
037    
038    
039    
040    /**
041     * This class defines an argument whose values are intended to be argument
042     * strings as might be provided to a command-line application (e.g.,
043     * "--arg1 arg1value --arg2 --arg3 arg3value").  Instances of this argument
044     * will have their own argument parser that may be used to process the argument
045     * strings.  This type of argument may not be particularly useful for use in
046     * command-line applications, but may be used in other applications that may use
047     * arguments in other ways.
048     */
049    @Mutable()
050    @ThreadSafety(level=ThreadSafetyLevel.NOT_THREADSAFE)
051    public final class ArgumentListArgument
052           extends Argument
053    {
054      /**
055       * The serial version UID for this serializable class.
056       */
057      private static final long serialVersionUID = 1926330851837348378L;
058    
059    
060    
061      // The argument parser that will be used to validate values given for this
062      // argument.
063      private final ArgumentParser parser;
064    
065      // The list of argument parsers that correspond to values actually provided
066      // to this argument.
067      private final List<ArgumentParser> values;
068    
069      // The string representations of the values provided for this argument.
070      private final List<String> valueStrings;
071    
072    
073    
074      /**
075       * Creates a new argument list argument with the provided information.  It
076       * will not be required, will permit at most one occurrence, and will use a
077       * default placeholder.
078       *
079       * @param  shortIdentifier   The short identifier for this argument.  It may
080       *                           not be {@code null} if the long identifier is
081       *                           {@code null}.
082       * @param  longIdentifier    The long identifier for this argument.  It may
083       *                           not be {@code null} if the short identifier is
084       *                           {@code null}.
085       * @param  description       A human-readable description for this argument.
086       *                           It must not be {@code null}.
087       * @param  parser            The argument parser that will be used to
088       *                           process values provided for this argument.
089       *
090       * @throws  ArgumentException  If there is a problem with the definition of
091       *                             this argument.
092       */
093      public ArgumentListArgument(final Character shortIdentifier,
094                                  final String longIdentifier,
095                                  final String description,
096                                  final ArgumentParser parser)
097             throws ArgumentException
098      {
099        this(shortIdentifier, longIdentifier, false, 1, null, description, parser);
100      }
101    
102    
103    
104      /**
105       * Creates a new argument list argument with the provided information.
106       *
107       * @param  shortIdentifier   The short identifier for this argument.  It may
108       *                           not be {@code null} if the long identifier is
109       *                           {@code null}.
110       * @param  longIdentifier    The long identifier for this argument.  It may
111       *                           not be {@code null} if the short identifier is
112       *                           {@code null}.
113       * @param  isRequired        Indicates whether this argument is required to
114       *                           be provided.
115       * @param  maxOccurrences    The maximum number of times this argument may be
116       *                           provided on the command line.  A value less than
117       *                           or equal to zero indicates that it may be present
118       *                           any number of times.
119       * @param  valuePlaceholder  A placeholder to display in usage information to
120       *                           indicate that a value must be provided.  It may
121       *                           be {@code null} if a default placeholder should
122       *                           be used.
123       * @param  description       A human-readable description for this argument.
124       *                           It must not be {@code null}.
125       * @param  parser            The argument parser that will be used to
126       *                           process values provided for this argument.
127       *
128       * @throws  ArgumentException  If there is a problem with the definition of
129       *                             this argument.
130       */
131      public ArgumentListArgument(final Character shortIdentifier,
132                                  final String longIdentifier,
133                                  final boolean isRequired,
134                                  final int maxOccurrences,
135                                  final String valuePlaceholder,
136                                  final String description,
137                                  final ArgumentParser parser)
138             throws ArgumentException
139      {
140        super(shortIdentifier, longIdentifier, isRequired, maxOccurrences,
141             (valuePlaceholder == null)
142                  ? INFO_PLACEHOLDER_ARGS.get()
143                  : valuePlaceholder,
144             description);
145    
146        this.parser = parser.getCleanCopy();
147    
148        values = new ArrayList<ArgumentParser>();
149        valueStrings = new ArrayList<String>();
150      }
151    
152    
153    
154      /**
155       * Creates a new argument list argument that is a "clean" copy of the provided
156       * source argument.
157       *
158       * @param  source  The source argument to use for this argument.
159       */
160      private ArgumentListArgument(final ArgumentListArgument source)
161      {
162        super(source);
163    
164        parser = source.parser;
165        values = new ArrayList<ArgumentParser>();
166        valueStrings = new ArrayList<String>();
167      }
168    
169    
170    
171      /**
172       * Retrieves a "clean" copy of the argument parser that will be used to
173       * process values provided for this argument.
174       *
175       * @return  A "clean" copy of the argument parser that will be used to process
176       *          values provided for this argument.
177       */
178      public ArgumentParser getCleanParser()
179      {
180        return parser.getCleanCopy();
181      }
182    
183    
184    
185      /**
186       * {@inheritDoc}
187       */
188      @Override()
189      protected void addValue(final String valueString)
190                throws ArgumentException
191      {
192        final List<String> argList;
193        try
194        {
195          argList = StaticUtils.toArgumentList(valueString);
196        }
197        catch (final ParseException pe)
198        {
199          Debug.debugException(pe);
200          throw new ArgumentException(ERR_ARG_LIST_MALFORMED_VALUE.get(valueString,
201               getIdentifierString(), pe.getMessage()), pe);
202        }
203    
204        final String[] args = new String[argList.size()];
205        argList.toArray(args);
206    
207        final ArgumentParser p = parser.getCleanCopy();
208        try
209        {
210          p.parse(args);
211        }
212        catch (final ArgumentException ae)
213        {
214          Debug.debugException(ae);
215          throw new ArgumentException(ERR_ARG_LIST_INVALID_VALUE.get(valueString,
216          getIdentifierString(), ae.getMessage()), ae);
217        }
218    
219        values.add(p);
220        valueStrings.add(valueString);
221      }
222    
223    
224    
225      /**
226       * Retrieves the list of argument parsers that have been used to process
227       * values provided to this argument.
228       *
229       * @return  The list of argument parsers that have been used to process values
230       *          provided to this argument.
231       */
232      public List<ArgumentParser> getValueParsers()
233      {
234        return Collections.unmodifiableList(values);
235      }
236    
237    
238    
239      /**
240       * Retrieves the list of the string representations of the values provided to
241       * this argument.
242       *
243       * @return  The list of the string representations of the values provided to
244       *          this argument.
245       */
246      public List<String> getValueStrings()
247      {
248        return Collections.unmodifiableList(valueStrings);
249      }
250    
251    
252    
253      /**
254       * {@inheritDoc}
255       */
256      @Override()
257      public List<String> getValueStringRepresentations(final boolean useDefault)
258      {
259        return Collections.unmodifiableList(valueStrings);
260      }
261    
262    
263    
264      /**
265       * {@inheritDoc}
266       */
267      @Override()
268      protected boolean hasDefaultValue()
269      {
270        return false;
271      }
272    
273    
274    
275      /**
276       * {@inheritDoc}
277       */
278      @Override()
279      public String getDataTypeName()
280      {
281        return INFO_ARG_LIST_TYPE_NAME.get();
282      }
283    
284    
285    
286      /**
287       * {@inheritDoc}
288       */
289      @Override()
290      public String getValueConstraints()
291      {
292        return INFO_ARG_LIST_CONSTRAINTS.get();
293      }
294    
295    
296    
297      /**
298       * {@inheritDoc}
299       */
300      @Override()
301      protected void reset()
302      {
303        super.reset();
304        values.clear();
305      }
306    
307    
308    
309      /**
310       * {@inheritDoc}
311       */
312      @Override()
313      public ArgumentListArgument getCleanCopy()
314      {
315        return new ArgumentListArgument(this);
316      }
317    
318    
319    
320      /**
321       * {@inheritDoc}
322       */
323      @Override()
324      protected void addToCommandLine(final List<String> argStrings)
325      {
326        if (valueStrings != null)
327        {
328          for (final String s : valueStrings)
329          {
330            argStrings.add(getIdentifierString());
331            if (isSensitive())
332            {
333              argStrings.add("***REDACTED***");
334            }
335            else
336            {
337              argStrings.add(s);
338            }
339          }
340        }
341      }
342    
343    
344    
345      /**
346       * {@inheritDoc}
347       */
348      @Override()
349      public void toString(final StringBuilder buffer)
350      {
351        buffer.append("ArgumentListArgument(");
352        appendBasicToStringInfo(buffer);
353        buffer.append(", parser=");
354        parser.toString(buffer);
355        buffer.append(')');
356      }
357    }