text: //
  // SQLChannel.cpp
  //
  // Library: Data
  // Package: Logging
  // Module:  SQLChannel
  //
  // Copyright (c) 2006, Applied Informatics Software Engineering GmbH.
  // and Contributors.
  //
  // SPDX-License-Identifier:	BSL-1.0
  //
  
  
  #include "Poco/SQL/SQLChannel.h"
  #include "Poco/SQL/SessionFactory.h"
  #include "Poco/DateTime.h"
  #include "Poco/LoggingFactory.h"
  #include "Poco/Instantiator.h"
  #include "Poco/NumberParser.h"
  #include "Poco/NumberFormatter.h"
  #include "Poco/Format.h"
  
  
  namespace Poco {
  namespace SQL {
  
  
  using namespace Keywords;
  
  
  const std::string SQLChannel::PROP_CONNECTOR("connector");
  const std::string SQLChannel::PROP_CONNECT("connect");
  const std::string SQLChannel::PROP_NAME("name");
  const std::string SQLChannel::PROP_TABLE("table");
  const std::string SQLChannel::PROP_ARCHIVE_TABLE("archive");
  const std::string SQLChannel::PROP_MAX_AGE("keep");
  const std::string SQLChannel::PROP_ASYNC("async");
  const std::string SQLChannel::PROP_TIMEOUT("timeout");
  const std::string SQLChannel::PROP_THROW("throw");
  
  
  SQLChannel::SQLChannel():
  	_name("-"),
  	_table("T_POCO_LOG"),
  	_timeout(1000),
  	_throw(true),
  	_async(true),
  	_pid(),
  	_tid(),
  	_priority()
  {
  }
  
  
  SQLChannel::SQLChannel(const std::string& connector,
  	const std::string& connect,
  	const std::string& name):
  	_connector(connector),
  	_connect(connect),
  	_name(name),
  	_table("T_POCO_LOG"),
  	_timeout(1000),
  	_throw(true),
  	_async(true),
  	_pid(),
  	_tid(),
  	_priority()
  {
  	open();
  }
  
  
  SQLChannel::~SQLChannel()
  {
  	try
  	{
  		close();
  	}
  	catch (...)
  	{
  		poco_unexpected();
  	}
  }
  
  
  void SQLChannel::open()
  {
  	if (_connector.empty() || _connect.empty())
  		throw IllegalStateException("Connector and connect string must be non-empty.");
  
  	_pSession = new Session(_connector, _connect);
  	initLogStatement();
  }
  
  	
  void SQLChannel::close()
  {
  	wait();
  }
  
  
  void SQLChannel::log(const Message& msg)
  {
  	if (_async) logAsync(msg);
  	else logSync(msg);
  }
  
  
  void SQLChannel::logAsync(const Message& msg)
  {
  	poco_check_ptr (_pLogStatement);
  	if (0 == wait() && !_pLogStatement->done() && !_pLogStatement->initialized())
  	{
  		if (_throw)
  			throw TimeoutException("Timed out waiting for previous statement completion");
  		else return;
  	}
  
  	if (!_pSession || !_pSession->isConnected()) open();
  	logSync(msg);
  }
  
  
  void SQLChannel::logSync(const Message& msg)
  {
  	if (_pArchiveStrategy) _pArchiveStrategy->archive();
  
  	_source = msg.getSource();
  	_pid = msg.getPid();
  	_thread = msg.getThread();
  	_tid = msg.getTid();
  	_priority = msg.getPriority();
  	_text = msg.getText();
  	_dateTime = msg.getTime();
  	if (_source.empty()) _source = _name;
  
  	try
  	{
  		_pLogStatement->execute();
  	}
  	catch (Exception&)
  	{
  		if (_throw) throw;
  	}
  }
  
  	
  void SQLChannel::setProperty(const std::string& name, const std::string& value)
  {
  	if (name == PROP_NAME)
  	{
  		_name = value;
  		if (_name.empty()) _name = "-";
  	}
  	else if (name == PROP_CONNECTOR)
  	{
  		_connector = value;
  		close(); open();
  	}
  	else if (name == PROP_CONNECT)
  	{
  		_connect = value;
  		close(); open();
  	}
  	else if (name == PROP_TABLE)
  	{
  		_table = value;
  		initLogStatement();
  	}
  	else if (name == PROP_ARCHIVE_TABLE)
  	{
  		if (value.empty())
  		{
  			_pArchiveStrategy = 0;
  		}
  		else if (_pArchiveStrategy)
  		{
  			_pArchiveStrategy->setDestination(value);
  		}
  		else
  		{
  			_pArchiveStrategy = new ArchiveByAgeStrategy(_connector, _connect, _table, value);
  		}
  	}
  	else if (name == PROP_MAX_AGE)
  	{
  		if (value.empty() || "forever" == value)
  		{
  			_pArchiveStrategy = 0;
  		}
  		else if (_pArchiveStrategy)
  		{
  			_pArchiveStrategy->setThreshold(value);
  		}
  		else
  		{
  			ArchiveByAgeStrategy* p = new ArchiveByAgeStrategy(_connector, _connect, _table);
  			p->setThreshold(value);
  			_pArchiveStrategy = p;
  		}
  	}
  	else if (name == PROP_ASYNC)
  	{
  		_async = isTrue(value);
  		initLogStatement();
  	}
  	else if (name == PROP_TIMEOUT)
  	{
  		if (value.empty() || '0' == value[0])
  			_timeout = Statement::WAIT_FOREVER;
  		else
  			_timeout = NumberParser::parse(value);
  	}
  	else if (name == PROP_THROW)
  	{
  		_throw = isTrue(value);
  	}
  	else
  	{
  		Channel::setProperty(name, value);
  	}
  }
  
  	
  std::string SQLChannel::getProperty(const std::string& name) const
  {
  	if (name == PROP_NAME)
  	{
  		if (_name != "-") return _name;
  		else return "";
  	}
  	else if (name == PROP_CONNECTOR)
  	{
  		return _connector;
  	}
  	else if (name == PROP_CONNECT)
  	{
  		return _connect;
  	}
  	else if (name == PROP_TABLE)
  	{
  		return _table;
  	}
  	else if (name == PROP_ARCHIVE_TABLE)
  	{
  		return _pArchiveStrategy ? _pArchiveStrategy->getDestination() : "" ;
  	}
  	else if (name == PROP_MAX_AGE)
  	{
  		return _pArchiveStrategy ? _pArchiveStrategy->getThreshold() : "forever";
  	}
  	else if (name == PROP_TIMEOUT)
  	{
  		return NumberFormatter::format(_timeout);
  	}
  	else if (name == PROP_THROW)
  	{
  		if (_throw) return "true";
  		else return "false";
  	}
  	else
  	{
  		return Channel::getProperty(name);
  	}
  }
  
  
  void SQLChannel::initLogStatement()
  {
  	_pLogStatement = new Statement(*_pSession);
  
  	std::string sql;
  	Poco::format(sql, "INSERT INTO %s VALUES (?,?,?,?,?,?,?,?)", _table);
  	*_pLogStatement << sql,
  		use(_source),
  		use(_name),
  		use(_pid),
  		use(_thread),
  		use(_tid),
  		use(_priority),
  		use(_text),
  		use(_dateTime);
  
  	if (_async) _pLogStatement->setAsync();
  }
  
  
  void SQLChannel::registerChannel()
  {
  	Poco::LoggingFactory::defaultFactory().registerChannelClass("SQLChannel",
  		new Poco::Instantiator<SQLChannel, Poco::Channel>);
  }
  
  
  } } // namespace Poco::SQL
  