001/*
002 * Copyright 2008-2014 UnboundID Corp.
003 * All Rights Reserved.
004 */
005/*
006 * Copyright (C) 2008-2014 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 */
021package com.unboundid.util.args;
022
023
024
025import java.util.ArrayList;
026import java.util.Arrays;
027import java.util.Collections;
028import java.util.Iterator;
029import java.util.List;
030
031import com.unboundid.ldap.sdk.Filter;
032import com.unboundid.ldap.sdk.LDAPException;
033import com.unboundid.util.Mutable;
034import com.unboundid.util.ThreadSafety;
035import com.unboundid.util.ThreadSafetyLevel;
036
037import static com.unboundid.util.Debug.*;
038import 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)
049public 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 list of default values for this argument.
063  private final List<Filter> defaultValues;
064
065
066
067  /**
068   * Creates a new filter argument with the provided information.  It will not
069   * have a default value.
070   *
071   * @param  shortIdentifier   The short identifier for this argument.  It may
072   *                           not be {@code null} if the long identifier is
073   *                           {@code null}.
074   * @param  longIdentifier    The long identifier for this argument.  It may
075   *                           not be {@code null} if the short identifier is
076   *                           {@code null}.
077   * @param  isRequired        Indicates whether this argument is required to
078   *                           be provided.
079   * @param  maxOccurrences    The maximum number of times this argument may be
080   *                           provided on the command line.  A value less than
081   *                           or equal to zero indicates that it may be present
082   *                           any number of times.
083   * @param  valuePlaceholder  A placeholder to display in usage information to
084   *                           indicate that a value must be provided.  It must
085   *                           not be {@code null}.
086   * @param  description       A human-readable description for this argument.
087   *                           It must not be {@code null}.
088   *
089   * @throws  ArgumentException  If there is a problem with the definition of
090   *                             this argument.
091   */
092  public FilterArgument(final Character shortIdentifier,
093                        final String longIdentifier, final boolean isRequired,
094                        final int maxOccurrences, final String valuePlaceholder,
095                        final String description)
096         throws ArgumentException
097  {
098    this(shortIdentifier, longIdentifier, isRequired,  maxOccurrences,
099         valuePlaceholder, description, (List<Filter>) null);
100  }
101
102
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>();
200  }
201
202
203
204  /**
205   * Creates a new filter argument that is a "clean" copy of the provided source
206   * argument.
207   *
208   * @param  source  The source argument to use for this argument.
209   */
210  private FilterArgument(final FilterArgument source)
211  {
212    super(source);
213
214    defaultValues = source.defaultValues;
215    values        = new ArrayList<Filter>();
216  }
217
218
219
220  /**
221   * Retrieves the list of default values for this argument, which will be used
222   * if no values were provided.
223   *
224   * @return   The list of default values for this argument, or {@code null} if
225   *           there are no default values.
226   */
227  public List<Filter> getDefaultValues()
228  {
229    return defaultValues;
230  }
231
232
233
234  /**
235   * {@inheritDoc}
236   */
237  @Override()
238  protected void addValue(final String valueString)
239            throws ArgumentException
240  {
241    final Filter filter;
242    try
243    {
244      filter = Filter.create(valueString);
245    }
246    catch (LDAPException le)
247    {
248      debugException(le);
249      throw new ArgumentException(ERR_FILTER_VALUE_NOT_FILTER.get(valueString,
250                                       getIdentifierString(), le.getMessage()),
251                                  le);
252    }
253
254    if (values.size() >= getMaxOccurrences())
255    {
256      throw new ArgumentException(ERR_ARG_MAX_OCCURRENCES_EXCEEDED.get(
257                                       getIdentifierString()));
258    }
259
260    values.add(filter);
261  }
262
263
264
265  /**
266   * Retrieves the value for this argument, or the default value if none was
267   * provided.  If there are multiple values, then the first will be returned.
268   *
269   * @return  The value for this argument, or the default value if none was
270   *          provided, or {@code null} if there is no value and no default
271   *          value.
272   */
273  public Filter getValue()
274  {
275    if (values.isEmpty())
276    {
277      if ((defaultValues == null) || defaultValues.isEmpty())
278      {
279        return null;
280      }
281      else
282      {
283        return defaultValues.get(0);
284      }
285    }
286    else
287    {
288      return values.get(0);
289    }
290  }
291
292
293
294  /**
295   * Retrieves the set of values for this argument, or the default values if
296   * none were provided.
297   *
298   * @return  The set of values for this argument, or the default values if none
299   *          were provided.
300   */
301  public List<Filter> getValues()
302  {
303    if (values.isEmpty() && (defaultValues != null))
304    {
305      return defaultValues;
306    }
307
308    return Collections.unmodifiableList(values);
309  }
310
311
312
313  /**
314   * {@inheritDoc}
315   */
316  @Override()
317  protected boolean hasDefaultValue()
318  {
319    return ((defaultValues != null) && (! defaultValues.isEmpty()));
320  }
321
322
323
324  /**
325   * {@inheritDoc}
326   */
327  @Override()
328  public String getDataTypeName()
329  {
330    return INFO_FILTER_TYPE_NAME.get();
331  }
332
333
334
335  /**
336   * {@inheritDoc}
337   */
338  @Override()
339  public String getValueConstraints()
340  {
341    return INFO_FILTER_CONSTRAINTS.get();
342  }
343
344
345
346  /**
347   * {@inheritDoc}
348   */
349  @Override()
350  public FilterArgument getCleanCopy()
351  {
352    return new FilterArgument(this);
353  }
354
355
356
357  /**
358   * {@inheritDoc}
359   */
360  @Override()
361  public void toString(final StringBuilder buffer)
362  {
363    buffer.append("FilterArgument(");
364    appendBasicToStringInfo(buffer);
365
366    if ((defaultValues != null) && (! defaultValues.isEmpty()))
367    {
368      if (defaultValues.size() == 1)
369      {
370        buffer.append(", defaultValue='");
371        buffer.append(defaultValues.get(0).toString());
372      }
373      else
374      {
375        buffer.append(", defaultValues={");
376
377        final Iterator<Filter> iterator = defaultValues.iterator();
378        while (iterator.hasNext())
379        {
380          buffer.append('\'');
381          buffer.append(iterator.next().toString());
382          buffer.append('\'');
383
384          if (iterator.hasNext())
385          {
386            buffer.append(", ");
387          }
388        }
389
390        buffer.append('}');
391      }
392    }
393
394    buffer.append(')');
395  }
396}