001/*
002 * Copyright 2008-2017 UnboundID Corp.
003 * All Rights Reserved.
004 */
005/*
006 * Copyright (C) 2008-2017 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 */
021package com.unboundid.util.args;
022
023
024
025import java.util.ArrayList;
026import java.util.Arrays;
027import java.util.Collections;
028import java.util.Iterator;
029import java.util.List;
030
031import com.unboundid.ldap.sdk.DN;
032import com.unboundid.ldap.sdk.LDAPException;
033import com.unboundid.util.Mutable;
034import com.unboundid.util.ThreadSafety;
035import com.unboundid.util.ThreadSafetyLevel;
036
037import static com.unboundid.util.Debug.*;
038import 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)
049public 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}