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