001/*
002 * Copyright 2010-2014 UnboundID Corp.
003 * All Rights Reserved.
004 */
005/*
006 * Copyright (C) 2010-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.Collections;
026import java.util.HashMap;
027import java.util.Map;
028import java.util.concurrent.atomic.AtomicReference;
029
030import com.unboundid.ldap.sdk.SearchScope;
031import com.unboundid.util.Mutable;
032import com.unboundid.util.StaticUtils;
033import com.unboundid.util.ThreadSafety;
034import com.unboundid.util.ThreadSafetyLevel;
035
036import static com.unboundid.util.args.ArgsMessages.*;
037
038
039
040/**
041 * This class defines an argument that is intended to hold one search scope
042 * values.  Scope arguments must take values, and those arguments must represent
043 * valid search scopes.  Supported scope values include:
044 * <UL>
045 *   <LI>baseObject scope -- base, baseObject, base-object, 0</LI>
046 *   <LI>singleLevel scope -- one, singleLevel, single-level, oneLevel,
047 *       one-level, 1</LI>
048 *   <LI>wholeSubtree scope -- sub, subtree, wholeSubtree, whole-subtree, 2</LI>
049 *   <LI>subordinateSubtree scope -- subord, subordinate, subordinateSubtree,
050 *       subordinate-subtree, 3</LI>
051 * </UL>
052 */
053@Mutable()
054@ThreadSafety(level=ThreadSafetyLevel.NOT_THREADSAFE)
055public final class ScopeArgument
056       extends Argument
057{
058  /**
059   * A map of value strings to the corresponding search scopes.
060   */
061  private static final Map<String,SearchScope> SCOPE_STRINGS;
062
063  static
064  {
065    final HashMap<String,SearchScope> scopeMap =
066         new HashMap<String,SearchScope>(20);
067
068    scopeMap.put("base", SearchScope.BASE);
069    scopeMap.put("baseobject", SearchScope.BASE);
070    scopeMap.put("base-object", SearchScope.BASE);
071    scopeMap.put("0", SearchScope.BASE);
072
073    scopeMap.put("one", SearchScope.ONE);
074    scopeMap.put("singlelevel", SearchScope.ONE);
075    scopeMap.put("single-level", SearchScope.ONE);
076    scopeMap.put("onelevel", SearchScope.ONE);
077    scopeMap.put("one-level", SearchScope.ONE);
078    scopeMap.put("1", SearchScope.ONE);
079
080    scopeMap.put("sub", SearchScope.SUB);
081    scopeMap.put("subtree", SearchScope.SUB);
082    scopeMap.put("wholesubtree", SearchScope.SUB);
083    scopeMap.put("whole-subtree", SearchScope.SUB);
084    scopeMap.put("2", SearchScope.SUB);
085
086    scopeMap.put("subord", SearchScope.SUBORDINATE_SUBTREE);
087    scopeMap.put("subordinate", SearchScope.SUBORDINATE_SUBTREE);
088    scopeMap.put("subordinatesubtree", SearchScope.SUBORDINATE_SUBTREE);
089    scopeMap.put("subordinate-subtree", SearchScope.SUBORDINATE_SUBTREE);
090    scopeMap.put("3", SearchScope.SUBORDINATE_SUBTREE);
091
092    SCOPE_STRINGS = Collections.unmodifiableMap(scopeMap);
093  }
094
095
096
097  /**
098   * The serial version UID for this serializable class.
099   */
100  private static final long serialVersionUID = 5962857448814911423L;
101
102
103
104  // The value assigned to this argument.
105  private final AtomicReference<SearchScope> value;
106
107  // The default value for this argument.
108  private final SearchScope defaultValue;
109
110
111
112  /**
113   * Creates a new search scope argument with the provided information.  It will
114   * not have a default value.
115   *
116   * @param  shortIdentifier   The short identifier for this argument.  It may
117   *                           not be {@code null} if the long identifier is
118   *                           {@code null}.
119   * @param  longIdentifier    The long identifier for this argument.  It may
120   *                           not be {@code null} if the short identifier is
121   *                           {@code null}.
122   * @param  isRequired        Indicates whether this argument is required to
123   *                           be provided.
124   * @param  valuePlaceholder  A placeholder to display in usage information to
125   *                           indicate that a value must be provided.  It must
126   *                           not be {@code null}.
127   * @param  description       A human-readable description for this argument.
128   *                           It must not be {@code null}.
129   *
130   * @throws  ArgumentException  If there is a problem with the definition of
131   *                             this argument.
132   */
133  public ScopeArgument(final Character shortIdentifier,
134                       final String longIdentifier, final boolean isRequired,
135                       final String valuePlaceholder, final String description)
136         throws ArgumentException
137  {
138    this(shortIdentifier, longIdentifier, isRequired,  valuePlaceholder,
139         description, null);
140  }
141
142
143
144
145
146
147  /**
148   * Creates a new search scope argument with the provided information.
149   *
150   * @param  shortIdentifier   The short identifier for this argument.  It may
151   *                           not be {@code null} if the long identifier is
152   *                           {@code null}.
153   * @param  longIdentifier    The long identifier for this argument.  It may
154   *                           not be {@code null} if the short identifier is
155   *                           {@code null}.
156   * @param  isRequired        Indicates whether this argument is required to
157   *                           be provided.
158   * @param  valuePlaceholder  A placeholder to display in usage information to
159   *                           indicate that a value must be provided.  It must
160   *                           not be {@code null}.
161   * @param  description       A human-readable description for this argument.
162   *                           It must not be {@code null}.
163   * @param  defaultValue      The default value to use for this argument if no
164   *                           values were provided.  It may be {@code null} if
165   *                           there should be no default values.
166   *
167   * @throws  ArgumentException  If there is a problem with the definition of
168   *                             this argument.
169   */
170  public ScopeArgument(final Character shortIdentifier,
171                       final String longIdentifier, final boolean isRequired,
172                       final String valuePlaceholder, final String description,
173                       final SearchScope defaultValue)
174         throws ArgumentException
175  {
176    super(shortIdentifier, longIdentifier, isRequired,  1, valuePlaceholder,
177         description);
178
179    if (valuePlaceholder == null)
180    {
181      throw new ArgumentException(ERR_ARG_MUST_TAKE_VALUE.get(
182                                       getIdentifierString()));
183    }
184
185    this.defaultValue = defaultValue;
186
187    value = new AtomicReference<SearchScope>();
188  }
189
190
191
192  /**
193   * Creates a new scope argument that is a "clean" copy of the provided
194   * source argument.
195   *
196   * @param  source  The source argument to use for this argument.
197   */
198  private ScopeArgument(final ScopeArgument source)
199  {
200    super(source);
201
202    defaultValue = source.defaultValue;
203    value        = new AtomicReference<SearchScope>();
204  }
205
206
207
208  /**
209   * Retrieves the default value for this argument, which will be used if no
210   * value was provided.
211   *
212   * @return  The default value for this argument, or {@code null} if there is
213   *          no default value.
214   */
215  public SearchScope getDefaultValue()
216  {
217    return defaultValue;
218  }
219
220
221
222  /**
223   * {@inheritDoc}
224   */
225  @Override()
226  protected void addValue(final String valueString)
227            throws ArgumentException
228  {
229    final SearchScope scope =
230         SCOPE_STRINGS.get(StaticUtils.toLowerCase(valueString));
231    if (scope == null)
232    {
233      throw new ArgumentException(ERR_SCOPE_VALUE_NOT_VALID.get(valueString,
234           getIdentifierString()));
235    }
236
237    if (! value.compareAndSet(null, scope))
238    {
239      throw new ArgumentException(ERR_ARG_MAX_OCCURRENCES_EXCEEDED.get(
240                                       getIdentifierString()));
241    }
242  }
243
244
245
246  /**
247   * Retrieves the value for this argument, or the default value if none was
248   * provided.
249   *
250   * @return  The value for this argument, or the default value if none was
251   *          provided, or {@code null} if there is no value and no default
252   *          value.
253   */
254  public SearchScope getValue()
255  {
256    final SearchScope s = value.get();
257    if (s == null)
258    {
259      return defaultValue;
260    }
261    else
262    {
263      return s;
264    }
265  }
266
267
268
269  /**
270   * {@inheritDoc}
271   */
272  @Override()
273  protected boolean hasDefaultValue()
274  {
275    return (defaultValue != null);
276  }
277
278
279
280  /**
281   * {@inheritDoc}
282   */
283  @Override()
284  public String getDataTypeName()
285  {
286    return INFO_SCOPE_TYPE_NAME.get();
287  }
288
289
290
291  /**
292   * {@inheritDoc}
293   */
294  @Override()
295  public String getValueConstraints()
296  {
297    return INFO_SCOPE_CONSTRAINTS.get();
298  }
299
300
301
302  /**
303   * {@inheritDoc}
304   */
305  @Override()
306  public ScopeArgument getCleanCopy()
307  {
308    return new ScopeArgument(this);
309  }
310
311
312
313  /**
314   * {@inheritDoc}
315   */
316  @Override()
317  public void toString(final StringBuilder buffer)
318  {
319    buffer.append("ScopeArgument(");
320    appendBasicToStringInfo(buffer);
321
322    if (defaultValue != null)
323    {
324      buffer.append(", defaultValue='");
325      switch (defaultValue.intValue())
326      {
327        case SearchScope.BASE_INT_VALUE:
328          buffer.append("base");
329          break;
330        case SearchScope.ONE_INT_VALUE:
331          buffer.append("one");
332          break;
333        case SearchScope.SUB_INT_VALUE:
334          buffer.append("sub");
335          break;
336        case SearchScope.SUBORDINATE_SUBTREE_INT_VALUE:
337          buffer.append("subordinate");
338          break;
339        default:
340          buffer.append(defaultValue.intValue());
341          break;
342      }
343      buffer.append('\'');
344    }
345
346    buffer.append(')');
347  }
348}