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