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 }