(file) Return to OptionManager.h CVS log (file) (dir) Up to [Pegasus] / pegasus / src / Pegasus / Common

  1 mike  1.1 //BEGIN_LICENSE
  2           //
  3           // Copyright (c) 2000 The Open Group, BMC Software, Tivoli Systems, IBM
  4           //
  5           // Permission is hereby granted, free of charge, to any person obtaining a
  6           // copy of this software and associated documentation files (the "Software"),
  7           // to deal in the Software without restriction, including without limitation
  8           // the rights to use, copy, modify, merge, publish, distribute, sublicense,
  9           // and/or sell copies of the Software, and to permit persons to whom the
 10           // Software is furnished to do so, subject to the following conditions:
 11           //
 12           // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 13           // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 14           // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 15           // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 16           // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 17           // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 18           // DEALINGS IN THE SOFTWARE.
 19           //
 20           //END_LICENSE
 21           //BEGIN_HISTORY
 22 mike  1.1 //
 23           // Author: Michael E. Brasher
 24           //
 25 mike  1.2 // $Log: OptionManager.h,v $
 26 mike  1.6 // Revision 1.5  2001/04/14 06:41:17  mike
 27           // New
 28           //
 29 mike  1.5 // Revision 1.4  2001/04/14 03:37:16  mike
 30           // Added new example to test option manager
 31           //
 32 mike  1.4 // Revision 1.3  2001/04/14 02:26:42  mike
 33           // More on option manager implementation
 34           //
 35 mike  1.3 // Revision 1.2  2001/04/14 02:11:41  mike
 36           // New option manager class.
 37           //
 38 mike  1.2 // Revision 1.1  2001/04/14 01:52:45  mike
 39           // New option management class.
 40           //
 41 mike  1.1 //
 42           //END_HISTORY
 43           
 44           #ifndef Pegasus_OptionManager_h
 45           #define Pegasus_OptionManager_h
 46           
 47           #include <Pegasus/Common/Config.h>
 48           #include <Pegasus/Common/String.h>
 49           #include <Pegasus/Common/Array.h>
 50 mike  1.4 #include <Pegasus/Common/Exception.h>
 51 mike  1.1 
 52           PEGASUS_NAMESPACE_BEGIN
 53           
 54           class Option;
 55 mike  1.5 struct OptionRow;
 56 mike  1.1 
 57           /** The OptionManager class manages a collection of program options. 
 58           
 59               <h4>Overview</h4>
 60           
 61               A program option may be specified in one of three ways:
 62           
 63               <ul>
 64           	<li>As an environment variable</li>
 65           	<li>In a configuration file</li>
 66           	<li>On the command line</li>
 67               </ul>
 68           
 69               This class provides methods for merging options from all three of these 
 70               sources into a single unified collection. The following example showss 
 71               how to merge options from a command line into the option manager.
 72           
 73               <pre>
 74           	int main(int argc, char** argv)
 75           	{
 76           	    OptionManager om;
 77 mike  1.1 
 78           	    ...
 79           
 80           	    // Merge options from the command line into the option manager's
 81           	    // option list. Remove arguments from command line.
 82           
 83           	    om.mergeCommandLine(argc, argv);
 84           
 85           	    ...
 86           	}
 87               </pre>
 88           
 89               Methods are also provided for merging options from files and the environment
 90               (see OptionManager::mergeFile(), OptionManager::mergeEnvironment()).
 91           
 92               Before options are merged into the option manager, information on each
 93               option must be registered with the option manager so that the following
 94               can be resolved:
 95           
 96               <ul>
 97           	<li>The option's name</li>
 98 mike  1.1 	<li>The default value (to be used if not specified elsewhere)</li>
 99           	<li>Whether the option is required</li>
100 mike  1.2 	<li>The option's type (e.g., boolean, integer or string)</li>
101 mike  1.1 	<li>The domain of the option if any (set of legal values)</li>
102           	<li>The name the option as it appears as an environment variable</li>
103           	<li>The name the option as it appears in a configuration file</li>
104           	<li>The name the option as it appears on the command line</li>
105               </ul>
106           
107               Here is how to regsiter an option:
108           
109               <pre>
110           	OptionManager om;
111           
112 mike  1.5 	Option* option = new Option("port", "80", false, Option::NATURAL_NUMBER,
113 mike  1.2 	    Array<String>(), "PEGASUS_PORT", "PORT", "p");
114 mike  1.1 
115           	om.registerOption(option);
116               </pre>
117           
118               The arguments of the Option constructor are the same (and in the same
119 mike  1.2     order) as the list just above. Notice that option name is "port", Whereas
120               the environment variable is named "PEGASUS_PORT" and the option name
121               in the configuration file is "port" and the command line option argument
122               name is "p" (will appear as -p on the command line).
123 mike  1.1 
124               Once options have been registered, the option values may be obtained using
125               the merge methods described earlier. During merging, certain validation is
126               done using the corresponding Option instance described above.
127           
128               Once options have been merged, they may obtained by calling the 
129               lookupOption() method like this:
130               
131               <pre>
132           	Option* option = om.lookupOption("port");
133           
134           	String port = option->getValue();
135               </pre>
136           
137               <h4>Command Line Options</h4>
138           
139               To merge option values from the command line argument, call
140               mergeCommandLine() like this:
141           
142               <pre>
143           	om.mergeCommandLine(argc, argv);
144 mike  1.1     </pre>
145               
146               This method searches the command line for options that match the registered 
147               ones. It will extract those options from the command line (argc and argv 
148               will be modified accordingly).
149           
150               <h4>Configuration File Otpions</h4>
151           
152               Options from a configuration file may be merged by calling the mergeFile() 
153               method like this:
154           
155               <pre>
156           	om.mergeFile(fileName);
157               </pre>
158           
159               This searches the file for options matching registered ones. Exceptions
160               are thrown for any unrecognized option names that are encountered.
161           
162               <h4>Environment Variable Options</h4>
163           
164               The mergeEnvironment() method merges options from the enviroment space of
165 mike  1.1     the process.
166           
167               <h4>Merge Validation</h4>
168           
169               During merging, the option manager validates the following (using the 
170               information optatined during option registration).
171           
172               <ul>
173           	<li>The type of the option - whether integer, positive integer,
174           	    or string.</li>
175           	<li>The domain of the option - whether the supplied option is a legal
176           	    value for that otpion</li>
177           	<li>User extended validation - whether the user overriden 
178           	    Option::isValid() returns true when the value is passed to it</li>
179               </ul>
180 mike  1.2 
181               <h4>Typcial Usage</h4>
182           
183               The OptionManager is typically used in the following way. First, options
184               are registered to establish the valid set of options. Next, values are
185               merged from the various sources by calling the merge functions. Finally,
186               checkRequiredOptions() is called to see if any required option values were
187               not provided.
188 mike  1.1 */
189 mike  1.2 class PEGASUS_COMMON_LINKAGE OptionManager
190 mike  1.1 {
191           public:
192           
193               /** Constructor. */
194               OptionManager();
195           
196               /** Destructor. Deletes all contained Options. */
197               ~OptionManager();
198           
199               /** Registers an option. The OptionManager is responsible for disposing
200           	of the option; the caller must not delete this object.
201           
202           	@param option - option to be registerd.
203 mike  1.5 	@throw NullPointer excpetion is option argument is null.
204           	@throw DuplicateOption is option already defined.
205               */
206               void registerOption(Option* option);
207           
208               /** Provides a simple way to register several options at once using
209           	a declartive style table. This may also be done programmitically
210           	by repeatedly calling registerOption above. See documentation for
211           	OptionRow for details on how to use them.
212 mike  1.1     */
213 mike  1.5     void registerOptions(OptionRow* options, Uint32 numOptions);
214 mike  1.1 
215               /** Merge option values from the command line. Searches the command 
216           	line for registered options whose names are given by the
217           	Option::getCommandLineOptionName() method. Validation is performed
218           	on each option value obtained by calling Option::isValid(). Valid
219           	option values are set by calling Option::setValue(). The argc and
220           	argv arguments are modified: the option and its argument are 
221           	stripped from the command line. The option and its argument have the
222           	following form: -option-name argument. A space must be supplied
223           	between the two. Boolean option arguments are an exception. They
224           	must have the form -option. If they are present, then they are
225           	taken to be true.
226           
227           	&param argc - number of argument on the command line.
228           	&param argv - list of command line arguments.
229 mike  1.5 	&throw InvalidOptionValue when validation fails.
230 mike  1.4 	&throw MissingCommandLineOptionArgument
231 mike  1.1     */
232               void mergeCommandLine(int& argc, char**& argv);
233           
234               /** Merge option values from the environment. Searches the environment
235           	for registered options whose names are given by the
236           	Option::getEnvironmentVariableName() method. Validation is performed
237           	on each option value  obtained by calling Option::isValid(). Valid
238           	option values are set by calling Option::setValue().
239           
240           	&throw BadEnvironmentOption when validation fails.
241               */
242               void mergeEnvironment();
243           
244               /** Merge option values from a file. Searches file for registered options
245           	whose names are given by the Option::getEnvironmentVariableName()
246           	method. Validation is performed on each option value by calling
247           	Option::isValid(). Valid option values are set by calling 
248           	Option::setValue().
249           
250           	&param fileName - name of file to be merged.
251           	&throw NoSuchFile
252 mike  1.1 	&throw BadConfigFileOption
253               */
254               void mergeFile(const String& fileName);
255           
256               /** After merging, this method is called to check for required options
257           	that were not merged (specified).
258           
259           	&throw UnspecifiedRequiredOption
260               */
261               void checkRequiredOptions() const;
262           
263 mike  1.2     /** Lookup the option with the given name.
264 mike  1.4 	@return 0 if no such option.
265 mike  1.2     */
266 mike  1.4     const Option* lookupOption(const String& name) const;
267 mike  1.3 
268 mike  1.6     /** Lookup value of an option.
269               */
270               Boolean lookupValue(const String& name, String& value) const;
271           
272 mike  1.3     /** Print all the options. */
273               void print() const;
274 mike  1.2 
275 mike  1.1 private:
276           
277 mike  1.4     /** Lookup the option by its commandLineOptionName.
278           	@return 0 if no such option.
279               */
280               Option* _lookupOptionByCommandLineOptionName(const String& name);
281           
282 mike  1.6     /** Lookup the option by its configFileOptionName.
283           	@return 0 if no such option.
284               */
285               Option* _lookupOptionByConfigFileOptionName(const String& name);
286           
287 mike  1.1     Array<Option*> _options;
288           };
289           
290           /** The Option class is used to specify information about an Option.
291           
292               See the OptionManager class for more details.
293           */
294 mike  1.2 class PEGASUS_COMMON_LINKAGE Option
295 mike  1.1 {
296           public:
297           
298               /** Valid value types. */
299 mike  1.5     enum Type 
300               {
301           	// (..., -3, -2, -1, 0, 1, 2, 3, ...)
302           	INTEGER, 
303           
304           	// (1, 2, 3, ...)
305           	NATURAL_NUMBER, 
306           
307           	// (0, 1, 2, 3, ...)
308           	WHOLE_NUMBER, 
309           
310           	// "true" or "false"
311           	BOOLEAN, 
312           
313           	// Anything
314           	STRING
315               };
316 mike  1.1 
317               // Hack to fix bug in MSVC.
318               typedef Array<String> StringArray;
319           
320               /** Constructor.
321           
322           	@param optionName - the name of this option.
323           
324           	@param defaultValue - the default value of this option.
325           
326           	@param required - whether the value of this option is required.
327           
328           	@param type - type of the value. This is used to validate the value.
329           
330           	@param domain - list of legal value for this option. If this list
331           	    is empty, then no domain is enforced.
332           
333           	@param environmentVariableName - name of the corresponding environment
334           	    variable (which may be different from the option name).
335           
336 mike  1.6 	@param configFileOptionName - name of the corresponding variable
337 mike  1.1 	    in the config file (which may be different from the option name).
338           
339           	@param commandLineOptionName - name of the corresponding command line
340           	    option (which may be different from the option name).
341               */
342               Option(
343                   const String& optionName,
344                   const String& defaultValue,
345                   Boolean required,
346                   Type type,
347                   const StringArray& domain = StringArray(),
348                   const String& environmentVariableName = String(),
349 mike  1.6         const String& configFileOptionName = String(),
350 mike  1.2         const String& commandLineOptionName = String());
351           
352               Option(const Option& x);
353 mike  1.1 
354               virtual ~Option();
355           
356 mike  1.2     Option& operator=(const Option& x);
357 mike  1.1 
358               /** Accessor */
359               const String& getOptionName() const
360               {
361                   return _optionName;
362               }
363           
364               /** Modifier */
365               void setOptionName(const String& optionName)
366               {
367                   _optionName = optionName;
368               }
369           
370               /** Accessor */
371               const String& getDefaultValue() const
372               {
373                   return _defaultValue;
374               }
375           
376               /** Modifier. */
377               void setDefaultValue(const String& defaultValue)
378 mike  1.1     {
379                   _defaultValue = defaultValue;
380               }
381           
382               /** Accessor */
383               const String& getValue() const
384               {
385                   return _value;
386               }
387           
388               /** Modifier */
389               void setValue(const String& value)
390               {
391                   _value = value;
392               }
393           
394               /** Accessor */
395               Boolean getRequired() const
396               {
397                   return _required;
398               }
399 mike  1.1 
400               /** Modifier */
401               void setRequired(Boolean required)
402               {
403                   _required = required;
404               }
405           
406               /** Accessor */
407               Type getType() const
408               {
409                   return _type;
410               }
411           
412               /** Modifier */
413               void setType(Type type)
414               {
415                   _type = type;
416               }
417           
418               /** Accessor */
419               const StringArray& getDomain() const
420 mike  1.1     {
421                   return _domain;
422               }
423           
424               /** Modifier */
425               void setDomain(const StringArray& domain)
426               {
427                   _domain = domain;
428               }
429           
430               /** Accessor */
431               const String& getEnvironmentVariableName() const
432               {
433                   return _environmentVariableName;
434               }
435           
436               /** Modifier */
437               void setEnvironmentVariableName(const String& environmentVariableName)
438               {
439                   _environmentVariableName = environmentVariableName;
440               }
441 mike  1.1 
442               /** Accessor */
443 mike  1.6     const String& getConfigFileOptionName() const
444 mike  1.1     {
445 mike  1.6         return _configFileOptionName;
446 mike  1.1     }
447           
448               /** Modifier */
449 mike  1.6     void setConfigFileOptionName(const String& configFileOptionName)
450 mike  1.1     {
451 mike  1.6         _configFileOptionName = configFileOptionName;
452 mike  1.1     }
453           
454               /** Accessor */
455               const String& getCommandLineOptionName() const
456               {
457                   return _commandLineOptionName;
458               }
459           
460               /** Modifier */
461               void setCommandLineOptionName(const String& commandLineOptionName)
462               {
463                   _commandLineOptionName = commandLineOptionName;
464               }
465           
466               /** Accesor. Returns true if an option value was ever obtained for 
467           	this option.
468               */
469               Boolean foundValue() const 
470               { 
471           	return _foundValue; 
472               }
473 mike  1.1 
474               /** Checks to see if the given value is valid or not. This method may be
475           	overriden by derived classes to do special purpose validation of the
476           	value. This implementation just checks the domain and type.
477               */
478               virtual Boolean isValid(const String& value) const;
479           
480           private:
481               String _optionName;
482               String _defaultValue;
483               String _value;
484               Boolean _required;
485               Type _type;
486               StringArray _domain;
487               String _environmentVariableName;
488 mike  1.6     String _configFileOptionName;
489 mike  1.1     String _commandLineOptionName;
490               Boolean _foundValue;
491 mike  1.4 };
492           
493 mike  1.5 /** The OptionRow provides a declarative way of defining Option objects.
494               For the declarative programming enthusiast, we provide this structure.
495               It provides a declarative way of defining options for the OptionManager
496               class. Some developers prefer this since it makes all the options visible
497               in a kind of table like structure. Here is an example of how it can be
498               used to define a port number and hostname options. We also show how to
499               register one of these option lists with an OptionManager.
500           
501               <pre>
502           	static OptionRow options[] =
503           	{
504           	    { "port", "80", false, Option::NATURAL_NUMBER },
505           	    { "hostname", "", true, Option::STRING }
506           	};
507           
508           	...
509           
510           	OptionManager om;
511           	om.registerOptions(options, sizeof(options) / sizeof(options[0]));
512               </pre>
513           
514 mike  1.5     Recall that static memory areas are initialized with zeros so that the
515               members that are not initialized explicitly in the example above are
516               initialized implicitly with zeros (which the OptionManager used to
517               determine that they are not used).
518           
519               It is possible to specify domains as well. For example, suppose we
520               want to define a "color" option that can be in the following set:
521               {"red", "green", "blue"}. Here is how to express that:
522           
523               <pre>
524           	static const char* colors[] = { "red", "green", "blue" };
525           
526           	static OptionRow options[] = 
527           	{
528           	    { "color", "red", false, Option::STRING, colors, 3 }
529           	};
530               </pre>
531           */
532           struct OptionRow
533           {
534               const char* optionName;
535 mike  1.5     const char* defaultValue;
536               Boolean required;
537               Option::Type type;
538               char** domain;
539               Uint32 domainSize;
540               const char* environmentVariableName;
541 mike  1.6     const char* configFileOptionName;
542 mike  1.5     const char* commandLineOptionName;
543           };
544           
545           /** Exception class */
546 mike  1.4 class MissingCommandLineOptionArgument : public Exception
547           {
548           public:
549           
550               MissingCommandLineOptionArgument(const String& optionName)
551           	: Exception("Missing command line option argument: " + optionName) { }
552           };
553           
554 mike  1.5 /** Exception class */
555           class InvalidOptionValue : public Exception
556           {
557           public:
558           
559               InvalidOptionValue(const String& name, const String& value)
560           	: Exception("Invalid option value: " + name + "=\"" + value + "\"") { }
561           };
562           
563           /** Exception class */
564           class DuplicateOption : public Exception
565 mike  1.4 {
566           public:
567           
568 mike  1.5     DuplicateOption(const String& name)
569           	: Exception("Duplicate option: " + name) { }
570 mike  1.6 };
571           
572           /** Exception class */
573           class ConfigFileSyntaxError : public Exception
574           {
575           public:
576           
577               ConfigFileSyntaxError(const String& file, Uint32 line)
578           	: Exception(_formatMessage(file, line)) { }
579           
580               static String _formatMessage(const String& file, Uint32 line);
581           };
582           
583           /** Exception class */
584           class UnrecognizedConfigFileOption : public Exception
585           {
586           public:
587           
588               UnrecognizedConfigFileOption(const String& name)
589           	: Exception("Unrecognized config file option: " + name) { }
590 mike  1.1 };
591           
592           PEGASUS_NAMESPACE_END
593           
594           #endif /* Pegasus_OptionManager_h */

No CVS admin address has been configured
Powered by
ViewCVS 0.9.2