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}