//
// Application.cpp
//
// $Id: //poco/Main/Util/src/Application.cpp#4 $
//
// Copyright (c) 2004-2005, Guenter Obiltschnig/Applied Informatics.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// 3. Redistributions in any form must be accompanied by information on
// how to obtain complete source code for this software and any
// accompanying software that uses this software. The source code
// must either be included in the distribution or be available for no
// more than the cost of distribution plus a nominal fee, and must be
// freely redistributable under reasonable conditions. For an
// executable file, complete source code means the source code for all
// modules it contains. It does not include source code for modules or
// files that typically accompany the major components of the operating
// system on which the executable file runs.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
// COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
#include "Util/Application.h"
#include "Util/SystemConfiguration.h"
#include "Util/MapConfiguration.h"
#include "Util/PropertyFileConfiguration.h"
#include "Util/IniFileConfiguration.h"
#include "Util/XMLConfiguration.h"
#include "Util/LoggingSubsystem.h"
#include "Util/Option.h"
#include "Util/OptionProcessor.h"
#include "Foundation/Environment.h"
#include "Foundation/Exception.h"
#include "Foundation/NumberFormatter.h"
#include "Foundation/File.h"
#include "Foundation/Path.h"
#include "Foundation/String.h"
#include "Foundation/ConsoleChannel.h"
#include "Foundation/AutoPtr.h"
#if defined(POCO_OS_FAMILY_WINDOWS)
#include
#endif
#if defined(POCO_OS_FAMILY_UNIX)
#include "Foundation/SignalHandler.h"
#endif
using Foundation::Logger;
using Foundation::Path;
using Foundation::File;
using Foundation::Environment;
using Foundation::SystemException;
using Foundation::ConsoleChannel;
using Foundation::NumberFormatter;
using Foundation::AutoPtr;
using Foundation::icompare;
Util_BEGIN
Application* Application::_pInstance = 0;
Application::Application():
_pConfig(new LayeredConfiguration),
_initialized(false),
_logger(Logger::get("Application")),
_unixOptions(true)
{
setup();
}
Application::Application(int argc, char* argv[]):
_pConfig(new LayeredConfiguration),
_initialized(false),
_logger(Logger::get("Application")),
_unixOptions(true)
{
setup();
init(argc, argv);
}
Application::~Application()
{
try
{
uninitialize();
}
catch (...)
{
}
_pInstance = 0;
}
void Application::setup()
{
poco_assert (_pInstance == 0);
_pConfig->add(new SystemConfiguration);
_pConfig->add(new MapConfiguration);
addSubsystem(new LoggingSubsystem);
#if defined(POCO_OS_FAMILY_UNIX)
#if !defined(_DEBUG)
Foundation::SignalHandler::install();
#endif
#else
setUnixOptions(false);
#endif
_pInstance = this;
AutoPtr pCC = new ConsoleChannel;
_logger.setChannel(pCC);
}
void Application::addSubsystem(Subsystem* pSubsystem)
{
poco_check_ptr (pSubsystem);
_subsystems.push_back(pSubsystem);
}
void Application::init(int argc, char* argv[])
{
setArgs(argc, argv);
Path appPath;
getApplicationPath(appPath);
_pConfig->setString("application.path", appPath.toString());
_pConfig->setString("application.name", appPath.getFileName());
_pConfig->setString("application.baseName", appPath.getBaseName());
_pConfig->setString("application.dir", appPath.parent().toString());
processOptions();
initialize(*this);
_initialized = true;
}
const char* Application::name() const
{
return "Application";
}
void Application::initialize(const Application& self)
{
for (SubsystemVec::iterator it = _subsystems.begin(); it != _subsystems.end(); ++it)
{
_logger.debug(std::string("Initializing subsystem: ") + (*it)->name());
(*it)->initialize(self);
}
}
void Application::uninitialize()
{
if (_initialized)
{
for (SubsystemVec::reverse_iterator it = _subsystems.rbegin(); it != _subsystems.rend(); ++it)
{
_logger.debug(std::string("Uninitializing subsystem: ") + (*it)->name());
(*it)->uninitialize();
}
}
}
void Application::reinitialize(const Application& self)
{
for (SubsystemVec::iterator it = _subsystems.begin(); it != _subsystems.end(); ++it)
{
_logger.debug(std::string("Re-initializing subsystem: ") + (*it)->name());
(*it)->reinitialize(self);
}
}
void Application::setUnixOptions(bool flag)
{
_unixOptions = flag;
}
int Application::loadConfiguration()
{
int n = 0;
Path appPath;
getApplicationPath(appPath);
appPath.setExtension("properties");
if (File(appPath).exists())
{
_pConfig->add(new PropertyFileConfiguration(appPath.toString()));
++n;
}
appPath.setExtension("ini");
if (File(appPath).exists())
{
_pConfig->add(new IniFileConfiguration(appPath.toString()));
++n;
}
appPath.setExtension("xml");
if (File(appPath).exists())
{
_pConfig->add(new XMLConfiguration(appPath.toString()));
++n;
}
return n;
}
void Application::loadConfiguration(const std::string& path)
{
Path confPath(path);
std::string ext = confPath.getExtension();
if (icompare(ext, "properties") == 0)
_pConfig->add(new PropertyFileConfiguration(confPath.toString()));
else if (icompare(ext, "ini") == 0)
_pConfig->add(new IniFileConfiguration(confPath.toString()));
else if (icompare(ext, "xml") == 0)
_pConfig->add(new XMLConfiguration(confPath.toString()));
else
throw Foundation::InvalidArgumentException("Unsupported configuration file type", ext);
}
std::string Application::commandName() const
{
return _pConfig->getString("application.baseName");
}
int Application::run()
{
try
{
return main(_args);
}
catch (Foundation::Exception& exc)
{
logger().log(exc);
return EXIT_SOFTWARE;
}
}
int Application::main(const std::vector& args)
{
return EXIT_OK;
}
void Application::setArgs(int argc, char* argv[])
{
_command = argv[0];
_pConfig->setInt("application.argc", argc);
_args.reserve(argc);
std::string argvKey = "application.argv[";
for (int i = 0; i < argc; ++i)
{
std::string arg(argv[i]);
_pConfig->setString(argvKey + NumberFormatter::format(i) + "]", arg);
_args.push_back(arg);
}
}
void Application::processOptions()
{
defineOptions(_options);
OptionProcessor processor(_options);
processor.setUnixStyle(_unixOptions);
ArgVec::iterator it = _args.begin();
_args.erase(it);
while (it != _args.end())
{
std::string name;
std::string value;
if (processor.process(*it, name, value))
{
handleOption(name, value);
_args.erase(it);
}
else ++it;
}
}
void Application::getApplicationPath(Foundation::Path& appPath)
{
#if defined(POCO_OS_FAMILY_UNIX)
if (_command.find('/') != std::string::npos)
{
Path path(_command);
if (path.isAbsolute())
{
appPath = path;
}
else
{
appPath = Path::current();
appPath.append(path);
}
}
else
{
if (!Path::find(Environment::get("PATH"), _command, appPath))
appPath = Path(Path::current(), _command);
}
#elif defined(POCO_OS_FAMILY_WINDOWS)
char path[1024];
int n = GetModuleFileName(0, path, sizeof(path));
if (n > 0)
appPath = path;
else
throw SystemException("Cannot get application file name.");
#else
appPath = _command;
#endif
}
void Application::defineOptions(OptionSet& options)
{
}
void Application::handleOption(const std::string& name, const std::string& value)
{
}
Util_END