001/* 002 * Copyright 2015-2017 UnboundID Corp. 003 * All Rights Reserved. 004 */ 005/* 006 * Copyright (C) 2015-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.Collections; 027import java.util.HashMap; 028import java.util.Iterator; 029import java.util.List; 030import java.util.Map; 031 032import com.unboundid.asn1.ASN1OctetString; 033import com.unboundid.ldap.sdk.Control; 034import com.unboundid.ldap.sdk.controls.AuthorizationIdentityRequestControl; 035import com.unboundid.ldap.sdk.controls.DontUseCopyRequestControl; 036import com.unboundid.ldap.sdk.controls.ManageDsaITRequestControl; 037import com.unboundid.ldap.sdk.controls.PermissiveModifyRequestControl; 038import com.unboundid.ldap.sdk.controls.SubentriesRequestControl; 039import com.unboundid.ldap.sdk.controls.SubtreeDeleteRequestControl; 040import com.unboundid.ldap.sdk.experimental. 041 DraftBeheraLDAPPasswordPolicy10RequestControl; 042import com.unboundid.ldap.sdk.experimental. 043 DraftZeilengaLDAPNoOp12RequestControl; 044import com.unboundid.util.Base64; 045import com.unboundid.util.Debug; 046import com.unboundid.util.Mutable; 047import com.unboundid.util.StaticUtils; 048import com.unboundid.util.ThreadSafety; 049import com.unboundid.util.ThreadSafetyLevel; 050 051import static com.unboundid.util.args.ArgsMessages.*; 052 053 054 055/** 056 * This class defines an argument that is intended to hold information about one 057 * or more LDAP controls. Values for this argument must be in one of the 058 * following formats: 059 * <UL> 060 * <LI> 061 * oid -- The numeric OID for the control. The control will not be critical 062 * and will not have a value. 063 * </LI> 064 * <LI> 065 * oid:criticality -- The numeric OID followed by a colon and the 066 * criticality. The control will be critical if the criticality value is 067 * any of the following: {@code true}, {@code t}, {@code yes}, {@code y}, 068 * {@code on}, or {@code 1}. The control will be non-critical if the 069 * criticality value is any of the following: {@code false}, {@code f}, 070 * {@code no}, {@code n}, {@code off}, or {@code 0}. No other criticality 071 * values will be accepted. 072 * </LI> 073 * <LI> 074 * oid:criticality:value -- The numeric OID followed by a colon and the 075 * criticality, then a colon and then a string that represents the value for 076 * the control. 077 * </LI> 078 * <LI> 079 * oid:criticality::base64value -- The numeric OID followed by a colon and 080 * the criticality, then two colons and then a string that represents the 081 * base64-encoded value for the control. 082 * </LI> 083 * </UL> 084 */ 085@Mutable() 086@ThreadSafety(level=ThreadSafetyLevel.NOT_THREADSAFE) 087public final class ControlArgument 088 extends Argument 089{ 090 /** 091 * A map of human-readable names to the corresponding numeric OIDs. 092 */ 093 private static final Map<String,String> OIDS_BY_NAME; 094 static 095 { 096 final HashMap<String,String> oidsByName = 097 new HashMap<String,String>(100); 098 099 // The authorization identity request control. 100 oidsByName.put("authzid", 101 AuthorizationIdentityRequestControl. 102 AUTHORIZATION_IDENTITY_REQUEST_OID); 103 oidsByName.put("authorizationidentity", 104 AuthorizationIdentityRequestControl. 105 AUTHORIZATION_IDENTITY_REQUEST_OID); 106 oidsByName.put("authorization-identity", 107 AuthorizationIdentityRequestControl. 108 AUTHORIZATION_IDENTITY_REQUEST_OID); 109 110 // The don't use copy request control. 111 oidsByName.put("nocopy", 112 DontUseCopyRequestControl.DONT_USE_COPY_REQUEST_OID); 113 oidsByName.put("dontusecopy", 114 DontUseCopyRequestControl.DONT_USE_COPY_REQUEST_OID); 115 oidsByName.put("no-copy", 116 DontUseCopyRequestControl.DONT_USE_COPY_REQUEST_OID); 117 oidsByName.put("dont-use-copy", 118 DontUseCopyRequestControl.DONT_USE_COPY_REQUEST_OID); 119 120 // The LDAP no-operation request control. 121 oidsByName.put("noop", 122 DraftZeilengaLDAPNoOp12RequestControl.NO_OP_REQUEST_OID); 123 oidsByName.put("nooperation", 124 DraftZeilengaLDAPNoOp12RequestControl.NO_OP_REQUEST_OID); 125 oidsByName.put("no-op", 126 DraftZeilengaLDAPNoOp12RequestControl.NO_OP_REQUEST_OID); 127 oidsByName.put("no-operation", 128 DraftZeilengaLDAPNoOp12RequestControl.NO_OP_REQUEST_OID); 129 130 // The LDAP subentries request control. 131 oidsByName.put("subentries", 132 SubentriesRequestControl.SUBENTRIES_REQUEST_OID); 133 oidsByName.put("ldapsubentries", 134 SubentriesRequestControl.SUBENTRIES_REQUEST_OID); 135 oidsByName.put("ldap-subentries", 136 SubentriesRequestControl.SUBENTRIES_REQUEST_OID); 137 138 // The manage DSA IT request control. 139 oidsByName.put("managedsait", 140 ManageDsaITRequestControl.MANAGE_DSA_IT_REQUEST_OID); 141 oidsByName.put("manage-dsa-it", 142 ManageDsaITRequestControl.MANAGE_DSA_IT_REQUEST_OID); 143 144 // The permissive modify request control. 145 oidsByName.put("permissivemodify", 146 PermissiveModifyRequestControl.PERMISSIVE_MODIFY_REQUEST_OID); 147 oidsByName.put("permissive-modify", 148 PermissiveModifyRequestControl.PERMISSIVE_MODIFY_REQUEST_OID); 149 150 // The password policy request control. 151 oidsByName.put("pwpolicy", 152 DraftBeheraLDAPPasswordPolicy10RequestControl. 153 PASSWORD_POLICY_REQUEST_OID); 154 oidsByName.put("passwordpolicy", 155 DraftBeheraLDAPPasswordPolicy10RequestControl. 156 PASSWORD_POLICY_REQUEST_OID); 157 oidsByName.put("pw-policy", 158 DraftBeheraLDAPPasswordPolicy10RequestControl. 159 PASSWORD_POLICY_REQUEST_OID); 160 oidsByName.put("password-policy", 161 DraftBeheraLDAPPasswordPolicy10RequestControl. 162 PASSWORD_POLICY_REQUEST_OID); 163 164 // The subtree delete request control. 165 oidsByName.put("subtreedelete", 166 SubtreeDeleteRequestControl.SUBTREE_DELETE_REQUEST_OID); 167 oidsByName.put("treedelete", 168 SubtreeDeleteRequestControl.SUBTREE_DELETE_REQUEST_OID); 169 oidsByName.put("subtree-delete", 170 SubtreeDeleteRequestControl.SUBTREE_DELETE_REQUEST_OID); 171 oidsByName.put("tree-delete", 172 SubtreeDeleteRequestControl.SUBTREE_DELETE_REQUEST_OID); 173 174 // The account usable request control. 175 oidsByName.put("accountusable", "1.3.6.1.4.1.42.2.27.9.5.8"); 176 oidsByName.put("account-usable", "1.3.6.1.4.1.42.2.27.9.5.8"); 177 178 // The get backend set ID request control. 179 oidsByName.put("backendsetid", "1.3.6.1.4.1.30221.2.5.33"); 180 oidsByName.put("getbackendsetid", "1.3.6.1.4.1.30221.2.5.33"); 181 oidsByName.put("backendset-id", "1.3.6.1.4.1.30221.2.5.33"); 182 oidsByName.put("get-backendset-id", "1.3.6.1.4.1.30221.2.5.33"); 183 184 // The get effective rights request control. 185 oidsByName.put("effectiverights", "1.3.6.1.4.1.42.2.27.9.5.2"); 186 oidsByName.put("geteffectiverights", "1.3.6.1.4.1.42.2.27.9.5.2"); 187 oidsByName.put("effective-rights", "1.3.6.1.4.1.42.2.27.9.5.2"); 188 oidsByName.put("get-effective-rights", "1.3.6.1.4.1.42.2.27.9.5.2"); 189 190 // The get password policy state issues request control. 191 oidsByName.put("pwpolicystateissues", "1.3.6.1.4.1.30221.2.5.46"); 192 oidsByName.put("getpwpolicystateissues", "1.3.6.1.4.1.30221.2.5.46"); 193 oidsByName.put("passwordpolicystateissues", "1.3.6.1.4.1.30221.2.5.46"); 194 oidsByName.put("getpasswordpolicystateissues", "1.3.6.1.4.1.30221.2.5.46"); 195 oidsByName.put("pw-policy-state-issues", "1.3.6.1.4.1.30221.2.5.46"); 196 oidsByName.put("get-pw-policy-state-issues", "1.3.6.1.4.1.30221.2.5.46"); 197 oidsByName.put("password-policy-state-issues", "1.3.6.1.4.1.30221.2.5.46"); 198 oidsByName.put("get-password-policy-state-issues", 199 "1.3.6.1.4.1.30221.2.5.46"); 200 201 // The get server ID request control. 202 oidsByName.put("serverid", "1.3.6.1.4.1.30221.2.5.14"); 203 oidsByName.put("getserverid", "1.3.6.1.4.1.30221.2.5.14"); 204 oidsByName.put("server-id", "1.3.6.1.4.1.30221.2.5.14"); 205 oidsByName.put("get-server-id", "1.3.6.1.4.1.30221.2.5.14"); 206 207 // The get user resource limits request control. 208 oidsByName.put("userresourcelimits", "1.3.6.1.4.1.30221.2.5.25"); 209 oidsByName.put("getuserresourcelimits", "1.3.6.1.4.1.30221.2.5.25"); 210 oidsByName.put("user-resource-limits", "1.3.6.1.4.1.30221.2.5.25"); 211 oidsByName.put("get-user-resource-limits", "1.3.6.1.4.1.30221.2.5.25"); 212 213 // The hard delete request control. 214 oidsByName.put("harddelete", "1.3.6.1.4.1.30221.2.5.22"); 215 oidsByName.put("hard-delete", "1.3.6.1.4.1.30221.2.5.22"); 216 217 // The ignore NO-USER-MODIFICATION request control. 218 oidsByName.put("ignorenousermod", "1.3.6.1.4.1.30221.2.5.5"); 219 oidsByName.put("ignorenousermodification", "1.3.6.1.4.1.30221.2.5.5"); 220 oidsByName.put("ignore-no-user-mod", "1.3.6.1.4.1.30221.2.5.5"); 221 oidsByName.put("ignore-no-user-modification", "1.3.6.1.4.1.30221.2.5.5"); 222 223 // The purge retired password request control. 224 oidsByName.put("purgepassword", "1.3.6.1.4.1.30221.2.5.32"); 225 oidsByName.put("purgeretiredpassword", "1.3.6.1.4.1.30221.2.5.32"); 226 oidsByName.put("purge-password", "1.3.6.1.4.1.30221.2.5.32"); 227 oidsByName.put("purge-retired-password", "1.3.6.1.4.1.30221.2.5.32"); 228 229 // The real attributes only request control. 230 oidsByName.put("realattrsonly", "2.16.840.1.113730.3.4.17"); 231 oidsByName.put("realattributesonly", "2.16.840.1.113730.3.4.17"); 232 oidsByName.put("real-attrs-only", "2.16.840.1.113730.3.4.17"); 233 oidsByName.put("real-attributes-only", "2.16.840.1.113730.3.4.17"); 234 235 // The replication repair request control. 236 oidsByName.put("replrepair", "1.3.6.1.4.1.30221.1.5.2"); 237 oidsByName.put("replicationrepair", "1.3.6.1.4.1.30221.1.5.2"); 238 oidsByName.put("repl-repair", "1.3.6.1.4.1.30221.1.5.2"); 239 oidsByName.put("replication-repair", "1.3.6.1.4.1.30221.1.5.2"); 240 241 // The retain identity request control. 242 oidsByName.put("retainidentity", "1.3.6.1.4.1.30221.2.5.3"); 243 oidsByName.put("retain-identity", "1.3.6.1.4.1.30221.2.5.3"); 244 245 // The retire password request control. 246 oidsByName.put("retirepassword", "1.3.6.1.4.1.30221.2.5.31"); 247 oidsByName.put("retire-password", "1.3.6.1.4.1.30221.2.5.31"); 248 249 // The return conflict entries request control. 250 oidsByName.put("returnconflictentries", "1.3.6.1.4.1.30221.2.5.13"); 251 oidsByName.put("return-conflict-entries", "1.3.6.1.4.1.30221.2.5.13"); 252 253 // The soft delete request control. 254 oidsByName.put("softdelete", "1.3.6.1.4.1.30221.2.5.20"); 255 oidsByName.put("soft-delete", "1.3.6.1.4.1.30221.2.5.20"); 256 257 // The soft-deleted entry access request control. 258 oidsByName.put("softdeleteentryaccess", "1.3.6.1.4.1.30221.2.5.24"); 259 oidsByName.put("softdeletedentryaccess", "1.3.6.1.4.1.30221.2.5.24"); 260 oidsByName.put("soft-delete-entry-access", "1.3.6.1.4.1.30221.2.5.24"); 261 oidsByName.put("soft-deleted-entry-access", "1.3.6.1.4.1.30221.2.5.24"); 262 263 // The suppress referential integrity updates request control. 264 oidsByName.put("suppressreferentialintegrity", "1.3.6.1.4.1.30221.2.5.30"); 265 oidsByName.put("suppressreferentialintegrityupdates", 266 "1.3.6.1.4.1.30221.2.5.30"); 267 oidsByName.put("suppress-referential-integrity", 268 "1.3.6.1.4.1.30221.2.5.30"); 269 oidsByName.put("suppress-referential-integrity-updates", 270 "1.3.6.1.4.1.30221.2.5.30"); 271 272 // The undelete request control. 273 oidsByName.put("undelete", "1.3.6.1.4.1.30221.2.5.23"); 274 275 // The virtual attributes only request control. 276 oidsByName.put("virtualattrsonly", "2.16.840.1.113730.3.4.19"); 277 oidsByName.put("virtualattributesonly", "2.16.840.1.113730.3.4.19"); 278 oidsByName.put("virtual-attrs-only", "2.16.840.1.113730.3.4.19"); 279 oidsByName.put("virtual-attributes-only", "2.16.840.1.113730.3.4.19"); 280 281 OIDS_BY_NAME = Collections.unmodifiableMap(oidsByName); 282 } 283 284 285 286 /** 287 * The serial version UID for this serializable class. 288 */ 289 private static final long serialVersionUID = -1889200072476038957L; 290 291 292 293 // The argument value validators that have been registered for this argument. 294 private final List<ArgumentValueValidator> validators; 295 296 // The list of default values for this argument. 297 private final List<Control> defaultValues; 298 299 // The set of values assigned to this argument. 300 private final List<Control> values; 301 302 303 304 /** 305 * Creates a new control argument with the provided information. It will not 306 * be required, will be allowed any number of times, will use a default 307 * placeholder, and will not have a default value. 308 * 309 * @param shortIdentifier The short identifier for this argument. It may 310 * not be {@code null} if the long identifier is 311 * {@code null}. 312 * @param longIdentifier The long identifier for this argument. It may 313 * not be {@code null} if the short identifier is 314 * {@code null}. 315 * @param description A human-readable description for this argument. 316 * It must not be {@code null}. 317 * 318 * @throws ArgumentException If there is a problem with the definition of 319 * this argument. 320 */ 321 public ControlArgument(final Character shortIdentifier, 322 final String longIdentifier, final String description) 323 throws ArgumentException 324 { 325 this(shortIdentifier, longIdentifier, false, 0, null, description); 326 } 327 328 329 330 /** 331 * Creates a new control argument with the provided information. It will not 332 * have a default value. 333 * 334 * @param shortIdentifier The short identifier for this argument. It may 335 * not be {@code null} if the long identifier is 336 * {@code null}. 337 * @param longIdentifier The long identifier for this argument. It may 338 * not be {@code null} if the short identifier is 339 * {@code null}. 340 * @param isRequired Indicates whether this argument is required to 341 * be provided. 342 * @param maxOccurrences The maximum number of times this argument may be 343 * provided on the command line. A value less than 344 * or equal to zero indicates that it may be present 345 * any number of times. 346 * @param valuePlaceholder A placeholder to display in usage information to 347 * indicate that a value must be provided. It may 348 * be {@code null} to use a default placeholder that 349 * describes the expected syntax for values. 350 * @param description A human-readable description for this argument. 351 * It must not be {@code null}. 352 * 353 * @throws ArgumentException If there is a problem with the definition of 354 * this argument. 355 */ 356 public ControlArgument(final Character shortIdentifier, 357 final String longIdentifier, final boolean isRequired, 358 final int maxOccurrences, 359 final String valuePlaceholder, 360 final String description) 361 throws ArgumentException 362 { 363 this(shortIdentifier, longIdentifier, isRequired, maxOccurrences, 364 valuePlaceholder, description, (List<Control>) null); 365 } 366 367 368 369 /** 370 * Creates a new control argument with the provided information. 371 * 372 * @param shortIdentifier The short identifier for this argument. It may 373 * not be {@code null} if the long identifier is 374 * {@code null}. 375 * @param longIdentifier The long identifier for this argument. It may 376 * not be {@code null} if the short identifier is 377 * {@code null}. 378 * @param isRequired Indicates whether this argument is required to 379 * be provided. 380 * @param maxOccurrences The maximum number of times this argument may be 381 * provided on the command line. A value less than 382 * or equal to zero indicates that it may be present 383 * any number of times. 384 * @param valuePlaceholder A placeholder to display in usage information to 385 * indicate that a value must be provided. It may 386 * be {@code null} to use a default placeholder that 387 * describes the expected syntax for values. 388 * @param description A human-readable description for this argument. 389 * It must not be {@code null}. 390 * @param defaultValue The default value to use for this argument if no 391 * values were provided. It may be {@code null} if 392 * there should be no default values. 393 * 394 * @throws ArgumentException If there is a problem with the definition of 395 * this argument. 396 */ 397 public ControlArgument(final Character shortIdentifier, 398 final String longIdentifier, final boolean isRequired, 399 final int maxOccurrences, 400 final String valuePlaceholder, 401 final String description, final Control defaultValue) 402 throws ArgumentException 403 { 404 this(shortIdentifier, longIdentifier, isRequired, maxOccurrences, 405 valuePlaceholder, description, 406 ((defaultValue == null) 407 ? null : 408 Collections.singletonList(defaultValue))); 409 } 410 411 412 413 /** 414 * Creates a new control argument with the provided information. 415 * 416 * @param shortIdentifier The short identifier for this argument. It may 417 * not be {@code null} if the long identifier is 418 * {@code null}. 419 * @param longIdentifier The long identifier for this argument. It may 420 * not be {@code null} if the short identifier is 421 * {@code null}. 422 * @param isRequired Indicates whether this argument is required to 423 * be provided. 424 * @param maxOccurrences The maximum number of times this argument may be 425 * provided on the command line. A value less than 426 * or equal to zero indicates that it may be present 427 * any number of times. 428 * @param valuePlaceholder A placeholder to display in usage information to 429 * indicate that a value must be provided. It may 430 * be {@code null} to use a default placeholder that 431 * describes the expected syntax for values. 432 * @param description A human-readable description for this argument. 433 * It must not be {@code null}. 434 * @param defaultValues The set of default values to use for this 435 * argument if no values were provided. 436 * 437 * @throws ArgumentException If there is a problem with the definition of 438 * this argument. 439 */ 440 public ControlArgument(final Character shortIdentifier, 441 final String longIdentifier, final boolean isRequired, 442 final int maxOccurrences, 443 final String valuePlaceholder, 444 final String description, 445 final List<Control> defaultValues) 446 throws ArgumentException 447 { 448 super(shortIdentifier, longIdentifier, isRequired, maxOccurrences, 449 (valuePlaceholder == null) 450 ? INFO_PLACEHOLDER_CONTROL.get() 451 : valuePlaceholder, 452 description); 453 454 if ((defaultValues == null) || defaultValues.isEmpty()) 455 { 456 this.defaultValues = null; 457 } 458 else 459 { 460 this.defaultValues = Collections.unmodifiableList(defaultValues); 461 } 462 463 values = new ArrayList<Control>(5); 464 validators = new ArrayList<ArgumentValueValidator>(5); 465 } 466 467 468 469 /** 470 * Creates a new control argument that is a "clean" copy of the provided 471 * source argument. 472 * 473 * @param source The source argument to use for this argument. 474 */ 475 private ControlArgument(final ControlArgument source) 476 { 477 super(source); 478 479 defaultValues = source.defaultValues; 480 validators = new ArrayList<ArgumentValueValidator>(source.validators); 481 values = new ArrayList<Control>(5); 482 } 483 484 485 486 /** 487 * Retrieves the list of default values for this argument, which will be used 488 * if no values were provided. 489 * 490 * @return The list of default values for this argument, or {@code null} if 491 * there are no default values. 492 */ 493 public List<Control> getDefaultValues() 494 { 495 return defaultValues; 496 } 497 498 499 500 /** 501 * Updates this argument to ensure that the provided validator will be invoked 502 * for any values provided to this argument. This validator will be invoked 503 * after all other validation has been performed for this argument. 504 * 505 * @param validator The argument value validator to be invoked. It must not 506 * be {@code null}. 507 */ 508 public void addValueValidator(final ArgumentValueValidator validator) 509 { 510 validators.add(validator); 511 } 512 513 514 515 /** 516 * {@inheritDoc} 517 */ 518 @Override() 519 protected void addValue(final String valueString) 520 throws ArgumentException 521 { 522 String oid; 523 boolean isCritical = false; 524 ASN1OctetString value = null; 525 526 final int firstColonPos = valueString.indexOf(':'); 527 if (firstColonPos < 0) 528 { 529 oid = valueString; 530 } 531 else 532 { 533 oid = valueString.substring(0, firstColonPos); 534 535 final String criticalityStr; 536 final int secondColonPos = valueString.indexOf(':', (firstColonPos+1)); 537 if (secondColonPos < 0) 538 { 539 criticalityStr = valueString.substring(firstColonPos+1); 540 } 541 else 542 { 543 criticalityStr = valueString.substring(firstColonPos+1, secondColonPos); 544 545 final int doubleColonPos = valueString.indexOf("::"); 546 if (doubleColonPos == secondColonPos) 547 { 548 try 549 { 550 value = new ASN1OctetString( 551 Base64.decode(valueString.substring(doubleColonPos+2))); 552 } 553 catch (final Exception e) 554 { 555 Debug.debugException(e); 556 throw new ArgumentException( 557 ERR_CONTROL_ARG_INVALID_BASE64_VALUE.get(valueString, 558 getIdentifierString(), 559 valueString.substring(doubleColonPos+2)), 560 e); 561 } 562 } 563 else 564 { 565 value = new ASN1OctetString(valueString.substring(secondColonPos+1)); 566 } 567 } 568 569 final String lowerCriticalityStr = 570 StaticUtils.toLowerCase(criticalityStr); 571 if (lowerCriticalityStr.equals("true") || 572 lowerCriticalityStr.equals("t") || 573 lowerCriticalityStr.equals("yes") || 574 lowerCriticalityStr.equals("y") || 575 lowerCriticalityStr.equals("on") || 576 lowerCriticalityStr.equals("1")) 577 { 578 isCritical = true; 579 } 580 else if (lowerCriticalityStr.equals("false") || 581 lowerCriticalityStr.equals("f") || 582 lowerCriticalityStr.equals("no") || 583 lowerCriticalityStr.equals("n") || 584 lowerCriticalityStr.equals("off") || 585 lowerCriticalityStr.equals("0")) 586 { 587 isCritical = false; 588 } 589 else 590 { 591 throw new ArgumentException(ERR_CONTROL_ARG_INVALID_CRITICALITY.get( 592 valueString, getIdentifierString(), criticalityStr)); 593 } 594 } 595 596 if (! StaticUtils.isNumericOID(oid)) 597 { 598 final String providedOID = oid; 599 oid = OIDS_BY_NAME.get(StaticUtils.toLowerCase(providedOID)); 600 if (oid == null) 601 { 602 throw new ArgumentException(ERR_CONTROL_ARG_INVALID_OID.get( 603 valueString, getIdentifierString(), providedOID)); 604 } 605 } 606 607 if (values.size() >= getMaxOccurrences()) 608 { 609 throw new ArgumentException(ERR_ARG_MAX_OCCURRENCES_EXCEEDED.get( 610 getIdentifierString())); 611 } 612 613 for (final ArgumentValueValidator v : validators) 614 { 615 v.validateArgumentValue(this, valueString); 616 } 617 618 values.add(new Control(oid, isCritical, value)); 619 } 620 621 622 623 /** 624 * Retrieves the value for this argument, or the default value if none was 625 * provided. If there are multiple values, then the first will be returned. 626 * 627 * @return The value for this argument, or the default value if none was 628 * provided, or {@code null} if there is no value and no default 629 * value. 630 */ 631 public Control getValue() 632 { 633 if (values.isEmpty()) 634 { 635 if ((defaultValues == null) || defaultValues.isEmpty()) 636 { 637 return null; 638 } 639 else 640 { 641 return defaultValues.get(0); 642 } 643 } 644 else 645 { 646 return values.get(0); 647 } 648 } 649 650 651 652 /** 653 * Retrieves the set of values for this argument, or the default values if 654 * none were provided. 655 * 656 * @return The set of values for this argument, or the default values if none 657 * were provided. 658 */ 659 public List<Control> getValues() 660 { 661 if (values.isEmpty() && (defaultValues != null)) 662 { 663 return defaultValues; 664 } 665 666 return Collections.unmodifiableList(values); 667 } 668 669 670 671 /** 672 * {@inheritDoc} 673 */ 674 @Override() 675 public List<String> getValueStringRepresentations(final boolean useDefault) 676 { 677 final List<Control> controls; 678 if (values.isEmpty()) 679 { 680 if (useDefault) 681 { 682 controls = defaultValues; 683 } 684 else 685 { 686 return Collections.emptyList(); 687 } 688 } 689 else 690 { 691 controls = values; 692 } 693 694 if ((controls == null) || controls.isEmpty()) 695 { 696 return Collections.emptyList(); 697 } 698 699 final StringBuilder buffer = new StringBuilder(); 700 final ArrayList<String> valueStrings = 701 new ArrayList<String>(controls.size()); 702 for (final Control c : controls) 703 { 704 buffer.setLength(0); 705 buffer.append(c.getOID()); 706 buffer.append(':'); 707 buffer.append(c.isCritical()); 708 709 if (c.hasValue()) 710 { 711 final byte[] valueBytes = c.getValue().getValue(); 712 if (StaticUtils.isPrintableString(valueBytes)) 713 { 714 buffer.append(':'); 715 buffer.append(c.getValue().stringValue()); 716 } 717 else 718 { 719 buffer.append("::"); 720 Base64.encode(valueBytes, buffer); 721 } 722 } 723 724 valueStrings.add(buffer.toString()); 725 } 726 727 return Collections.unmodifiableList(valueStrings); 728 } 729 730 731 732 /** 733 * {@inheritDoc} 734 */ 735 @Override() 736 protected boolean hasDefaultValue() 737 { 738 return ((defaultValues != null) && (! defaultValues.isEmpty())); 739 } 740 741 742 743 /** 744 * {@inheritDoc} 745 */ 746 @Override() 747 public String getDataTypeName() 748 { 749 return INFO_CONTROL_TYPE_NAME.get(); 750 } 751 752 753 754 /** 755 * {@inheritDoc} 756 */ 757 @Override() 758 public String getValueConstraints() 759 { 760 return INFO_CONTROL_CONSTRAINTS.get(); 761 } 762 763 764 765 /** 766 * {@inheritDoc} 767 */ 768 @Override() 769 protected void reset() 770 { 771 super.reset(); 772 values.clear(); 773 } 774 775 776 777 /** 778 * {@inheritDoc} 779 */ 780 @Override() 781 public ControlArgument getCleanCopy() 782 { 783 return new ControlArgument(this); 784 } 785 786 787 788 /** 789 * {@inheritDoc} 790 */ 791 @Override() 792 protected void addToCommandLine(final List<String> argStrings) 793 { 794 if (values != null) 795 { 796 final StringBuilder buffer = new StringBuilder(); 797 for (final Control c : values) 798 { 799 argStrings.add(getIdentifierString()); 800 801 if (isSensitive()) 802 { 803 argStrings.add("***REDACTED***"); 804 continue; 805 } 806 807 buffer.setLength(0); 808 buffer.append(c.getOID()); 809 buffer.append(':'); 810 buffer.append(c.isCritical()); 811 812 if (c.hasValue()) 813 { 814 final byte[] valueBytes = c.getValue().getValue(); 815 if (StaticUtils.isPrintableString(valueBytes)) 816 { 817 buffer.append(':'); 818 buffer.append(c.getValue().stringValue()); 819 } 820 else 821 { 822 buffer.append("::"); 823 Base64.encode(valueBytes, buffer); 824 } 825 } 826 827 argStrings.add(buffer.toString()); 828 } 829 } 830 } 831 832 833 834 /** 835 * {@inheritDoc} 836 */ 837 @Override() 838 public void toString(final StringBuilder buffer) 839 { 840 buffer.append("ControlArgument("); 841 appendBasicToStringInfo(buffer); 842 843 if ((defaultValues != null) && (! defaultValues.isEmpty())) 844 { 845 if (defaultValues.size() == 1) 846 { 847 buffer.append(", defaultValue='"); 848 buffer.append(defaultValues.get(0).toString()); 849 } 850 else 851 { 852 buffer.append(", defaultValues={"); 853 854 final Iterator<Control> iterator = defaultValues.iterator(); 855 while (iterator.hasNext()) 856 { 857 buffer.append('\''); 858 buffer.append(iterator.next().toString()); 859 buffer.append('\''); 860 861 if (iterator.hasNext()) 862 { 863 buffer.append(", "); 864 } 865 } 866 867 buffer.append('}'); 868 } 869 } 870 871 buffer.append(')'); 872 } 873}