001/* 002 * Copyright 2015-2019 Ping Identity Corporation 003 * All Rights Reserved. 004 */ 005/* 006 * Copyright (C) 2015-2019 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.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<>(StaticUtils.computeMapCapacity(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("accountusability", "1.3.6.1.4.1.42.2.27.9.5.8"); 177 oidsByName.put("account-usable", "1.3.6.1.4.1.42.2.27.9.5.8"); 178 oidsByName.put("account-usability", "1.3.6.1.4.1.42.2.27.9.5.8"); 179 180 // The generate password request control. 181 oidsByName.put("generatepassword", "1.3.6.1.4.1.30221.2.5.58"); 182 oidsByName.put("generate-password", "1.3.6.1.4.1.30221.2.5.58"); 183 oidsByName.put("generatepw", "1.3.6.1.4.1.30221.2.5.58"); 184 oidsByName.put("generate-pw", "1.3.6.1.4.1.30221.2.5.58"); 185 186 // The get backend set ID request control. 187 oidsByName.put("backendsetid", "1.3.6.1.4.1.30221.2.5.33"); 188 oidsByName.put("getbackendsetid", "1.3.6.1.4.1.30221.2.5.33"); 189 oidsByName.put("backendset-id", "1.3.6.1.4.1.30221.2.5.33"); 190 oidsByName.put("backend-set-id", "1.3.6.1.4.1.30221.2.5.33"); 191 oidsByName.put("get-backendset-id", "1.3.6.1.4.1.30221.2.5.33"); 192 oidsByName.put("get-backend-set-id", "1.3.6.1.4.1.30221.2.5.33"); 193 194 // The get effective rights request control. 195 oidsByName.put("effectiverights", "1.3.6.1.4.1.42.2.27.9.5.2"); 196 oidsByName.put("geteffectiverights", "1.3.6.1.4.1.42.2.27.9.5.2"); 197 oidsByName.put("effective-rights", "1.3.6.1.4.1.42.2.27.9.5.2"); 198 oidsByName.put("get-effective-rights", "1.3.6.1.4.1.42.2.27.9.5.2"); 199 200 // The get password policy state issues request control. 201 oidsByName.put("pwpolicystateissues", "1.3.6.1.4.1.30221.2.5.46"); 202 oidsByName.put("getpwpolicystateissues", "1.3.6.1.4.1.30221.2.5.46"); 203 oidsByName.put("passwordpolicystateissues", "1.3.6.1.4.1.30221.2.5.46"); 204 oidsByName.put("getpasswordpolicystateissues", "1.3.6.1.4.1.30221.2.5.46"); 205 oidsByName.put("pw-policy-state-issues", "1.3.6.1.4.1.30221.2.5.46"); 206 oidsByName.put("get-pw-policy-state-issues", "1.3.6.1.4.1.30221.2.5.46"); 207 oidsByName.put("password-policy-state-issues", "1.3.6.1.4.1.30221.2.5.46"); 208 oidsByName.put("get-password-policy-state-issues", 209 "1.3.6.1.4.1.30221.2.5.46"); 210 211 // The get server ID request control. 212 oidsByName.put("serverid", "1.3.6.1.4.1.30221.2.5.14"); 213 oidsByName.put("getserverid", "1.3.6.1.4.1.30221.2.5.14"); 214 oidsByName.put("server-id", "1.3.6.1.4.1.30221.2.5.14"); 215 oidsByName.put("get-server-id", "1.3.6.1.4.1.30221.2.5.14"); 216 217 // The get user resource limits request control. 218 oidsByName.put("userresourcelimits", "1.3.6.1.4.1.30221.2.5.25"); 219 oidsByName.put("getuserresourcelimits", "1.3.6.1.4.1.30221.2.5.25"); 220 oidsByName.put("user-resource-limits", "1.3.6.1.4.1.30221.2.5.25"); 221 oidsByName.put("get-user-resource-limits", "1.3.6.1.4.1.30221.2.5.25"); 222 223 // The hard delete request control. 224 oidsByName.put("harddelete", "1.3.6.1.4.1.30221.2.5.22"); 225 oidsByName.put("hard-delete", "1.3.6.1.4.1.30221.2.5.22"); 226 227 // The ignore NO-USER-MODIFICATION request control. 228 oidsByName.put("ignorenousermod", "1.3.6.1.4.1.30221.2.5.5"); 229 oidsByName.put("ignorenousermodification", "1.3.6.1.4.1.30221.2.5.5"); 230 oidsByName.put("ignore-no-user-mod", "1.3.6.1.4.1.30221.2.5.5"); 231 oidsByName.put("ignore-no-user-modification", "1.3.6.1.4.1.30221.2.5.5"); 232 233 // The purge retired password request control. 234 oidsByName.put("purgepassword", "1.3.6.1.4.1.30221.2.5.32"); 235 oidsByName.put("purgeretiredpassword", "1.3.6.1.4.1.30221.2.5.32"); 236 oidsByName.put("purge-password", "1.3.6.1.4.1.30221.2.5.32"); 237 oidsByName.put("purge-retired-password", "1.3.6.1.4.1.30221.2.5.32"); 238 239 // The real attributes only request control. 240 oidsByName.put("realattrsonly", "2.16.840.1.113730.3.4.17"); 241 oidsByName.put("realattributesonly", "2.16.840.1.113730.3.4.17"); 242 oidsByName.put("real-attrs-only", "2.16.840.1.113730.3.4.17"); 243 oidsByName.put("real-attributes-only", "2.16.840.1.113730.3.4.17"); 244 245 // The replication repair request control. 246 oidsByName.put("replrepair", "1.3.6.1.4.1.30221.1.5.2"); 247 oidsByName.put("replicationrepair", "1.3.6.1.4.1.30221.1.5.2"); 248 oidsByName.put("repl-repair", "1.3.6.1.4.1.30221.1.5.2"); 249 oidsByName.put("replication-repair", "1.3.6.1.4.1.30221.1.5.2"); 250 251 // The retain identity request control. 252 oidsByName.put("retainidentity", "1.3.6.1.4.1.30221.2.5.3"); 253 oidsByName.put("retain-identity", "1.3.6.1.4.1.30221.2.5.3"); 254 255 // The retire password request control. 256 oidsByName.put("retirepassword", "1.3.6.1.4.1.30221.2.5.31"); 257 oidsByName.put("retire-password", "1.3.6.1.4.1.30221.2.5.31"); 258 259 // The return conflict entries request control. 260 oidsByName.put("returnconflictentries", "1.3.6.1.4.1.30221.2.5.13"); 261 oidsByName.put("return-conflict-entries", "1.3.6.1.4.1.30221.2.5.13"); 262 263 // The soft delete request control. 264 oidsByName.put("softdelete", "1.3.6.1.4.1.30221.2.5.20"); 265 oidsByName.put("soft-delete", "1.3.6.1.4.1.30221.2.5.20"); 266 267 // The soft-deleted entry access request control. 268 oidsByName.put("softdeleteentryaccess", "1.3.6.1.4.1.30221.2.5.24"); 269 oidsByName.put("softdeletedentryaccess", "1.3.6.1.4.1.30221.2.5.24"); 270 oidsByName.put("soft-delete-entry-access", "1.3.6.1.4.1.30221.2.5.24"); 271 oidsByName.put("soft-deleted-entry-access", "1.3.6.1.4.1.30221.2.5.24"); 272 273 // The suppress referential integrity updates request control. 274 oidsByName.put("suppressreferentialintegrity", "1.3.6.1.4.1.30221.2.5.30"); 275 oidsByName.put("suppressreferentialintegrityupdates", 276 "1.3.6.1.4.1.30221.2.5.30"); 277 oidsByName.put("suppress-referential-integrity", 278 "1.3.6.1.4.1.30221.2.5.30"); 279 oidsByName.put("suppress-referential-integrity-updates", 280 "1.3.6.1.4.1.30221.2.5.30"); 281 282 // The undelete request control. 283 oidsByName.put("undelete", "1.3.6.1.4.1.30221.2.5.23"); 284 285 // The virtual attributes only request control. 286 oidsByName.put("virtualattrsonly", "2.16.840.1.113730.3.4.19"); 287 oidsByName.put("virtualattributesonly", "2.16.840.1.113730.3.4.19"); 288 oidsByName.put("virtual-attrs-only", "2.16.840.1.113730.3.4.19"); 289 oidsByName.put("virtual-attributes-only", "2.16.840.1.113730.3.4.19"); 290 291 OIDS_BY_NAME = Collections.unmodifiableMap(oidsByName); 292 } 293 294 295 296 /** 297 * The serial version UID for this serializable class. 298 */ 299 private static final long serialVersionUID = -1889200072476038957L; 300 301 302 303 // The argument value validators that have been registered for this argument. 304 private final List<ArgumentValueValidator> validators; 305 306 // The list of default values for this argument. 307 private final List<Control> defaultValues; 308 309 // The set of values assigned to this argument. 310 private final List<Control> values; 311 312 313 314 /** 315 * Creates a new control argument with the provided information. It will not 316 * be required, will be allowed any number of times, will use a default 317 * placeholder, and will not have a default value. 318 * 319 * @param shortIdentifier The short identifier for this argument. It may 320 * not be {@code null} if the long identifier is 321 * {@code null}. 322 * @param longIdentifier The long identifier for this argument. It may 323 * not be {@code null} if the short identifier is 324 * {@code null}. 325 * @param description A human-readable description for this argument. 326 * It must not be {@code null}. 327 * 328 * @throws ArgumentException If there is a problem with the definition of 329 * this argument. 330 */ 331 public ControlArgument(final Character shortIdentifier, 332 final String longIdentifier, final String description) 333 throws ArgumentException 334 { 335 this(shortIdentifier, longIdentifier, false, 0, null, description); 336 } 337 338 339 340 /** 341 * Creates a new control argument with the provided information. It will not 342 * have a default value. 343 * 344 * @param shortIdentifier The short identifier for this argument. It may 345 * not be {@code null} if the long identifier is 346 * {@code null}. 347 * @param longIdentifier The long identifier for this argument. It may 348 * not be {@code null} if the short identifier is 349 * {@code null}. 350 * @param isRequired Indicates whether this argument is required to 351 * be provided. 352 * @param maxOccurrences The maximum number of times this argument may be 353 * provided on the command line. A value less than 354 * or equal to zero indicates that it may be present 355 * any number of times. 356 * @param valuePlaceholder A placeholder to display in usage information to 357 * indicate that a value must be provided. It may 358 * be {@code null} to use a default placeholder that 359 * describes the expected syntax for values. 360 * @param description A human-readable description for this argument. 361 * It must not be {@code null}. 362 * 363 * @throws ArgumentException If there is a problem with the definition of 364 * this argument. 365 */ 366 public ControlArgument(final Character shortIdentifier, 367 final String longIdentifier, final boolean isRequired, 368 final int maxOccurrences, 369 final String valuePlaceholder, 370 final String description) 371 throws ArgumentException 372 { 373 this(shortIdentifier, longIdentifier, isRequired, maxOccurrences, 374 valuePlaceholder, description, (List<Control>) null); 375 } 376 377 378 379 /** 380 * Creates a new control argument with the provided information. 381 * 382 * @param shortIdentifier The short identifier for this argument. It may 383 * not be {@code null} if the long identifier is 384 * {@code null}. 385 * @param longIdentifier The long identifier for this argument. It may 386 * not be {@code null} if the short identifier is 387 * {@code null}. 388 * @param isRequired Indicates whether this argument is required to 389 * be provided. 390 * @param maxOccurrences The maximum number of times this argument may be 391 * provided on the command line. A value less than 392 * or equal to zero indicates that it may be present 393 * any number of times. 394 * @param valuePlaceholder A placeholder to display in usage information to 395 * indicate that a value must be provided. It may 396 * be {@code null} to use a default placeholder that 397 * describes the expected syntax for values. 398 * @param description A human-readable description for this argument. 399 * It must not be {@code null}. 400 * @param defaultValue The default value to use for this argument if no 401 * values were provided. It may be {@code null} if 402 * there should be no default values. 403 * 404 * @throws ArgumentException If there is a problem with the definition of 405 * this argument. 406 */ 407 public ControlArgument(final Character shortIdentifier, 408 final String longIdentifier, final boolean isRequired, 409 final int maxOccurrences, 410 final String valuePlaceholder, 411 final String description, final Control defaultValue) 412 throws ArgumentException 413 { 414 this(shortIdentifier, longIdentifier, isRequired, maxOccurrences, 415 valuePlaceholder, description, 416 ((defaultValue == null) 417 ? null : 418 Collections.singletonList(defaultValue))); 419 } 420 421 422 423 /** 424 * Creates a new control argument with the provided information. 425 * 426 * @param shortIdentifier The short identifier for this argument. It may 427 * not be {@code null} if the long identifier is 428 * {@code null}. 429 * @param longIdentifier The long identifier for this argument. It may 430 * not be {@code null} if the short identifier is 431 * {@code null}. 432 * @param isRequired Indicates whether this argument is required to 433 * be provided. 434 * @param maxOccurrences The maximum number of times this argument may be 435 * provided on the command line. A value less than 436 * or equal to zero indicates that it may be present 437 * any number of times. 438 * @param valuePlaceholder A placeholder to display in usage information to 439 * indicate that a value must be provided. It may 440 * be {@code null} to use a default placeholder that 441 * describes the expected syntax for values. 442 * @param description A human-readable description for this argument. 443 * It must not be {@code null}. 444 * @param defaultValues The set of default values to use for this 445 * argument if no values were provided. 446 * 447 * @throws ArgumentException If there is a problem with the definition of 448 * this argument. 449 */ 450 public ControlArgument(final Character shortIdentifier, 451 final String longIdentifier, final boolean isRequired, 452 final int maxOccurrences, 453 final String valuePlaceholder, 454 final String description, 455 final List<Control> defaultValues) 456 throws ArgumentException 457 { 458 super(shortIdentifier, longIdentifier, isRequired, maxOccurrences, 459 (valuePlaceholder == null) 460 ? INFO_PLACEHOLDER_CONTROL.get() 461 : valuePlaceholder, 462 description); 463 464 if ((defaultValues == null) || defaultValues.isEmpty()) 465 { 466 this.defaultValues = null; 467 } 468 else 469 { 470 this.defaultValues = Collections.unmodifiableList(defaultValues); 471 } 472 473 values = new ArrayList<>(5); 474 validators = new ArrayList<>(5); 475 } 476 477 478 479 /** 480 * Creates a new control argument that is a "clean" copy of the provided 481 * source argument. 482 * 483 * @param source The source argument to use for this argument. 484 */ 485 private ControlArgument(final ControlArgument source) 486 { 487 super(source); 488 489 defaultValues = source.defaultValues; 490 validators = new ArrayList<>(source.validators); 491 values = new ArrayList<>(5); 492 } 493 494 495 496 /** 497 * Retrieves the list of default values for this argument, which will be used 498 * if no values were provided. 499 * 500 * @return The list of default values for this argument, or {@code null} if 501 * there are no default values. 502 */ 503 public List<Control> getDefaultValues() 504 { 505 return defaultValues; 506 } 507 508 509 510 /** 511 * Updates this argument to ensure that the provided validator will be invoked 512 * for any values provided to this argument. This validator will be invoked 513 * after all other validation has been performed for this argument. 514 * 515 * @param validator The argument value validator to be invoked. It must not 516 * be {@code null}. 517 */ 518 public void addValueValidator(final ArgumentValueValidator validator) 519 { 520 validators.add(validator); 521 } 522 523 524 525 /** 526 * {@inheritDoc} 527 */ 528 @Override() 529 protected void addValue(final String valueString) 530 throws ArgumentException 531 { 532 String oid = null; 533 boolean isCritical = false; 534 ASN1OctetString value = null; 535 536 final int firstColonPos = valueString.indexOf(':'); 537 if (firstColonPos < 0) 538 { 539 oid = valueString; 540 } 541 else 542 { 543 oid = valueString.substring(0, firstColonPos); 544 545 final String criticalityStr; 546 final int secondColonPos = valueString.indexOf(':', (firstColonPos+1)); 547 if (secondColonPos < 0) 548 { 549 criticalityStr = valueString.substring(firstColonPos+1); 550 } 551 else 552 { 553 criticalityStr = valueString.substring(firstColonPos+1, secondColonPos); 554 555 final int doubleColonPos = valueString.indexOf("::"); 556 if (doubleColonPos == secondColonPos) 557 { 558 try 559 { 560 value = new ASN1OctetString( 561 Base64.decode(valueString.substring(doubleColonPos+2))); 562 } 563 catch (final Exception e) 564 { 565 Debug.debugException(e); 566 throw new ArgumentException( 567 ERR_CONTROL_ARG_INVALID_BASE64_VALUE.get(valueString, 568 getIdentifierString(), 569 valueString.substring(doubleColonPos+2)), 570 e); 571 } 572 } 573 else 574 { 575 value = new ASN1OctetString(valueString.substring(secondColonPos+1)); 576 } 577 } 578 579 final String lowerCriticalityStr = 580 StaticUtils.toLowerCase(criticalityStr); 581 if (lowerCriticalityStr.equals("true") || 582 lowerCriticalityStr.equals("t") || 583 lowerCriticalityStr.equals("yes") || 584 lowerCriticalityStr.equals("y") || 585 lowerCriticalityStr.equals("on") || 586 lowerCriticalityStr.equals("1")) 587 { 588 isCritical = true; 589 } 590 else if (lowerCriticalityStr.equals("false") || 591 lowerCriticalityStr.equals("f") || 592 lowerCriticalityStr.equals("no") || 593 lowerCriticalityStr.equals("n") || 594 lowerCriticalityStr.equals("off") || 595 lowerCriticalityStr.equals("0")) 596 { 597 isCritical = false; 598 } 599 else 600 { 601 throw new ArgumentException(ERR_CONTROL_ARG_INVALID_CRITICALITY.get( 602 valueString, getIdentifierString(), criticalityStr)); 603 } 604 } 605 606 if (! StaticUtils.isNumericOID(oid)) 607 { 608 final String providedOID = oid; 609 oid = OIDS_BY_NAME.get(StaticUtils.toLowerCase(providedOID)); 610 if (oid == null) 611 { 612 throw new ArgumentException(ERR_CONTROL_ARG_INVALID_OID.get( 613 valueString, getIdentifierString(), providedOID)); 614 } 615 } 616 617 if (values.size() >= getMaxOccurrences()) 618 { 619 throw new ArgumentException(ERR_ARG_MAX_OCCURRENCES_EXCEEDED.get( 620 getIdentifierString())); 621 } 622 623 for (final ArgumentValueValidator v : validators) 624 { 625 v.validateArgumentValue(this, valueString); 626 } 627 628 values.add(new Control(oid, isCritical, value)); 629 } 630 631 632 633 /** 634 * Retrieves the value for this argument, or the default value if none was 635 * provided. If there are multiple values, then the first will be returned. 636 * 637 * @return The value for this argument, or the default value if none was 638 * provided, or {@code null} if there is no value and no default 639 * value. 640 */ 641 public Control getValue() 642 { 643 if (values.isEmpty()) 644 { 645 if ((defaultValues == null) || defaultValues.isEmpty()) 646 { 647 return null; 648 } 649 else 650 { 651 return defaultValues.get(0); 652 } 653 } 654 else 655 { 656 return values.get(0); 657 } 658 } 659 660 661 662 /** 663 * Retrieves the set of values for this argument, or the default values if 664 * none were provided. 665 * 666 * @return The set of values for this argument, or the default values if none 667 * were provided. 668 */ 669 public List<Control> getValues() 670 { 671 if (values.isEmpty() && (defaultValues != null)) 672 { 673 return defaultValues; 674 } 675 676 return Collections.unmodifiableList(values); 677 } 678 679 680 681 /** 682 * {@inheritDoc} 683 */ 684 @Override() 685 public List<String> getValueStringRepresentations(final boolean useDefault) 686 { 687 final List<Control> controls; 688 if (values.isEmpty()) 689 { 690 if (useDefault) 691 { 692 controls = defaultValues; 693 } 694 else 695 { 696 return Collections.emptyList(); 697 } 698 } 699 else 700 { 701 controls = values; 702 } 703 704 if ((controls == null) || controls.isEmpty()) 705 { 706 return Collections.emptyList(); 707 } 708 709 final StringBuilder buffer = new StringBuilder(); 710 final ArrayList<String> valueStrings = new ArrayList<>(controls.size()); 711 for (final Control c : controls) 712 { 713 buffer.setLength(0); 714 buffer.append(c.getOID()); 715 buffer.append(':'); 716 buffer.append(c.isCritical()); 717 718 if (c.hasValue()) 719 { 720 final byte[] valueBytes = c.getValue().getValue(); 721 if (StaticUtils.isPrintableString(valueBytes)) 722 { 723 buffer.append(':'); 724 buffer.append(c.getValue().stringValue()); 725 } 726 else 727 { 728 buffer.append("::"); 729 Base64.encode(valueBytes, buffer); 730 } 731 } 732 733 valueStrings.add(buffer.toString()); 734 } 735 736 return Collections.unmodifiableList(valueStrings); 737 } 738 739 740 741 /** 742 * {@inheritDoc} 743 */ 744 @Override() 745 protected boolean hasDefaultValue() 746 { 747 return ((defaultValues != null) && (! defaultValues.isEmpty())); 748 } 749 750 751 752 /** 753 * {@inheritDoc} 754 */ 755 @Override() 756 public String getDataTypeName() 757 { 758 return INFO_CONTROL_TYPE_NAME.get(); 759 } 760 761 762 763 /** 764 * {@inheritDoc} 765 */ 766 @Override() 767 public String getValueConstraints() 768 { 769 return INFO_CONTROL_CONSTRAINTS.get(); 770 } 771 772 773 774 /** 775 * {@inheritDoc} 776 */ 777 @Override() 778 protected void reset() 779 { 780 super.reset(); 781 values.clear(); 782 } 783 784 785 786 /** 787 * {@inheritDoc} 788 */ 789 @Override() 790 public ControlArgument getCleanCopy() 791 { 792 return new ControlArgument(this); 793 } 794 795 796 797 /** 798 * {@inheritDoc} 799 */ 800 @Override() 801 protected void addToCommandLine(final List<String> argStrings) 802 { 803 if (values != null) 804 { 805 final StringBuilder buffer = new StringBuilder(); 806 for (final Control c : values) 807 { 808 argStrings.add(getIdentifierString()); 809 810 if (isSensitive()) 811 { 812 argStrings.add("***REDACTED***"); 813 continue; 814 } 815 816 buffer.setLength(0); 817 buffer.append(c.getOID()); 818 buffer.append(':'); 819 buffer.append(c.isCritical()); 820 821 if (c.hasValue()) 822 { 823 final byte[] valueBytes = c.getValue().getValue(); 824 if (StaticUtils.isPrintableString(valueBytes)) 825 { 826 buffer.append(':'); 827 buffer.append(c.getValue().stringValue()); 828 } 829 else 830 { 831 buffer.append("::"); 832 Base64.encode(valueBytes, buffer); 833 } 834 } 835 836 argStrings.add(buffer.toString()); 837 } 838 } 839 } 840 841 842 843 /** 844 * {@inheritDoc} 845 */ 846 @Override() 847 public void toString(final StringBuilder buffer) 848 { 849 buffer.append("ControlArgument("); 850 appendBasicToStringInfo(buffer); 851 852 if ((defaultValues != null) && (! defaultValues.isEmpty())) 853 { 854 if (defaultValues.size() == 1) 855 { 856 buffer.append(", defaultValue='"); 857 buffer.append(defaultValues.get(0).toString()); 858 } 859 else 860 { 861 buffer.append(", defaultValues={"); 862 863 final Iterator<Control> iterator = defaultValues.iterator(); 864 while (iterator.hasNext()) 865 { 866 buffer.append('\''); 867 buffer.append(iterator.next().toString()); 868 buffer.append('\''); 869 870 if (iterator.hasNext()) 871 { 872 buffer.append(", "); 873 } 874 } 875 876 buffer.append('}'); 877 } 878 } 879 880 buffer.append(')'); 881 } 882}