001 /* 002 * CDDL HEADER START 003 * 004 * The contents of this file are subject to the terms of the 005 * Common Development and Distribution License, Version 1.0 only 006 * (the "License"). You may not use this file except in compliance 007 * with the License. 008 * 009 * You can obtain a copy of the license at 010 * trunk/opends/resource/legal-notices/OpenDS.LICENSE 011 * or https://OpenDS.dev.java.net/OpenDS.LICENSE. 012 * See the License for the specific language governing permissions 013 * and limitations under the License. 014 * 015 * When distributing Covered Code, include this CDDL HEADER in each 016 * file and include the License file at 017 * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable, 018 * add the following below this CDDL HEADER, with the fields enclosed 019 * by brackets "[]" replaced with your own identifying information: 020 * Portions Copyright [yyyy] [name of copyright owner] 021 * 022 * CDDL HEADER END 023 * 024 * 025 * Copyright 2006-2008 Sun Microsystems, Inc. 026 */ 027 package org.opends.server.util.args; 028 import org.opends.messages.Message; 029 030 031 032 import java.util.ArrayList; 033 import java.util.HashMap; 034 import java.util.LinkedList; 035 036 import static org.opends.messages.UtilityMessages.*; 037 038 import static org.opends.server.util.StaticUtils.*; 039 040 041 042 /** 043 * This class defines a data structure for holding information about a 044 * subcommand that may be used with the subcommand argument parser. The 045 * subcommand has a name, a description, and a set of arguments. 046 */ 047 public class SubCommand 048 { 049 // Indicates whether this subCommand should be hidden in the usage 050 // information. 051 private boolean isHidden; 052 053 // The mapping between the short argument IDs and the arguments for this 054 // subcommand. 055 private HashMap<Character,Argument> shortIDMap; 056 057 // The mapping between the long argument IDs and the arguments for this 058 // subcommand. 059 private HashMap<String,Argument> longIDMap; 060 061 // The list of arguments associated with this subcommand. 062 private LinkedList<Argument> arguments; 063 064 // The description for this subcommand. 065 private Message description; 066 067 // The name of this subcommand. 068 private String name; 069 070 // The argument parser with which this subcommand is associated. 071 private SubCommandArgumentParser parser; 072 073 // Indicates whether this parser will allow additional unnamed 074 // arguments at the end of the list. 075 private boolean allowsTrailingArguments; 076 077 // The maximum number of unnamed trailing arguments that may be 078 // provided. 079 private int maxTrailingArguments; 080 081 // The minimum number of unnamed trailing arguments that may be 082 // provided. 083 private int minTrailingArguments; 084 085 // The display name that will be used for the trailing arguments in 086 // the usage information. 087 private String trailingArgsDisplayName; 088 089 /** 090 * Creates a new subcommand with the provided information. The 091 * subcommand will be automatically registered with the associated 092 * parser. 093 * 094 * @param parser 095 * The argument parser with which this subcommand is 096 * associated. 097 * @param name 098 * The name of this subcommand. 099 * @param description 100 * The description of this subcommand. 101 * @throws ArgumentException 102 * If the associated argument parser already has a 103 * subcommand with the same name. 104 */ 105 public SubCommand(SubCommandArgumentParser parser, String name, 106 Message description) throws ArgumentException 107 { 108 this(parser, name, false, 0, 0, null, description); 109 } 110 111 112 113 /** 114 * Creates a new subcommand with the provided information. The 115 * subcommand will be automatically registered with the associated 116 * parser. 117 * 118 * @param parser 119 * The argument parser with which this subcommand is 120 * associated. 121 * @param name 122 * The name of this subcommand. 123 * @param allowsTrailingArguments 124 * Indicates whether this parser allows unnamed trailing 125 * arguments to be provided. 126 * @param minTrailingArguments 127 * The minimum number of unnamed trailing arguments that 128 * must be provided. A value less than or equal to zero 129 * indicates that no minimum will be enforced. 130 * @param maxTrailingArguments 131 * The maximum number of unnamed trailing arguments that 132 * may be provided. A value less than or equal to zero 133 * indicates that no maximum will be enforced. 134 * @param trailingArgsDisplayName 135 * The display name that should be used as a placeholder 136 * for unnamed trailing arguments in the generated usage 137 * information. 138 * @param description 139 * The description of this subcommand. 140 * @throws ArgumentException 141 * If the associated argument parser already has a 142 * subcommand with the same name. 143 */ 144 public SubCommand(SubCommandArgumentParser parser, String name, 145 boolean allowsTrailingArguments, int minTrailingArguments, 146 int maxTrailingArguments, String trailingArgsDisplayName, 147 Message description) throws ArgumentException 148 { 149 this.parser = parser; 150 this.name = name; 151 this.description = description; 152 this.allowsTrailingArguments = allowsTrailingArguments; 153 this.minTrailingArguments = minTrailingArguments; 154 this.maxTrailingArguments = maxTrailingArguments; 155 this.trailingArgsDisplayName = trailingArgsDisplayName; 156 this.isHidden = false; 157 158 String nameToCheck = name; 159 if (parser.longArgumentsCaseSensitive()) 160 { 161 nameToCheck = toLowerCase(name); 162 } 163 164 if (parser.hasSubCommand(nameToCheck)) 165 { 166 Message message = ERR_ARG_SUBCOMMAND_DUPLICATE_SUBCOMMAND.get(name); 167 throw new ArgumentException(message); 168 } 169 170 parser.addSubCommand(this); 171 shortIDMap = new HashMap<Character,Argument>(); 172 longIDMap = new HashMap<String,Argument>(); 173 arguments = new LinkedList<Argument>(); 174 } 175 176 177 178 /** 179 * Retrieves the name of this subcommand. 180 * 181 * @return The name of this subcommand. 182 */ 183 public String getName() 184 { 185 return name; 186 } 187 188 189 /** 190 * Retrieves the description for this subcommand. 191 * 192 * @return The description for this subcommand. 193 */ 194 public Message getDescription() 195 { 196 return description; 197 } 198 199 200 201 /** 202 * Retrieves the set of arguments for this subcommand. 203 * 204 * @return The set of arguments for this subcommand. 205 */ 206 public LinkedList<Argument> getArguments() 207 { 208 return arguments; 209 } 210 211 212 213 /** 214 * Retrieves the subcommand argument with the specified short identifier. 215 * 216 * @param shortID The short identifier of the argument to retrieve. 217 * 218 * @return The subcommand argument with the specified short identifier, or 219 * <CODE>null</CODE> if there is none. 220 */ 221 public Argument getArgument(Character shortID) 222 { 223 return shortIDMap.get(shortID); 224 } 225 226 227 228 /** 229 * Retrieves the subcommand argument with the specified long identifier. 230 * 231 * @param longID The long identifier of the argument to retrieve. 232 * 233 * @return The subcommand argument with the specified long identifier, or 234 * <CODE>null</CODE> if there is none. 235 */ 236 public Argument getArgument(String longID) 237 { 238 return longIDMap.get(longID); 239 } 240 241 242 243 /** 244 * Retrieves the subcommand argument with the specified name. 245 * 246 * @param name The name of the argument to retrieve. 247 * 248 * @return The subcommand argument with the specified name, or 249 * <CODE>null</CODE> if there is no such argument. 250 */ 251 public Argument getArgumentForName(String name) 252 { 253 for (Argument a : arguments) 254 { 255 if (a.getName().equals(name)) 256 { 257 return a; 258 } 259 } 260 261 return null; 262 } 263 264 265 266 /** 267 * Adds the provided argument for use with this subcommand. 268 * 269 * @param argument The argument to add for use with this subcommand. 270 * 271 * @throws ArgumentException If either the short ID or long ID for the 272 * argument conflicts with that of another 273 * argument already associated with this 274 * subcommand. 275 */ 276 public void addArgument(Argument argument) 277 throws ArgumentException 278 { 279 String argumentName = argument.getName(); 280 for (Argument a : arguments) 281 { 282 if (argumentName.equals(a.getName())) 283 { 284 Message message = 285 ERR_ARG_SUBCOMMAND_DUPLICATE_ARGUMENT_NAME.get(name, argumentName); 286 throw new ArgumentException(message); 287 } 288 } 289 290 if (parser.hasGlobalArgument(argumentName)) 291 { 292 Message message = 293 ERR_ARG_SUBCOMMAND_ARGUMENT_GLOBAL_CONFLICT.get(argumentName, name); 294 throw new ArgumentException(message); 295 } 296 297 298 Character shortID = argument.getShortIdentifier(); 299 if (shortID != null) 300 { 301 if (shortIDMap.containsKey(shortID)) 302 { 303 Message message = ERR_ARG_SUBCOMMAND_DUPLICATE_SHORT_ID. 304 get(argumentName, name, String.valueOf(shortID), 305 shortIDMap.get(shortID).getName()); 306 throw new ArgumentException(message); 307 } 308 309 Argument arg = parser.getGlobalArgumentForShortID(shortID); 310 if (arg != null) 311 { 312 Message message = ERR_ARG_SUBCOMMAND_ARGUMENT_SHORT_ID_GLOBAL_CONFLICT. 313 get(argumentName, name, String.valueOf(shortID), arg.getName()); 314 throw new ArgumentException(message); 315 } 316 } 317 318 319 String longID = argument.getLongIdentifier(); 320 if (longID != null) 321 { 322 if (! parser.longArgumentsCaseSensitive()) 323 { 324 longID = toLowerCase(longID); 325 } 326 327 if (longIDMap.containsKey(longID)) 328 { 329 Message message = ERR_ARG_SUBCOMMAND_DUPLICATE_LONG_ID.get( 330 argumentName, name, argument.getLongIdentifier(), 331 longIDMap.get(longID).getName()); 332 throw new ArgumentException(message); 333 } 334 335 Argument arg = parser.getGlobalArgumentForLongID(longID); 336 if (arg != null) 337 { 338 Message message = ERR_ARG_SUBCOMMAND_ARGUMENT_LONG_ID_GLOBAL_CONFLICT. 339 get(argumentName, name, argument.getLongIdentifier(), 340 arg.getName()); 341 throw new ArgumentException(message); 342 } 343 } 344 345 346 arguments.add(argument); 347 348 if (shortID != null) 349 { 350 shortIDMap.put(shortID, argument); 351 } 352 353 if (longID != null) 354 { 355 longIDMap.put(longID, argument); 356 } 357 } 358 359 360 361 /** 362 * Indicates whether this sub-command will allow unnamed trailing 363 * arguments. These will be arguments at the end of the list that 364 * are not preceded by either a long or short identifier and will 365 * need to be manually parsed by the application using this parser. 366 * Note that once an unnamed trailing argument has been identified, 367 * all remaining arguments will be classified as such. 368 * 369 * @return <CODE>true</CODE> if this sub-command allows unnamed 370 * trailing arguments, or <CODE>false</CODE> if it does 371 * not. 372 */ 373 public boolean allowsTrailingArguments() 374 { 375 return allowsTrailingArguments; 376 } 377 378 379 380 /** 381 * Retrieves the minimum number of unnamed trailing arguments that 382 * must be provided. 383 * 384 * @return The minimum number of unnamed trailing arguments that 385 * must be provided, or a value less than or equal to zero 386 * if no minimum will be enforced. 387 */ 388 public int getMinTrailingArguments() 389 { 390 return minTrailingArguments; 391 } 392 393 394 395 /** 396 * Retrieves the maximum number of unnamed trailing arguments that 397 * may be provided. 398 * 399 * @return The maximum number of unnamed trailing arguments that may 400 * be provided, or a value less than or equal to zero if no 401 * maximum will be enforced. 402 */ 403 public int getMaxTrailingArguments() 404 { 405 return maxTrailingArguments; 406 } 407 408 409 410 /** 411 * Retrieves the trailing arguments display name. 412 * 413 * @return Returns the trailing arguments display name. 414 */ 415 public String getTrailingArgumentsDisplayName() 416 { 417 return trailingArgsDisplayName; 418 } 419 420 421 422 /** 423 * Retrieves the set of unnamed trailing arguments that were provided on the 424 * command line. 425 * 426 * @return The set of unnamed trailing arguments that were provided on the 427 * command line. 428 */ 429 public ArrayList<String> getTrailingArguments() 430 { 431 return parser.getTrailingArguments(); 432 } 433 434 /** 435 * Indicates whether this subcommand should be hidden from the usage 436 * information. 437 * 438 * @return <CODE>true</CODE> if this subcommand should be hidden 439 * from the usage information, or <CODE>false</CODE> if 440 * not. 441 */ 442 public boolean isHidden() 443 { 444 return isHidden; 445 } 446 447 448 449 /** 450 * Specifies whether this subcommand should be hidden from the usage 451 * information. 452 * 453 * @param isHidden 454 * Indicates whether this subcommand should be hidden from 455 * the usage information. 456 */ 457 public void setHidden(boolean isHidden) 458 { 459 this.isHidden = isHidden; 460 } 461 } 462