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