001 /*
002 * Copyright 2008-2016 UnboundID Corp.
003 * All Rights Reserved.
004 */
005 /*
006 * Copyright (C) 2008-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.Arrays;
027 import java.util.Collections;
028 import java.util.Iterator;
029 import java.util.List;
030
031 import com.unboundid.ldap.sdk.Filter;
032 import com.unboundid.ldap.sdk.LDAPException;
033 import com.unboundid.util.Mutable;
034 import com.unboundid.util.ThreadSafety;
035 import com.unboundid.util.ThreadSafetyLevel;
036
037 import static com.unboundid.util.Debug.*;
038 import static com.unboundid.util.args.ArgsMessages.*;
039
040
041
042 /**
043 * This class defines an argument that is intended to hold one or more
044 * search filter values. Filter arguments must take values, and those values
045 * must be able to be parsed as LDAP search filters.
046 */
047 @Mutable()
048 @ThreadSafety(level=ThreadSafetyLevel.NOT_THREADSAFE)
049 public final class FilterArgument
050 extends Argument
051 {
052 /**
053 * The serial version UID for this serializable class.
054 */
055 private static final long serialVersionUID = -1889200072476038957L;
056
057
058
059 // The set of values assigned to this argument.
060 private final ArrayList<Filter> values;
061
062 // The argument value validators that have been registered for this argument.
063 private final List<ArgumentValueValidator> validators;
064
065 // The list of default values for this argument.
066 private final List<Filter> defaultValues;
067
068
069
070 /**
071 * Creates a new filter argument with the provided information. It will not
072 * be required, will permit at most one occurrence, will use a default
073 * placeholder, and will not have a default value.
074 *
075 * @param shortIdentifier The short identifier for this argument. It may
076 * not be {@code null} if the long identifier is
077 * {@code null}.
078 * @param longIdentifier The long identifier for this argument. It may
079 * not be {@code null} if the short identifier is
080 * {@code null}.
081 * @param description A human-readable description for this argument.
082 * It must not be {@code null}.
083 *
084 * @throws ArgumentException If there is a problem with the definition of
085 * this argument.
086 */
087 public FilterArgument(final Character shortIdentifier,
088 final String longIdentifier, final String description)
089 throws ArgumentException
090 {
091 this(shortIdentifier, longIdentifier, false, 1, null, description);
092 }
093
094
095
096 /**
097 * Creates a new filter argument with the provided information. It will not
098 * have a default value.
099 *
100 * @param shortIdentifier The short identifier for this argument. It may
101 * not be {@code null} if the long identifier is
102 * {@code null}.
103 * @param longIdentifier The long identifier for this argument. It may
104 * not be {@code null} if the short identifier is
105 * {@code null}.
106 * @param isRequired Indicates whether this argument is required to
107 * be provided.
108 * @param maxOccurrences The maximum number of times this argument may be
109 * provided on the command line. A value less than
110 * or equal to zero indicates that it may be present
111 * any number of times.
112 * @param valuePlaceholder A placeholder to display in usage information to
113 * indicate that a value must be provided. It may
114 * be {@code null} if a default placeholder should
115 * be used.
116 * @param description A human-readable description for this argument.
117 * It must not be {@code null}.
118 *
119 * @throws ArgumentException If there is a problem with the definition of
120 * this argument.
121 */
122 public FilterArgument(final Character shortIdentifier,
123 final String longIdentifier, final boolean isRequired,
124 final int maxOccurrences, final String valuePlaceholder,
125 final String description)
126 throws ArgumentException
127 {
128 this(shortIdentifier, longIdentifier, isRequired, maxOccurrences,
129 valuePlaceholder, description, (List<Filter>) null);
130 }
131
132
133
134 /**
135 * Creates a new filter argument with the provided information.
136 *
137 * @param shortIdentifier The short identifier for this argument. It may
138 * not be {@code null} if the long identifier is
139 * {@code null}.
140 * @param longIdentifier The long identifier for this argument. It may
141 * not be {@code null} if the short identifier is
142 * {@code null}.
143 * @param isRequired Indicates whether this argument is required to
144 * be provided.
145 * @param maxOccurrences The maximum number of times this argument may be
146 * provided on the command line. A value less than
147 * or equal to zero indicates that it may be present
148 * any number of times.
149 * @param valuePlaceholder A placeholder to display in usage information to
150 * indicate that a value must be provided. It may
151 * be {@code null} if a default placeholder should
152 * be used.
153 * @param description A human-readable description for this argument.
154 * It must not be {@code null}.
155 * @param defaultValue The default value to use for this argument if no
156 * values were provided. It may be {@code null} if
157 * there should be no default values.
158 *
159 * @throws ArgumentException If there is a problem with the definition of
160 * this argument.
161 */
162 public FilterArgument(final Character shortIdentifier,
163 final String longIdentifier, final boolean isRequired,
164 final int maxOccurrences, final String valuePlaceholder,
165 final String description,
166 final Filter defaultValue)
167 throws ArgumentException
168 {
169 this(shortIdentifier, longIdentifier, isRequired, maxOccurrences,
170 valuePlaceholder, description,
171 ((defaultValue == null) ? null : Arrays.asList(defaultValue)));
172 }
173
174
175
176 /**
177 * Creates a new filter argument with the provided information.
178 *
179 * @param shortIdentifier The short identifier for this argument. It may
180 * not be {@code null} if the long identifier is
181 * {@code null}.
182 * @param longIdentifier The long identifier for this argument. It may
183 * not be {@code null} if the short identifier is
184 * {@code null}.
185 * @param isRequired Indicates whether this argument is required to
186 * be provided.
187 * @param maxOccurrences The maximum number of times this argument may be
188 * provided on the command line. A value less than
189 * or equal to zero indicates that it may be present
190 * any number of times.
191 * @param valuePlaceholder A placeholder to display in usage information to
192 * indicate that a value must be provided. It may
193 * be {@code null} if a default placeholder should
194 * be used.
195 * @param description A human-readable description for this argument.
196 * It must not be {@code null}.
197 * @param defaultValues The set of default values to use for this
198 * argument if no values were provided.
199 *
200 * @throws ArgumentException If there is a problem with the definition of
201 * this argument.
202 */
203 public FilterArgument(final Character shortIdentifier,
204 final String longIdentifier, final boolean isRequired,
205 final int maxOccurrences, final String valuePlaceholder,
206 final String description,
207 final List<Filter> defaultValues)
208 throws ArgumentException
209 {
210 super(shortIdentifier, longIdentifier, isRequired, maxOccurrences,
211 (valuePlaceholder == null)
212 ? INFO_PLACEHOLDER_FILTER.get()
213 : valuePlaceholder,
214 description);
215
216 if ((defaultValues == null) || defaultValues.isEmpty())
217 {
218 this.defaultValues = null;
219 }
220 else
221 {
222 this.defaultValues = Collections.unmodifiableList(defaultValues);
223 }
224
225 values = new ArrayList<Filter>(5);
226 validators = new ArrayList<ArgumentValueValidator>(5);
227 }
228
229
230
231 /**
232 * Creates a new filter argument that is a "clean" copy of the provided source
233 * argument.
234 *
235 * @param source The source argument to use for this argument.
236 */
237 private FilterArgument(final FilterArgument source)
238 {
239 super(source);
240
241 defaultValues = source.defaultValues;
242 validators = new ArrayList<ArgumentValueValidator>(source.validators);
243 values = new ArrayList<Filter>(5);
244 }
245
246
247
248 /**
249 * Retrieves the list of default values for this argument, which will be used
250 * if no values were provided.
251 *
252 * @return The list of default values for this argument, or {@code null} if
253 * there are no default values.
254 */
255 public List<Filter> getDefaultValues()
256 {
257 return defaultValues;
258 }
259
260
261
262 /**
263 * Updates this argument to ensure that the provided validator will be invoked
264 * for any values provided to this argument. This validator will be invoked
265 * after all other validation has been performed for this argument.
266 *
267 * @param validator The argument value validator to be invoked. It must not
268 * be {@code null}.
269 */
270 public void addValueValidator(final ArgumentValueValidator validator)
271 {
272 validators.add(validator);
273 }
274
275
276
277 /**
278 * {@inheritDoc}
279 */
280 @Override()
281 protected void addValue(final String valueString)
282 throws ArgumentException
283 {
284 final Filter filter;
285 try
286 {
287 filter = Filter.create(valueString);
288 }
289 catch (LDAPException le)
290 {
291 debugException(le);
292 throw new ArgumentException(ERR_FILTER_VALUE_NOT_FILTER.get(valueString,
293 getIdentifierString(), le.getMessage()),
294 le);
295 }
296
297 if (values.size() >= getMaxOccurrences())
298 {
299 throw new ArgumentException(ERR_ARG_MAX_OCCURRENCES_EXCEEDED.get(
300 getIdentifierString()));
301 }
302
303 for (final ArgumentValueValidator v : validators)
304 {
305 v.validateArgumentValue(this, valueString);
306 }
307
308 values.add(filter);
309 }
310
311
312
313 /**
314 * Retrieves the value for this argument, or the default value if none was
315 * provided. If there are multiple values, then the first will be returned.
316 *
317 * @return The value for this argument, or the default value if none was
318 * provided, or {@code null} if there is no value and no default
319 * value.
320 */
321 public Filter getValue()
322 {
323 if (values.isEmpty())
324 {
325 if ((defaultValues == null) || defaultValues.isEmpty())
326 {
327 return null;
328 }
329 else
330 {
331 return defaultValues.get(0);
332 }
333 }
334 else
335 {
336 return values.get(0);
337 }
338 }
339
340
341
342 /**
343 * Retrieves the set of values for this argument, or the default values if
344 * none were provided.
345 *
346 * @return The set of values for this argument, or the default values if none
347 * were provided.
348 */
349 public List<Filter> getValues()
350 {
351 if (values.isEmpty() && (defaultValues != null))
352 {
353 return defaultValues;
354 }
355
356 return Collections.unmodifiableList(values);
357 }
358
359
360
361 /**
362 * {@inheritDoc}
363 */
364 @Override()
365 public List<String> getValueStringRepresentations(final boolean useDefault)
366 {
367 final List<Filter> filters;
368 if (values.isEmpty())
369 {
370 if (useDefault)
371 {
372 filters = defaultValues;
373 }
374 else
375 {
376 return Collections.emptyList();
377 }
378 }
379 else
380 {
381 filters = values;
382 }
383
384 if ((filters == null) || filters.isEmpty())
385 {
386 return Collections.emptyList();
387 }
388
389 final ArrayList<String> valueStrings =
390 new ArrayList<String>(filters.size());
391 for (final Filter f : filters)
392 {
393 valueStrings.add(f.toString());
394 }
395 return Collections.unmodifiableList(valueStrings);
396 }
397
398
399
400 /**
401 * {@inheritDoc}
402 */
403 @Override()
404 protected boolean hasDefaultValue()
405 {
406 return ((defaultValues != null) && (! defaultValues.isEmpty()));
407 }
408
409
410
411 /**
412 * {@inheritDoc}
413 */
414 @Override()
415 public String getDataTypeName()
416 {
417 return INFO_FILTER_TYPE_NAME.get();
418 }
419
420
421
422 /**
423 * {@inheritDoc}
424 */
425 @Override()
426 public String getValueConstraints()
427 {
428 return INFO_FILTER_CONSTRAINTS.get();
429 }
430
431
432
433 /**
434 * {@inheritDoc}
435 */
436 @Override()
437 protected void reset()
438 {
439 super.reset();
440 values.clear();
441 }
442
443
444
445 /**
446 * {@inheritDoc}
447 */
448 @Override()
449 public FilterArgument getCleanCopy()
450 {
451 return new FilterArgument(this);
452 }
453
454
455
456 /**
457 * {@inheritDoc}
458 */
459 @Override()
460 protected void addToCommandLine(final List<String> argStrings)
461 {
462 if (values != null)
463 {
464 for (final Filter f : values)
465 {
466 argStrings.add(getIdentifierString());
467 if (isSensitive())
468 {
469 argStrings.add("***REDACTED***");
470 }
471 else
472 {
473 argStrings.add(f.toString());
474 }
475 }
476 }
477 }
478
479
480
481 /**
482 * {@inheritDoc}
483 */
484 @Override()
485 public void toString(final StringBuilder buffer)
486 {
487 buffer.append("FilterArgument(");
488 appendBasicToStringInfo(buffer);
489
490 if ((defaultValues != null) && (! defaultValues.isEmpty()))
491 {
492 if (defaultValues.size() == 1)
493 {
494 buffer.append(", defaultValue='");
495 buffer.append(defaultValues.get(0).toString());
496 }
497 else
498 {
499 buffer.append(", defaultValues={");
500
501 final Iterator<Filter> iterator = defaultValues.iterator();
502 while (iterator.hasNext())
503 {
504 buffer.append('\'');
505 buffer.append(iterator.next().toString());
506 buffer.append('\'');
507
508 if (iterator.hasNext())
509 {
510 buffer.append(", ");
511 }
512 }
513
514 buffer.append('}');
515 }
516 }
517
518 buffer.append(')');
519 }
520 }