001 /*
002 * Copyright 2008-2015 UnboundID Corp.
003 * All Rights Reserved.
004 */
005 /*
006 * Copyright (C) 2008-2015 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 * have a default value.
073 *
074 * @param shortIdentifier The short identifier for this argument. It may
075 * not be {@code null} if the long identifier is
076 * {@code null}.
077 * @param longIdentifier The long identifier for this argument. It may
078 * not be {@code null} if the short identifier is
079 * {@code null}.
080 * @param isRequired Indicates whether this argument is required to
081 * be provided.
082 * @param maxOccurrences The maximum number of times this argument may be
083 * provided on the command line. A value less than
084 * or equal to zero indicates that it may be present
085 * any number of times.
086 * @param valuePlaceholder A placeholder to display in usage information to
087 * indicate that a value must be provided. It must
088 * not be {@code null}.
089 * @param description A human-readable description for this argument.
090 * It must not be {@code null}.
091 *
092 * @throws ArgumentException If there is a problem with the definition of
093 * this argument.
094 */
095 public FilterArgument(final Character shortIdentifier,
096 final String longIdentifier, final boolean isRequired,
097 final int maxOccurrences, final String valuePlaceholder,
098 final String description)
099 throws ArgumentException
100 {
101 this(shortIdentifier, longIdentifier, isRequired, maxOccurrences,
102 valuePlaceholder, description, (List<Filter>) null);
103 }
104
105
106
107 /**
108 * Creates a new filter argument with the provided information.
109 *
110 * @param shortIdentifier The short identifier for this argument. It may
111 * not be {@code null} if the long identifier is
112 * {@code null}.
113 * @param longIdentifier The long identifier for this argument. It may
114 * not be {@code null} if the short identifier is
115 * {@code null}.
116 * @param isRequired Indicates whether this argument is required to
117 * be provided.
118 * @param maxOccurrences The maximum number of times this argument may be
119 * provided on the command line. A value less than
120 * or equal to zero indicates that it may be present
121 * any number of times.
122 * @param valuePlaceholder A placeholder to display in usage information to
123 * indicate that a value must be provided. It must
124 * not be {@code null}.
125 * @param description A human-readable description for this argument.
126 * It must not be {@code null}.
127 * @param defaultValue The default value to use for this argument if no
128 * values were provided. It may be {@code null} if
129 * there should be no default values.
130 *
131 * @throws ArgumentException If there is a problem with the definition of
132 * this argument.
133 */
134 public FilterArgument(final Character shortIdentifier,
135 final String longIdentifier, final boolean isRequired,
136 final int maxOccurrences, final String valuePlaceholder,
137 final String description,
138 final Filter defaultValue)
139 throws ArgumentException
140 {
141 this(shortIdentifier, longIdentifier, isRequired, maxOccurrences,
142 valuePlaceholder, description,
143 ((defaultValue == null) ? null : Arrays.asList(defaultValue)));
144 }
145
146
147
148 /**
149 * Creates a new filter argument with the provided information.
150 *
151 * @param shortIdentifier The short identifier for this argument. It may
152 * not be {@code null} if the long identifier is
153 * {@code null}.
154 * @param longIdentifier The long identifier for this argument. It may
155 * not be {@code null} if the short identifier is
156 * {@code null}.
157 * @param isRequired Indicates whether this argument is required to
158 * be provided.
159 * @param maxOccurrences The maximum number of times this argument may be
160 * provided on the command line. A value less than
161 * or equal to zero indicates that it may be present
162 * any number of times.
163 * @param valuePlaceholder A placeholder to display in usage information to
164 * indicate that a value must be provided. It must
165 * not be {@code null}.
166 * @param description A human-readable description for this argument.
167 * It must not be {@code null}.
168 * @param defaultValues The set of default values to use for this
169 * argument if no values were provided.
170 *
171 * @throws ArgumentException If there is a problem with the definition of
172 * this argument.
173 */
174 public FilterArgument(final Character shortIdentifier,
175 final String longIdentifier, final boolean isRequired,
176 final int maxOccurrences, final String valuePlaceholder,
177 final String description,
178 final List<Filter> defaultValues)
179 throws ArgumentException
180 {
181 super(shortIdentifier, longIdentifier, isRequired, maxOccurrences,
182 valuePlaceholder, description);
183
184 if (valuePlaceholder == null)
185 {
186 throw new ArgumentException(ERR_ARG_MUST_TAKE_VALUE.get(
187 getIdentifierString()));
188 }
189
190 if ((defaultValues == null) || defaultValues.isEmpty())
191 {
192 this.defaultValues = null;
193 }
194 else
195 {
196 this.defaultValues = Collections.unmodifiableList(defaultValues);
197 }
198
199 values = new ArrayList<Filter>(5);
200 validators = new ArrayList<ArgumentValueValidator>(5);
201 }
202
203
204
205 /**
206 * Creates a new filter argument that is a "clean" copy of the provided source
207 * argument.
208 *
209 * @param source The source argument to use for this argument.
210 */
211 private FilterArgument(final FilterArgument source)
212 {
213 super(source);
214
215 defaultValues = source.defaultValues;
216 validators = new ArrayList<ArgumentValueValidator>(source.validators);
217 values = new ArrayList<Filter>(5);
218 }
219
220
221
222 /**
223 * Retrieves the list of default values for this argument, which will be used
224 * if no values were provided.
225 *
226 * @return The list of default values for this argument, or {@code null} if
227 * there are no default values.
228 */
229 public List<Filter> getDefaultValues()
230 {
231 return defaultValues;
232 }
233
234
235
236 /**
237 * Updates this argument to ensure that the provided validator will be invoked
238 * for any values provided to this argument. This validator will be invoked
239 * after all other validation has been performed for this argument.
240 *
241 * @param validator The argument value validator to be invoked. It must not
242 * be {@code null}.
243 */
244 public void addValueValidator(final ArgumentValueValidator validator)
245 {
246 validators.add(validator);
247 }
248
249
250
251 /**
252 * {@inheritDoc}
253 */
254 @Override()
255 protected void addValue(final String valueString)
256 throws ArgumentException
257 {
258 final Filter filter;
259 try
260 {
261 filter = Filter.create(valueString);
262 }
263 catch (LDAPException le)
264 {
265 debugException(le);
266 throw new ArgumentException(ERR_FILTER_VALUE_NOT_FILTER.get(valueString,
267 getIdentifierString(), le.getMessage()),
268 le);
269 }
270
271 if (values.size() >= getMaxOccurrences())
272 {
273 throw new ArgumentException(ERR_ARG_MAX_OCCURRENCES_EXCEEDED.get(
274 getIdentifierString()));
275 }
276
277 for (final ArgumentValueValidator v : validators)
278 {
279 v.validateArgumentValue(this, valueString);
280 }
281
282 values.add(filter);
283 }
284
285
286
287 /**
288 * Retrieves the value for this argument, or the default value if none was
289 * provided. If there are multiple values, then the first will be returned.
290 *
291 * @return The value for this argument, or the default value if none was
292 * provided, or {@code null} if there is no value and no default
293 * value.
294 */
295 public Filter getValue()
296 {
297 if (values.isEmpty())
298 {
299 if ((defaultValues == null) || defaultValues.isEmpty())
300 {
301 return null;
302 }
303 else
304 {
305 return defaultValues.get(0);
306 }
307 }
308 else
309 {
310 return values.get(0);
311 }
312 }
313
314
315
316 /**
317 * Retrieves the set of values for this argument, or the default values if
318 * none were provided.
319 *
320 * @return The set of values for this argument, or the default values if none
321 * were provided.
322 */
323 public List<Filter> getValues()
324 {
325 if (values.isEmpty() && (defaultValues != null))
326 {
327 return defaultValues;
328 }
329
330 return Collections.unmodifiableList(values);
331 }
332
333
334
335 /**
336 * {@inheritDoc}
337 */
338 @Override()
339 protected boolean hasDefaultValue()
340 {
341 return ((defaultValues != null) && (! defaultValues.isEmpty()));
342 }
343
344
345
346 /**
347 * {@inheritDoc}
348 */
349 @Override()
350 public String getDataTypeName()
351 {
352 return INFO_FILTER_TYPE_NAME.get();
353 }
354
355
356
357 /**
358 * {@inheritDoc}
359 */
360 @Override()
361 public String getValueConstraints()
362 {
363 return INFO_FILTER_CONSTRAINTS.get();
364 }
365
366
367
368 /**
369 * {@inheritDoc}
370 */
371 @Override()
372 public FilterArgument getCleanCopy()
373 {
374 return new FilterArgument(this);
375 }
376
377
378
379 /**
380 * {@inheritDoc}
381 */
382 @Override()
383 public void toString(final StringBuilder buffer)
384 {
385 buffer.append("FilterArgument(");
386 appendBasicToStringInfo(buffer);
387
388 if ((defaultValues != null) && (! defaultValues.isEmpty()))
389 {
390 if (defaultValues.size() == 1)
391 {
392 buffer.append(", defaultValue='");
393 buffer.append(defaultValues.get(0).toString());
394 }
395 else
396 {
397 buffer.append(", defaultValues={");
398
399 final Iterator<Filter> iterator = defaultValues.iterator();
400 while (iterator.hasNext())
401 {
402 buffer.append('\'');
403 buffer.append(iterator.next().toString());
404 buffer.append('\'');
405
406 if (iterator.hasNext())
407 {
408 buffer.append(", ");
409 }
410 }
411
412 buffer.append('}');
413 }
414 }
415
416 buffer.append(')');
417 }
418 }