Remove dynamic exceptions
[anna.git] / include / anna / comm / CompatCodec.hpp
1 // ANNA - Anna is Not Nothingness Anymore                                                         //
2 //                                                                                                //
3 // (c) Copyright 2005-2015 Eduardo Ramos Testillano & Francisco Ruiz Rayo                         //
4 //                                                                                                //
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 //
7
8
9 #ifndef anna_comm_CompatCodec_hpp
10 #define anna_comm_CompatCodec_hpp
11
12 #include <map>
13
14 #include <anna/core/DataBlock.hpp>
15 #include <anna/core/RuntimeException.hpp>
16 #include <anna/core/util/SortedVector.hpp>
17
18 #include <anna/comm/Message.hpp>
19 #include <anna/comm/Variable.hpp>
20
21 namespace anna {
22
23 class DataBlock;
24 class Second;
25 class Millisecond;
26 class Microsecond;
27
28 namespace comm {
29
30 /**
31    Codificador/Decodificador compatible con los mensajes
32
33    Esta clase ofrece una forma muy eficaz para codificar estructuras de datos complejas y pretende
34    sustituir los tipicos aplanadores y desaplanadores ya que permite que cualquier proceso
35    defina facilmente la forma de transferir cierta informacion sobre un bloque de memoria
36    y viceversa.
37
38    Vamos a ver un ejemplo de uso. Primero vamos a definir la clase MensajeDemo:
39
40 * \code
41 *
42 * #include <anna.comm.CompatCodec.h>
43 *
44 * class MensajeDemo : public CompatCodec {
45 * public:
46 *    static const CompatCodec::Type type = 10;
47 *
48 *    MensajeDemo () : CompatCodec (type),
49 *       a_dataBlock (true)
50 *    {
51 *       attach ("Entero", 0, a_entero);
52 *       attach ("Cadena", 1, a_cadena);
53 *       attach ("Bloque datos", 2, a_dataBlock);
54 *    }
55 *
56 *    // Accesores
57 *    const int obtenerEntero () const { return a_entero; }
58 *    const std::string& obtenerCadena () const { return a_cadena; }
59 *    const DataBlock& obtenerDataBlock () const { return a_dataBlock; }
60 *
61 *    // Modificadores
62 *    void establecerEntero (const int entero) { a_entero = entero; }
63 *    void establecerCadena (const std::string& cadena) { a_cadena = cadena; }
64 *    void establecerCadena (const char* cadena) { a_cadena = cadena; }
65 *    void establecerDataBlock (const DataBlock& dataBlock) { a_dataBlock = dataBlock; }
66 *
67 * private:
68 *    int a_entero;
69 *    std::string a_cadena;
70 *    DataBlock a_dataBlock;
71 * };
72 *
73 * \endcode
74 *
75    La clase que use esta clase para enviar un mensaje debe establecer los valores de cada uno de
76    los datos mediante los modificadores definidos y luego invocar al metodo #code que
77    transferiria el contenido de las variables asociadas a este mensaje a un bloque de memoria,
78    que normalmente seriausado como mensaje.
79
80    Por otra parte la clase que recibe el mensaje invocar�al metodo #decode que transfiere
81    el contenido del bloque de memoria a cada una de las variables asociadas al mensaje.
82    Posteriormente, podremos acceder al contenido de cada una de las variables asociadas al
83    mensaje atraves de los accesores definidos para el caso.
84
85    Estos codificadores nos dan la posibilidad de definir variables opcionales, de forma que
86    una determinada variable puede no ser transferida al bloque de memoria, y por tanto puede
87    no ser recibida en el otro extremo. Ver el metodo #isNull y #setNull para mas informacion.
88
89    \warning Esta clase no establece proteccion ante accesos concurrentes
90 */
91 class CompatCodec : public Message {
92   struct SortById {
93     static short int value(const comm::Variable* variable) {
94       return variable->getId();
95     }
96   };
97
98   class VariableContainer {
99   public:
100     typedef comm::Variable* type_pointer;
101
102     typedef type_pointer* iterator;
103     typedef const type_pointer* const_iterator;
104
105     VariableContainer();
106
107     void clear() ;
108     void add(comm::Variable* variable) ;
109     comm::Variable* find(const int id) ;
110     const comm::Variable* find(const int id) const ;
111
112     int size() const { return a_size; }
113
114     iterator begin() { return a_variables; }
115     iterator end() { return a_variables + a_size; }
116
117     const_iterator begin() const { return a_variables; }
118     const_iterator end() const { return a_variables + a_size; }
119
120     static comm::Variable* data(iterator ii) { return *ii; }
121     static const comm::Variable* data(const_iterator ii) { return *ii; }
122
123   private:
124     comm::Variable** a_variables;
125     int a_maxSize;
126     int a_size;
127   };
128
129 public:
130 //   typedef SortedVector <comm::Variable, SortById, short int> container;
131   typedef VariableContainer container;
132   typedef container::iterator iterator;
133   typedef container::const_iterator const_iterator;
134   typedef unsigned char Type;
135
136   /**
137      Constructor.
138
139      @param type Tipo por el que sera conocido este tipo de mensaje.
140      @param scramble Indica si el mensaje debe ser codificado de forma que no se pueda ver el contenido
141      del mismo con una simple herramienta de monitorizacion de mensajes de red. Por defecto esta
142      activo ya que la codificacion realizada es muy simple y rapida y el tiempo empleado es casi
143      inapreciable.
144   */
145   explicit CompatCodec(const Type type, const bool scramble = true);
146
147   /**
148      Destructor.
149   */
150   virtual ~CompatCodec();
151
152   // Accesores
153   /**
154      Devuelve el identificador del mensaje indicado en el constructor.
155     @return El identificador de este mensaje.
156   */
157   Type getType() const { return a_type; }
158
159 // Metodos
160   /**
161      Asocia el valor recibido como parametro al dato interno identificado por `id'. Esta clase
162      estapensada principalmente para comunicar entre si procesos remotos.
163      La unica restriccion que se les imponen a ambos que es compartan el significado que cada uno
164      de ellos le da a un determinado `id'.
165
166      \param name Nombre logico de la variable
167      @param id Identificador asignado al dato.
168      @param value Rerencia a una variable de nuestro entorno usada para transferir los datos de la memoria
169      al mensaje y viceversa.
170      @return Un puntero que hace referencia al nuevo dato interno que ha sido creado.
171   */
172   const Variable* attach(const char* name, const short int id, std::string& value) noexcept(false);
173
174   /**
175      Asocia el valor recibido como parametro al dato interno identificado por `id'. Esta clase
176      estapensada principalmente para comunicar entre si procesos remotos
177      La unica restriccion que se les imponen a ambos que es compartan el significado que cada uno
178      de ellos le da a un determinado `id'.
179
180      \param name Nombre logico de la variable
181      @param id Identificador asignado al dato.
182      @param value Rerencia a una variable de nuestro entorno usada para transferir los datos de la memoria
183      al mensaje y viceversa.
184      @return Un puntero que hace referencia al nuevo dato interno que ha sido creado.
185   */
186   const Variable* attach(const char* name, const short int id, const char*& value) noexcept(false);
187
188   /**
189      Asocia el valor recibido como parametro al dato interno identificado por `id'. Esta clase
190      estapensada principalmente para comunicar entre si procesos remotos
191      La unica restriccion que se les imponen a ambos que es compartan el significado que cada uno
192      de ellos le da a un determinado `id'.
193
194      \param name Nombre logico de la variable
195      @param id Identificador asignado al dato.
196      @param value Rerencia a una variable de nuestro entorno usada para transferir los datos de la memoria
197      al mensaje y viceversa.
198      @return Un puntero que hace referencia al nuevo dato interno que ha sido creado.
199   */
200   const Variable* attach(const char* name, const short int id, int& value) noexcept(false);
201
202   /**
203      Asocia el valor recibido como parametro al dato interno identificado por `id'. Esta clase
204      estapensada principalmente para comunicar entre si procesos remotos
205      La unica restriccion que se les imponen a ambos que es compartan el significado que cada uno
206      de ellos le da a un determinado `id'.
207
208      \param name Nombre logico de la variable
209      @param id Identificador asignado al dato.
210      @param value Rerencia a una variable de nuestro entorno usada para transferir los datos de la memoria
211      al mensaje y viceversa.
212      @return Un puntero que hace referencia al nuevo dato interno que ha sido creado.
213   */
214   const Variable* attach(const char* name, const short int id, S64& value) noexcept(false);
215
216   /**
217      Asocia el valor recibido como parametro al dato interno identificado por `id'. Esta clase
218      estapensada principalmente para comunicar entre si procesos remotos
219      La unica restriccion que se les imponen a ambos que es compartan el significado que cada uno
220      de ellos le da a un determinado `id'.
221
222      \param name Nombre logico de la variable
223      @param id Identificador asignado al dato.
224      @param value Rerencia a una variable de nuestro entorno usada para transferir los datos de la memoria
225      al mensaje y viceversa.
226      @return Un puntero que hace referencia al nuevo dato interno que ha sido creado.
227   */
228   const Variable* attach(const char* name, const short int id, bool& value) noexcept(false);
229
230   /**
231      Asocia el valor recibido como parametro al dato interno identificado por `id'. Esta clase
232      estapensada principalmente para comunicar entre si procesos remotos
233      La unica restriccion que se les imponen a ambos que es compartan el significado que cada uno
234      de ellos le da a un determinado `id'.
235
236      \param name Nombre logico de la variable
237      @param id Identificador asignado al dato.
238      @param value Rerencia a una variable de nuestro entorno usada para transferir los datos de la memoria
239      al mensaje y viceversa. Debe tener activado el sistema de copia profunda.
240      @return Un puntero que hace referencia al nuevo dato interno que ha sido creado.
241   */
242   const Variable* attach(const char* name, const short int id, DataBlock& value) noexcept(false);
243
244   /**
245      Asocia el valor recibido como parametro al dato interno identificado por `id'. Esta clase
246      estapensada principalmente para comunicar entre si procesos remotos
247      La unica restriccion que se les imponen a ambos que es compartan el significado que cada uno
248      de ellos le da a un determinado `id'.
249
250      \param name Nombre logico de la variable
251      @param id Identificador asignado al dato.
252      @param value Rerencia a una variable de nuestro entorno usada para transferir los datos de la memoria
253      al mensaje y viceversa. Debe tener activado el sistema de copia profunda.
254      @return Un puntero que hace referencia al nuevo dato interno que ha sido creado.
255   */
256   const Variable* attach(const char* name, const short int id, float& value) noexcept(false);
257
258   /**
259      Asocia el valor recibido como parametro al dato interno identificado por `id'. Esta clase
260      estapensada principalmente para comunicar entre si procesos remotos
261      La unica restriccion que se les imponen a ambos que es compartan el significado que cada uno
262      de ellos le da a un determinado `id'.
263
264      \param name Nombre logico de la variable
265      @param id Identificador asignado al dato.
266      @param value Rerencia a una variable de nuestro entorno usada para transferir los datos de la memoria
267      al mensaje y viceversa. Debe tener activado el sistema de copia profunda.
268      @return Un puntero que hace referencia al nuevo dato interno que ha sido creado.
269   */
270   const Variable* attach(const char* name, const short int id, double& value) noexcept(false);
271
272   const Variable* attach(const char* name, const short int id, Second& value) noexcept(false);
273   const Variable* attach(const char* name, const short int id, Millisecond& value) noexcept(false);
274   const Variable* attach(const char* name, const short int id, Microsecond& value) noexcept(false);
275
276   /**
277    * Asocia el mensaje recibido como un parámetro interno especificado por \em id.
278    * \param name Nombre lógico de la variable.
279    * \param id Identificador del dato asignado.
280    * \param value Instancia del mensaje que se codificará/decodificará de forma recursiva.
281    */
282   const Variable* attach(const char* name, const short int id, comm::CompatCodec& value) noexcept(false);
283
284   /**
285      Devuelve la referencia al dato interno identificado por el `id' recibido como parametro.
286
287      @param id Identificador asignado al dato que queremos obtener.
288
289      @return La referencia de la variable identificada por 'id'. Si no existe se lanzar�una excepcin.
290   */
291   const Variable& find(const short int id) const noexcept(false);
292
293   /**
294      Marca el dato asociado al identificador recibido como nulo, lo cual conlleva que el dato no seria
295      transferido al bloque de memoria del mensaje en caso de invocar al metodo de codificacion.
296
297      @param id Identificador asignado al dato.
298      @param isNull Indica la nueva marca de la variable.
299   */
300   void setNull(const short int id, const bool isNull = true) noexcept(false);
301
302   /**
303      Marca el dato recibido como nulo, lo cual conlleva que el dato no seria transferido al bloque
304      de memoria del mensaje en caso de invocar al metodo de codificacion.
305
306      @param variable Instancia de Varaible obtenida al invocar al método #attach
307      @param isNull Indica la nueva marca de la variable.
308   */
309   void setNull(const Variable* variable, const bool isNull = true) ;
310
311   /**
312      @param id Identificador asignado al dato.
313   *
314      @return Devuelve @em false si el dato identificado por `id' tiene algun valor o @em true en caso de que
315      el dato haya sido marcado como nulo. Por defecto se considera que todos los datos tienen valor.
316      Un dato puede tener un value nulo, bien por que se ha invocado a la funcin @ref setNull
317      o bien porque se recibio un mensaje en el que no venia contenido el identificador del dato.
318   */
319   bool isNull(const short int id) const noexcept(false);
320
321   /**
322      Devuelve un iterador al comienzo de la lista de variables asociados a este mensaje.
323      \return Un iterador al comienzo de la lista de variables asociados a este mensaje.
324   */
325   iterator begin() { return a_variables.begin(); }
326
327   /**
328      Devuelve un iterador al comienzo de la lista de variables asociados a este mensaje.
329      \return Un iterador al comienzo de la lista de variables asociados a este mensaje.
330   */
331   const_iterator begin() const { return a_variables.begin(); }
332
333   /**
334      Devuelve un iterador al comienzo de la lista de variables asociados a este mensaje.
335      \return Un iterador al final de la lista de variables asociados a este mensaje.
336   */
337   iterator end() { return a_variables.end(); }
338
339   /**
340      Devuelve un iterador al comienzo de la lista de variables asociados a este mensaje.
341      \return Un iterador al final de la lista de variables asociados a este mensaje.
342   */
343   const_iterator end() const { return a_variables.end(); }
344
345   /**
346      Devuelve el número de enginees asociados a.esta instancia.
347      \return el número de enginees asociados a.esta instancia.
348   */
349   int size() const { return a_variables.size(); }
350
351   /**
352      Devuelve la instancia de la variable sobre el que esta posicionado el iterador recibido
353      como parametro.
354      \param ii Iterador que debera estar comprendido entre begin y end.
355      \return La instancia de la variable sobre el que esta posicionado el iterador recibido
356   */
357   static Variable* variable(iterator ii) { return container::data(ii); }
358
359   /**
360      Devuelve la instancia de la variable sobre el que esta posicionado el iterador recibido
361      como parametro.
362      \param ii Iterador que debera estar comprendido entre begin y end.
363      \return La instancia de la variable sobre el que esta posicionado el iterador recibido
364   */
365   static const Variable* variable(const_iterator ii) { return container::data(ii); }
366
367   /**
368      Transfiene los datos establecidos en este mensaje interno a un bloque de memoria cuya instancia es devuelta por este metodo.
369      @return Bloque de memoria que contiene la informacion del mensaje.
370   */
371   virtual const DataBlock& code() noexcept(false);
372
373   /**
374      Transfiene la informacion contenida en el bloque de memoria recibido hacia las variables asociadas a este mensaje interno.
375      Las variables cuyo value no esta incluidas en el bloque de memoria seria marcadas como nulas.
376
377      @param dataBlock Bloque de memoria que contiene las variables codificadas.
378   */
379   virtual void decode(const DataBlock& dataBlock) noexcept(false);
380
381   /**
382      Permite conocer el identificador del mensaje que viene contenido en el bloque de memoria
383      antes de realizar la decodificacion.
384
385      @param dataBlock Bloque de memoria que contiene la informacion del mensaje.
386
387      @return El tipo del mensaje contenido en el bloque de memoria.
388   */
389   static Type getType(const DataBlock& dataBlock) noexcept(false);
390
391 protected:
392   bool a_scramble;
393
394 private:
395   const Type a_type;
396   container a_variables;
397   int a_nullCounter;
398
399   static bool st_initScramble;
400
401   CompatCodec(const CompatCodec&);
402   CompatCodec& operator = (const CompatCodec&);
403
404   void normalDecode(const char* data, const int size, const int maxdata) noexcept(false);
405   bool optimizedDecode(const char* data, const int size) noexcept(false);
406 };
407
408 }
409 }
410
411 #endif