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
46 #include <sys/types.h>
48 #include <anna/core/RuntimeException.hpp>
49 #include <anna/core/tracing/Logger.hpp>
50 #include <anna/core/functions.hpp>
51 #include <anna/core/tracing/TraceWriter.hpp>
52 #include <anna/core/tracing/TraceMethod.hpp>
53 #include <anna/core/internal/ModuleManager.hpp>
54 #include <anna/core/util/CommandLine.hpp>
56 #include <anna/app/Application.hpp>
57 #include <anna/app/Component.hpp>
58 #include <anna/app/internal/sccs.hpp>
59 #include <anna/app/functions.hpp>
61 #include <anna/xml/Node.hpp>
62 #include <anna/xml/Attribute.hpp>
63 #include <anna/xml/Compiler.hpp>
69 #define WEBSITE_PROJECT "http://redmine.teslayout.com/projects/anna-suite"
70 #define WEBSITE_GENERAL "http://www.teslayout.com"
72 app::Application* app::Application::st_application = NULL;
74 app::Application::Application(const char* shortName, const char* title, const char* version, const char* date, const char* time) :
75 a_shortName(shortName),
80 sigset(SIGUSR1, handlerSignalUSR);
81 sigset(SIGUSR2, handlerSignalUSR);
82 sigset(SIGTERM, handlerSignalTerminate);
84 app::sccs::activate();
85 a_version += functions::getArchitecture();
88 if(st_application == NULL)
89 st_application = this;
91 cout << a_shortName << " - " << a_title << ". Version " << a_version << endl;
94 cout << "Revision date: ";
96 if(date) cout << date << " ";
98 if(time) cout << time;
103 cout << "(c) Copyright 2001-2006 Eduardo Ramos Testillano & Francisco Antonio Ruiz Rayo" << endl;
104 cout << " eduardo.ramos.testillano@gmail.com & cisco.tierra@gmail.com" << endl;
105 cout << " (project site: " << WEBSITE_PROJECT << ")" << endl << endl;
106 //cout << " - Project site: " << WEBSITE_PROJECT << endl;
107 //cout << " - Main site: " << WEBSITE_GENERAL << endl << endl;
110 app::Component* app::Application::find(const char* className)
112 Component* component;
114 for(iterator ii = begin(), maxii = end(); ii != maxii; ii ++) {
115 component = Application::component(ii);
117 if(anna_strcmp(className, component->getClassName()) == 0)
125 * (1) Si se ejecuta el metodo clone evita que los hijos que termina se queden como zombies.
127 void app::Application::start()
128 throw(RuntimeException) {
129 TraceMethod tm("app::Application", "start", ANNA_FILE_LOCATION);
130 ModuleManager& moduleManager = ModuleManager::instantiate();
132 if(a_running == true) {
133 string msg("app::Application { Name; ");
135 msg += " | Already on execution";
136 throw RuntimeException(msg, ANNA_FILE_LOCATION);
139 if(sigset(SIGCHLD, handlerChildTerminate) != 0) // (1)
140 throw RuntimeException("Error installing terminate handler", ANNA_FILE_LOCATION);
143 if(a_enableGPL == true) {
144 cout << "This program is free software: you can redistribute it and/or modify" << endl;
145 cout << "it under the terms of the GNU General Public License as published by" << endl;
146 cout << "the Free Software Foundation, either version 3 of the License, or" << endl;
147 cout << "(at your option) any later version." << endl << endl;
148 cout << "This program is distributed in the hope that it will be useful," << endl;
149 cout << "but WITHOUT ANY WARRANTY; without even the implied warranty of" << endl;
150 cout << "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the" << endl;
151 cout << "GNU General Public License for more details." << endl << endl;
152 cout << "You should have received a copy of the GNU General Public License" << endl;
153 cout << "along with this program. If not, see <http://www.gnu.org/licenses/>." << endl << endl;
156 cout << "ANNA Suite. Version " << functions::getVersion() << endl;
157 cout << "Revision date: " << __DATE__ << " " << __TIME__ << endl;
158 cout << "(c) Copyright 2001-2006 Eduardo Ramos Testillano & Francisco Antonio Ruiz Rayo" << endl;
159 cout << " eduardo.ramos.testillano@gmail.com & cisco.tierra@gmail.com" << endl << endl;
161 cout << "Activating application modules ....................." << endl;
163 for(ModuleManager::const_iterator ii = moduleManager.begin(), maxii = moduleManager.end(); ii != maxii; ii ++) {
164 cout << "\t Module " << ModuleManager::module(ii) << endl;
173 } catch(RuntimeException& ex) {
180 void app::Application::startComponents()
181 throw(RuntimeException) {
182 LOGMETHOD(TraceMethod tm("app::Application", "startComponents", ANNA_FILE_LOCATION));
183 Component* component;
185 for(iterator ii = begin(); ii != end(); ii ++) {
186 component = Application::component(ii);
188 std::string msg("Starting component | ");
189 msg += component->asString();
190 Logger::write(Logger::Information, msg, ANNA_FILE_LOCATION);
192 component->initialize();
196 void app::Application::stopComponents()
197 throw(RuntimeException) {
198 LOGMETHOD(TraceMethod tm("app::Application", "stopComponents", ANNA_FILE_LOCATION));
199 Component* component;
201 for(iterator ii = begin(); ii != end(); ii ++) {
202 component = Application::component(ii);
204 std::string msg("Stopping component | ");
205 msg += component->asString();
206 Logger::write(Logger::Information, msg, ANNA_FILE_LOCATION);
213 * (1) Este el codigo que ejecuta la copia que acabamos de crear.
214 * (1.1) Limpia la lista de hijos que pudiera tener el padre.
216 app::Application& app::Application::clone()
217 throw(RuntimeException) {
218 if(anna::functions::supportMultithread() == true) {
219 string msg("app::Application::clone | pid: ");
220 msg += functions::asString((int) a_pid);
221 msg += " | Application clone is only supported for ST applications";
222 throw RuntimeException(msg, errno, ANNA_FILE_LOCATION);
225 const pid_t pid = ::fork();
228 string msg("app::Application::clone | pid: ");
229 msg += functions::asString((int) a_pid);
230 throw RuntimeException(msg, errno, ANNA_FILE_LOCATION);
233 Component* component;
235 if(pid == 0) { // (1)
236 Logger::showPID(true);
238 a_pids.clear(); // (1.1)
241 for(iterator ii = begin(); ii != end(); ii ++) {
242 component = Application::component(ii);
244 std::string msg("Cloning component on child | ");
245 msg += component->asString();
246 Logger::write(Logger::Information, msg, ANNA_FILE_LOCATION);
248 component->do_cloneChild();
252 } catch(RuntimeException& ex) {
258 string msg("app::Application::clone | Parent pid: ");
259 msg += functions::asString((int) a_pid);
260 msg += " | Child pid: ";
261 msg += functions::asString((int) pid);
262 Logger::warning(msg, ANNA_FILE_LOCATION);
266 for(iterator ii = begin(); ii != end(); ii ++) {
267 component = Application::component(ii);
269 std::string msg("Cloning component on parent | ");
270 msg += component->asString();
271 Logger::write(Logger::Information, msg, ANNA_FILE_LOCATION);
273 component->do_cloneParent();
277 a_pids.push_back(pid);
278 } catch(RuntimeException& ex) {
279 string msg("app::Application::clone | Abort execution: ");
280 msg += msg += functions::asString((int) pid);
281 Logger::error(msg, ANNA_FILE_LOCATION);
290 //---------------------------------------------------------------------------------------
291 // (1) Se invoca desde los constructores de los componentes => no se puede invocar a
292 // ningn m�odo virtual => obliga a que est� definidos antes de comenzar la
293 // ejecucin de la aplicacin => se inicilizar� en el Application::start ya que en
294 // ese momento los objetos est� completamente creados.
295 //---------------------------------------------------------------------------------------
296 void app::Application::attach(app::Component* component)
297 throw(RuntimeException) {
298 if(component == NULL)
299 throw RuntimeException("Cannot attach a NULL component", ANNA_FILE_LOCATION);
301 iterator ii = std::find(begin(), end(), component);
305 string msg((*ii)->asString());
306 msg += " | Was previously attached";
307 Logger::write(Logger::Information, msg, ANNA_FILE_LOCATION);
313 string msg("app::Application::attach | ");
314 msg += component->asString();
315 Logger::debug(msg, ANNA_FILE_LOCATION);
317 a_components.push_back(component);
321 std::string msg("Starting component | ");
322 msg += component->asString();
323 Logger::write(Logger::Information, msg, ANNA_FILE_LOCATION);
325 component->initialize();
329 void app::Application::detach(app::Component* component)
330 throw(RuntimeException) {
331 LOGMETHOD(TraceMethod tm("app::Application", "detach(component)", ANNA_FILE_LOCATION));
333 if(component == NULL)
334 throw RuntimeException("Cannot detach a NULL component", ANNA_FILE_LOCATION);
337 string msg("app::Application::detach | ");
338 msg += component->asString();
339 Logger::debug(msg, ANNA_FILE_LOCATION);
341 iterator ii = std::find(begin(), end(), component);
344 LOGDEBUG(Logger::write(Logger::Debug, "Detached", (*ii)->asString(), ANNA_FILE_LOCATION));
345 a_components.erase(ii);
349 void app::Application::writeContext(const std::string& file)
350 throw(RuntimeException) {
352 out.open(file.c_str());
354 if(out.is_open() == false) {
355 string msg("Error opening '");
358 throw RuntimeException(msg, ANNA_FILE_LOCATION);
362 string msg("app::Application::writeContext | File: ");
364 Logger::notice(msg, ANNA_FILE_LOCATION);
366 xml::Node root("Application");
367 out << xml::Compiler().apply(asXML(&root)) << endl;
371 xml::Node* app::Application::asXML(xml::Node* app) const
373 xml::Node* node(NULL);
374 app->createAttribute("Name", getShortName());
375 app->createAttribute("Version", getVersion());
376 app->createAttribute("pid", getPid());
378 CommandLine::instantiate().asXML(app);
379 node = app->createChild("app.Clones");
381 for(const_pid_iterator ii = pid_begin(), maxii = pid_end(); ii != maxii; ii ++)
382 node->createChild("Clone")->createAttribute("PID", pid(ii));
384 ModuleManager& moduleManager = ModuleManager::instantiate();
385 node = app->createChild("app.Modules");
387 for(ModuleManager::const_iterator ii = moduleManager.begin(), maxii = moduleManager.end(); ii != maxii; ii ++)
388 node->createChild("Module")->createAttribute("Id", ModuleManager::module(ii));
391 node = app->createChild("app.Components");
393 for(const_iterator ii = begin(), maxii = end(); ii != maxii; ii ++) {
394 Guard guard(cc = component(ii));
401 void app::Application::signalUSR(int signal)
402 throw(RuntimeException) {
403 if (signal == SIGUSR1) signalUSR1();
404 else if (signal == SIGUSR2) signalUSR2();
407 void app::Application::signalUSR1()
408 throw(RuntimeException) {
409 writeContext(anna::functions::asString("/var/tmp/anna.context.%05d", getPid()));
412 void app::Application::signalUSR2()
413 throw(RuntimeException) {
414 Logger::notice("Captured signal SIGUSR2. Nothing implemented at the moment", ANNA_FILE_LOCATION);
417 void app::Application::sendSignalToChilds(const int signal)
419 for(pid_iterator ii = pid_begin(), maxii = pid_end(); ii != maxii; ii ++)
420 kill(pid(ii), signal);
423 void app::Application::handlerSignalUSR(int signal)
428 Application& app = anna::app::functions::getApp();
429 app.sendSignalToChilds(signal);
430 app.signalUSR(signal);
431 } catch(Exception& ex) {
435 sigset(signal, handlerSignalUSR);
438 void app::Application::handlerSignalTerminate(int)
444 Logger::write(Logger::Warning, "app::Application | Received SIGTERM", ANNA_FILE_LOCATION);
446 Application& app = anna::app::functions::getApp();
447 app.sendSignalToChilds(SIGTERM);
448 app.signalTerminate();
449 } catch(Exception& ex) {
454 sigset(SIGTERM, handlerSignalTerminate);
458 * Se recoge el estado de terminacion del hijo para que no se quede considerado como un zombie y se
459 * elimina de la lista de procesos hijos.
461 void app::Application::handlerChildTerminate(int sig)
465 pid_t pid = wait(&status);
467 if(st_application == NULL)
470 pid_iterator maxii = st_application->pid_end();
471 pid_iterator ii = ::find(st_application->pid_begin(), maxii, pid);
474 st_application->a_pids.erase(ii);