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