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}