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