001/* 002 * Copyright 2008-2020 Ping Identity Corporation 003 * All Rights Reserved. 004 */ 005/* 006 * Copyright 2008-2020 Ping Identity Corporation 007 * 008 * Licensed under the Apache License, Version 2.0 (the "License"); 009 * you may not use this file except in compliance with the License. 010 * You may obtain a copy of the License at 011 * 012 * http://www.apache.org/licenses/LICENSE-2.0 013 * 014 * Unless required by applicable law or agreed to in writing, software 015 * distributed under the License is distributed on an "AS IS" BASIS, 016 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 017 * See the License for the specific language governing permissions and 018 * limitations under the License. 019 */ 020/* 021 * Copyright (C) 2008-2020 Ping Identity Corporation 022 * 023 * This program is free software; you can redistribute it and/or modify 024 * it under the terms of the GNU General Public License (GPLv2 only) 025 * or the terms of the GNU Lesser General Public License (LGPLv2.1 only) 026 * as published by the Free Software Foundation. 027 * 028 * This program is distributed in the hope that it will be useful, 029 * but WITHOUT ANY WARRANTY; without even the implied warranty of 030 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 031 * GNU General Public License for more details. 032 * 033 * You should have received a copy of the GNU General Public License 034 * along with this program; if not, see <http://www.gnu.org/licenses>. 035 */ 036package com.unboundid.util.args; 037 038 039 040import java.util.ArrayList; 041import java.util.Collections; 042import java.util.Iterator; 043import java.util.List; 044 045import com.unboundid.ldap.sdk.DN; 046import com.unboundid.ldap.sdk.LDAPException; 047import com.unboundid.util.Debug; 048import com.unboundid.util.Mutable; 049import com.unboundid.util.ThreadSafety; 050import com.unboundid.util.ThreadSafetyLevel; 051 052import static com.unboundid.util.args.ArgsMessages.*; 053 054 055 056/** 057 * This class defines an argument that is intended to hold one or more 058 * distinguished name values. DN arguments must take values, and those values 059 * must be able to be parsed as distinguished names. 060 */ 061@Mutable() 062@ThreadSafety(level=ThreadSafetyLevel.NOT_THREADSAFE) 063public final class DNArgument 064 extends Argument 065{ 066 /** 067 * The serial version UID for this serializable class. 068 */ 069 private static final long serialVersionUID = 7956577383262400167L; 070 071 072 073 // The set of values assigned to this argument. 074 private final ArrayList<DN> values; 075 076 // The argument value validators that have been registered for this argument. 077 private final List<ArgumentValueValidator> validators; 078 079 // The list of default values for this argument. 080 private final List<DN> defaultValues; 081 082 083 084 /** 085 * Creates a new DN argument with the provided information. It will not be 086 * required, will permit at most one occurrence, will use a default 087 * placeholder, and will not have a default value. 088 * 089 * @param shortIdentifier The short identifier for this argument. It may 090 * not be {@code null} if the long identifier is 091 * {@code null}. 092 * @param longIdentifier The long identifier for this argument. It may 093 * not be {@code null} if the short identifier is 094 * {@code null}. 095 * @param description A human-readable description for this argument. 096 * It must not be {@code null}. 097 * 098 * @throws ArgumentException If there is a problem with the definition of 099 * this argument. 100 */ 101 public DNArgument(final Character shortIdentifier, 102 final String longIdentifier, final String description) 103 throws ArgumentException 104 { 105 this(shortIdentifier, longIdentifier, false, 1, null, description); 106 } 107 108 109 110 /** 111 * Creates a new DN argument with the provided information. It will not have 112 * a default value. 113 * 114 * @param shortIdentifier The short identifier for this argument. It may 115 * not be {@code null} if the long identifier is 116 * {@code null}. 117 * @param longIdentifier The long identifier for this argument. It may 118 * not be {@code null} if the short identifier is 119 * {@code null}. 120 * @param isRequired Indicates whether this argument is required to 121 * be provided. 122 * @param maxOccurrences The maximum number of times this argument may be 123 * provided on the command line. A value less than 124 * or equal to zero indicates that it may be present 125 * any number of times. 126 * @param valuePlaceholder A placeholder to display in usage information to 127 * indicate that a value must be provided. It may 128 * be {@code null} if a default placeholder should 129 * be used. 130 * @param description A human-readable description for this argument. 131 * It must not be {@code null}. 132 * 133 * @throws ArgumentException If there is a problem with the definition of 134 * this argument. 135 */ 136 public DNArgument(final Character shortIdentifier, 137 final String longIdentifier, final boolean isRequired, 138 final int maxOccurrences, final String valuePlaceholder, 139 final String description) 140 throws ArgumentException 141 { 142 this(shortIdentifier, longIdentifier, isRequired, maxOccurrences, 143 valuePlaceholder, description, (List<DN>) null); 144 } 145 146 147 148 /** 149 * Creates a new DN argument with the provided information. 150 * 151 * @param shortIdentifier The short identifier for this argument. It may 152 * not be {@code null} if the long identifier is 153 * {@code null}. 154 * @param longIdentifier The long identifier for this argument. It may 155 * not be {@code null} if the short identifier is 156 * {@code null}. 157 * @param isRequired Indicates whether this argument is required to 158 * be provided. 159 * @param maxOccurrences The maximum number of times this argument may be 160 * provided on the command line. A value less than 161 * or equal to zero indicates that it may be present 162 * any number of times. 163 * @param valuePlaceholder A placeholder to display in usage information to 164 * indicate that a value must be provided. It may 165 * be {@code null} if a default placeholder should 166 * be used. 167 * @param description A human-readable description for this argument. 168 * It must not be {@code null}. 169 * @param defaultValue The default value to use for this argument if no 170 * values were provided. 171 * 172 * @throws ArgumentException If there is a problem with the definition of 173 * this argument. 174 */ 175 public DNArgument(final Character shortIdentifier, 176 final String longIdentifier, final boolean isRequired, 177 final int maxOccurrences, final String valuePlaceholder, 178 final String description, final DN defaultValue) 179 throws ArgumentException 180 { 181 this(shortIdentifier, longIdentifier, isRequired, maxOccurrences, 182 valuePlaceholder, description, 183 ((defaultValue == null) 184 ? null : 185 Collections.singletonList(defaultValue))); 186 } 187 188 189 190 /** 191 * Creates a new DN argument with the provided information. 192 * 193 * @param shortIdentifier The short identifier for this argument. It may 194 * not be {@code null} if the long identifier is 195 * {@code null}. 196 * @param longIdentifier The long identifier for this argument. It may 197 * not be {@code null} if the short identifier is 198 * {@code null}. 199 * @param isRequired Indicates whether this argument is required to 200 * be provided. 201 * @param maxOccurrences The maximum number of times this argument may be 202 * provided on the command line. A value less than 203 * or equal to zero indicates that it may be present 204 * any number of times. 205 * @param valuePlaceholder A placeholder to display in usage information to 206 * indicate that a value must be provided. It may 207 * be {@code null} if a default placeholder should 208 * be used. 209 * @param description A human-readable description for this argument. 210 * It must not be {@code null}. 211 * @param defaultValues The set of default values to use for this 212 * argument if no values were provided. 213 * 214 * @throws ArgumentException If there is a problem with the definition of 215 * this argument. 216 */ 217 public DNArgument(final Character shortIdentifier, 218 final String longIdentifier, final boolean isRequired, 219 final int maxOccurrences, final String valuePlaceholder, 220 final String description, final List<DN> defaultValues) 221 throws ArgumentException 222 { 223 super(shortIdentifier, longIdentifier, isRequired, maxOccurrences, 224 (valuePlaceholder == null) 225 ? INFO_PLACEHOLDER_DN.get() 226 : valuePlaceholder, 227 description); 228 229 if ((defaultValues == null) || defaultValues.isEmpty()) 230 { 231 this.defaultValues = null; 232 } 233 else 234 { 235 this.defaultValues = Collections.unmodifiableList(defaultValues); 236 } 237 238 values = new ArrayList<>(5); 239 validators = new ArrayList<>(5); 240 } 241 242 243 244 /** 245 * Creates a new DN argument that is a "clean" copy of the provided source 246 * argument. 247 * 248 * @param source The source argument to use for this argument. 249 */ 250 private DNArgument(final DNArgument source) 251 { 252 super(source); 253 254 defaultValues = source.defaultValues; 255 values = new ArrayList<>(5); 256 validators = new ArrayList<>(source.validators); 257 } 258 259 260 261 /** 262 * Retrieves the list of default values for this argument, which will be used 263 * if no values were provided. 264 * 265 * @return The list of default values for this argument, or {@code null} if 266 * there are no default values. 267 */ 268 public List<DN> getDefaultValues() 269 { 270 return defaultValues; 271 } 272 273 274 275 /** 276 * Updates this argument to ensure that the provided validator will be invoked 277 * for any values provided to this argument. This validator will be invoked 278 * after all other validation has been performed for this argument. 279 * 280 * @param validator The argument value validator to be invoked. It must not 281 * be {@code null}. 282 */ 283 public void addValueValidator(final ArgumentValueValidator validator) 284 { 285 validators.add(validator); 286 } 287 288 289 290 /** 291 * {@inheritDoc} 292 */ 293 @Override() 294 protected void addValue(final String valueString) 295 throws ArgumentException 296 { 297 final DN parsedDN; 298 try 299 { 300 parsedDN = new DN(valueString); 301 } 302 catch (final LDAPException le) 303 { 304 Debug.debugException(le); 305 throw new ArgumentException(ERR_DN_VALUE_NOT_DN.get(valueString, 306 getIdentifierString(), le.getMessage()), 307 le); 308 } 309 310 if (values.size() >= getMaxOccurrences()) 311 { 312 throw new ArgumentException(ERR_ARG_MAX_OCCURRENCES_EXCEEDED.get( 313 getIdentifierString())); 314 } 315 316 for (final ArgumentValueValidator v : validators) 317 { 318 v.validateArgumentValue(this, valueString); 319 } 320 321 values.add(parsedDN); 322 } 323 324 325 326 /** 327 * Retrieves the value for this argument, or the default value if none was 328 * provided. If there are multiple values, then the first will be returned. 329 * 330 * @return The value for this argument, or the default value if none was 331 * provided, or {@code null} if there is no value and no default 332 * value. 333 */ 334 public DN getValue() 335 { 336 if (values.isEmpty()) 337 { 338 if ((defaultValues == null) || defaultValues.isEmpty()) 339 { 340 return null; 341 } 342 else 343 { 344 return defaultValues.get(0); 345 } 346 } 347 else 348 { 349 return values.get(0); 350 } 351 } 352 353 354 355 /** 356 * Retrieves the set of values for this argument. 357 * 358 * @return The set of values for this argument. 359 */ 360 public List<DN> getValues() 361 { 362 if (values.isEmpty() && (defaultValues != null)) 363 { 364 return defaultValues; 365 } 366 367 return Collections.unmodifiableList(values); 368 } 369 370 371 372 /** 373 * Retrieves a string representation of the value for this argument, or a 374 * string representation of the default value if none was provided. If there 375 * are multiple values, then the first will be returned. 376 * 377 * @return The string representation of the value for this argument, or the 378 * string representation of the default value if none was provided, 379 * or {@code null} if there is no value and no default value. 380 */ 381 public String getStringValue() 382 { 383 final DN valueDN = getValue(); 384 if (valueDN == null) 385 { 386 return null; 387 } 388 389 return valueDN.toString(); 390 } 391 392 393 394 /** 395 * {@inheritDoc} 396 */ 397 @Override() 398 public List<String> getValueStringRepresentations(final boolean useDefault) 399 { 400 if (values.isEmpty()) 401 { 402 if (useDefault && (defaultValues != null)) 403 { 404 final ArrayList<String> valueStrings = 405 new ArrayList<>(defaultValues.size()); 406 for (final DN dn : defaultValues) 407 { 408 valueStrings.add(dn.toString()); 409 } 410 return Collections.unmodifiableList(valueStrings); 411 } 412 else 413 { 414 return Collections.emptyList(); 415 } 416 } 417 else 418 { 419 final ArrayList<String> valueStrings = new ArrayList<>(values.size()); 420 for (final DN dn : values) 421 { 422 valueStrings.add(dn.toString()); 423 } 424 return Collections.unmodifiableList(valueStrings); 425 } 426 } 427 428 429 430 /** 431 * {@inheritDoc} 432 */ 433 @Override() 434 protected boolean hasDefaultValue() 435 { 436 return ((defaultValues != null) && (! defaultValues.isEmpty())); 437 } 438 439 440 441 /** 442 * {@inheritDoc} 443 */ 444 @Override() 445 public String getDataTypeName() 446 { 447 return INFO_DN_TYPE_NAME.get(); 448 } 449 450 451 452 /** 453 * {@inheritDoc} 454 */ 455 @Override() 456 public String getValueConstraints() 457 { 458 return INFO_DN_CONSTRAINTS.get(); 459 } 460 461 462 463 /** 464 * {@inheritDoc} 465 */ 466 @Override() 467 protected void reset() 468 { 469 super.reset(); 470 values.clear(); 471 } 472 473 474 475 /** 476 * {@inheritDoc} 477 */ 478 @Override() 479 public DNArgument getCleanCopy() 480 { 481 return new DNArgument(this); 482 } 483 484 485 486 /** 487 * {@inheritDoc} 488 */ 489 @Override() 490 protected void addToCommandLine(final List<String> argStrings) 491 { 492 if (values != null) 493 { 494 for (final DN dn : values) 495 { 496 argStrings.add(getIdentifierString()); 497 if (isSensitive()) 498 { 499 argStrings.add("***REDACTED***"); 500 } 501 else 502 { 503 argStrings.add(String.valueOf(dn)); 504 } 505 } 506 } 507 } 508 509 510 511 /** 512 * {@inheritDoc} 513 */ 514 @Override() 515 public void toString(final StringBuilder buffer) 516 { 517 buffer.append("DNArgument("); 518 appendBasicToStringInfo(buffer); 519 520 if ((defaultValues != null) && (! defaultValues.isEmpty())) 521 { 522 if (defaultValues.size() == 1) 523 { 524 buffer.append(", defaultValue='"); 525 buffer.append(defaultValues.get(0).toString()); 526 } 527 else 528 { 529 buffer.append(", defaultValues={"); 530 531 final Iterator<DN> iterator = defaultValues.iterator(); 532 while (iterator.hasNext()) 533 { 534 buffer.append('\''); 535 buffer.append(iterator.next().toString()); 536 buffer.append('\''); 537 538 if (iterator.hasNext()) 539 { 540 buffer.append(", "); 541 } 542 } 543 544 buffer.append('}'); 545 } 546 } 547 548 buffer.append(')'); 549 } 550}