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