X-Git-Url: https://git.teslayout.com/public/public/public/?a=blobdiff_plain;f=source%2Fdbms%2FDatabase.cpp;fp=source%2Fdbms%2FDatabase.cpp;h=987038f4b97d399fcb201696eeb8622711063c10;hb=78be86969d2f26a9084b0c4af6ce43d5fa4ed3fd;hp=0000000000000000000000000000000000000000;hpb=a3b95648bd76140ef55e0b5941d423eee6c3856f;p=anna.git diff --git a/source/dbms/Database.cpp b/source/dbms/Database.cpp new file mode 100644 index 0000000..987038f --- /dev/null +++ b/source/dbms/Database.cpp @@ -0,0 +1,325 @@ +// ANNA - Anna is Not Nothingness Anymore // +// // +// (c) Copyright 2005-2015 Eduardo Ramos Testillano & Francisco Ruiz Rayo // +// // +// See project site at http://redmine.teslayout.com/projects/anna-suite // +// See accompanying file LICENSE or copy at http://www.teslayout.com/projects/public/anna.LICENSE // + + +#include +#include + +#include +#include + +#include + +#include +#include + +#include + +#include +#include +#include +#include +#include +#include + +using namespace std; +using namespace anna; +using namespace anna::dbms; + +Database::Database(const char* className, const char* dbmsName) : + Component(className), + a_name((dbmsName == NULL) ? "local" : dbmsName), + a_type((dbmsName == NULL) ? Type::Local : Type::Remote), + a_failRecoveryHandler(NULL), + a_statementTranslator(NULL) { + dbms::sccs::activate(); +} + +Database::~Database() { + stop(); +} + +void Database::do_initialize() +throw(RuntimeException) { + LOGMETHOD(TraceMethod tm("dbms::Database", "do_initialize", ANNA_FILE_LOCATION)); + int counter(0); + bool error = false; + + for(connection_iterator iic = connection_begin(), maxiic = connection_end(); iic != maxiic; iic ++) { + try { + connection(iic)->open(); + counter ++; + } catch(Exception& ex) { + ex.trace(); + error = true; + } + } + + if(counter == 0 && error == true) { + string msg(asString()); + msg += " | No available connections"; + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + + LOGINFORMATION( + Logger::information(asString(), ANNA_FILE_LOCATION); + ); +} + +void Database::do_stop() +throw() { + LOGMETHOD(TraceMethod tm("dbms::Database", "do_stop", ANNA_FILE_LOCATION)); + + try { + Connection* _connection; + + for(connection_iterator iic = connection_begin(), maxiic = connection_end(); iic != maxiic; iic ++) { + _connection = connection(iic); + _connection->close(); + delete _connection; + } + + a_connections.clear(); + } catch(Exception& ex) { + ex.trace(); + a_connections.clear(); + } +} + +/** + * Para evitar que todos los clones usen la misma conexion a la base de datos, se realiza en + * cada uno de ellos una re-conexion, es decir, se cierra la original (abierta por el proceso + * padre) y se abre una nueva conexion con los mismos parametros y contra la misma base de datos. + */ +void Database::do_cloneChild() +throw(RuntimeException) { + LOGMETHOD(TraceMethod tm("dbms::Database", "do_cloneChild", ANNA_FILE_LOCATION)); + + for(connection_iterator ii = connection_begin(), maxii = connection_end(); ii != maxii; ii ++) { + dbms::Connection* conn = connection(ii); + LOGDEBUG( + string msg("dbms::Database::do_cloneChild | "); + msg += conn->asString(); + Logger::debug(msg, ANNA_FILE_LOCATION); + ); + recover(*conn, 0); + } +} + +Connection* Database::createConnection(const char* name, const char* user, const char* password) +throw(RuntimeException, DatabaseException) { + Guard guard(this, "dbms::Database (createConnection)"); + + if(a_connections.size() >= MaxConnection) { + string msg("Database::createConnection | "); + msg += asString(); + msg += functions::asText(" | Cannot create more than %d connections per database", MaxConnection); + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + + for(connection_iterator ii = connection_begin(), maxii = connection_end(); ii != maxii; ii ++) { + if(connection(ii)->getName() == name) { + string msg("Database::createConnection | "); + msg += asString(); + msg += " | Connection: "; + msg += name; + msg += " | Previously registered"; + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + } + + string strname(name); + Connection* result = allocateConnection(strname, user, password); + + if(result == NULL) { + string msg(asString()); + msg += " | "; + msg += strname; + msg += " | Unable to instance connection"; + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + + LOGDEBUG( + string msg("dbms::Database::createConnection | "); + msg += result->asString(); + Logger::write(Logger::Debug, msg, ANNA_FILE_LOCATION); + ); + + if(getState() == Component::State::Running) { + try { + result->open(); + a_connections.push_back(result); + } catch(RuntimeException& ex) { + ex.trace(); + delete result; + throw; + } catch(DatabaseException& edbms) { + edbms.trace(); + delete result; + throw; + } + } else + a_connections.push_back(result); + + return result; +} + +Connection& Database::findConnection(const char* name) +throw(RuntimeException) { + Guard guard(this, "dbms::Database (findConnection)"); + Connection* result = NULL; + + for(connection_iterator ii = connection_begin(), maxii = connection_end(); ii != maxii; ii ++) { + if(anna_strcmp(connection(ii)->getName().c_str(), name) == 0) { + result = connection(ii); + break; + } + } + + if(result == NULL) { + string msg("Database::findConnection | "); + msg += asString(); + msg += " | Conexion: "; + msg += name; + msg += " | Unregistered"; + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + + if(result->isAvailable() == false || result->isEnabled() == false) { + string msg("Database::findConnection | "); + msg += asString(); + msg += " | Connection: "; + msg += name; + msg += " | Unavailable"; + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + + LOGDEBUG( + string msg("Database::findConnection | "); + msg += result->asString(); + Logger::debug(msg, ANNA_FILE_LOCATION); + ); + return *result; +} + +Statement* Database::createStatement(const char* name, const char* expression, const bool isCritical) +throw(RuntimeException) { + if(findStatement(name) != NULL) + throw RuntimeException(functions::asString("Sentence: %s | Name already in use", name), ANNA_FILE_LOCATION); + + Guard guard(this, "dbms::Database::createStatement"); + + if(a_statementTranslator != NULL) + expression = a_statementTranslator->apply(expression); + + Statement* result = allocateStatement(name, expression, isCritical); + LOGDEBUG( + string msg("dbms::Database::createStatement | "); + msg += result->asString(); + + if(a_statementTranslator != NULL) { + msg += " | Translator: "; + msg += a_statementTranslator->getName(); + } + Logger::debug(msg, ANNA_FILE_LOCATION); + ); + a_statements.push_back(result); + return result; +} + +Statement* Database::findStatement(const char* name) +throw() { + Guard guard(this, "dbms::Database::findStatement"); + vector ::iterator ii, maxii; + Statement* result(NULL); + + for(ii = a_statements.begin(), maxii = a_statements.end(); ii != maxii; ii ++) { + if(anna_strcmp((*ii)->getName().c_str(), name) == 0) { + result = *ii; + break; + } + } + + return result; +} + +void Database::releaseStatement(Statement* statement) +throw() { + if(statement == NULL) { + Logger::write(Logger::Warning, asString(), "Cannot release a NULL SQL sentence", ANNA_FILE_LOCATION); + return; + } + + LOGDEBUG( + string msg("dbms::Database::releaseStatement | "); + msg += statement->asString(); + Logger::debug(msg, ANNA_FILE_LOCATION); + ); + Guard guard(this, "dbms::Database::releaseStatement"); + vector ::iterator end = a_statements.end(); + vector ::iterator ii = find(a_statements.begin(), end, statement); + + if(ii != end) { + a_statements.erase(ii); + delete statement; + } +} + +void Database::recover(Connection& connection, const int tryCounter) +throw(RuntimeException) { + try { + connection.close(); + connection.open(); + } catch(DatabaseException& edbms) { + edbms.trace(); + + if(a_failRecoveryHandler != NULL) + a_failRecoveryHandler->apply(connection, tryCounter); + } +} + +string Database::asString() const +throw() { + string result("dbms::Database { "); + result += Component::asString(); + + if(a_type == Type::Local) + result += " | Type: Local"; + else { + result += " | Type: Remote | Name: "; + result += a_name; + } + + return result += " }"; +} + +xml::Node* Database::asXML(xml::Node* parent) const +throw() { + parent = Component::asXML(parent); + xml::Node* result = parent->createChild("dbms.Database"); + xml::Node* node; + result->createAttribute("Type", (a_type == Type::Local) ? "Local" : "Remote"); + + if(a_type != Type::Local) + result->createAttribute("Name", a_name); + + if(a_statementTranslator != NULL) + result->createAttribute("Translator", a_statementTranslator->getName()); + + node = result-> createChild("Connections"); + + for(const_connection_iterator ii = connection_begin(), maxii = connection_end(); ii != maxii; ii ++) + connection(ii)->asXML(node); + + node = result-> createChild("Statements"); + + for(const_statement_iterator ii = statement_begin(), maxii = statement_end(); ii != maxii; ii ++) + statement(ii)->asXML(node); + + return result; +} +