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