001    /*
002     * Copyright 2008-2013 UnboundID Corp.
003     * All Rights Reserved.
004     */
005    /*
006     * Copyright (C) 2008-2013 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 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    }