1 // ANNA - Anna is Not Nothingness Anymore
3 // (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo
5 // http://redmine.teslayout.com/projects/anna-suite
7 // Redistribution and use in source and binary forms, with or without
8 // modification, are permitted provided that the following conditions
11 // * Redistributions of source code must retain the above copyright
12 // notice, this list of conditions and the following disclaimer.
13 // * Redistributions in binary form must reproduce the above
14 // copyright notice, this list of conditions and the following disclaimer
15 // in the documentation and/or other materials provided with the
17 // * Neither the name of the copyright holder nor the names of its
18 // contributors may be used to endorse or promote products derived from
19 // this software without specific prior written permission.
21 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 // Authors: eduardo.ramos.testillano@gmail.com
34 // cisco.tierra@gmail.com
43 #include <anna/core/tracing/TraceMethod.hpp>
45 #include <anna/xml/Node.hpp>
46 #include <anna/xml/Attribute.hpp>
48 #include <anna/comm/INetAddress.hpp>
50 #include <anna/dbms/Database.hpp>
51 #include <anna/dbms/Statement.hpp>
52 #include <anna/dbms/FailRecoveryHandler.hpp>
53 #include <anna/dbms/internal/sccs.hpp>
54 #include <anna/dbms/Float.hpp>
55 #include <anna/dbms/StatementTranslator.hpp>
59 using namespace anna::dbms;
61 Database::Database(const char* className, const char* dbmsName) :
63 a_name((dbmsName == NULL) ? "local" : dbmsName),
64 a_type((dbmsName == NULL) ? Type::Local : Type::Remote),
65 a_failRecoveryHandler(NULL),
66 a_statementTranslator(NULL) {
67 dbms::sccs::activate();
70 Database::~Database() {
74 void Database::do_initialize()
75 throw(RuntimeException) {
76 LOGMETHOD(TraceMethod tm("dbms::Database", "do_initialize", ANNA_FILE_LOCATION));
80 for(connection_iterator iic = connection_begin(), maxiic = connection_end(); iic != maxiic; iic ++) {
82 connection(iic)->open();
84 } catch(Exception& ex) {
90 if(counter == 0 && error == true) {
91 string msg(asString());
92 msg += " | No available connections";
93 throw RuntimeException(msg, ANNA_FILE_LOCATION);
97 Logger::information(asString(), ANNA_FILE_LOCATION);
101 void Database::do_stop()
103 LOGMETHOD(TraceMethod tm("dbms::Database", "do_stop", ANNA_FILE_LOCATION));
106 Connection* _connection;
108 for(connection_iterator iic = connection_begin(), maxiic = connection_end(); iic != maxiic; iic ++) {
109 _connection = connection(iic);
110 _connection->close();
114 a_connections.clear();
115 } catch(Exception& ex) {
117 a_connections.clear();
122 * Para evitar que todos los clones usen la misma conexion a la base de datos, se realiza en
123 * cada uno de ellos una re-conexion, es decir, se cierra la original (abierta por el proceso
124 * padre) y se abre una nueva conexion con los mismos parametros y contra la misma base de datos.
126 void Database::do_cloneChild()
127 throw(RuntimeException) {
128 LOGMETHOD(TraceMethod tm("dbms::Database", "do_cloneChild", ANNA_FILE_LOCATION));
130 for(connection_iterator ii = connection_begin(), maxii = connection_end(); ii != maxii; ii ++) {
131 dbms::Connection* conn = connection(ii);
133 string msg("dbms::Database::do_cloneChild | ");
134 msg += conn->asString();
135 Logger::debug(msg, ANNA_FILE_LOCATION);
141 Connection* Database::createConnection(const char* name, const char* user, const char* password)
142 throw(RuntimeException, DatabaseException) {
143 Guard guard(this, "dbms::Database (createConnection)");
145 if(a_connections.size() >= MaxConnection) {
146 string msg("Database::createConnection | ");
148 msg += functions::asText(" | Cannot create more than %d connections per database", MaxConnection);
149 throw RuntimeException(msg, ANNA_FILE_LOCATION);
152 for(connection_iterator ii = connection_begin(), maxii = connection_end(); ii != maxii; ii ++) {
153 if(connection(ii)->getName() == name) {
154 string msg("Database::createConnection | ");
156 msg += " | Connection: ";
158 msg += " | Previously registered";
159 throw RuntimeException(msg, ANNA_FILE_LOCATION);
163 string strname(name);
164 Connection* result = allocateConnection(strname, user, password);
167 string msg(asString());
170 msg += " | Unable to instance connection";
171 throw RuntimeException(msg, ANNA_FILE_LOCATION);
175 string msg("dbms::Database::createConnection | ");
176 msg += result->asString();
177 Logger::write(Logger::Debug, msg, ANNA_FILE_LOCATION);
180 if(getState() == Component::State::Running) {
183 a_connections.push_back(result);
184 } catch(RuntimeException& ex) {
188 } catch(DatabaseException& edbms) {
194 a_connections.push_back(result);
199 Connection& Database::findConnection(const char* name)
200 throw(RuntimeException) {
201 Guard guard(this, "dbms::Database (findConnection)");
202 Connection* result = NULL;
204 for(connection_iterator ii = connection_begin(), maxii = connection_end(); ii != maxii; ii ++) {
205 if(anna_strcmp(connection(ii)->getName().c_str(), name) == 0) {
206 result = connection(ii);
212 string msg("Database::findConnection | ");
214 msg += " | Conexion: ";
216 msg += " | Unregistered";
217 throw RuntimeException(msg, ANNA_FILE_LOCATION);
220 if(result->isAvailable() == false || result->isEnabled() == false) {
221 string msg("Database::findConnection | ");
223 msg += " | Connection: ";
225 msg += " | Unavailable";
226 throw RuntimeException(msg, ANNA_FILE_LOCATION);
230 string msg("Database::findConnection | ");
231 msg += result->asString();
232 Logger::debug(msg, ANNA_FILE_LOCATION);
237 Statement* Database::createStatement(const char* name, const char* expression, const bool isCritical)
238 throw(RuntimeException) {
239 if(findStatement(name) != NULL)
240 throw RuntimeException(functions::asString("Sentence: %s | Name already in use", name), ANNA_FILE_LOCATION);
242 Guard guard(this, "dbms::Database::createStatement");
244 if(a_statementTranslator != NULL)
245 expression = a_statementTranslator->apply(expression);
247 Statement* result = allocateStatement(name, expression, isCritical);
249 string msg("dbms::Database::createStatement | ");
250 msg += result->asString();
252 if(a_statementTranslator != NULL) {
253 msg += " | Translator: ";
254 msg += a_statementTranslator->getName();
256 Logger::debug(msg, ANNA_FILE_LOCATION);
258 a_statements.push_back(result);
262 Statement* Database::findStatement(const char* name)
264 Guard guard(this, "dbms::Database::findStatement");
265 vector <Statement*>::iterator ii, maxii;
266 Statement* result(NULL);
268 for(ii = a_statements.begin(), maxii = a_statements.end(); ii != maxii; ii ++) {
269 if(anna_strcmp((*ii)->getName().c_str(), name) == 0) {
278 void Database::releaseStatement(Statement* statement)
280 if(statement == NULL) {
281 Logger::write(Logger::Warning, asString(), "Cannot release a NULL SQL sentence", ANNA_FILE_LOCATION);
286 string msg("dbms::Database::releaseStatement | ");
287 msg += statement->asString();
288 Logger::debug(msg, ANNA_FILE_LOCATION);
290 Guard guard(this, "dbms::Database::releaseStatement");
291 vector <Statement*>::iterator end = a_statements.end();
292 vector <Statement*>::iterator ii = find(a_statements.begin(), end, statement);
295 a_statements.erase(ii);
300 void Database::recover(Connection& connection, const int tryCounter)
301 throw(RuntimeException) {
305 } catch(DatabaseException& edbms) {
308 if(a_failRecoveryHandler != NULL)
309 a_failRecoveryHandler->apply(connection, tryCounter);
313 string Database::asString() const
315 string result("dbms::Database { ");
316 result += Component::asString();
318 if(a_type == Type::Local)
319 result += " | Type: Local";
321 result += " | Type: Remote | Name: ";
325 return result += " }";
328 xml::Node* Database::asXML(xml::Node* parent) const
330 parent = Component::asXML(parent);
331 xml::Node* result = parent->createChild("dbms.Database");
333 result->createAttribute("Type", (a_type == Type::Local) ? "Local" : "Remote");
335 if(a_type != Type::Local)
336 result->createAttribute("Name", a_name);
338 if(a_statementTranslator != NULL)
339 result->createAttribute("Translator", a_statementTranslator->getName());
341 node = result-> createChild("Connections");
343 for(const_connection_iterator ii = connection_begin(), maxii = connection_end(); ii != maxii; ii ++)
344 connection(ii)->asXML(node);
346 node = result-> createChild("Statements");
348 for(const_statement_iterator ii = statement_begin(), maxii = statement_end(); ii != maxii; ii ++)
349 statement(ii)->asXML(node);