001/*
002 * Copyright 2008-2024 Ping Identity Corporation
003 * All Rights Reserved.
004 */
005/*
006 * Copyright 2008-2024 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) 2008-2024 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.util.ArrayList;
041import java.util.Collections;
042import java.util.HashSet;
043import java.util.Iterator;
044import java.util.List;
045import java.util.Set;
046import java.util.regex.Matcher;
047import java.util.regex.Pattern;
048
049import com.unboundid.util.Mutable;
050import com.unboundid.util.NotNull;
051import com.unboundid.util.Nullable;
052import com.unboundid.util.StaticUtils;
053import com.unboundid.util.ThreadSafety;
054import com.unboundid.util.ThreadSafetyLevel;
055
056import static com.unboundid.util.args.ArgsMessages.*;
057
058
059
060/**
061 * This class defines an argument that is intended to hold one or more string
062 * values.  String arguments must take values.  By default, any value will be
063 * allowed, but it is possible to restrict the set of values so that only values
064 * from a specified set (ignoring differences in capitalization) will be
065 * allowed.
066 */
067@Mutable()
068@ThreadSafety(level=ThreadSafetyLevel.NOT_THREADSAFE)
069public final class StringArgument
070       extends Argument
071{
072  /**
073   * The serial version UID for this serializable class.
074   */
075  private static final long serialVersionUID = 1088032496970585118L;
076
077
078
079  // The set of values assigned to this argument.
080  @NotNull private final ArrayList<String> values;
081
082  // The argument value validators that have been registered for this argument.
083  @NotNull private final List<ArgumentValueValidator> validators;
084
085  // The list of default values that will be used if no values were provided.
086  @Nullable private final List<String> defaultValues;
087
088  // A regular expression that may be enforced for values of this argument.
089  @Nullable private volatile Pattern valueRegex;
090
091  // The set of allowed values for this argument.
092  @Nullable private final Set<String> allowedValues;
093
094  // A human-readable explanation of the regular expression pattern.
095  @Nullable private volatile String valueRegexExplanation;
096
097
098
099  /**
100   * Creates a new string argument with the provided information.  It will not
101   * be required, will permit at most one value, will use a default placeholder,
102   * will not have any default value, and will not place any restriction on
103   * values that may be assigned.
104   *
105   * @param  shortIdentifier   The short identifier for this argument.  It may
106   *                           not be {@code null} if the long identifier is
107   *                           {@code null}.
108   * @param  longIdentifier    The long identifier for this argument.  It may
109   *                           not be {@code null} if the short identifier is
110   *                           {@code null}.
111   * @param  description       A human-readable description for this argument.
112   *                           It must not be {@code null}.
113   *
114   * @throws  ArgumentException  If there is a problem with the definition of
115   *                             this argument.
116   */
117  public StringArgument(@Nullable final Character shortIdentifier,
118                        @Nullable final String longIdentifier,
119                        @NotNull final String description)
120         throws ArgumentException
121  {
122    this(shortIdentifier, longIdentifier, false, 1, null, description);
123  }
124
125
126
127  /**
128   * Creates a new string argument with the provided information.  There will
129   * not be any default values, nor will there be any restriction on values that
130   * may be assigned to this argument.
131   *
132   * @param  shortIdentifier   The short identifier for this argument.  It may
133   *                           not be {@code null} if the long identifier is
134   *                           {@code null}.
135   * @param  longIdentifier    The long identifier for this argument.  It may
136   *                           not be {@code null} if the short identifier is
137   *                           {@code null}.
138   * @param  isRequired        Indicates whether this argument is required to
139   *                           be provided.
140   * @param  maxOccurrences    The maximum number of times this argument may be
141   *                           provided on the command line.  A value less than
142   *                           or equal to zero indicates that it may be present
143   *                           any number of times.
144   * @param  valuePlaceholder  A placeholder to display in usage information to
145   *                           indicate that a value must be provided.  It may
146   *                           be {@code null} if a default placeholder should
147   *                           be used.
148   * @param  description       A human-readable description for this argument.
149   *                           It must not be {@code null}.
150   *
151   * @throws  ArgumentException  If there is a problem with the definition of
152   *                             this argument.
153   */
154  public StringArgument(@Nullable final Character shortIdentifier,
155                        @Nullable final String longIdentifier,
156                        final boolean isRequired, final int maxOccurrences,
157                        @Nullable final String valuePlaceholder,
158                        @NotNull final String description)
159         throws ArgumentException
160  {
161    this(shortIdentifier, longIdentifier, isRequired,  maxOccurrences,
162         valuePlaceholder, description, null, (List<String>) null);
163  }
164
165
166
167  /**
168   * Creates a new string argument with the provided information.  There will
169   * not be any default values.
170   *
171   * @param  shortIdentifier   The short identifier for this argument.  It may
172   *                           not be {@code null} if the long identifier is
173   *                           {@code null}.
174   * @param  longIdentifier    The long identifier for this argument.  It may
175   *                           not be {@code null} if the short identifier is
176   *                           {@code null}.
177   * @param  isRequired        Indicates whether this argument is required to
178   *                           be provided.
179   * @param  maxOccurrences    The maximum number of times this argument may be
180   *                           provided on the command line.  A value less than
181   *                           or equal to zero indicates that it may be present
182   *                           any number of times.
183   * @param  valuePlaceholder  A placeholder to display in usage information to
184   *                           indicate that a value must be provided.  It may
185   *                           be {@code null} if a default placeholder should
186   *                           be used.
187   * @param  description       A human-readable description for this argument.
188   *                           It must not be {@code null}.
189   * @param  allowedValues     The set of allowed values for this argument, or
190   *                           {@code null} if it should not be restricted.
191   *
192   * @throws  ArgumentException  If there is a problem with the definition of
193   *                             this argument.
194   */
195  public StringArgument(@Nullable final Character shortIdentifier,
196                        @Nullable final String longIdentifier,
197                        final boolean isRequired, final int maxOccurrences,
198                        @Nullable final String valuePlaceholder,
199                        @NotNull final String description,
200                        @Nullable final Set<String> allowedValues)
201         throws ArgumentException
202  {
203    this(shortIdentifier, longIdentifier, isRequired,  maxOccurrences,
204         valuePlaceholder, description, allowedValues, (List<String>) null);
205  }
206
207
208
209  /**
210   * Creates a new string argument with the provided information.  There will
211   * not be any restriction on values that may be assigned to this argument.
212   *
213   * @param  shortIdentifier   The short identifier for this argument.  It may
214   *                           not be {@code null} if the long identifier is
215   *                           {@code null}.
216   * @param  longIdentifier    The long identifier for this argument.  It may
217   *                           not be {@code null} if the short identifier is
218   *                           {@code null}.
219   * @param  isRequired        Indicates whether this argument is required to
220   *                           be provided.
221   * @param  maxOccurrences    The maximum number of times this argument may be
222   *                           provided on the command line.  A value less than
223   *                           or equal to zero indicates that it may be present
224   *                           any number of times.
225   * @param  valuePlaceholder  A placeholder to display in usage information to
226   *                           indicate that a value must be provided.  It may
227   *                           be {@code null} if a default placeholder should
228   *                           be used.
229   * @param  description       A human-readable description for this argument.
230   *                           It must not be {@code null}.
231   * @param  defaultValue      The default value that will be used for this
232   *                           argument if no values are provided.  It may be
233   *                           {@code null} if there should not be a default
234   *                           value.
235   *
236   * @throws  ArgumentException  If there is a problem with the definition of
237   *                             this argument.
238   */
239  public StringArgument(@Nullable final Character shortIdentifier,
240                        @Nullable final String longIdentifier,
241                        final boolean isRequired, final int maxOccurrences,
242                        @Nullable final String valuePlaceholder,
243                        @NotNull final String description,
244                        @Nullable final String defaultValue)
245         throws ArgumentException
246  {
247    this(shortIdentifier, longIdentifier, isRequired,  maxOccurrences,
248         valuePlaceholder, description, null,
249         ((defaultValue == null)
250              ? null
251              : Collections.singletonList(defaultValue)));
252  }
253
254
255
256  /**
257   * Creates a new string argument with the provided information.  There will
258   * not be any restriction on values that may be assigned to this argument.
259   *
260   * @param  shortIdentifier   The short identifier for this argument.  It may
261   *                           not be {@code null} if the long identifier is
262   *                           {@code null}.
263   * @param  longIdentifier    The long identifier for this argument.  It may
264   *                           not be {@code null} if the short identifier is
265   *                           {@code null}.
266   * @param  isRequired        Indicates whether this argument is required to
267   *                           be provided.
268   * @param  maxOccurrences    The maximum number of times this argument may be
269   *                           provided on the command line.  A value less than
270   *                           or equal to zero indicates that it may be present
271   *                           any number of times.
272   * @param  valuePlaceholder  A placeholder to display in usage information to
273   *                           indicate that a value must be provided.  It may
274   *                           be {@code null} if a default placeholder should
275   *                           be used.
276   * @param  description       A human-readable description for this argument.
277   *                           It must not be {@code null}.
278   * @param  defaultValues     The set of default values that will be used for
279   *                           this argument if no values are provided.
280   *
281   * @throws  ArgumentException  If there is a problem with the definition of
282   *                             this argument.
283   */
284  public StringArgument(@Nullable final Character shortIdentifier,
285                        @Nullable final String longIdentifier,
286                        final boolean isRequired, final int maxOccurrences,
287                        @Nullable final String valuePlaceholder,
288                        @NotNull final String description,
289                        @Nullable final List<String> defaultValues)
290         throws ArgumentException
291  {
292    this(shortIdentifier, longIdentifier, isRequired,  maxOccurrences,
293         valuePlaceholder, description, null, defaultValues);
294  }
295
296
297
298  /**
299   * Creates a new string argument with the provided information.
300   *
301   * @param  shortIdentifier   The short identifier for this argument.  It may
302   *                           not be {@code null} if the long identifier is
303   *                           {@code null}.
304   * @param  longIdentifier    The long identifier for this argument.  It may
305   *                           not be {@code null} if the short identifier is
306   *                           {@code null}.
307   * @param  isRequired        Indicates whether this argument is required to
308   *                           be provided.
309   * @param  maxOccurrences    The maximum number of times this argument may be
310   *                           provided on the command line.  A value less than
311   *                           or equal to zero indicates that it may be present
312   *                           any number of times.
313   * @param  valuePlaceholder  A placeholder to display in usage information to
314   *                           indicate that a value must be provided.  It may
315   *                           be {@code null} if a default placeholder should
316   *                           be used.
317   * @param  description       A human-readable description for this argument.
318   *                           It must not be {@code null}.
319   * @param  allowedValues     The set of allowed values for this argument, or
320   *                           {@code null} if it should not be restricted.
321   * @param  defaultValue      The default value that will be used for this
322   *                           argument if no values are provided.  It may be
323   *                           {@code null} if there should not be a default
324   *                           value.
325   *
326   * @throws  ArgumentException  If there is a problem with the definition of
327   *                             this argument.
328   */
329  public StringArgument(@Nullable final Character shortIdentifier,
330                        @Nullable final String longIdentifier,
331                        final boolean isRequired, final int maxOccurrences,
332                        @Nullable final String valuePlaceholder,
333                        @NotNull final String description,
334                        @Nullable final Set<String> allowedValues,
335                        @Nullable final String defaultValue)
336         throws ArgumentException
337  {
338    this(shortIdentifier, longIdentifier, isRequired,  maxOccurrences,
339         valuePlaceholder, description, allowedValues,
340         ((defaultValue == null)
341              ? null
342              : Collections.singletonList(defaultValue)));
343  }
344
345
346
347  /**
348   * Creates a new string argument with the provided information.
349   *
350   * @param  shortIdentifier   The short identifier for this argument.  It may
351   *                           not be {@code null} if the long identifier is
352   *                           {@code null}.
353   * @param  longIdentifier    The long identifier for this argument.  It may
354   *                           not be {@code null} if the short identifier is
355   *                           {@code null}.
356   * @param  isRequired        Indicates whether this argument is required to
357   *                           be provided.
358   * @param  maxOccurrences    The maximum number of times this argument may be
359   *                           provided on the command line.  A value less than
360   *                           or equal to zero indicates that it may be present
361   *                           any number of times.
362   * @param  valuePlaceholder  A placeholder to display in usage information to
363   *                           indicate that a value must be provided.  It may
364   *                           be {@code null} if a default placeholder should
365   *                           be used.
366   * @param  description       A human-readable description for this argument.
367   *                           It must not be {@code null}.
368   * @param  allowedValues     The set of allowed values for this argument, or
369   *                           {@code null} if it should not be restricted.
370   * @param  defaultValues     The set of default values that will be used for
371   *                           this argument if no values are provided.
372   *
373   * @throws  ArgumentException  If there is a problem with the definition of
374   *                             this argument.
375   */
376  public StringArgument(@Nullable final Character shortIdentifier,
377                        @Nullable final String longIdentifier,
378                        final boolean isRequired, final int maxOccurrences,
379                        @Nullable final String valuePlaceholder,
380                        @NotNull final String description,
381                        @Nullable final Set<String> allowedValues,
382                        @Nullable final List<String> defaultValues)
383         throws ArgumentException
384  {
385    super(shortIdentifier, longIdentifier, isRequired,  maxOccurrences,
386         (valuePlaceholder == null)
387              ? INFO_PLACEHOLDER_VALUE.get()
388              : valuePlaceholder,
389         description);
390
391    if ((allowedValues == null) || allowedValues.isEmpty())
392    {
393      this.allowedValues = null;
394    }
395    else
396    {
397      final HashSet<String> lowerValues =
398           new HashSet<>(StaticUtils.computeMapCapacity(allowedValues.size()));
399      for (final String s : allowedValues)
400      {
401        lowerValues.add(StaticUtils.toLowerCase(s));
402      }
403      this.allowedValues = Collections.unmodifiableSet(lowerValues);
404    }
405
406    if ((defaultValues == null) || defaultValues.isEmpty())
407    {
408      this.defaultValues = null;
409    }
410    else
411    {
412      this.defaultValues = Collections.unmodifiableList(defaultValues);
413    }
414
415    if ((this.allowedValues != null) && (this.defaultValues != null))
416    {
417      for (final String s : this.defaultValues)
418      {
419        final String lowerDefault = StaticUtils.toLowerCase(s);
420        if (! this.allowedValues.contains(lowerDefault))
421        {
422          throw new ArgumentException(
423               ERR_ARG_DEFAULT_VALUE_NOT_ALLOWED.get(s, getIdentifierString()));
424        }
425      }
426    }
427
428    values                = new ArrayList<>(5);
429    validators            = new ArrayList<>(5);
430    valueRegex            = null;
431    valueRegexExplanation = null;
432  }
433
434
435
436  /**
437   * Creates a new string argument that is a "clean" copy of the provided source
438   * argument.
439   *
440   * @param  source  The source argument to use for this argument.
441   */
442  private StringArgument(@NotNull final StringArgument source)
443  {
444    super(source);
445
446    allowedValues         = source.allowedValues;
447    defaultValues         = source.defaultValues;
448    valueRegex            = source.valueRegex;
449    valueRegexExplanation = source.valueRegexExplanation;
450    values                = new ArrayList<>(5);
451    validators            = new ArrayList<>(source.validators);
452  }
453
454
455
456  /**
457   * Retrieves the set of allowed values for this argument, if applicable.
458   *
459   * @return  The set of allowed values for this argument, or {@code null} if
460   *          there is no restriction on the allowed values.
461   */
462  @Nullable()
463  public Set<String> getAllowedValues()
464  {
465    return allowedValues;
466  }
467
468
469
470  /**
471   * Retrieves the list of default values for this argument, which will be used
472   * if no values were provided.
473   *
474   * @return   The list of default values for this argument, or {@code null} if
475   *           there are no default values.
476   */
477  @Nullable()
478  public List<String> getDefaultValues()
479  {
480    return defaultValues;
481  }
482
483
484
485  /**
486   * Retrieves the regular expression that values of this argument will be
487   * required to match, if any.
488   *
489   * @return  The regular expression that values of this argument will be
490   *          required to match, or {@code null} if none is defined.
491   */
492  @Nullable()
493  public Pattern getValueRegex()
494  {
495    return valueRegex;
496  }
497
498
499
500  /**
501   * Retrieves a human-readable explanation of the regular expression pattern
502   * that may be required to match any provided values, if any.
503   *
504   * @return  A human-readable explanation of the regular expression pattern, or
505   *          {@code null} if none is available.
506   */
507  @Nullable()
508  public String getValueRegexExplanation()
509  {
510    return valueRegexExplanation;
511  }
512
513
514
515  /**
516   * Specifies the regular expression that values of this argument will be
517   * required to match, if any.
518   *
519   * @param  valueRegex   The regular expression that values of this argument
520   *                      will be required to match.  It may be {@code null} if
521   *                      no pattern matching should be required.
522   * @param  explanation  A human-readable explanation for the pattern which may
523   *                      be used to clarify the kinds of values that are
524   *                      acceptable.  It may be {@code null} if no pattern
525   *                      matching should be required, or if the regular
526   *                      expression pattern should be sufficiently clear for
527   *                      the target audience.
528   */
529  public void setValueRegex(@Nullable final Pattern valueRegex,
530                            @Nullable final String explanation)
531  {
532    this.valueRegex = valueRegex;
533    valueRegexExplanation = explanation;
534  }
535
536
537
538  /**
539   * Updates this argument to ensure that the provided validator will be invoked
540   * for any values provided to this argument.  This validator will be invoked
541   * after all other validation has been performed for this argument.
542   *
543   * @param  validator  The argument value validator to be invoked.  It must not
544   *                    be {@code null}.
545   */
546  public void addValueValidator(@NotNull final ArgumentValueValidator validator)
547  {
548    validators.add(validator);
549  }
550
551
552
553  /**
554   * {@inheritDoc}
555   */
556  @Override()
557  protected void addValue(@NotNull final String valueString)
558            throws ArgumentException
559  {
560    final String lowerValue = StaticUtils.toLowerCase(valueString);
561    if (allowedValues != null)
562    {
563      if (! allowedValues.contains(lowerValue))
564      {
565        final StringBuilder allowedValuesBuffer = new StringBuilder();
566        for (final String allowedValue : allowedValues)
567        {
568          if (allowedValuesBuffer.length() > 0)
569          {
570            allowedValuesBuffer.append(", ");
571          }
572
573          allowedValuesBuffer.append('\'');
574          allowedValuesBuffer.append(allowedValue);
575          allowedValuesBuffer.append('\'');
576        }
577
578        throw new ArgumentException(ERR_ARG_VALUE_NOT_ALLOWED.get(
579             valueString, getIdentifierString(),
580             allowedValuesBuffer.toString()));
581      }
582    }
583
584    if (values.size() >= getMaxOccurrences())
585    {
586      throw new ArgumentException(ERR_ARG_MAX_OCCURRENCES_EXCEEDED.get(
587                                       getIdentifierString()));
588    }
589
590    if (valueRegex != null)
591    {
592      final Matcher matcher = valueRegex.matcher(valueString);
593      if (! matcher.matches())
594      {
595        final String pattern = valueRegex.pattern();
596        if (valueRegexExplanation == null)
597        {
598          throw new ArgumentException(
599               ERR_ARG_VALUE_DOES_NOT_MATCH_PATTERN_WITHOUT_EXPLANATION.get(
600                    valueString, getIdentifierString(), pattern));
601        }
602        else
603        {
604          throw new ArgumentException(
605               ERR_ARG_VALUE_DOES_NOT_MATCH_PATTERN_WITH_EXPLANATION.get(
606                    valueString, getIdentifierString(), pattern,
607                    valueRegexExplanation));
608        }
609      }
610    }
611
612    for (final ArgumentValueValidator v : validators)
613    {
614      v.validateArgumentValue(this, valueString);
615    }
616
617    values.add(valueString);
618  }
619
620
621
622  /**
623   * Retrieves the value for this argument, or the default value if none was
624   * provided.  If this argument has multiple values, then the first will be
625   * returned.
626   *
627   * @return  The value for this argument, or the default value if none was
628   *          provided, or {@code null} if it does not have any values or
629   *          default values.
630   */
631  @Nullable()
632  public String getValue()
633  {
634    if (values.isEmpty())
635    {
636      if ((defaultValues == null) || defaultValues.isEmpty())
637      {
638        return null;
639      }
640      else
641      {
642        return defaultValues.get(0);
643      }
644    }
645
646    return values.get(0);
647  }
648
649
650
651  /**
652   * Retrieves the set of values for this argument, or the default values if
653   * none were provided.
654   *
655   * @return  The set of values for this argument, or the default values if none
656   *          were provided.
657   */
658  @NotNull()
659  public List<String> getValues()
660  {
661    if (values.isEmpty() && (defaultValues != null))
662    {
663      return defaultValues;
664    }
665
666    return Collections.unmodifiableList(values);
667  }
668
669
670
671  /**
672   * {@inheritDoc}
673   */
674  @Override()
675  @NotNull()
676  public List<String> getValueStringRepresentations(final boolean useDefault)
677  {
678    if (! values.isEmpty())
679    {
680      return Collections.unmodifiableList(values);
681    }
682    else if (useDefault && (defaultValues != null))
683    {
684      return Collections.unmodifiableList(defaultValues);
685    }
686    else
687    {
688      return Collections.emptyList();
689    }
690  }
691
692
693
694  /**
695   * {@inheritDoc}
696   */
697  @Override()
698  protected boolean hasDefaultValue()
699  {
700    return ((defaultValues != null) && (! defaultValues.isEmpty()));
701  }
702
703
704
705  /**
706   * {@inheritDoc}
707   */
708  @Override()
709  @NotNull()
710  public String getDataTypeName()
711  {
712    return INFO_STRING_TYPE_NAME.get();
713  }
714
715
716
717  /**
718   * {@inheritDoc}
719   */
720  @Override()
721  @Nullable()
722  public String getValueConstraints()
723  {
724    StringBuilder buffer = null;
725
726    if (valueRegex != null)
727    {
728      buffer = new StringBuilder();
729      final String pattern = valueRegex.pattern();
730      if ((valueRegexExplanation == null) ||
731          (valueRegexExplanation.length() == 0))
732      {
733        buffer.append(INFO_STRING_CONSTRAINTS_REGEX_WITHOUT_EXPLANATION.get(
734             pattern));
735      }
736      else
737      {
738        buffer.append(INFO_STRING_CONSTRAINTS_REGEX_WITHOUT_EXPLANATION.get(
739             pattern, valueRegexExplanation));
740      }
741    }
742
743    if ((allowedValues != null) && (! allowedValues.isEmpty()))
744    {
745      if (buffer == null)
746      {
747        buffer = new StringBuilder();
748      }
749      else
750      {
751        buffer.append("  ");
752      }
753
754      buffer.append(INFO_STRING_CONSTRAINTS_ALLOWED_VALUE.get());
755      buffer.append("  ");
756
757      final Iterator<String> iterator = allowedValues.iterator();
758      while (iterator.hasNext())
759      {
760        buffer.append('\'');
761        buffer.append(iterator.next());
762        buffer.append('\'');
763
764        if (iterator.hasNext())
765        {
766          buffer.append(", ");
767        }
768      }
769      buffer.append('.');
770    }
771
772    if (buffer == null)
773    {
774      return null;
775    }
776    else
777    {
778      return buffer.toString();
779    }
780  }
781
782
783
784  /**
785   * {@inheritDoc}
786   */
787  @Override()
788  protected void reset()
789  {
790    super.reset();
791    values.clear();
792  }
793
794
795
796  /**
797   * {@inheritDoc}
798   */
799  @Override()
800  @NotNull()
801  public StringArgument getCleanCopy()
802  {
803    return new StringArgument(this);
804  }
805
806
807
808  /**
809   * {@inheritDoc}
810   */
811  @Override()
812  protected void addToCommandLine(@NotNull final List<String> argStrings)
813  {
814    for (final String s : values)
815    {
816      argStrings.add(getIdentifierString());
817      if (isSensitive())
818      {
819        argStrings.add("***REDACTED***");
820      }
821      else
822      {
823        argStrings.add(s);
824      }
825    }
826  }
827
828
829
830  /**
831   * {@inheritDoc}
832   */
833  @Override()
834  public void toString(@NotNull final StringBuilder buffer)
835  {
836    buffer.append("StringArgument(");
837    appendBasicToStringInfo(buffer);
838
839    if ((allowedValues != null) && (! allowedValues.isEmpty()))
840    {
841      buffer.append(", allowedValues={");
842      final Iterator<String> iterator = allowedValues.iterator();
843      while (iterator.hasNext())
844      {
845        buffer.append('\'');
846        buffer.append(iterator.next());
847        buffer.append('\'');
848
849        if (iterator.hasNext())
850        {
851          buffer.append(", ");
852        }
853      }
854      buffer.append('}');
855    }
856
857    if (valueRegex != null)
858    {
859      buffer.append(", valueRegex='");
860      buffer.append(valueRegex.pattern());
861      buffer.append('\'');
862
863      if (valueRegexExplanation != null)
864      {
865        buffer.append(", valueRegexExplanation='");
866        buffer.append(valueRegexExplanation);
867        buffer.append('\'');
868      }
869    }
870
871    if ((defaultValues != null) && (! defaultValues.isEmpty()))
872    {
873      if (defaultValues.size() == 1)
874      {
875        buffer.append(", defaultValue='");
876        buffer.append(defaultValues.get(0));
877      }
878      else
879      {
880        buffer.append(", defaultValues={");
881
882        final Iterator<String> iterator = defaultValues.iterator();
883        while (iterator.hasNext())
884        {
885          buffer.append('\'');
886          buffer.append(iterator.next());
887          buffer.append('\'');
888
889          if (iterator.hasNext())
890          {
891            buffer.append(", ");
892          }
893        }
894
895        buffer.append('}');
896      }
897    }
898
899    buffer.append(')');
900  }
901}