001 /*
002 * Copyright 2010-2013 UnboundID Corp.
003 * All Rights Reserved.
004 */
005 /*
006 * Copyright (C) 2010-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.Collections;
026 import java.util.HashMap;
027 import java.util.Map;
028 import java.util.concurrent.atomic.AtomicReference;
029
030 import com.unboundid.ldap.sdk.SearchScope;
031 import com.unboundid.util.Mutable;
032 import com.unboundid.util.StaticUtils;
033 import com.unboundid.util.ThreadSafety;
034 import com.unboundid.util.ThreadSafetyLevel;
035
036 import 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)
055 public 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 }