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 //
11 #include <anna/core/tracing/TraceMethod.hpp>
12 #include <anna/core/functions.hpp>
13 #include <anna/core/tracing/Logger.hpp>
15 #include <anna/xml/Node.hpp>
17 #include <anna/comm/Delivery.hpp>
18 #include <anna/comm/Resource.hpp>
19 #include <anna/comm/Delivery.hpp>
24 const Millisecond comm::Delivery::DefaultRecoveryTime(60000);
26 void comm::Delivery::initialize()
27 throw(RuntimeException) {
28 LOGMETHOD(TraceMethod tm("comm::Delivery", "initialize", ANNA_FILE_LOCATION));
29 // No es necesario protegerlo porque cuando se ejecuta todavía estarmos en la parte
30 // en la que no se han lanzado los thread's
31 // Guard guard (*this, "comm::Delivery::initialize");
34 if(a_resources.empty() == true) {
35 string msg(asString());
36 msg += " | No resources assigned";
37 Logger::warning(msg, ANNA_FILE_LOCATION);
40 a_isAvailable = isAvailable();
42 string msg("comm::Delivery::initialize | ");
44 Logger::debug(msg, ANNA_FILE_LOCATION);
48 //---------------------------------------------------------------------------------------------
49 // Selecciona alguno de los recursos que tiene asociados este servicio de reparto.
51 // (1) Cada cierto tiempo comprueba si hay que habilitar alguno de los recursos que han sido
52 // desactivados con motivo de errores internos. Los que hayan sido desactivados por motivos
53 // externos seran recuperados por el comm::ConnectionRecover, que se estara encargando de
54 // intentar reconectar cada cierto tiempo.
56 // (2) En principio, supone que va a recuperar todos los recursos con problemas.
57 // (2.1) Si queda algun recurso con problemas, activa el timeStamp para seguir comprobando
58 // los recursos con fallos internos.
59 //---------------------------------------------------------------------------------------------
60 comm::Resource* comm::Delivery::apply()
61 throw(RuntimeException) {
62 LOGMETHOD(TraceMethod tm(Logger::Local7, "comm::Delivery", "apply", ANNA_FILE_LOCATION));
63 Guard guard(*this, "comm::Delivery::apply");
65 if(a_timeStamp != 0) { // (1)
66 const Millisecond now = functions::millisecond();
68 if((now - a_timeStamp) > (a_recoveryTime >> 1)) {
69 comm::Resource* resource;
70 a_timeStamp = 0; // (2)
72 for(iterator ii = begin(), maxii = end(); ii != maxii; ii ++) {
73 resource = Delivery::resource(ii);
75 if(internalErrorDetected(resource) == false)
78 if((now - resource->getTimeStamp()) > a_recoveryTime)
79 unsafe_recover(resource);
80 else if(a_timeStamp == 0)
81 a_timeStamp = now; // (2.1)
86 comm::Resource* result = do_apply();
89 string msg(asString());
90 msg += " | No resources available";
91 throw RuntimeException(msg, ANNA_FILE_LOCATION);
95 string msg("comm::Delivery::apply | ");
98 msg += result->asString();
99 Logger::debug(msg, ANNA_FILE_LOCATION)
104 bool comm::Delivery::fault(const Resource* resource)
106 LOGMETHOD(TraceMethod tm(Logger::Local7, "comm::Delivery", "fault", ANNA_FILE_LOCATION));
109 return !a_isAvailable;
111 Guard guard(*this, "comm::Delivery::fault");
113 if(find(comm::Delivery::begin(), end(), resource) == end()) // (1)
114 return !a_isAvailable;
116 const bool result = do_fault(resource); // (2)
118 if(a_timeStamp == 0 && internalErrorDetected(resource) == true)
119 a_timeStamp = functions::millisecond();
121 const int aux = a_isAvailable;
122 a_isAvailable = !result;
124 string msg("comm::Delivery::fault | ");
127 msg += resource->asString();
128 Logger::warning(msg, ANNA_FILE_LOCATION)
131 if(a_isAvailable == false && a_isAvailable != aux) {
132 string msg("comm::Delivery::fault | ");
134 Logger::error(msg, ANNA_FILE_LOCATION);
140 bool comm::Delivery::recover(const Resource* resource)
143 return a_isAvailable;
145 LOGMETHOD(TraceMethod tm(Logger::Local7, "comm::Delivery", "recover", ANNA_FILE_LOCATION));
146 Guard guard(*this, "comm::Delivery::recover");
147 return unsafe_recover(resource);
150 bool comm::Delivery::unsafe_recover(const Resource* resource)
152 LOGMETHOD(TraceMethod tm(Logger::Local7, "comm::Delivery", "unsafe_recover", ANNA_FILE_LOCATION));
154 if(find(comm::Delivery::begin(), end(), resource) == end()) // (1)
155 return a_isAvailable;
157 a_isAvailable = do_recover(resource);
159 string msg("comm::Delivery::recover | ");
162 msg += resource->asString();
163 Logger::warning(msg, ANNA_FILE_LOCATION)
165 return a_isAvailable;
168 bool comm::Delivery::contains(const Resource* resource) const
173 Guard guard(*this, "comm::Delivery::contains");
174 return do_contains(resource);
177 // Devolverá true si no tiene disponible ninguno de los recursos asociados.
178 bool comm::Delivery::do_fault(const Resource* resource)
180 return (isAvailable() == true) ? false : true;
183 // Devolverá true si tiene disponible alguno de los recursos que tiene asociados.
184 bool comm::Delivery::do_recover(const Resource* resource)
186 return isAvailable();
189 //-------------------------------------------------------------------------------------------
190 // Un recurso puede estar desactivado porque el Communicator a detectado una rotura de
191 // conexion, lo que consideraremos un error externo, o porque se han detectado errores al
192 // intentar enviar, lo que consideraremos un error interno.
194 //-------------------------------------------------------------------------------------------
195 bool comm::Delivery::isAvailable() const
199 for(const_iterator ii = begin(), maxii = end(); ii != maxii; ii ++) {
200 const comm::Resource* resource = Delivery::resource(ii);
202 if(resource->isEnabled() == true && resource->isAvailable() == true) {
211 void comm::Delivery::add(Resource* resource)
212 throw(RuntimeException) {
213 if(resource == NULL) {
214 string msg(asString());
215 msg += " | Cannot attach a NULL resource";
216 throw RuntimeException(msg, ANNA_FILE_LOCATION);
219 Guard guard(*this, "comm::Delivery::add");
221 if(do_contains(resource) == true)
225 string msg("comm::Delivery::add | ");
228 msg += resource->asString();
229 Logger::information(msg, ANNA_FILE_LOCATION);
231 a_resources.push_back(resource);
234 bool comm::Delivery::do_contains(const comm::Resource* resource) const
236 for(const_iterator ii = begin(), maxii = end(); ii != maxii; ii ++)
237 if(*Delivery::resource(ii) == *resource)
243 string comm::Delivery::asString() const
245 string result("comm::Delivery { Name: ");
247 result += functions::asText(" | Available: ", a_isAvailable);
249 result += functions::asString(a_resources.size());
252 result += " | InternalError: Detected";
254 return result += " }";
257 xml::Node* comm::Delivery::asXML(xml::Node* parent) const
259 xml::Node* node = parent->createChild("comm.Delivery");
260 node->createAttribute("Name", a_name);
261 node->createAttribute("Available", functions::asString(a_isAvailable));
264 node->createAttribute("InternalError", "Detected");
266 xml::Node* resources = node->createChild("comm.Resources");
268 for(const_iterator ii = begin(), maxii = end(); ii != maxii; ii ++) {
269 const Resource* commResource = resource(ii);
270 commResource->asAttribute(resources->createChild("comm.Resource"));
277 * Devuelve true si el recurso recibido como parametro ha sido desactivado como
278 * resultado de un error interno, es decir, que se ha intentado enviar un mensaje
279 * y se ha obtenido una excepcion (EAGAIN, EPIPE, etc, etc), o false en otro caso.
281 * Si el 'isAvailable' fuera 'false' => que la conexion con el servidor remoto
282 * esta rota, y por tanto, en caso de que este marcado como de auto-reconexion
283 * estara siendo recuperada por el comm::ConnectionRecover.
286 bool comm::Delivery::internalErrorDetected(const Resource* resource)
288 return resource->isEnabled() == false && resource->isAvailable() == true;