001/*
002 * Copyright 2011-2017 UnboundID Corp.
003 * All Rights Reserved.
004 */
005/*
006 * Copyright (C) 2011-2017 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 */
021package com.unboundid.util.args;
022
023
024
025import java.text.ParseException;
026import java.util.ArrayList;
027import java.util.Collections;
028import java.util.List;
029
030import com.unboundid.util.Debug;
031import com.unboundid.util.Mutable;
032import com.unboundid.util.StaticUtils;
033import com.unboundid.util.ThreadSafety;
034import com.unboundid.util.ThreadSafetyLevel;
035
036import 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)
051public 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}