1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
|
//
// Application.h
//
// Library: Util
// Package: Application
// Module: Application
//
// Definition of the Application class.
//
// Copyright (c) 2004-2006, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#ifndef Util_Application_INCLUDED
#define Util_Application_INCLUDED
#include "Poco/Util/Util.h"
#include "Poco/Util/Subsystem.h"
#include "Poco/Util/LayeredConfiguration.h"
#include "Poco/Util/OptionSet.h"
#include "Poco/AutoPtr.h"
#include "Poco/Logger.h"
#include "Poco/Path.h"
#include "Poco/Timestamp.h"
#include "Poco/Timespan.h"
#include "Poco/AutoPtr.h"
#if defined(POCO_VXWORKS)
#include <cstdarg>
#endif
#include <vector>
#include <typeinfo>
namespace Poco {
namespace Util {
class OptionSet;
class Util_API Application: public Subsystem
/// The Application class implements the main subsystem
/// in a process. The application class is responsible for
/// initializing all its subsystems.
///
/// Subclasses can and should override the following virtual methods:
/// - initialize() (the one-argument, protected variant)
/// - uninitialize()
/// - reinitialize()
/// - defineOptions()
/// - handleOption()
/// - main()
///
/// The application's main logic should be implemented in
/// the main() method.
///
/// There may be at most one instance of the Application class
/// in a process.
///
/// The Application class maintains a LayeredConfiguration (available
/// via the config() member function) consisting of:
/// - a MapConfiguration (priority -100) storing application-specific
/// properties, as well as properties from bound command line arguments.
/// - a SystemConfiguration (priority 100)
/// - the configurations loaded with loadConfiguration().
///
/// The Application class sets a few default properties in
/// its configuration. These are:
/// - application.path: the absolute path to application executable
/// - application.name: the file name of the application executable
/// - application.baseName: the file name (excluding extension) of the application executable
/// - application.dir: the path to the directory where the application executable resides
/// - application.configDir: the path to the directory where user specific configuration files of the application should be stored.
/// - application.cacheDir: the path to the directory where user specific non-essential data files of the application should be stored.
/// - application.dataDir: the path to the directory where user specific data files of the application should be stored.
/// - application.tempDir: the path to the directory where user specific temporary files and other file objects of the application should be stored.
///
/// If loadConfiguration() has never been called, application.configDir will be equal to application.dir.
///
/// The POCO_APP_MAIN macro can be used to implement main(argc, argv).
/// If POCO has been built with POCO_WIN32_UTF8, POCO_APP_MAIN supports
/// Unicode command line arguments.
{
public:
typedef std::vector<std::string> ArgVec;
typedef Poco::AutoPtr<Subsystem> SubsystemPtr;
typedef std::vector<SubsystemPtr> SubsystemVec;
enum ExitCode
/// Commonly used exit status codes.
/// Based on the definitions in the 4.3BSD <sysexits.h> header file.
{
EXIT_OK = 0, /// successful termination
EXIT_USAGE = 64, /// command line usage error
EXIT_DATAERR = 65, /// data format error
EXIT_NOINPUT = 66, /// cannot open input
EXIT_NOUSER = 67, /// addressee unknown
EXIT_NOHOST = 68, /// host name unknown
EXIT_UNAVAILABLE = 69, /// service unavailable
EXIT_SOFTWARE = 70, /// internal software error
EXIT_OSERR = 71, /// system error (e.g., can't fork)
EXIT_OSFILE = 72, /// critical OS file missing
EXIT_CANTCREAT = 73, /// can't create (user) output file
EXIT_IOERR = 74, /// input/output error
EXIT_TEMPFAIL = 75, /// temp failure; user is invited to retry
EXIT_PROTOCOL = 76, /// remote error in protocol
EXIT_NOPERM = 77, /// permission denied
EXIT_CONFIG = 78 /// configuration error
};
enum ConfigPriority
{
PRIO_APPLICATION = -100,
PRIO_DEFAULT = 0,
PRIO_SYSTEM = 100
};
Application();
/// Creates the Application.
Application(int argc, char* argv[]);
/// Creates the Application and calls init(argc, argv).
void addSubsystem(Subsystem* pSubsystem);
/// Adds a new subsystem to the application. The
/// application immediately takes ownership of it, so that a
/// call in the form
/// Application::instance().addSubsystem(new MySubsystem);
/// is okay.
void init(int argc, char* argv[]);
/// Processes the application's command line arguments
/// and sets the application's properties (e.g.,
/// "application.path", "application.name", etc.).
///
/// Note that as of release 1.3.7, init() no longer
/// calls initialize(). This is now called from run().
#if defined(POCO_WIN32_UTF8) && !defined(POCO_NO_WSTRING)
void init(int argc, wchar_t* argv[]);
/// Processes the application's command line arguments
/// and sets the application's properties (e.g.,
/// "application.path", "application.name", etc.).
///
/// Note that as of release 1.3.7, init() no longer
/// calls initialize(). This is now called from run().
///
/// This Windows-specific version of init is used for passing
/// Unicode command line arguments from wmain().
#endif
void init(const ArgVec& args);
/// Processes the application's command line arguments
/// and sets the application's properties (e.g.,
/// "application.path", "application.name", etc.).
///
/// Note that as of release 1.3.7, init() no longer
/// calls initialize(). This is now called from run().
bool initialized() const;
/// Returns true iff the application is in initialized state
/// (that means, has been initialized but not yet uninitialized).
void setUnixOptions(bool flag);
/// Specify whether command line option handling is Unix-style
/// (flag == true; default) or Windows/OpenVMS-style (flag == false).
///
/// This member function should be called from the constructor of
/// a subclass to be effective.
int loadConfiguration(int priority = PRIO_DEFAULT);
/// Loads configuration information from a default location.
///
/// The configuration(s) will be added to the application's
/// LayeredConfiguration with the given priority.
///
/// The configuration file(s) must be located in the same directory
/// as the executable or a parent directory of it, and must have the
/// same base name as the executable, with one of the following extensions:
/// .properties, .ini or .xml.
///
/// The .properties file, if it exists, is loaded first, followed
/// by the .ini file and the .xml file.
///
/// If the application is built in debug mode (the _DEBUG preprocessor
/// macro is defined) and the base name of the appication executable
/// ends with a 'd', a config file without the 'd' ending its base name is
/// also found.
///
/// Example: Given the application "SampleAppd.exe", built in debug mode.
/// Then loadConfiguration() will automatically find a configuration file
/// named "SampleApp.properties" if it exists and if "SampleAppd.properties"
/// cannot be found.
///
/// Returns the number of configuration files loaded, which may be zero.
///
/// This method must not be called before init(argc, argv)
/// has been called.
void loadConfiguration(const std::string& path, int priority = PRIO_DEFAULT);
/// Loads configuration information from the file specified by
/// the given path. The file type is determined by the file
/// extension. The following extensions are supported:
/// - .properties - properties file (PropertyFileConfiguration)
/// - .ini - initialization file (IniFileConfiguration)
/// - .xml - XML file (XMLConfiguration)
///
/// Extensions are not case sensitive.
///
/// The configuration will be added to the application's
/// LayeredConfiguration with the given priority.
template <class C> C& getSubsystem() const;
/// Returns a reference to the subsystem of the class
/// given as template argument.
///
/// Throws a NotFoundException if such a subsystem has
/// not been registered.
SubsystemVec& subsystems();
/// Returns a reference to the subsystem list
virtual int run();
/// Runs the application by performing additional (un)initializations
/// and calling the main() method.
///
/// First calls initialize(), then calls main(), and
/// finally calls uninitialize(). The latter will be called
/// even if main() throws an exception. If initialize() throws
/// an exception, main() will not be called and the exception
/// will be propagated to the caller. If uninitialize() throws
/// an exception, the exception will be propagated to the caller.
std::string commandName() const;
/// Returns the command name used to invoke the application.
std::string commandPath() const;
/// Returns the full command path used to invoke the application.
LayeredConfiguration& config() const;
/// Returns the application's configuration.
Poco::Logger& logger() const;
/// Returns the application's logger.
///
/// Before the logging subsystem has been initialized, the
/// application's logger is "ApplicationStartup", which is
/// connected to a ConsoleChannel.
///
/// After the logging subsystem has been initialized, which
/// usually happens as the first action in Application::initialize(),
/// the application's logger is the one specified by the
/// "application.logger" configuration property. If that property
/// is not specified, the logger is "Application".
const ArgVec& argv() const;
/// Returns reference to vector of the application's arguments as
/// specified on the command line. If user overrides the
/// Application::main(const ArgVec&) function, it will receive
/// only the command line parameters that were not processed in
/// Application::processOptons(). This function returns the
/// full set of command line parameters as received in
/// main(argc, argv*).
const OptionSet& options() const;
/// Returns the application's option set.
static Application& instance();
/// Returns a reference to the Application singleton.
///
/// Throws a NullPointerException if no Application instance exists.
const Poco::Timestamp& startTime() const;
/// Returns the application start time (UTC).
Poco::Timespan uptime() const;
/// Returns the application uptime.
void stopOptionsProcessing();
/// If called from an option callback, stops all further
/// options processing.
///
/// If called, the following options on the command line
/// will not be processed, and required options will not
/// be checked.
///
/// This is useful, for example, if an option for displaying
/// help information has been encountered and no other things
/// besides displaying help shall be done.
const char* name() const;
protected:
void initialize(Application& self);
/// Initializes the application and all registered subsystems.
/// Subsystems are always initialized in the exact same order
/// in which they have been registered.
///
/// Overriding implementations must call the base class implementation.
void uninitialize();
/// Uninitializes the application and all registered subsystems.
/// Subsystems are always uninitialized in reverse order in which
/// they have been initialized.
///
/// Overriding implementations must call the base class implementation.
void reinitialize(Application& self);
/// Re-nitializes the application and all registered subsystems.
/// Subsystems are always reinitialized in the exact same order
/// in which they have been registered.
///
/// Overriding implementations must call the base class implementation.
virtual void defineOptions(OptionSet& options);
/// Called before command line processing begins.
/// If a subclass wants to support command line arguments,
/// it must override this method.
/// The default implementation does not define any options itself,
/// but calls defineOptions() on all registered subsystems.
///
/// Overriding implementations should call the base class implementation.
virtual void handleOption(const std::string& name, const std::string& value);
/// Called when the option with the given name is encountered
/// during command line arguments processing.
///
/// The default implementation does option validation, bindings
/// and callback handling.
///
/// Overriding implementations must call the base class implementation.
void setLogger(Poco::Logger& logger);
/// Sets the logger used by the application.
virtual int main(const std::vector<std::string>& args);
/// The application's main logic.
///
/// Unprocessed command line arguments are passed in args.
/// Note that all original command line arguments are available
/// via the properties application.argc and application.argv[<n>].
///
/// Returns an exit code which should be one of the values
/// from the ExitCode enumeration.
bool findFile(Poco::Path& path) const;
/// Searches for the file in path in the application directory.
///
/// If path is absolute, the method immediately returns true and
/// leaves path unchanged.
///
/// If path is relative, searches for the file in the application
/// directory and in all subsequent parent directories.
/// Returns true and stores the absolute path to the file in
/// path if the file could be found. Returns false and leaves path
/// unchanged otherwise.
void init();
/// Common initialization code.
~Application();
/// Destroys the Application and deletes all registered subsystems.
private:
void setup();
void setArgs(int argc, char* argv[]);
void setArgs(const ArgVec& args);
void getApplicationPath(Poco::Path& path) const;
void processOptions();
bool findAppConfigFile(const std::string& appName, const std::string& extension, Poco::Path& path) const;
bool findAppConfigFile(const Path& basePath, const std::string& appName, const std::string& extension, Poco::Path& path) const;
typedef Poco::AutoPtr<LayeredConfiguration> ConfigPtr;
ConfigPtr _pConfig;
SubsystemVec _subsystems;
bool _initialized;
std::string _command;
ArgVec _argv;
ArgVec _unprocessedArgs;
OptionSet _options;
bool _unixOptions;
Poco::Logger* _pLogger;
Poco::Timestamp _startTime;
bool _stopOptionsProcessing;
#if defined(POCO_OS_FAMILY_UNIX) && !defined(POCO_VXWORKS)
std::string _workingDirAtLaunch;
#endif
static Application* _pInstance;
friend class LoggingSubsystem;
Application(const Application&);
Application& operator = (const Application&);
};
//
// inlines
//
template <class C> C& Application::getSubsystem() const
{
for (SubsystemVec::const_iterator it = _subsystems.begin(); it != _subsystems.end(); ++it)
{
const Subsystem* pSS(it->get());
const C* pC = dynamic_cast<const C*>(pSS);
if (pC) return *const_cast<C*>(pC);
}
throw Poco::NotFoundException("The subsystem has not been registered", typeid(C).name());
}
inline Application::SubsystemVec& Application::subsystems()
{
return _subsystems;
}
inline bool Application::initialized() const
{
return _initialized;
}
inline LayeredConfiguration& Application::config() const
{
return *const_cast<LayeredConfiguration*>(_pConfig.get());
}
inline Poco::Logger& Application::logger() const
{
poco_check_ptr (_pLogger);
return *_pLogger;
}
inline const Application::ArgVec& Application::argv() const
{
return _argv;
}
inline const OptionSet& Application::options() const
{
return _options;
}
inline Application& Application::instance()
{
poco_check_ptr (_pInstance);
return *_pInstance;
}
inline const Poco::Timestamp& Application::startTime() const
{
return _startTime;
}
inline Poco::Timespan Application::uptime() const
{
Poco::Timestamp now;
Poco::Timespan uptime = now - _startTime;
return uptime;
}
} } // namespace Poco::Util
//
// Macro to implement main()
//
#if defined(_WIN32) && defined(POCO_WIN32_UTF8) && !defined(POCO_NO_WSTRING)
#define POCO_APP_MAIN(App) \
int wmain(int argc, wchar_t** argv) \
{ \
Poco::AutoPtr<App> pApp = new App; \
try \
{ \
pApp->init(argc, argv); \
} \
catch (Poco::Exception& exc) \
{ \
pApp->logger().log(exc); \
return Poco::Util::Application::EXIT_CONFIG;\
} \
return pApp->run(); \
}
#elif defined(POCO_VXWORKS)
#define POCO_APP_MAIN(App) \
int pocoAppMain(const char* appName, ...) \
{ \
std::vector<std::string> args; \
args.push_back(std::string(appName)); \
va_list vargs; \
va_start(vargs, appName); \
const char* arg = va_arg(vargs, const char*); \
while (arg) \
{ \
args.push_back(std::string(arg)); \
arg = va_arg(vargs, const char*); \
} \
va_end(vargs); \
Poco::AutoPtr<App> pApp = new App; \
try \
{ \
pApp->init(args); \
} \
catch (Poco::Exception& exc) \
{ \
pApp->logger().log(exc); \
return Poco::Util::Application::EXIT_CONFIG;\
} \
return pApp->run(); \
}
#else
#define POCO_APP_MAIN(App) \
int main(int argc, char** argv) \
{ \
Poco::AutoPtr<App> pApp = new App; \
try \
{ \
pApp->init(argc, argv); \
} \
catch (Poco::Exception& exc) \
{ \
pApp->logger().log(exc); \
return Poco::Util::Application::EXIT_CONFIG;\
} \
return pApp->run(); \
}
#endif
#endif // Util_Application_INCLUDED
|