001/*
002 * Copyright 2008-2018 Ping Identity Corporation
003 * All Rights Reserved.
004 */
005/*
006 * Copyright (C) 2008-2018 Ping Identity Corporation
007 *
008 * This program is free software; you can redistribute it and/or modify
009 * it under the terms of the GNU General Public License (GPLv2 only)
010 * or the terms of the GNU Lesser General Public License (LGPLv2.1 only)
011 * as published by the Free Software Foundation.
012 *
013 * This program is distributed in the hope that it will be useful,
014 * but WITHOUT ANY WARRANTY; without even the implied warranty of
015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
016 * GNU General Public License for more details.
017 *
018 * You should have received a copy of the GNU General Public License
019 * along with this program; if not, see <http://www.gnu.org/licenses>.
020 */
021package com.unboundid.util.args;
022
023
024
025import java.util.ArrayList;
026import java.util.Collections;
027import java.util.Iterator;
028import java.util.List;
029
030import com.unboundid.ldap.sdk.DN;
031import com.unboundid.ldap.sdk.LDAPException;
032import com.unboundid.util.Debug;
033import com.unboundid.util.Mutable;
034import com.unboundid.util.ThreadSafety;
035import com.unboundid.util.ThreadSafetyLevel;
036
037import static com.unboundid.util.args.ArgsMessages.*;
038
039
040
041/**
042 * This class defines an argument that is intended to hold one or more
043 * distinguished name values.  DN arguments must take values, and those values
044 * must be able to be parsed as distinguished names.
045 */
046@Mutable()
047@ThreadSafety(level=ThreadSafetyLevel.NOT_THREADSAFE)
048public final class DNArgument
049       extends Argument
050{
051  /**
052   * The serial version UID for this serializable class.
053   */
054  private static final long serialVersionUID = 7956577383262400167L;
055
056
057
058  // The set of values assigned to this argument.
059  private final ArrayList<DN> values;
060
061  // The argument value validators that have been registered for this argument.
062  private final List<ArgumentValueValidator> validators;
063
064  // The list of default values for this argument.
065  private final List<DN> defaultValues;
066
067
068
069  /**
070   * Creates a new DN argument with the provided information.  It will not be
071   * required, will permit at most one occurrence, will use a default
072   * placeholder, and will not have a default value.
073   *
074   * @param  shortIdentifier   The short identifier for this argument.  It may
075   *                           not be {@code null} if the long identifier is
076   *                           {@code null}.
077   * @param  longIdentifier    The long identifier for this argument.  It may
078   *                           not be {@code null} if the short identifier is
079   *                           {@code null}.
080   * @param  description       A human-readable description for this argument.
081   *                           It must not be {@code null}.
082   *
083   * @throws  ArgumentException  If there is a problem with the definition of
084   *                             this argument.
085   */
086  public DNArgument(final Character shortIdentifier,
087                    final String longIdentifier, final String description)
088         throws ArgumentException
089  {
090    this(shortIdentifier, longIdentifier, false, 1, null, description);
091  }
092
093
094
095  /**
096   * Creates a new DN argument with the provided information.  It will not have
097   * a default value.
098   *
099   * @param  shortIdentifier   The short identifier for this argument.  It may
100   *                           not be {@code null} if the long identifier is
101   *                           {@code null}.
102   * @param  longIdentifier    The long identifier for this argument.  It may
103   *                           not be {@code null} if the short identifier is
104   *                           {@code null}.
105   * @param  isRequired        Indicates whether this argument is required to
106   *                           be provided.
107   * @param  maxOccurrences    The maximum number of times this argument may be
108   *                           provided on the command line.  A value less than
109   *                           or equal to zero indicates that it may be present
110   *                           any number of times.
111   * @param  valuePlaceholder  A placeholder to display in usage information to
112   *                           indicate that a value must be provided.  It may
113   *                           be {@code null} if a default placeholder should
114   *                           be used.
115   * @param  description       A human-readable description for this argument.
116   *                           It must not be {@code null}.
117   *
118   * @throws  ArgumentException  If there is a problem with the definition of
119   *                             this argument.
120   */
121  public DNArgument(final Character shortIdentifier,
122                    final String longIdentifier, final boolean isRequired,
123                    final int maxOccurrences, final String valuePlaceholder,
124                    final String description)
125         throws ArgumentException
126  {
127    this(shortIdentifier, longIdentifier, isRequired,  maxOccurrences,
128         valuePlaceholder, description, (List<DN>) null);
129  }
130
131
132
133  /**
134   * Creates a new DN argument with the provided information.
135   *
136   * @param  shortIdentifier   The short identifier for this argument.  It may
137   *                           not be {@code null} if the long identifier is
138   *                           {@code null}.
139   * @param  longIdentifier    The long identifier for this argument.  It may
140   *                           not be {@code null} if the short identifier is
141   *                           {@code null}.
142   * @param  isRequired        Indicates whether this argument is required to
143   *                           be provided.
144   * @param  maxOccurrences    The maximum number of times this argument may be
145   *                           provided on the command line.  A value less than
146   *                           or equal to zero indicates that it may be present
147   *                           any number of times.
148   * @param  valuePlaceholder  A placeholder to display in usage information to
149   *                           indicate that a value must be provided.  It may
150   *                           be {@code null} if a default placeholder should
151   *                           be used.
152   * @param  description       A human-readable description for this argument.
153   *                           It must not be {@code null}.
154   * @param  defaultValue      The default value to use for this argument if no
155   *                           values were provided.
156   *
157   * @throws  ArgumentException  If there is a problem with the definition of
158   *                             this argument.
159   */
160  public DNArgument(final Character shortIdentifier,
161                    final String longIdentifier, final boolean isRequired,
162                    final int maxOccurrences, final String valuePlaceholder,
163                    final String description, final DN defaultValue)
164         throws ArgumentException
165  {
166    this(shortIdentifier, longIdentifier, isRequired, maxOccurrences,
167         valuePlaceholder, description,
168         ((defaultValue == null)
169              ? null :
170              Collections.singletonList(defaultValue)));
171  }
172
173
174
175  /**
176   * Creates a new DN argument with the provided information.
177   *
178   * @param  shortIdentifier   The short identifier for this argument.  It may
179   *                           not be {@code null} if the long identifier is
180   *                           {@code null}.
181   * @param  longIdentifier    The long identifier for this argument.  It may
182   *                           not be {@code null} if the short identifier is
183   *                           {@code null}.
184   * @param  isRequired        Indicates whether this argument is required to
185   *                           be provided.
186   * @param  maxOccurrences    The maximum number of times this argument may be
187   *                           provided on the command line.  A value less than
188   *                           or equal to zero indicates that it may be present
189   *                           any number of times.
190   * @param  valuePlaceholder  A placeholder to display in usage information to
191   *                           indicate that a value must be provided.  It may
192   *                           be {@code null} if a default placeholder should
193   *                           be used.
194   * @param  description       A human-readable description for this argument.
195   *                           It must not be {@code null}.
196   * @param  defaultValues     The set of default values to use for this
197   *                           argument if no values were provided.
198   *
199   * @throws  ArgumentException  If there is a problem with the definition of
200   *                             this argument.
201   */
202  public DNArgument(final Character shortIdentifier,
203                    final String longIdentifier, final boolean isRequired,
204                    final int maxOccurrences, final String valuePlaceholder,
205                    final String description, final List<DN> defaultValues)
206         throws ArgumentException
207  {
208    super(shortIdentifier, longIdentifier, isRequired,  maxOccurrences,
209         (valuePlaceholder == null)
210              ? INFO_PLACEHOLDER_DN.get()
211              : valuePlaceholder,
212         description);
213
214    if ((defaultValues == null) || defaultValues.isEmpty())
215    {
216      this.defaultValues = null;
217    }
218    else
219    {
220      this.defaultValues = Collections.unmodifiableList(defaultValues);
221    }
222
223    values = new ArrayList<>(5);
224    validators = new ArrayList<>(5);
225  }
226
227
228
229  /**
230   * Creates a new DN argument that is a "clean" copy of the provided source
231   * argument.
232   *
233   * @param  source  The source argument to use for this argument.
234   */
235  private DNArgument(final DNArgument source)
236  {
237    super(source);
238
239    defaultValues = source.defaultValues;
240    values        = new ArrayList<>(5);
241    validators    = new ArrayList<>(source.validators);
242  }
243
244
245
246  /**
247   * Retrieves the list of default values for this argument, which will be used
248   * if no values were provided.
249   *
250   * @return   The list of default values for this argument, or {@code null} if
251   *           there are no default values.
252   */
253  public List<DN> getDefaultValues()
254  {
255    return defaultValues;
256  }
257
258
259
260  /**
261   * Updates this argument to ensure that the provided validator will be invoked
262   * for any values provided to this argument.  This validator will be invoked
263   * after all other validation has been performed for this argument.
264   *
265   * @param  validator  The argument value validator to be invoked.  It must not
266   *                    be {@code null}.
267   */
268  public void addValueValidator(final ArgumentValueValidator validator)
269  {
270    validators.add(validator);
271  }
272
273
274
275  /**
276   * {@inheritDoc}
277   */
278  @Override()
279  protected void addValue(final String valueString)
280            throws ArgumentException
281  {
282    final DN parsedDN;
283    try
284    {
285      parsedDN = new DN(valueString);
286    }
287    catch (final LDAPException le)
288    {
289      Debug.debugException(le);
290      throw new ArgumentException(ERR_DN_VALUE_NOT_DN.get(valueString,
291                                       getIdentifierString(), le.getMessage()),
292                                  le);
293    }
294
295    if (values.size() >= getMaxOccurrences())
296    {
297      throw new ArgumentException(ERR_ARG_MAX_OCCURRENCES_EXCEEDED.get(
298                                       getIdentifierString()));
299    }
300
301    for (final ArgumentValueValidator v : validators)
302    {
303      v.validateArgumentValue(this, valueString);
304    }
305
306    values.add(parsedDN);
307  }
308
309
310
311  /**
312   * Retrieves the value for this argument, or the default value if none was
313   * provided.  If there are multiple values, then the first will be returned.
314   *
315   * @return  The value for this argument, or the default value if none was
316   *          provided, or {@code null} if there is no value and no default
317   *          value.
318   */
319  public DN getValue()
320  {
321    if (values.isEmpty())
322    {
323      if ((defaultValues == null) || defaultValues.isEmpty())
324      {
325        return null;
326      }
327      else
328      {
329        return defaultValues.get(0);
330      }
331    }
332    else
333    {
334      return values.get(0);
335    }
336  }
337
338
339
340  /**
341   * Retrieves the set of values for this argument.
342   *
343   * @return  The set of values for this argument.
344   */
345  public List<DN> getValues()
346  {
347    if (values.isEmpty() && (defaultValues != null))
348    {
349      return defaultValues;
350    }
351
352    return Collections.unmodifiableList(values);
353  }
354
355
356
357  /**
358   * Retrieves a string representation of the value for this argument, or a
359   * string representation of the default value if none was provided.  If there
360   * are multiple values, then the first will be returned.
361   *
362   * @return  The string representation of the value for this argument, or the
363   *          string representation of the default value if none was provided,
364   *          or {@code null} if there is no value and no default value.
365   */
366  public String getStringValue()
367  {
368    final DN valueDN = getValue();
369    if (valueDN == null)
370    {
371      return null;
372    }
373
374    return valueDN.toString();
375  }
376
377
378
379  /**
380   * {@inheritDoc}
381   */
382  @Override()
383  public List<String> getValueStringRepresentations(final boolean useDefault)
384  {
385    if (values.isEmpty())
386    {
387      if (useDefault && (defaultValues != null))
388      {
389        final ArrayList<String> valueStrings =
390             new ArrayList<>(defaultValues.size());
391        for (final DN dn : defaultValues)
392        {
393          valueStrings.add(dn.toString());
394        }
395        return Collections.unmodifiableList(valueStrings);
396      }
397      else
398      {
399        return Collections.emptyList();
400      }
401    }
402    else
403    {
404      final ArrayList<String> valueStrings = new ArrayList<>(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}