001 /*
002 * Copyright 2015-2016 UnboundID Corp.
003 * All Rights Reserved.
004 */
005 /*
006 * Copyright (C) 2015-2016 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 */
021 package com.unboundid.util.args;
022
023
024
025 import java.util.ArrayList;
026 import java.util.Collections;
027 import java.util.HashMap;
028 import java.util.Iterator;
029 import java.util.List;
030 import java.util.Map;
031
032 import com.unboundid.asn1.ASN1OctetString;
033 import com.unboundid.ldap.sdk.Control;
034 import com.unboundid.ldap.sdk.controls.AuthorizationIdentityRequestControl;
035 import com.unboundid.ldap.sdk.controls.DontUseCopyRequestControl;
036 import com.unboundid.ldap.sdk.controls.ManageDsaITRequestControl;
037 import com.unboundid.ldap.sdk.controls.PermissiveModifyRequestControl;
038 import com.unboundid.ldap.sdk.controls.SubentriesRequestControl;
039 import com.unboundid.ldap.sdk.controls.SubtreeDeleteRequestControl;
040 import com.unboundid.ldap.sdk.experimental.
041 DraftBeheraLDAPPasswordPolicy10RequestControl;
042 import com.unboundid.ldap.sdk.experimental.
043 DraftZeilengaLDAPNoOp12RequestControl;
044 import com.unboundid.util.Base64;
045 import com.unboundid.util.Debug;
046 import com.unboundid.util.Mutable;
047 import com.unboundid.util.StaticUtils;
048 import com.unboundid.util.ThreadSafety;
049 import com.unboundid.util.ThreadSafetyLevel;
050
051 import 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)
087 public 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 }