1 // ANNA - Anna is Not Nothingness Anymore //
3 // (c) Copyright 2005-2015 Eduardo Ramos Testillano & Francisco Ruiz Rayo //
5 // See project site at http://redmine.teslayout.com/projects/anna-suite //
6 // See accompanying file LICENSE or copy at http://www.teslayout.com/projects/public/anna.LICENSE //
15 #include <anna/core/tracing/TraceMethod.hpp>
17 #include <anna/xml/Node.hpp>
18 #include <anna/xml/Attribute.hpp>
20 #include <anna/comm/INetAddress.hpp>
22 #include <anna/dbms/Database.hpp>
23 #include <anna/dbms/Statement.hpp>
24 #include <anna/dbms/FailRecoveryHandler.hpp>
25 #include <anna/dbms/internal/sccs.hpp>
26 #include <anna/dbms/Float.hpp>
27 #include <anna/dbms/StatementTranslator.hpp>
31 using namespace anna::dbms;
33 Database::Database(const char* className, const char* dbmsName) :
35 a_name((dbmsName == NULL) ? "local" : dbmsName),
36 a_type((dbmsName == NULL) ? Type::Local : Type::Remote),
37 a_failRecoveryHandler(NULL),
38 a_statementTranslator(NULL) {
39 dbms::sccs::activate();
42 Database::~Database() {
46 void Database::do_initialize()
47 throw(RuntimeException) {
48 LOGMETHOD(TraceMethod tm("dbms::Database", "do_initialize", ANNA_FILE_LOCATION));
52 for(connection_iterator iic = connection_begin(), maxiic = connection_end(); iic != maxiic; iic ++) {
54 connection(iic)->open();
56 } catch(Exception& ex) {
62 if(counter == 0 && error == true) {
63 string msg(asString());
64 msg += " | No available connections";
65 throw RuntimeException(msg, ANNA_FILE_LOCATION);
69 Logger::information(asString(), ANNA_FILE_LOCATION);
73 void Database::do_stop()
75 LOGMETHOD(TraceMethod tm("dbms::Database", "do_stop", ANNA_FILE_LOCATION));
78 Connection* _connection;
80 for(connection_iterator iic = connection_begin(), maxiic = connection_end(); iic != maxiic; iic ++) {
81 _connection = connection(iic);
86 a_connections.clear();
87 } catch(Exception& ex) {
89 a_connections.clear();
94 * Para evitar que todos los clones usen la misma conexion a la base de datos, se realiza en
95 * cada uno de ellos una re-conexion, es decir, se cierra la original (abierta por el proceso
96 * padre) y se abre una nueva conexion con los mismos parametros y contra la misma base de datos.
98 void Database::do_cloneChild()
99 throw(RuntimeException) {
100 LOGMETHOD(TraceMethod tm("dbms::Database", "do_cloneChild", ANNA_FILE_LOCATION));
102 for(connection_iterator ii = connection_begin(), maxii = connection_end(); ii != maxii; ii ++) {
103 dbms::Connection* conn = connection(ii);
105 string msg("dbms::Database::do_cloneChild | ");
106 msg += conn->asString();
107 Logger::debug(msg, ANNA_FILE_LOCATION);
113 Connection* Database::createConnection(const char* name, const char* user, const char* password)
114 throw(RuntimeException, DatabaseException) {
115 Guard guard(this, "dbms::Database (createConnection)");
117 if(a_connections.size() >= MaxConnection) {
118 string msg("Database::createConnection | ");
120 msg += functions::asText(" | Cannot create more than %d connections per database", MaxConnection);
121 throw RuntimeException(msg, ANNA_FILE_LOCATION);
124 for(connection_iterator ii = connection_begin(), maxii = connection_end(); ii != maxii; ii ++) {
125 if(connection(ii)->getName() == name) {
126 string msg("Database::createConnection | ");
128 msg += " | Connection: ";
130 msg += " | Previously registered";
131 throw RuntimeException(msg, ANNA_FILE_LOCATION);
135 string strname(name);
136 Connection* result = allocateConnection(strname, user, password);
139 string msg(asString());
142 msg += " | Unable to instance connection";
143 throw RuntimeException(msg, ANNA_FILE_LOCATION);
147 string msg("dbms::Database::createConnection | ");
148 msg += result->asString();
149 Logger::write(Logger::Debug, msg, ANNA_FILE_LOCATION);
152 if(getState() == Component::State::Running) {
155 a_connections.push_back(result);
156 } catch(RuntimeException& ex) {
160 } catch(DatabaseException& edbms) {
166 a_connections.push_back(result);
171 Connection& Database::findConnection(const char* name)
172 throw(RuntimeException) {
173 Guard guard(this, "dbms::Database (findConnection)");
174 Connection* result = NULL;
176 for(connection_iterator ii = connection_begin(), maxii = connection_end(); ii != maxii; ii ++) {
177 if(anna_strcmp(connection(ii)->getName().c_str(), name) == 0) {
178 result = connection(ii);
184 string msg("Database::findConnection | ");
186 msg += " | Conexion: ";
188 msg += " | Unregistered";
189 throw RuntimeException(msg, ANNA_FILE_LOCATION);
192 if(result->isAvailable() == false || result->isEnabled() == false) {
193 string msg("Database::findConnection | ");
195 msg += " | Connection: ";
197 msg += " | Unavailable";
198 throw RuntimeException(msg, ANNA_FILE_LOCATION);
202 string msg("Database::findConnection | ");
203 msg += result->asString();
204 Logger::debug(msg, ANNA_FILE_LOCATION);
209 Statement* Database::createStatement(const char* name, const char* expression, const bool isCritical)
210 throw(RuntimeException) {
211 if(findStatement(name) != NULL)
212 throw RuntimeException(functions::asString("Sentence: %s | Name already in use", name), ANNA_FILE_LOCATION);
214 Guard guard(this, "dbms::Database::createStatement");
216 if(a_statementTranslator != NULL)
217 expression = a_statementTranslator->apply(expression);
219 Statement* result = allocateStatement(name, expression, isCritical);
221 string msg("dbms::Database::createStatement | ");
222 msg += result->asString();
224 if(a_statementTranslator != NULL) {
225 msg += " | Translator: ";
226 msg += a_statementTranslator->getName();
228 Logger::debug(msg, ANNA_FILE_LOCATION);
230 a_statements.push_back(result);
234 Statement* Database::findStatement(const char* name)
236 Guard guard(this, "dbms::Database::findStatement");
237 vector <Statement*>::iterator ii, maxii;
238 Statement* result(NULL);
240 for(ii = a_statements.begin(), maxii = a_statements.end(); ii != maxii; ii ++) {
241 if(anna_strcmp((*ii)->getName().c_str(), name) == 0) {
250 void Database::releaseStatement(Statement* statement)
252 if(statement == NULL) {
253 Logger::write(Logger::Warning, asString(), "Cannot release a NULL SQL sentence", ANNA_FILE_LOCATION);
258 string msg("dbms::Database::releaseStatement | ");
259 msg += statement->asString();
260 Logger::debug(msg, ANNA_FILE_LOCATION);
262 Guard guard(this, "dbms::Database::releaseStatement");
263 vector <Statement*>::iterator end = a_statements.end();
264 vector <Statement*>::iterator ii = find(a_statements.begin(), end, statement);
267 a_statements.erase(ii);
272 void Database::recover(Connection& connection, const int tryCounter)
273 throw(RuntimeException) {
277 } catch(DatabaseException& edbms) {
280 if(a_failRecoveryHandler != NULL)
281 a_failRecoveryHandler->apply(connection, tryCounter);
285 string Database::asString() const
287 string result("dbms::Database { ");
288 result += Component::asString();
290 if(a_type == Type::Local)
291 result += " | Type: Local";
293 result += " | Type: Remote | Name: ";
297 return result += " }";
300 xml::Node* Database::asXML(xml::Node* parent) const
302 parent = Component::asXML(parent);
303 xml::Node* result = parent->createChild("dbms.Database");
305 result->createAttribute("Type", (a_type == Type::Local) ? "Local" : "Remote");
307 if(a_type != Type::Local)
308 result->createAttribute("Name", a_name);
310 if(a_statementTranslator != NULL)
311 result->createAttribute("Translator", a_statementTranslator->getName());
313 node = result-> createChild("Connections");
315 for(const_connection_iterator ii = connection_begin(), maxii = connection_end(); ii != maxii; ii ++)
316 connection(ii)->asXML(node);
318 node = result-> createChild("Statements");
320 for(const_statement_iterator ii = statement_begin(), maxii = statement_end(); ii != maxii; ii ++)
321 statement(ii)->asXML(node);