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.Iterator;
033    import java.util.LinkedList;
034    
035    import static org.opends.messages.UtilityMessages.*;
036    
037    import org.opends.messages.MessageBuilder;
038    import static org.opends.server.util.StaticUtils.*;
039    
040    
041    
042    /**
043     * This class defines a generic argument that may be used in the argument list
044     * for an application.  This is an abstract class that must be subclassed in
045     * order to provide specific functionality.
046     */
047    public abstract class Argument
048    {
049      // Indicates whether this argument should be hidden in the usage information.
050      private boolean isHidden;
051    
052      // Indicates whether this argument may be specified more than once for
053      // multiple values.
054      private boolean isMultiValued;
055    
056      // Indicates whether this argument was provided in the set of command-line
057      // arguments.
058      private boolean isPresent;
059    
060      // Indicates whether this argument is required to have a value.
061      private boolean isRequired;
062    
063      // Indicates whether this argument requires a value.
064      private boolean needsValue;
065    
066      // The single-character identifier for this argument.
067      private Character shortIdentifier;
068    
069      // The unique ID of the description for this argument.
070      private Message description;
071    
072      // The set of values for this argument.
073      private LinkedList<String> values;
074    
075      // The default value for the argument if none other is provided.
076      private String defaultValue;
077    
078      // The long identifier for this argument.
079      private String longIdentifier;
080    
081      // The generic name that will be used to refer to this argument.
082      private String name;
083    
084      // The name of the property that can be used to set the default value.
085      private String propertyName;
086    
087      // The value placeholder for this argument, which will be used in usage
088      // information.
089      private Message valuePlaceholder;
090    
091      // Indicates whether this argument was provided in the set of properties
092      // found is a properties file.
093      private boolean isValueSetByProperty;
094    
095    
096      /**
097       * Creates a new argument with the provided information.
098       *
099       * @param  name              The generic name that should be used to refer to
100       *                           this argument.
101       * @param  shortIdentifier   The single-character identifier for this
102       *                           argument, or <CODE>null</CODE> if there is none.
103       * @param  longIdentifier    The long identifier for this argument, or
104       *                           <CODE>null</CODE> if there is none.
105       * @param  isRequired        Indicates whether this argument must be specified
106       *                           on the command line.
107       * @param  isMultiValued     Indicates whether this argument may be specified
108       *                           more than once to provide multiple values.
109       * @param  needsValue        Indicates whether this argument requires a value.
110       * @param  valuePlaceholder  The placeholder for the argument value that will
111       *                           be displayed in usage information, or
112       *                           <CODE>null</CODE> if this argument does not
113       *                           require a value.
114       * @param  defaultValue      The default value that should be used for this
115       *                           argument if none is provided in a properties file
116       *                           or on the command line.  This may be
117       *                           <CODE>null</CODE> if there is no generic default.
118       * @param  propertyName      The name of the property in a property file that
119       *                           may be used to override the default value but
120       *                           will be overridden by a command-line argument.
121       * @param  description       Message for the description of this
122       *                           argument.
123       *
124       * @throws  ArgumentException  If there is a problem with any of the
125       *                             parameters used to create this argument.
126       */
127      protected Argument(String name, Character shortIdentifier,
128                         String longIdentifier, boolean isRequired,
129                         boolean isMultiValued, boolean needsValue,
130                         Message valuePlaceholder, String defaultValue,
131                         String propertyName,
132                         Message description)
133                throws ArgumentException
134      {
135        this.name             = name;
136        this.shortIdentifier  = shortIdentifier;
137        this.longIdentifier   = longIdentifier;
138        this.isRequired       = isRequired;
139        this.isMultiValued    = isMultiValued;
140        this.needsValue       = needsValue;
141        this.valuePlaceholder = valuePlaceholder;
142        this.defaultValue     = defaultValue;
143        this.propertyName     = propertyName;
144        this.description      = description;
145        this.isValueSetByProperty = false ;
146    
147        if ((shortIdentifier == null) && (longIdentifier == null))
148        {
149          Message message = ERR_ARG_NO_IDENTIFIER.get(name);
150          throw new ArgumentException(message);
151        }
152    
153        if (needsValue && (valuePlaceholder == null))
154        {
155          Message message = ERR_ARG_NO_VALUE_PLACEHOLDER.get(name);
156          throw new ArgumentException(message);
157        }
158    
159        values    = new LinkedList<String>();
160        isPresent = false;
161        isHidden  = false;
162      }
163    
164    
165    
166      /**
167       * Retrieves the generic name that will be used to refer to this argument.
168       *
169       * @return  The generic name that will be used to refer to this argument.
170       */
171      public String getName()
172      {
173        return name;
174      }
175    
176    
177    
178      /**
179       * Retrieves the single-character identifier that may be used to specify the
180       * value of this argument.
181       *
182       * @return  The single-character identifier that may be used to specify the
183       *          value of this argument, or <CODE>null</CODE> if there is none.
184       */
185      public Character getShortIdentifier()
186      {
187        return shortIdentifier;
188      }
189    
190    
191    
192      /**
193       * Retrieves the long (multi-character) identifier that may be used to specify
194       * the value of this argument.
195       *
196       * @return  The long (multi-character) identifier that may be used to specify
197       *          the value of this argument.
198       */
199      public String getLongIdentifier()
200      {
201        return longIdentifier;
202      }
203    
204    
205    
206      /**
207       * Indicates whether this argument is required to have at least one value.
208       *
209       * @return  <CODE>true</CODE> if this argument is required to have at least
210       *          one value, or <CODE>false</CODE> if it does not need to have a
211       *          value.
212       */
213      public boolean isRequired()
214      {
215        return isRequired;
216      }
217    
218    
219    
220      /**
221       * Specifies whether this argument is required to have at least one value.
222       *
223       * @param  isRequired  Indicates whether this argument is required to have at
224       *                     least one value.
225       */
226      public void setRequired(boolean isRequired)
227      {
228        this.isRequired = isRequired;
229      }
230    
231    
232    
233      /**
234       * Indicates whether this argument is present in the parsed set of
235       * command-line arguments.
236       *
237       * @return  <CODE>true</CODE> if this argument is present in the parsed set of
238       *          command-line arguments, or <CODE>false</CODE> if not.
239       */
240      public boolean isPresent()
241      {
242        return isPresent;
243      }
244    
245    
246    
247      /**
248       * Specifies whether this argument is present in the parsed set of
249       * command-line arguments.
250       *
251       * @param  isPresent  Indicates whether this argument is present in the set of
252       *                    command-line arguments.
253       */
254      public void setPresent(boolean isPresent)
255      {
256        this.isPresent = isPresent;
257      }
258    
259    
260    
261      /**
262       * Indicates whether this argument should be hidden from the usage
263       * information.
264       *
265       * @return  <CODE>true</CODE> if this argument should be hidden from the usage
266       *          information, or <CODE>false</CODE> if not.
267       */
268      public boolean isHidden()
269      {
270        return isHidden;
271      }
272    
273    
274    
275      /**
276       * Specifies whether this argument should be hidden from the usage
277       * information.
278       *
279       * @param  isHidden  Indicates whether this argument should be hidden from the
280       *                   usage information.
281       */
282      public void setHidden(boolean isHidden)
283      {
284        this.isHidden = isHidden;
285      }
286    
287    
288    
289      /**
290       * Indicates whether this argument may be provided more than once on the
291       * command line to specify multiple values.
292       *
293       * @return  <CODE>true</CODE> if this argument may be provided more than once
294       *          on the command line to specify multiple values, or
295       *          <CODE>false</CODE> if it may have at most one value.
296       */
297      public boolean isMultiValued()
298      {
299        return isMultiValued;
300      }
301    
302    
303    
304      /**
305       * Specifies whether this argument may be provided more than once on the
306       * command line to specify multiple values.
307       *
308       * @param  isMultiValued  Indicates whether this argument may be provided more
309       *                        than once on the command line to specify multiple
310       *                        values.
311       */
312      public void setMultiValued(boolean isMultiValued)
313      {
314        this.isMultiValued = isMultiValued;
315      }
316    
317    
318    
319      /**
320       * Indicates whether a value must be provided with this argument if it is
321       * present.
322       *
323       * @return  <CODE>true</CODE> if a value must be provided with the argument if
324       *          it is present, or <CODE>false</CODE> if the argument does not take
325       *          a value and the presence of the argument identifier itself is
326       *          sufficient to convey the necessary information.
327       */
328      public boolean needsValue()
329      {
330        return needsValue;
331      }
332    
333    
334    
335      /**
336       * Specifies whether a value must be provided with this argument if it is
337       * present.  If this is changed from <CODE>false</CODE> to <CODE>true</CODE>,
338       * then a value placeholder must also be provided.
339       *
340       * @param  needsValue  Indicates whether a value must be provided with this
341       *                     argument if it is present.
342    
343       */
344      public void setNeedsValue(boolean needsValue)
345      {
346        this.needsValue = needsValue;
347      }
348    
349    
350    
351      /**
352       * Retrieves the value placeholder that will be displayed for this argument in
353       * the generated usage information.
354       *
355       * @return  The value placeholder that will be displayed for this argument in
356       *          the generated usage information, or <CODE>null</CODE> if there is
357       *          none.
358       */
359      public Message getValuePlaceholder()
360      {
361        return valuePlaceholder;
362      }
363    
364    
365    
366      /**
367       * Specifies the value placeholder that will be displayed for this argument in
368       * the generated usage information.  It may be <CODE>null</CODE> only if
369       * <CODE>needsValue()</CODE> returns <CODE>false</CODE>.
370       *
371       * @param  valuePlaceholder  The value placeholder that will be displayed for
372       *                           this argument in the generated usage information.
373       */
374      public void setValuePlaceholder(Message valuePlaceholder)
375      {
376        this.valuePlaceholder = valuePlaceholder;
377      }
378    
379    
380    
381      /**
382       * Retrieves the default value that will be used for this argument if it is
383       * not specified on the command line and it is not set from a properties file.
384       *
385       * @return  The default value that will be used for this argument if it is not
386       *          specified on the command line and it is not set from a properties
387       *          file, or <CODE>null</CODE> if there is no default value.
388       */
389      public String getDefaultValue()
390      {
391        return defaultValue;
392      }
393    
394    
395    
396      /**
397       * Specifies the default value that will be used for this argument if it is
398       * not specified on the command line and it is not set from a properties file.
399       *
400       * @param  defaultValue  The default value that will be used for this argument
401       *                       if it is not specified on the command line and it is
402       *                       not set from a properties file.
403       */
404      public void setDefaultValue(String defaultValue)
405      {
406        this.defaultValue = defaultValue;
407      }
408    
409    
410    
411      /**
412       * Retrieves the name of a property in a properties file that may be used to
413       * set the default value for this argument if it is present.  A value read
414       * from a properties file will override the default value returned from the
415       * <CODE>getDefaultValue</CODE>, but the properties file value will be
416       * overridden by a value supplied on the command line.
417       *
418       * @return  The name of a property in a properties file that may be used to
419       *          set the default value for this argument if it is present.
420       */
421      public String getPropertyName()
422      {
423        return propertyName;
424      }
425    
426    
427    
428      /**
429       * Specifies the name of a property in a properties file that may be used to
430       * set the default value for this argument if it is present.
431       *
432       * @param  propertyName  The name of a property in a properties file that may
433       *                       be used to set the default value for this argument if
434       *                       it is present.
435       */
436      public void setPropertyName(String propertyName)
437      {
438        this.propertyName = propertyName;
439      }
440    
441      /**
442       * Indicates whether this argument was provided in the set of
443       * properties found is a properties file.
444       *
445       * @return <CODE>true</CODE> if this argument was provided in the
446       *         set of properties found is a properties file, or
447       *         <CODE>false</CODE> if not.
448       */
449      public boolean isValueSetByProperty()
450      {
451        return isValueSetByProperty;
452      }
453    
454      /**
455       * Specifies whether this argument was provided in the set of
456       * properties found is a properties file.
457       *
458       * @param isValueSetByProperty
459       *          Specify whether this argument was provided in the set
460       *          of properties found is a properties file.
461       */
462      public void setValueSetByProperty(boolean isValueSetByProperty)
463      {
464        this.isValueSetByProperty = isValueSetByProperty;
465      }
466    
467      /**
468       * Retrieves the human-readable description for this argument.
469       *
470       * @return  The human-readable description for this argument.
471       */
472      public Message getDescription()
473      {
474        return description != null ? description : Message.EMPTY;
475      }
476    
477    
478    
479      /**
480       * Indicates whether this argument has at least one value.
481       *
482       * @return  <CODE>true</CODE> if this argument has at least one value, or
483       *          <CODE>false</CODE> if it does not have any values.
484       */
485      public boolean hasValue()
486      {
487        return (! values.isEmpty());
488      }
489    
490    
491    
492      /**
493       * Retrieves the string vale for this argument.  If it has multiple values,
494       * then the first will be returned.  If it does not have any values, then the
495       * default value will be returned.
496       *
497       * @return  The string value for this argument, or <CODE>null</CODE> if there
498       *          are no values and no default value has been given.
499       */
500      public String getValue()
501      {
502        if (values.isEmpty())
503        {
504          return defaultValue;
505        }
506    
507        return values.getFirst();
508      }
509    
510    
511    
512      /**
513       * Retrieves the set of string values for this argument.
514       *
515       * @return  The set of string values for this argument.
516       */
517      public LinkedList<String> getValues()
518      {
519        return values;
520      }
521    
522    
523    
524      /**
525       * Retrieves the value of this argument as an integer.
526       *
527       * @return  The value of this argument as an integer.
528       *
529       * @throws  ArgumentException  If there are multiple values, or the value
530       *                             cannot be parsed as an integer.
531       */
532      public int getIntValue()
533             throws ArgumentException
534      {
535        if (values.isEmpty())
536        {
537          Message message = ERR_ARG_NO_INT_VALUE.get(name);
538          throw new ArgumentException(message);
539        }
540    
541        Iterator<String> iterator = values.iterator();
542        String valueString = iterator.next();
543    
544        int intValue;
545        try
546        {
547          intValue = Integer.parseInt(valueString);
548        }
549        catch (Exception e)
550        {
551          Message message = ERR_ARG_CANNOT_DECODE_AS_INT.get(valueString, name);
552          throw new ArgumentException(message, e);
553        }
554    
555        if (iterator.hasNext())
556        {
557          Message message = ERR_ARG_INT_MULTIPLE_VALUES.get(name);
558          throw new ArgumentException(message);
559        }
560        else
561        {
562          return intValue;
563        }
564      }
565    
566    
567    
568      /**
569       * Retrieves the set of values for this argument as a list of integers.
570       *
571       * @return  A list of the integer representations of the values for this
572       *          argument.
573       *
574       * @throws  ArgumentException  If any of the values cannot be parsed as an
575       *                             integer.
576       */
577      public LinkedList<Integer> getIntValues()
578             throws ArgumentException
579      {
580        LinkedList<Integer> intList = new LinkedList<Integer>();
581    
582        Iterator<String> iterator = values.iterator();
583        while (iterator.hasNext())
584        {
585          String valueString = iterator.next();
586    
587          try
588          {
589            intList.add(Integer.valueOf(valueString));
590          }
591          catch (Exception e)
592          {
593            Message message = ERR_ARG_CANNOT_DECODE_AS_INT.get(valueString, name);
594            throw new ArgumentException(message, e);
595          }
596        }
597    
598        return intList;
599      }
600    
601    
602    
603      /**
604       * Retrieves the value of this argument as a <CODE>Boolean</CODE>.
605       *
606       * @return  The value of this argument as a <CODE>Boolean</CODE>.
607       *
608       * @throws  ArgumentException  If this argument cannot be interpreted as a
609       *                             Boolean value.
610       */
611      public boolean getBooleanValue()
612             throws ArgumentException
613      {
614        if (values.isEmpty())
615        {
616          Message message = ERR_ARG_NO_BOOLEAN_VALUE.get(name);
617          throw new ArgumentException(message);
618        }
619    
620        Iterator<String> iterator = values.iterator();
621        String valueString = toLowerCase(iterator.next());
622    
623        boolean booleanValue;
624        if (valueString.equals("true") || valueString.equals("yes") ||
625            valueString.equals("on") || valueString.equals("1"))
626        {
627          booleanValue = true;
628        }
629        else if (valueString.equals("false") || valueString.equals("no") ||
630                 valueString.equals("off") || valueString.equals("0"))
631        {
632          booleanValue = false;
633        }
634        else
635        {
636          Message message = ERR_ARG_CANNOT_DECODE_AS_BOOLEAN.get(valueString, name);
637          throw new ArgumentException(message);
638        }
639    
640        if (iterator.hasNext())
641        {
642          Message message = ERR_ARG_BOOLEAN_MULTIPLE_VALUES.get(name);
643          throw new ArgumentException(message);
644        }
645        else
646        {
647          return booleanValue;
648        }
649      }
650    
651    
652    
653      /**
654       * Indicates whether the provided value is acceptable for use in this
655       * argument.
656       *
657       * @param  valueString    The value for which to make the determination.
658       * @param  invalidReason  A buffer into which the invalid reason may be
659       *                        written if the value is not acceptable.
660       *
661       * @return  <CODE>true</CODE> if the value is acceptable, or
662       *          <CODE>false</CODE> if it is not.
663       */
664      public abstract boolean valueIsAcceptable(String valueString,
665                                                MessageBuilder invalidReason);
666    
667    
668    
669      /**
670       * Adds a value to the set of values for this argument.  This should only be
671       * called if the value is allowed by the <CODE>valueIsAcceptable</CODE>
672       * method.
673       *
674       * @param  valueString  The string representation of the value to add to this
675       *                      argument.
676       */
677      public void addValue(String valueString)
678      {
679        values.add(valueString);
680      }
681    
682    
683    
684      /**
685       * Clears the set of values assigned to this argument.
686       */
687      public void clearValues()
688      {
689        values.clear();
690      }
691    }
692