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}