First commit
[anna.git] / include / anna / dbos / ObjectFacade.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_dbos_ObjectFacade_hpp
38 #define anna_dbos_ObjectFacade_hpp
39
40 #include <anna/core/RuntimeException.hpp>
41
42 #include <anna/dbms/DatabaseException.hpp>
43
44 #include <anna/dbos/StorageArea.hpp>
45 #include <anna/dbos/Creator.hpp>
46 #include <anna/dbos/Loader.hpp>
47 #include <anna/dbos/Recorder.hpp>
48 #include <anna/dbos/Eraser.hpp>
49
50 namespace anna {
51
52 namespace dbms {
53 class Connection;
54 }
55
56 namespace dbos {
57
58 class Object;
59
60 /**
61    Clase que facilita el acceso y uso de las clases encargadas de la instanciacion de objetos a partir de los datos
62    contenidos en un medio fisico, que normalmente seria la tabla de una base de datos.
63
64    \param T clase debe ser heredada de anna::dbos::Object.
65
66    Ejemplo de definicion de una clase usando esta interfaz:
67
68    \include dbos_demo.p/oodb.d/hdrs/dbos_demo.oodb.Table01.h
69
70    Ejemplo de implementacion de la clase correspondiente a la definicion:
71
72    \include dbos_demo.p/oodb.d/oodb.Table01.cc
73
74    \see dbos_declare_object
75    \see dbos_prepare_object
76 */
77 template <typename T> class ObjectFacade {
78 public:
79   /**
80      Devuelve un numerico que puede ser usado en la definicion del area de almacenamiento.
81
82      \return Un numerico que puede ser usado en la definicion del area de almacenamiento.
83      \see Database::createStorageArea
84   */
85   static StorageId getStorageAreaId() throw() { return (StorageId) anna_ptrnumber_cast(&st_storageArea); }
86
87   /**
88       Devuelve el area de almacenamiento asociado a esta clase.
89       \return Devuelve el area de almacenamiento asociado a esta clase.
90   */
91   static StorageArea* getStorageArea() throw() { return st_storageArea; }
92
93   /**
94      Establece el area de almacenamiento asociado a esta clase, que deberiaser creado mediante la invocacin al metodo
95      Database::createStorageArea.
96
97      \param storageArea area de almacenamiento asociada esta clase.
98
99      \warning El area de almacenamiento debe establecerse antes de invocar a cualquier otro metodo de esta clase.
100   */
101   static void setStorageArea(StorageArea* storageArea) throw() {
102     (st_storageArea = storageArea)->setSizeof(sizeof(T));
103   }
104
105   /**
106      Carga la informacion de un objeto contenida en un medio fisico y la interpreta para adecuarla a
107      una clase C++.
108
109      Este cargador deberia tener todos los datos necesarios para localizar la informacion del objeto que
110      debe cargar. Por ejemplo, en caso de tener que obtener el objeto a partir de los datos contenidos
111      en una tabla de una base de datos deberia conocer la clave primaria del objeto a cargar, o alguna
112      otra combinacion de columnas que lo identifiquen univocamente.
113
114      \param connection Conexion usada si fuera necesario extraer los datos del medio fisico.
115      \param loader Cargador de clase encargado de localizar y obtener la informacion referente al objeto
116      que deseamos cargar en memoria.
117
118      \return Una instancia que cumple el patron establecido por el cargador. Puede ser NULL en caso de
119      que al inicializar el area de almacenamiento asociado a esta clase se halla indicado un \em errorCode
120      igual a -1 en otro caso si no encuentra el objeto que cumpla el patron devolveria  una
121      excepcion.
122
123      \warning Cada llamada a este metodo deberia tener su correspondiente liberacion invocando a #release
124      cuando dejemos de usar la instancia.
125   */
126   static T* instance(dbms::Connection& connection, Loader& loader)
127   throw(RuntimeException, dbms::DatabaseException) {
128     if(st_storageArea == NULL) {
129       std::string msg(loader.asString());
130       msg += " | ObjectFacade uninitialized ";
131       throw RuntimeException(msg, ANNA_FILE_LOCATION);
132     }
133
134     return static_cast <T*>(st_storageArea->instance(connection, loader));
135   }
136
137   /**
138      Carga la informacion de un objeto contenida en un medio fisico y la interpreta para adecuarla a
139      una clase C++.
140
141      Este cargador deberia tener todos los datos necesarios para localizar la informacion del objeto que
142      debe cargar.
143
144      \param loader Cargador de clase encargado de localizar y obtener la informacion referente al objeto
145      que deseamos cargar en memoria.
146
147      \return Una instancia que cumple el patron establecido por el cargador. Puede ser NULL en caso de
148      que al inicializar el area de almacenamiento asociado a esta clase se halla indicado un \em errorCode
149      igual a -1 en otro caso si no encuentra el objeto que cumpla el patron devolveria  una
150      excepcion.
151
152      \warning Cada llamada a este metodo deberia tener su correspondiente liberacion invocando a #release
153      cuando dejemos de usar la instancia.
154   */
155   static T* instance(Loader& loader)
156   throw(RuntimeException, dbms::DatabaseException) {
157     if(st_storageArea == NULL) {
158       std::string msg(loader.asString());
159       msg += " | ObjectFacade uninitialized ";
160       throw RuntimeException(msg, ANNA_FILE_LOCATION);
161     }
162
163     return static_cast <T*>(st_storageArea->instance(loader));
164   }
165
166   /**
167       Carga la informacion de un objeto contenida en un medio fisico y la interpreta para adecuarla a
168       una clase C++.
169
170       Este cargador deberia tener todos los datos necesarios para localizar la informacion del objeto que
171       debe cargar. Por ejemplo, en caso de tener que obtener el objeto a partir de los datos contenidos
172       en una tabla de una base de datos deberia conocer la clave primaria del objeto a cargar, o alguna
173       otra combinacion de columnas que lo identifiquen univocamente.
174
175       \param connection Conexion usada si fuera necesario extraer los datos del medio fisico.
176       \param  crossedLoader Cargador encargado de encontrar la clave principal a aplicar con el #Loader
177       recibido como parámetro en base a una clave alternativa contenida en el mismo.
178       \param loader Cargador de clase encargado de localizar y obtener la informacion referente al objeto
179       que deseamos cargar en memoria.
180
181       \return Una instancia que cumple el patron establecido por el cargador. Puede ser NULL en caso de
182       que al inicializar esta clase \em errorCode se halla indicado un #NoExceptionWhenNotFound en otro
183       caso si no encuentra el objeto que cumpla el patron devolveria una excepcion de ejecucion.
184
185       \warning Cada llamada a este método deberia tener su correspondiente liberacion invocando a #release
186       cuando dejemos de usar la instancia.
187    */
188   static T* instance(dbms::Connection& connection, CrossedLoader& crossedLoader,  Loader& loader)
189   throw(RuntimeException, dbms::DatabaseException) {
190     if(st_storageArea == NULL) {
191       std::string msg(loader.asString());
192       msg += " | ObjectFacade uninitialized ";
193       throw RuntimeException(msg, ANNA_FILE_LOCATION);
194     }
195
196     return static_cast <T*>(st_storageArea->instance(connection, crossedLoader, loader));
197   }
198
199   /**
200       Crea un objeto en el area de almacenamiento un y lo prepara para ser transferido al medio fisico
201       si fuera necesario.
202
203       Este cargador deberia tener todos los datos necesarios para localizar la informacion del objeto que
204       debe cargar. Por ejemplo, en caso de tener que obtener el objeto a partir de los datos contenidos
205       en una tabla de una base de datos deberia conocer la clave primaria del objeto a cargar, o alguna
206       otra combinacion de columnas que lo identifiquen univocamente.
207
208       \param connection Conexion usada si fuera necesario acceder al medio fisico.
209       \param creator Creador encargado de generar el objeto de forma que sea facil de localizar posteriormente
210       en el area de almacenamiento.
211
212       \return La nueva instancia que cumple el patron establecido por el creador.
213
214       \warning Cada llamada a este metodo deberia tener su correspondiente liberacion invocando a #release
215       cuando dejemos de usar la instancia.
216    */
217   static T* create(dbms::Connection& connection, Creator& creator)
218   throw(RuntimeException, dbms::DatabaseException) {
219     if(st_storageArea == NULL) {
220       std::string msg(creator.asString());
221       msg += " | ObjectFacade uninitialized ";
222       throw RuntimeException(msg, ANNA_FILE_LOCATION);
223     }
224
225     return static_cast <T*>(st_storageArea->create(connection, creator));
226   }
227
228   /**
229       Devuelve la informacion de un objeto cargado desde el medio fisico.
230
231       Este cargador deberia tener todos los datos necesarios para localizar la informacion del objeto que
232       debe buscar. Por ejemplo, en caso de tener que obtener el objeto a partir de los datos contenidos
233       en una tabla de una base de datos deberia conocer la clave primaria del objeto a cargar, o alguna
234       otra combinacion de columnas que lo identifiquen univocamente.
235
236       \param loader Cargador de clase encargado de localizar la informacion referente al objeto buscado.
237
238       \return Una instancia que cumple el patron establecido por el cargador. Puede ser NULL si el
239       objeto no fue cargado en el area de almacenamiento.
240
241       \warning Cada llamada a este metodo deberia tener su correspondiente liberacion invocando a #release
242       cuando dejemos de usar la instancia.
243    */
244   static T* find(Loader& loader)
245   throw(RuntimeException) {
246     if(st_storageArea == NULL) {
247       std::string msg(loader.asString());
248       msg += " | ObjectFacade uninitialized ";
249       throw RuntimeException(msg, ANNA_FILE_LOCATION);
250     }
251
252     return static_cast <T*>(st_storageArea->find(loader));
253   }
254
255   /**
256      Habilita la reutilizacion del espacio de memoria ocupado por un objeto alojado en el area de almacenamiento.
257
258      Este metodo no saca al objeto de la memoria de almacenamiento, sino que marca su espacio de memoria
259      como subceptible de ser reutilizado. De esta forma, si el numero de objetos cargados en memoria se
260      acerca al tamao maximo indicado en la inicializacion, se intentara reusar espacios libres en vez
261      de continuar ampliando la memoria reservada.
262
263      \param t Instancia del tipo T que vamos a liberar.
264
265      \warning Si el objeto recibido como parametro no fue reservado mediate alguno de los metodos de reserva de
266      objetos ofrecidos por esta clase no tendra ningun efecto.
267   */
268   static void release(T*& t)
269   throw() {
270     if(st_storageArea == NULL)
271       return;
272
273     try {
274       st_storageArea->release(reinterpret_cast <Object**>(&t));
275     } catch(RuntimeException& ex) {
276       ex.trace();
277     }
278   }
279
280   /**
281      Descarga todos los objetos contenidos en el area de almacenamiento.
282   */
283   static void clear()
284   throw(RuntimeException) {
285     if(st_storageArea == NULL)
286       throw RuntimeException("ObjectFacade uninitialized ", ANNA_FILE_LOCATION);
287
288     st_storageArea->clear();
289   }
290
291   /**
292      Devuelve de una copia del objeto recibido como parametro e incrementa la cuenta de utilizacion
293      asociada a la instancia.
294
295      \param t Instancia del tipo T obtenida mediate el metodo #instance.
296
297      \return Una copia del objeto recibido como parametro. Si el parametro recibido es NULL devolveria NULL.
298
299      \warning Cada llamada a este metodo deberia tener su correspondiente liberacion invocando a #release
300      cuando dejemos de usar la instancia.
301   */
302   static T* duplicate(const T* t)
303   throw(RuntimeException) {
304     if(st_storageArea == NULL)
305       throw RuntimeException("ObjectFacade uninitialized ", ANNA_FILE_LOCATION);
306
307     return static_cast <T*>(st_storageArea->duplicate(t));
308   }
309
310   /**
311      Permite conocer si un determinado objeto esta alojado en el area de almacenamiento.
312
313      \param loader Cargador de clase encargado de localizar la informacion referente al objeto buscado.
314
315      \return \em true Si el objeto identificado por el Loader esta en el area de almacenamiento o
316      \em false en otro caso.
317   */
318   static bool isLoaded(const Loader& loader)
319   throw(RuntimeException) {
320     if(st_storageArea == NULL)
321       throw RuntimeException("ObjectFacade uninitialized ", ANNA_FILE_LOCATION);
322
323     return st_storageArea->isLoaded(loader);
324   }
325
326   /**
327      Transfiere la informacion del objeto recibido como parametro al medio fisico usando el Recorder
328      recibido como parametro.
329
330      \param connection Conexion usada si fuera necesario extraer los datos del medio fisico.
331      \param recorder Grabador usado para transferir los datos al medio fisico.
332   */
333   static void apply(dbms::Connection& connection, Recorder& recorder)
334   throw(RuntimeException, dbms::DatabaseException) {
335     if(st_storageArea == NULL) {
336       std::string msg(recorder.asString());
337       msg += " | ObjectFacade uninitialized";
338       throw RuntimeException(msg, ANNA_FILE_LOCATION);
339     }
340
341     st_storageArea->apply(connection, recorder);
342   }
343
344   /**
345      Elimina la informacion del objeto recibido como parametro del medio fisico usando el Eraser
346      recibido como parametro.
347
348      \param connection Conexion usada si fuera necesario extraer los datos del medio fisico.
349      \param eraser Objecto usado para eliminar los datos al medio fisico.
350
351      \warning Si la cuanta de utilizacion de T es 1 se liberaria en otro caso se devolveria una excepcion.
352   */
353   static void apply(dbms::Connection& connection, Eraser& eraser)
354   throw(RuntimeException, dbms::DatabaseException) {
355     if(st_storageArea == NULL) {
356       std::string msg(eraser.asString());
357       msg += " | ObjectFacade uninitialized";
358       throw RuntimeException(msg, ANNA_FILE_LOCATION);
359     }
360
361     st_storageArea->apply(connection, eraser);
362   }
363
364   /**
365      Elimina toda la informacion referente al objeto recibido como parametro, siempre y cuando
366      solo tenga un unica referencia activa. Descarga el objeto de la memoria de almacenamiento,
367
368      \param t Instancia del tipo T que vamos a descargar de la memoria de almacenamiento.
369
370      \warning \li Si el objeto recibido como parametro no fue reservado mediate #instance no tiene
371      ningun efecto. \li La instancia a liberar solo puede tener 1 en su cuenta de utilizacion.
372      \li La memoria asignada a la instancia recibida es liberada, por lo que podemos evitar la invocacion
373      al metodo #release para esta instancia.
374   */
375   static void erase(T*& t)
376   throw(RuntimeException) {
377     if(st_storageArea == NULL)
378       return;
379
380     st_storageArea->erase(reinterpret_cast <Object**>(&t));
381   }
382
383   /**
384      Devuelve el puntero sobre el que estaria posicionado el iterador recibido como parametro.
385      \return El puntero sobre el que estaria posicionado el iterador recibido como parametro.
386   */
387   static T* data(StorageArea::iterator& ii) throw() { return static_cast <T*>(StorageArea::data(ii)); }
388
389   /**
390      Devuelve el puntero sobre el que estaria posicionado el iterador recibido como parametro.
391      \return El puntero sobre el que estaria posicionado el iterador recibido como parametro.
392   */
393   static const T* data(StorageArea::const_iterator& ii) throw() { return static_cast <const T*>(StorageArea::data(ii)); }
394
395   /**
396      Metodo creador de nuevas instancias de la clase T.
397      \return Una nueva instancia del tipo de objeto T.
398      \warning Solo deberia ser llamado desde anna::comm::StorageArea cuando sea preciso crear
399      nuevas instancias de objetos.
400   */
401   static Object* allocator() throw() { return new T; }
402
403 protected:
404   static StorageArea* st_storageArea;
405
406   /**
407      Constructor.
408   */
409   ObjectFacade() {}
410 };
411
412 }
413 }
414
415 /**
416    Definicion a la que hay que invocar en la implementacion de la clase que hereda
417    de anna::dbos::ObjectFacade.
418
419    \param T Nombre de la clase que vamos a tratar en el ambito de C++.
420 */
421 #define dbos_prepare_object(T) \
422    template <> anna::dbos::StorageArea* anna::dbos::ObjectFacade< T >::st_storageArea = NULL
423
424 /**
425    Definicion a la que hay que invocar dentro de la definicion de la clase que hereda
426    de anna::dbos::ObjectFacade.
427
428    \param T Nombre de la clase que vamos a tratar en el ambito de C++.
429 */
430 #define dbos_declare_object(T) \
431    friend class anna::dbos::ObjectFacade <T>
432
433
434 #endif