001/* 002 * Copyright 2011-2023 Ping Identity Corporation 003 * All Rights Reserved. 004 */ 005/* 006 * Copyright 2011-2023 Ping Identity Corporation 007 * 008 * Licensed under the Apache License, Version 2.0 (the "License"); 009 * you may not use this file except in compliance with the License. 010 * You may obtain a copy of the License at 011 * 012 * http://www.apache.org/licenses/LICENSE-2.0 013 * 014 * Unless required by applicable law or agreed to in writing, software 015 * distributed under the License is distributed on an "AS IS" BASIS, 016 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 017 * See the License for the specific language governing permissions and 018 * limitations under the License. 019 */ 020/* 021 * Copyright (C) 2011-2023 Ping Identity Corporation 022 * 023 * This program is free software; you can redistribute it and/or modify 024 * it under the terms of the GNU General Public License (GPLv2 only) 025 * or the terms of the GNU Lesser General Public License (LGPLv2.1 only) 026 * as published by the Free Software Foundation. 027 * 028 * This program is distributed in the hope that it will be useful, 029 * but WITHOUT ANY WARRANTY; without even the implied warranty of 030 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 031 * GNU General Public License for more details. 032 * 033 * You should have received a copy of the GNU General Public License 034 * along with this program; if not, see <http://www.gnu.org/licenses>. 035 */ 036package com.unboundid.util.args; 037 038 039 040import java.text.ParseException; 041import java.util.ArrayList; 042import java.util.Collections; 043import java.util.List; 044 045import com.unboundid.util.Debug; 046import com.unboundid.util.Mutable; 047import com.unboundid.util.NotNull; 048import com.unboundid.util.Nullable; 049import com.unboundid.util.StaticUtils; 050import com.unboundid.util.ThreadSafety; 051import com.unboundid.util.ThreadSafetyLevel; 052 053import static com.unboundid.util.args.ArgsMessages.*; 054 055 056 057/** 058 * This class defines an argument whose values are intended to be argument 059 * strings as might be provided to a command-line application (e.g., 060 * "--arg1 arg1value --arg2 --arg3 arg3value"). Instances of this argument 061 * will have their own argument parser that may be used to process the argument 062 * strings. This type of argument may not be particularly useful for use in 063 * command-line applications, but may be used in other applications that may use 064 * arguments in other ways. 065 */ 066@Mutable() 067@ThreadSafety(level=ThreadSafetyLevel.NOT_THREADSAFE) 068public final class ArgumentListArgument 069 extends Argument 070{ 071 /** 072 * The serial version UID for this serializable class. 073 */ 074 private static final long serialVersionUID = 1926330851837348378L; 075 076 077 078 // The argument parser that will be used to validate values given for this 079 // argument. 080 @NotNull private final ArgumentParser parser; 081 082 // The list of argument parsers that correspond to values actually provided 083 // to this argument. 084 @NotNull private final List<ArgumentParser> values; 085 086 // The string representations of the values provided for this argument. 087 @NotNull private final List<String> valueStrings; 088 089 090 091 /** 092 * Creates a new argument list argument with the provided information. It 093 * will not be required, will permit at most one occurrence, and will use a 094 * default placeholder. 095 * 096 * @param shortIdentifier The short identifier for this argument. It may 097 * not be {@code null} if the long identifier is 098 * {@code null}. 099 * @param longIdentifier The long identifier for this argument. It may 100 * not be {@code null} if the short identifier is 101 * {@code null}. 102 * @param description A human-readable description for this argument. 103 * It must not be {@code null}. 104 * @param parser The argument parser that will be used to 105 * process values provided for this argument. 106 * 107 * @throws ArgumentException If there is a problem with the definition of 108 * this argument. 109 */ 110 public ArgumentListArgument(@Nullable final Character shortIdentifier, 111 @Nullable final String longIdentifier, 112 @NotNull final String description, 113 @NotNull final ArgumentParser parser) 114 throws ArgumentException 115 { 116 this(shortIdentifier, longIdentifier, false, 1, null, description, parser); 117 } 118 119 120 121 /** 122 * Creates a new argument list argument with the provided information. 123 * 124 * @param shortIdentifier The short identifier for this argument. It may 125 * not be {@code null} if the long identifier is 126 * {@code null}. 127 * @param longIdentifier The long identifier for this argument. It may 128 * not be {@code null} if the short identifier is 129 * {@code null}. 130 * @param isRequired Indicates whether this argument is required to 131 * be provided. 132 * @param maxOccurrences The maximum number of times this argument may be 133 * provided on the command line. A value less than 134 * or equal to zero indicates that it may be present 135 * any number of times. 136 * @param valuePlaceholder A placeholder to display in usage information to 137 * indicate that a value must be provided. It may 138 * be {@code null} if a default placeholder should 139 * be used. 140 * @param description A human-readable description for this argument. 141 * It must not be {@code null}. 142 * @param parser The argument parser that will be used to 143 * process values provided for this argument. 144 * 145 * @throws ArgumentException If there is a problem with the definition of 146 * this argument. 147 */ 148 public ArgumentListArgument(@Nullable final Character shortIdentifier, 149 @Nullable final String longIdentifier, 150 final boolean isRequired, 151 final int maxOccurrences, 152 @Nullable final String valuePlaceholder, 153 @NotNull final String description, 154 @NotNull final ArgumentParser parser) 155 throws ArgumentException 156 { 157 super(shortIdentifier, longIdentifier, isRequired, maxOccurrences, 158 (valuePlaceholder == null) 159 ? INFO_PLACEHOLDER_ARGS.get() 160 : valuePlaceholder, 161 description); 162 163 this.parser = parser.getCleanCopy(); 164 165 values = new ArrayList<>(10); 166 valueStrings = new ArrayList<>(10); 167 } 168 169 170 171 /** 172 * Creates a new argument list argument that is a "clean" copy of the provided 173 * source argument. 174 * 175 * @param source The source argument to use for this argument. 176 */ 177 private ArgumentListArgument(@NotNull final ArgumentListArgument source) 178 { 179 super(source); 180 181 parser = source.parser; 182 values = new ArrayList<>(10); 183 valueStrings = new ArrayList<>(10); 184 } 185 186 187 188 /** 189 * Retrieves a "clean" copy of the argument parser that will be used to 190 * process values provided for this argument. 191 * 192 * @return A "clean" copy of the argument parser that will be used to process 193 * values provided for this argument. 194 */ 195 @NotNull() 196 public ArgumentParser getCleanParser() 197 { 198 return parser.getCleanCopy(); 199 } 200 201 202 203 /** 204 * {@inheritDoc} 205 */ 206 @Override() 207 protected void addValue(@NotNull final String valueString) 208 throws ArgumentException 209 { 210 final List<String> argList; 211 try 212 { 213 argList = StaticUtils.toArgumentList(valueString); 214 } 215 catch (final ParseException pe) 216 { 217 Debug.debugException(pe); 218 throw new ArgumentException(ERR_ARG_LIST_MALFORMED_VALUE.get(valueString, 219 getIdentifierString(), pe.getMessage()), pe); 220 } 221 222 final String[] args = new String[argList.size()]; 223 argList.toArray(args); 224 225 final ArgumentParser p = parser.getCleanCopy(); 226 try 227 { 228 p.parse(args); 229 } 230 catch (final ArgumentException ae) 231 { 232 Debug.debugException(ae); 233 throw new ArgumentException(ERR_ARG_LIST_INVALID_VALUE.get(valueString, 234 getIdentifierString(), ae.getMessage()), ae); 235 } 236 237 values.add(p); 238 valueStrings.add(valueString); 239 } 240 241 242 243 /** 244 * Retrieves the list of argument parsers that have been used to process 245 * values provided to this argument. 246 * 247 * @return The list of argument parsers that have been used to process values 248 * provided to this argument. 249 */ 250 @NotNull() 251 public List<ArgumentParser> getValueParsers() 252 { 253 return Collections.unmodifiableList(values); 254 } 255 256 257 258 /** 259 * Retrieves the list of the string representations of the values provided to 260 * this argument. 261 * 262 * @return The list of the string representations of the values provided to 263 * this argument. 264 */ 265 @NotNull() 266 public List<String> getValueStrings() 267 { 268 return Collections.unmodifiableList(valueStrings); 269 } 270 271 272 273 /** 274 * {@inheritDoc} 275 */ 276 @Override() 277 @NotNull() 278 public List<String> getValueStringRepresentations(final boolean useDefault) 279 { 280 return Collections.unmodifiableList(valueStrings); 281 } 282 283 284 285 /** 286 * {@inheritDoc} 287 */ 288 @Override() 289 protected boolean hasDefaultValue() 290 { 291 return false; 292 } 293 294 295 296 /** 297 * {@inheritDoc} 298 */ 299 @Override() 300 @NotNull() 301 public String getDataTypeName() 302 { 303 return INFO_ARG_LIST_TYPE_NAME.get(); 304 } 305 306 307 308 /** 309 * {@inheritDoc} 310 */ 311 @Override() 312 @NotNull() 313 public String getValueConstraints() 314 { 315 return INFO_ARG_LIST_CONSTRAINTS.get(); 316 } 317 318 319 320 /** 321 * {@inheritDoc} 322 */ 323 @Override() 324 protected void reset() 325 { 326 super.reset(); 327 values.clear(); 328 } 329 330 331 332 /** 333 * {@inheritDoc} 334 */ 335 @Override() 336 @NotNull() 337 public ArgumentListArgument getCleanCopy() 338 { 339 return new ArgumentListArgument(this); 340 } 341 342 343 344 /** 345 * {@inheritDoc} 346 */ 347 @Override() 348 protected void addToCommandLine(@NotNull final List<String> argStrings) 349 { 350 for (final String s : valueStrings) 351 { 352 argStrings.add(getIdentifierString()); 353 if (isSensitive()) 354 { 355 argStrings.add("***REDACTED***"); 356 } 357 else 358 { 359 argStrings.add(s); 360 } 361 } 362 } 363 364 365 366 /** 367 * {@inheritDoc} 368 */ 369 @Override() 370 public void toString(@NotNull final StringBuilder buffer) 371 { 372 buffer.append("ArgumentListArgument("); 373 appendBasicToStringInfo(buffer); 374 buffer.append(", parser="); 375 parser.toString(buffer); 376 buffer.append(')'); 377 } 378}