First commit
[anna.git] / include / anna / app / Application.hpp
1 // ANNA - Anna is Not 'N' Anymore
2 //
3 // (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo
4 //
5 // https://bitbucket.org/testillano/anna
6 //
7 // Redistribution and use in source and binary forms, with or without
8 // modification, are permitted provided that the following conditions
9 // are met:
10 //
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
16 // distribution.
17 //     * Neither the name of Google Inc. 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.
20 //
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.
32 //
33 // Authors: eduardo.ramos.testillano@gmail.com
34 //          cisco.tierra@gmail.com
35
36
37 #ifndef anna_app_Application_hpp
38 #define anna_app_Application_hpp
39
40 #include <vector>
41
42 #include <anna/core/RuntimeException.hpp>
43
44 namespace anna {
45
46 class Configuration;
47
48 namespace xml {
49 class Node;
50 }
51
52 namespace app {
53
54 class Component;
55 struct functions;
56
57 /**
58    Abstraccion de la aplicacion.
59
60    Mantiene la informacion de todos los recursos usados (version, titulo, linea de comandos,
61    threads, etc ...) por nuestras aplicaciones.
62
63    Slo puede haber una nica instancia de la aplicacio, que seria accesible mediante el
64    metodo anna::functions::getApp.
65 */
66 class Application {
67 public:
68   typedef std::vector <Component*>::iterator iterator;
69   typedef std::vector <Component*>::const_iterator const_iterator;
70   typedef std::vector <pid_t> pid_container;
71   typedef pid_container::iterator pid_iterator;
72   typedef pid_container::const_iterator const_pid_iterator;
73
74   /**
75      Constructor.
76
77      @param shortName Nombre logico de esta instancia.
78      @param title Titulo de la aplicacion que aparecera al arrancar.
79      @param version version de este programa. Aconsejamos el forma X.YRZZ. Donde X es la
80      version principal, Y la version secundaria y ZZ es el numero de entrega realizada.
81      \param date Fecha de realizacion del componente. Normalmente sera el contenido de la macro __DATE__.
82      \param time Hora de realizacion del componente. Normalmente sera el contenido de la macro __TIME__.
83   */
84   Application(const char* shortName, const char* title, const char* version, const char* date = NULL, const char* time = NULL);
85
86   /**
87      Destructor.
88   */
89   virtual ~Application() { a_components.clear(); }
90
91   // Accesores
92   /**
93      Devuelve el nombre corto indicado en el constructor.
94      \return El nombre corto indicado en el constructor.
95   */
96   const char* getShortName() const throw() { return a_shortName; }
97
98   /**
99      Devuelve la version indicado en el contructor de esta aplicacion.
100      \return La version indicado en el contructor de esta aplicacion.
101   */
102   const std::string& getVersion() const throw() { return a_version; }
103
104   /**
105      Devuelve el titulo indicado en el contructor de esta aplicacion.
106      \return el titulo indicado en el contructor de esta aplicacion.
107   */
108   const std::string& getTitle() const throw() { return a_title; }
109
110   /**
111      Devuelve el pid asignado por el sistema operativo a la aplicacion que estamos ejecutando.
112      @return El pid asignado por el sistema operativo a la aplicacion que estamos ejecutando.
113   */
114   pid_t getPid() const throw() { return a_pid; }
115
116   /**
117      Activa la salida por pantalla del mensaje referente a la licencia GPL 3.0.
118      \warning Para que tenga efecto debe ser invocado antes de ejecutar el metodo Application::start.
119   */
120   void activateGeneralPublicLicense() throw() { a_enableGPL = true; }
121
122   /**
123    * Crea un nuevo proceso a partir de este usando el metodo \em fork.
124    *
125    * Estrictamente este metodo retonara dos veces, una en el ambito del proceso que lo invoco y
126    * otra en el ambito del nuevo proceso, llamado proceso hijo.
127    *
128    * Si la duplicacion se realiza de forma correcta se invoca a los metodos #do_cloneChild y #do_cloneParent de nuestra
129    * aplicacion y Component::do_cloneChild y Component::do_cloneParent de cada uno de los componentes registrados.
130    *
131    * Para saber en cual de los procesos
132    * \return La instancia de la nueva aplicacion.
133    */
134   Application& clone() throw(RuntimeException);
135
136   /**
137      Devuelve la instancia del componente que corresponde con el nombre recibido.
138      \return La instancia del componente que corresponde con el nombre recibido. Puede ser NULL si no
139      hay ningun componente asociado a la �ta aplicacion que corresponda con el nombre.
140   */
141   Component* find(const char* className) throw();
142
143   /**
144      Inicializa los elementos propios de nuestra aplicacio, invoca al metodo #initialize
145      e invoca al metodo #run.
146   */
147   void start() throw(RuntimeException);
148
149   /**
150      Devuelve un iterador al primer componente definido en la aplicacion.
151      \return un iterador al primer componente definido en la aplicacion.
152   */
153   const_iterator begin() const throw() { return a_components.begin(); }
154
155   /**
156      Devuelve un iterador al primer componente definido en la aplicacion.
157      \return un iterador al primer componente definido en la aplicacion.
158   */
159   iterator begin() throw() { return a_components.begin(); }
160
161   /**
162      Devuelve un iterador al ultimo componente definido en la aplicacion.
163      \return un iterador al ultimo componente definido en la aplicacion.
164   */
165   const_iterator end() const throw() { return a_components.end(); }
166
167   /**
168      Devuelve un iterador al ultimo componente definido en la aplicacion.
169      \return un iterador al ultimo componente definido en la aplicacion.
170   */
171   iterator end() throw() { return a_components.end(); }
172
173   /**
174      Vuelva un documento XML con el contexto de la aplicacion.
175      \param file Ruta completa del fichero en el que grabar el contexto de la aplicacion.
176   */
177   void writeContext(const std::string& file) throw(RuntimeException);
178
179   /**
180      metodo que puede ser reescrito en las clases heredadas de Application y que nos
181      da la posibilidad de inicializar los elementos particulares de nuestra aplicacion.
182      Por defecto no realiza ninguna operacion.
183      \warning En el momento de invocar a esta funcin los componentes (\see Component) pueden no
184      estar disponibles.
185   */
186   virtual void initialize() throw(RuntimeException) {;}
187
188   /**
189      Devuelve si esta aplicacion tiene soporto para comunicaciones entre procesos.
190      \return \em true si la aplicacion tiene soporta para comunicacion entre proceso o \em false
191      en otro caso.
192   */
193   virtual bool supportCommunication() const throw() { return false; }
194
195   /**
196    * Este método se invocará cuando alguna capa superior a ésta detecte un problema tan grave
197    * como para parar la aplicación de forma súbita.
198    * \param className Nombre de la clase que genera el evento.
199    *
200    * \warning En el momento de invocar a este método la aplicación puede estar en un estado
201    * no muy estable por lo que se deberían minizar las operaciones a realizar para evitar
202    * bloquear la aplicación.
203    */
204   virtual void eventAbnormalTermination(const char* className) throw() { ; }
205
206   /**
207      Devuelve una cadena con la informacion referente a esta instancia.
208      \param parent Nodo XML del que dependende la informacion.
209      @return Una cadena con la informacion referente a esta instancia.
210   */
211   virtual xml::Node* asXML(xml::Node* parent) const throw();
212
213   /**
214      Devuelve el objeto sobre el que esta posicionado el iterator recibido como parametro.
215      \param ii Iterator que deberia estar comprendido entre #begin y #end.
216      \return El objeto sobre el que esta posicionado el iterator recibido como parametro.
217   */
218   static const Component* component(const_iterator& ii) throw() { return *ii; }
219
220   /**
221      Devuelve el objeto sobre el que esta posicionado el iterator recibido como parametro.
222      \param ii Iterator que deberia estar comprendido entre #begin y #end.
223      \return El objeto sobre el que esta posicionado el iterator recibido como parametro.
224   */
225   static Component* component(iterator& ii) throw() { return *ii; }
226
227 protected:
228   static Application* st_application;
229
230   /**
231      metodo que debemos implementar para ejecutar nuestra aplicacion.
232   */
233   virtual void run() throw(RuntimeException) = 0;
234
235   /**
236      Metodo manejador que podemos re-escribir para tratar la recepcion de la senhal USR1.
237      Por defecto
238   */
239   virtual void signalUSR1() throw(RuntimeException);
240
241   /**
242      Metodo manejador que podemos re-escribir para tratar la recepcion de la senhal SIGTERM.
243   */
244   virtual void signalTerminate() throw(RuntimeException) {;}
245
246   /**
247    * Metodo que debemos implementar en la clase heredada para tratar el proceso de clonado de
248    * esta aplicacion desde el punto de vista del proceso original.
249    * \warning Si se detecta algun error terminara abortara la ejecucion del proceso hijo.
250    */
251   virtual void do_cloneParent() throw(RuntimeException) {;}
252
253   /**
254    * Metodo que debemos implementar en la clase heredada para tratar el proceso de clonado de
255    * esta aplicacion desde el punto de vista del proceso hijo.
256    * \warning Si se detecta algun error terminara abortara la ejecucion de este proceso.
257    */
258   virtual void do_cloneChild() throw(RuntimeException) {;}
259
260   /**
261      Devuelve un iterador al primer proceso hijo creado por la aplicacion (ver #clone),
262      \return un iterador al primer proceso hijo definido en la aplicacion.
263   */
264   pid_iterator pid_begin() throw() { return a_pids.begin(); }
265
266   /**
267      Devuelve un iterador al final de lista lista de procesos hijos creados por la aplicacion (ver #clone).
268      \return un iterador al primer proceso hijo definido en la aplicacion.
269   */
270   pid_iterator pid_end() throw() { return a_pids.end(); }
271
272   /**
273    * Devuelve el numero de procesos hijos.
274    * \return el numero de procesos hijos.
275    */
276   int pid_size() const throw() { return a_pids.size(); }
277
278   /**
279      Devuelve un iterador al primer proceso hijo creado por la aplicacion (ver #clone),
280      \return un iterador al primer proceso hijo definido en la aplicacion.
281   */
282   const_pid_iterator pid_begin() const throw() { return a_pids.begin(); }
283
284   /**
285      Devuelve un iterador al final de lista lista de procesos hijos creados por la aplicacion (ver #clone).
286      \return un iterador al primer proceso hijo definido en la aplicacion.
287   */
288   const_pid_iterator pid_end() const throw() { return a_pids.end(); }
289
290   /**
291      Devuelve el PID sobre el que esta posicionado el iterator recibido como parametro.
292      \param ii Iterator que deberia estar comprendido entre #pid_begin y #pid_end.
293      \return El objeto sobre el que esta posicionado el iterator recibido como parametro.
294   */
295   static pid_t pid(pid_iterator& ii) throw() { return *ii; }
296
297   /**
298      Devuelve el PID sobre el que esta posicionado el iterator recibido como parametro.
299      \param ii Iterator que deberia estar comprendido entre #pid_begin y #pid_end.
300      \return El objeto sobre el que esta posicionado el iterator recibido como parametro.
301   */
302   static pid_t pid(const_pid_iterator& ii) throw() { return *ii; }
303
304 private:
305   bool a_running;
306   std::string a_version;
307   const std::string a_title;
308   std::vector <Component*> a_components;
309   pid_t a_pid;
310   const char* a_shortName;
311   bool a_enableGPL;
312   pid_container a_pids;
313
314   void attach(Component*) throw(RuntimeException);
315   void detach(Component*) throw(RuntimeException);
316
317   void startComponents() throw(RuntimeException);
318   void stopComponents() throw(RuntimeException);
319   void sendSignalToChilds(const int signal) throw();
320
321   static void handlerSignalUSR1(int) throw();
322   static void handlerSignalTerminate(int) throw();
323   static void handlerChildTerminate(int sig) throw();
324
325   friend class Component;  // Para poder acceder a los metodo attach y detach
326   friend struct functions;
327 };
328
329 }
330 }
331
332 #endif
333