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.Iterator;
029    import java.util.List;
030    
031    import com.unboundid.ldap.sdk.DN;
032    import com.unboundid.ldap.sdk.LDAPException;
033    import com.unboundid.util.Mutable;
034    import com.unboundid.util.ThreadSafety;
035    import com.unboundid.util.ThreadSafetyLevel;
036    
037    import static com.unboundid.util.Debug.*;
038    import static com.unboundid.util.args.ArgsMessages.*;
039    
040    
041    
042    /**
043     * This class defines an argument that is intended to hold one or more
044     * distinguished name values.  DN arguments must take values, and those values
045     * must be able to be parsed as distinguished names.
046     */
047    @Mutable()
048    @ThreadSafety(level=ThreadSafetyLevel.NOT_THREADSAFE)
049    public final class DNArgument
050           extends Argument
051    {
052      /**
053       * The serial version UID for this serializable class.
054       */
055      private static final long serialVersionUID = 7956577383262400167L;
056    
057    
058    
059      // The set of values assigned to this argument.
060      private final ArrayList<DN> values;
061    
062      // The argument value validators that have been registered for this argument.
063      private final List<ArgumentValueValidator> validators;
064    
065      // The list of default values for this argument.
066      private final List<DN> defaultValues;
067    
068    
069    
070      /**
071       * Creates a new DN argument with the provided information.  It will not be
072       * required, will permit at most one occurrence, will use a default
073       * placeholder, and will not have a default value.
074       *
075       * @param  shortIdentifier   The short identifier for this argument.  It may
076       *                           not be {@code null} if the long identifier is
077       *                           {@code null}.
078       * @param  longIdentifier    The long identifier for this argument.  It may
079       *                           not be {@code null} if the short identifier is
080       *                           {@code null}.
081       * @param  description       A human-readable description for this argument.
082       *                           It must not be {@code null}.
083       *
084       * @throws  ArgumentException  If there is a problem with the definition of
085       *                             this argument.
086       */
087      public DNArgument(final Character shortIdentifier,
088                        final String longIdentifier, final String description)
089             throws ArgumentException
090      {
091        this(shortIdentifier, longIdentifier, false, 1, null, description);
092      }
093    
094    
095    
096      /**
097       * Creates a new DN argument with the provided information.  It will not have
098       * a default value.
099       *
100       * @param  shortIdentifier   The short identifier for this argument.  It may
101       *                           not be {@code null} if the long identifier is
102       *                           {@code null}.
103       * @param  longIdentifier    The long identifier for this argument.  It may
104       *                           not be {@code null} if the short identifier is
105       *                           {@code null}.
106       * @param  isRequired        Indicates whether this argument is required to
107       *                           be provided.
108       * @param  maxOccurrences    The maximum number of times this argument may be
109       *                           provided on the command line.  A value less than
110       *                           or equal to zero indicates that it may be present
111       *                           any number of times.
112       * @param  valuePlaceholder  A placeholder to display in usage information to
113       *                           indicate that a value must be provided.  It may
114       *                           be {@code null} if a default placeholder should
115       *                           be used.
116       * @param  description       A human-readable description for this argument.
117       *                           It must not be {@code null}.
118       *
119       * @throws  ArgumentException  If there is a problem with the definition of
120       *                             this argument.
121       */
122      public DNArgument(final Character shortIdentifier,
123                        final String longIdentifier, final boolean isRequired,
124                        final int maxOccurrences, final String valuePlaceholder,
125                        final String description)
126             throws ArgumentException
127      {
128        this(shortIdentifier, longIdentifier, isRequired,  maxOccurrences,
129             valuePlaceholder, description, (List<DN>) null);
130      }
131    
132    
133    
134      /**
135       * Creates a new DN argument with the provided information.
136       *
137       * @param  shortIdentifier   The short identifier for this argument.  It may
138       *                           not be {@code null} if the long identifier is
139       *                           {@code null}.
140       * @param  longIdentifier    The long identifier for this argument.  It may
141       *                           not be {@code null} if the short identifier is
142       *                           {@code null}.
143       * @param  isRequired        Indicates whether this argument is required to
144       *                           be provided.
145       * @param  maxOccurrences    The maximum number of times this argument may be
146       *                           provided on the command line.  A value less than
147       *                           or equal to zero indicates that it may be present
148       *                           any number of times.
149       * @param  valuePlaceholder  A placeholder to display in usage information to
150       *                           indicate that a value must be provided.  It may
151       *                           be {@code null} if a default placeholder should
152       *                           be used.
153       * @param  description       A human-readable description for this argument.
154       *                           It must not be {@code null}.
155       * @param  defaultValue      The default value to use for this argument if no
156       *                           values were provided.
157       *
158       * @throws  ArgumentException  If there is a problem with the definition of
159       *                             this argument.
160       */
161      public DNArgument(final Character shortIdentifier,
162                        final String longIdentifier, final boolean isRequired,
163                        final int maxOccurrences, final String valuePlaceholder,
164                        final String description, final DN defaultValue)
165             throws ArgumentException
166      {
167        this(shortIdentifier, longIdentifier, isRequired, maxOccurrences,
168             valuePlaceholder, description,
169             ((defaultValue == null) ? null : Arrays.asList(defaultValue)));
170      }
171    
172    
173    
174      /**
175       * Creates a new DN argument with the provided information.
176       *
177       * @param  shortIdentifier   The short identifier for this argument.  It may
178       *                           not be {@code null} if the long identifier is
179       *                           {@code null}.
180       * @param  longIdentifier    The long identifier for this argument.  It may
181       *                           not be {@code null} if the short identifier is
182       *                           {@code null}.
183       * @param  isRequired        Indicates whether this argument is required to
184       *                           be provided.
185       * @param  maxOccurrences    The maximum number of times this argument may be
186       *                           provided on the command line.  A value less than
187       *                           or equal to zero indicates that it may be present
188       *                           any number of times.
189       * @param  valuePlaceholder  A placeholder to display in usage information to
190       *                           indicate that a value must be provided.  It may
191       *                           be {@code null} if a default placeholder should
192       *                           be used.
193       * @param  description       A human-readable description for this argument.
194       *                           It must not be {@code null}.
195       * @param  defaultValues     The set of default values to use for this
196       *                           argument if no values were provided.
197       *
198       * @throws  ArgumentException  If there is a problem with the definition of
199       *                             this argument.
200       */
201      public DNArgument(final Character shortIdentifier,
202                        final String longIdentifier, final boolean isRequired,
203                        final int maxOccurrences, final String valuePlaceholder,
204                        final String description, final List<DN> defaultValues)
205             throws ArgumentException
206      {
207        super(shortIdentifier, longIdentifier, isRequired,  maxOccurrences,
208             (valuePlaceholder == null)
209                  ? INFO_PLACEHOLDER_DN.get()
210                  : valuePlaceholder,
211             description);
212    
213        if ((defaultValues == null) || defaultValues.isEmpty())
214        {
215          this.defaultValues = null;
216        }
217        else
218        {
219          this.defaultValues = Collections.unmodifiableList(defaultValues);
220        }
221    
222        values = new ArrayList<DN>(5);
223        validators = new ArrayList<ArgumentValueValidator>(5);
224      }
225    
226    
227    
228      /**
229       * Creates a new DN argument that is a "clean" copy of the provided source
230       * argument.
231       *
232       * @param  source  The source argument to use for this argument.
233       */
234      private DNArgument(final DNArgument source)
235      {
236        super(source);
237    
238        defaultValues = source.defaultValues;
239        values        = new ArrayList<DN>(5);
240        validators    = new ArrayList<ArgumentValueValidator>(source.validators);
241      }
242    
243    
244    
245      /**
246       * Retrieves the list of default values for this argument, which will be used
247       * if no values were provided.
248       *
249       * @return   The list of default values for this argument, or {@code null} if
250       *           there are no default values.
251       */
252      public List<DN> getDefaultValues()
253      {
254        return defaultValues;
255      }
256    
257    
258    
259      /**
260       * Updates this argument to ensure that the provided validator will be invoked
261       * for any values provided to this argument.  This validator will be invoked
262       * after all other validation has been performed for this argument.
263       *
264       * @param  validator  The argument value validator to be invoked.  It must not
265       *                    be {@code null}.
266       */
267      public void addValueValidator(final ArgumentValueValidator validator)
268      {
269        validators.add(validator);
270      }
271    
272    
273    
274      /**
275       * {@inheritDoc}
276       */
277      @Override()
278      protected void addValue(final String valueString)
279                throws ArgumentException
280      {
281        final DN parsedDN;
282        try
283        {
284          parsedDN = new DN(valueString);
285        }
286        catch (LDAPException le)
287        {
288          debugException(le);
289          throw new ArgumentException(ERR_DN_VALUE_NOT_DN.get(valueString,
290                                           getIdentifierString(), le.getMessage()),
291                                      le);
292        }
293    
294        if (values.size() >= getMaxOccurrences())
295        {
296          throw new ArgumentException(ERR_ARG_MAX_OCCURRENCES_EXCEEDED.get(
297                                           getIdentifierString()));
298        }
299    
300        for (final ArgumentValueValidator v : validators)
301        {
302          v.validateArgumentValue(this, valueString);
303        }
304    
305        values.add(parsedDN);
306      }
307    
308    
309    
310      /**
311       * Retrieves the value for this argument, or the default value if none was
312       * provided.  If there are multiple values, then the first will be returned.
313       *
314       * @return  The value for this argument, or the default value if none was
315       *          provided, or {@code null} if there is no value and no default
316       *          value.
317       */
318      public DN getValue()
319      {
320        if (values.isEmpty())
321        {
322          if ((defaultValues == null) || defaultValues.isEmpty())
323          {
324            return null;
325          }
326          else
327          {
328            return defaultValues.get(0);
329          }
330        }
331        else
332        {
333          return values.get(0);
334        }
335      }
336    
337    
338    
339      /**
340       * Retrieves the set of values for this argument.
341       *
342       * @return  The set of values for this argument.
343       */
344      public List<DN> getValues()
345      {
346        if (values.isEmpty() && (defaultValues != null))
347        {
348          return defaultValues;
349        }
350    
351        return Collections.unmodifiableList(values);
352      }
353    
354    
355    
356      /**
357       * Retrieves a string representation of the value for this argument, or a
358       * string representation of the default value if none was provided.  If there
359       * are multiple values, then the first will be returned.
360       *
361       * @return  The string representation of the value for this argument, or the
362       *          string representation of the default value if none was provided,
363       *          or {@code null} if there is no value and no default value.
364       */
365      public String getStringValue()
366      {
367        final DN valueDN = getValue();
368        if (valueDN == null)
369        {
370          return null;
371        }
372    
373        return valueDN.toString();
374      }
375    
376    
377    
378      /**
379       * {@inheritDoc}
380       */
381      @Override()
382      public List<String> getValueStringRepresentations(final boolean useDefault)
383      {
384        if (values.isEmpty())
385        {
386          if (useDefault && (defaultValues != null))
387          {
388            final ArrayList<String> valueStrings =
389                 new ArrayList<String>(defaultValues.size());
390            for (final DN dn : defaultValues)
391            {
392              valueStrings.add(dn.toString());
393            }
394            return Collections.unmodifiableList(valueStrings);
395          }
396          else
397          {
398            return Collections.emptyList();
399          }
400        }
401        else
402        {
403          final ArrayList<String> valueStrings =
404               new ArrayList<String>(values.size());
405          for (final DN dn : values)
406          {
407            valueStrings.add(dn.toString());
408          }
409          return Collections.unmodifiableList(valueStrings);
410        }
411      }
412    
413    
414    
415      /**
416       * {@inheritDoc}
417       */
418      @Override()
419      protected boolean hasDefaultValue()
420      {
421        return ((defaultValues != null) && (! defaultValues.isEmpty()));
422      }
423    
424    
425    
426      /**
427       * {@inheritDoc}
428       */
429      @Override()
430      public String getDataTypeName()
431      {
432        return INFO_DN_TYPE_NAME.get();
433      }
434    
435    
436    
437      /**
438       * {@inheritDoc}
439       */
440      @Override()
441      public String getValueConstraints()
442      {
443        return INFO_DN_CONSTRAINTS.get();
444      }
445    
446    
447    
448      /**
449       * {@inheritDoc}
450       */
451      @Override()
452      protected void reset()
453      {
454        super.reset();
455        values.clear();
456      }
457    
458    
459    
460      /**
461       * {@inheritDoc}
462       */
463      @Override()
464      public DNArgument getCleanCopy()
465      {
466        return new DNArgument(this);
467      }
468    
469    
470    
471      /**
472       * {@inheritDoc}
473       */
474      @Override()
475      protected void addToCommandLine(final List<String> argStrings)
476      {
477        if (values != null)
478        {
479          for (final DN dn : values)
480          {
481            argStrings.add(getIdentifierString());
482            if (isSensitive())
483            {
484              argStrings.add("***REDACTED***");
485            }
486            else
487            {
488              argStrings.add(String.valueOf(dn));
489            }
490          }
491        }
492      }
493    
494    
495    
496      /**
497       * {@inheritDoc}
498       */
499      @Override()
500      public void toString(final StringBuilder buffer)
501      {
502        buffer.append("DNArgument(");
503        appendBasicToStringInfo(buffer);
504    
505        if ((defaultValues != null) && (! defaultValues.isEmpty()))
506        {
507          if (defaultValues.size() == 1)
508          {
509            buffer.append(", defaultValue='");
510            buffer.append(defaultValues.get(0).toString());
511          }
512          else
513          {
514            buffer.append(", defaultValues={");
515    
516            final Iterator<DN> iterator = defaultValues.iterator();
517            while (iterator.hasNext())
518            {
519              buffer.append('\'');
520              buffer.append(iterator.next().toString());
521              buffer.append('\'');
522    
523              if (iterator.hasNext())
524              {
525                buffer.append(", ");
526              }
527            }
528    
529            buffer.append('}');
530          }
531        }
532    
533        buffer.append(')');
534      }
535    }