1 /********************************************************************\
2  * qofbook.c -- dataset access (set of books of entities)           *
3  *                                                                  *
4  * This program is free software; you can redistribute it and/or    *
5  * modify it under the terms of the GNU General Public License as   *
6  * published by the Free Software Foundation; either version 2 of   *
7  * the License, or (at your option) any later version.              *
8  *                                                                  *
9  * This program is distributed in the hope that it will be useful,  *
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of   *
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the    *
12  * GNU General Public License for more details.                     *
13  *                                                                  *
14  * You should have received a copy of the GNU General Public License*
15  * along with this program; if not, contact:                        *
16  *                                                                  *
17  * Free Software Foundation           Voice:  +1-617-542-5942       *
18  * 51 Franklin Street, Fifth Floor    Fax:    +1-617-542-2652       *
19  * Boston, MA  02110-1301,  USA       gnu@gnu.org                   *
20 \********************************************************************/
21 
22 /*
23  * FILE:
24  * qofbook.c
25  *
26  * FUNCTION:
27  * Encapsulate all the information about a QOF dataset.
28  *
29  * HISTORY:
30  * Created by Linas Vepstas December 1998
31  * Copyright (c) 1998-2001,2003 Linas Vepstas <linas@linas.org>
32  * Copyright (c) 2000 Dave Peticolas
33  * Copyright (c) 2006 Neil Williams <linux@codehelp.co.uk>
34  */
35 
36 #include "config.h"
37 #include <stdlib.h>
38 #include <string.h>
39 #include <glib.h>
40 #include "qof.h"
41 #include "qofevent-p.h"
42 #include "qofbackend-p.h"
43 #include "qofbook-p.h"
44 #include "qofid-p.h"
45 #include "qofobject-p.h"
46 
47 static QofLogModule log_module = QOF_MOD_ENGINE;
48 
49 static void
coll_destroy(gpointer col)50 coll_destroy (gpointer col)
51 {
52 	qof_collection_destroy ((QofCollection *) col);
53 }
54 
55 static void
qof_book_init(QofBook * book)56 qof_book_init (QofBook * book)
57 {
58 	if (!book)
59 		return;
60 
61 	book->hash_of_collections =
62 		g_hash_table_new_full (g_str_hash, g_str_equal,
63 		(GDestroyNotify) qof_util_string_cache_remove, coll_destroy);
64 	qof_instance_init (&book->inst, QOF_ID_BOOK, book);
65 	book->data_tables = g_hash_table_new (g_str_hash, g_str_equal);
66 	book->data_table_finalizers =
67 		g_hash_table_new (g_str_hash, g_str_equal);
68 	book->book_open = 'y';
69 	book->version = 0;
70 	book->idata = 0;
71 	book->undo_data = g_new0 (QofUndo, 1);
72 }
73 
74 QofBook *
qof_book_new(void)75 qof_book_new (void)
76 {
77 	QofBook *book;
78 
79 	ENTER (" ");
80 	book = g_new0 (QofBook, 1);
81 	qof_book_init (book);
82 	qof_object_book_begin (book);
83 	qof_event_gen (&book->inst.entity, QOF_EVENT_CREATE, NULL);
84 	LEAVE ("book=%p", book);
85 	return book;
86 }
87 
88 static void
book_final(gpointer key,gpointer value,gpointer booq)89 book_final (gpointer key, gpointer value, gpointer booq)
90 {
91 	QofBookFinalCB cb = value;
92 	QofBook *book = booq;
93 
94 	gpointer user_data = g_hash_table_lookup (book->data_tables, key);
95 	(*cb) (book, key, user_data);
96 }
97 
98 void
qof_book_destroy(QofBook * book)99 qof_book_destroy (QofBook * book)
100 {
101 	if (!book)
102 		return;
103 	ENTER ("book=%p", book);
104 	book->shutting_down = TRUE;
105 	qof_event_force (&book->inst.entity, QOF_EVENT_DESTROY, NULL);
106 	/* Call the list of finalizers, let them do their thing.
107 	 * Do this before tearing into the rest of the book.
108 	 */
109 	g_hash_table_foreach (book->data_table_finalizers, book_final, book);
110 	qof_object_book_end (book);
111 	g_hash_table_destroy (book->data_table_finalizers);
112 	book->data_table_finalizers = NULL;
113 	g_hash_table_destroy (book->data_tables);
114 	book->data_tables = NULL;
115 	qof_instance_release (&book->inst);
116 	g_hash_table_destroy (book->hash_of_collections);
117 	book->hash_of_collections = NULL;
118 	g_free (book);
119 	LEAVE ("book=%p", book);
120 }
121 
122 /* call is_equal callbacks on QofObject ? */
123 
124 gboolean
qof_book_equal(QofBook * book_1,QofBook * book_2)125 qof_book_equal (QofBook * book_1, QofBook * book_2)
126 {
127 	if (book_1 == book_2)
128 		return TRUE;
129 	if (!book_1 || !book_2)
130 		return FALSE;
131 	return TRUE;
132 }
133 
134 gboolean
qof_book_not_saved(QofBook * book)135 qof_book_not_saved (QofBook * book)
136 {
137 	if (!book)
138 		return FALSE;
139 
140 	return (book->inst.dirty || qof_object_is_dirty (book));
141 }
142 
143 void
qof_book_mark_saved(QofBook * book)144 qof_book_mark_saved (QofBook * book)
145 {
146 	if (!book)
147 		return;
148 
149 	book->inst.dirty = FALSE;
150 	qof_object_mark_clean (book);
151 }
152 
153 QofBackend *
qof_book_get_backend(QofBook * book)154 qof_book_get_backend (QofBook * book)
155 {
156 	if (!book)
157 		return NULL;
158 	return book->backend;
159 }
160 
161 gboolean
qof_book_shutting_down(QofBook * book)162 qof_book_shutting_down (QofBook * book)
163 {
164 	if (!book)
165 		return FALSE;
166 	return book->shutting_down;
167 }
168 
169 void
qof_book_set_backend(QofBook * book,QofBackend * be)170 qof_book_set_backend (QofBook * book, QofBackend * be)
171 {
172 	if (!book)
173 		return;
174 	ENTER ("book=%p be=%p", book, be);
175 	book->backend = be;
176 	LEAVE (" ");
177 }
178 
179 void
qof_book_kvp_changed(QofBook * book)180 qof_book_kvp_changed (QofBook * book)
181 {
182 	if (!book)
183 		return;
184 	book->inst.dirty = TRUE;
185 }
186 
187 /* Store arbitrary pointers in the QofBook for data storage extensibility */
188 /* XXX if data is NULL, we should remove the key from the hash table!
189  */
190 void
qof_book_set_data(QofBook * book,const gchar * key,gpointer data)191 qof_book_set_data (QofBook * book, const gchar * key, gpointer data)
192 {
193 	if (!book || !key)
194 		return;
195 	g_hash_table_insert (book->data_tables, (gpointer) key, data);
196 }
197 
198 void
qof_book_set_data_fin(QofBook * book,const gchar * key,gpointer data,QofBookFinalCB cb)199 qof_book_set_data_fin (QofBook * book, const gchar * key,
200 	gpointer data, QofBookFinalCB cb)
201 {
202 	if (!book || !key)
203 		return;
204 	g_hash_table_insert (book->data_tables, (gpointer) key, data);
205 
206 	if (!cb)
207 		return;
208 	g_hash_table_insert (book->data_table_finalizers, (gpointer) key, cb);
209 }
210 
211 gpointer
qof_book_get_data(QofBook * book,const gchar * key)212 qof_book_get_data (QofBook * book, const gchar * key)
213 {
214 	if (!book || !key)
215 		return NULL;
216 	return g_hash_table_lookup (book->data_tables, (gpointer) key);
217 }
218 
219 QofCollection *
qof_book_get_collection(QofBook * book,QofIdType entity_type)220 qof_book_get_collection (QofBook * book, QofIdType entity_type)
221 {
222 	QofCollection *col;
223 
224 	if (!book || !entity_type)
225 		return NULL;
226 	col = g_hash_table_lookup (book->hash_of_collections, entity_type);
227 	if (!col)
228 	{
229 		col = qof_collection_new (entity_type);
230 		g_hash_table_insert (book->hash_of_collections,
231 			qof_util_string_cache_insert ((gpointer) entity_type), col);
232 	}
233 	return col;
234 }
235 
236 struct _iterate
237 {
238 	QofCollectionForeachCB fn;
239 	gpointer data;
240 };
241 
242 static void
foreach_cb(gpointer key,gpointer item,gpointer arg)243 foreach_cb (gpointer key __attribute__ ((unused)), gpointer item, gpointer arg)
244 {
245 	struct _iterate *qiter = arg;
246 	QofCollection *col = item;
247 
248 	qiter->fn (col, qiter->data);
249 }
250 
251 void
qof_book_foreach_collection(QofBook * book,QofCollectionForeachCB cb,gpointer user_data)252 qof_book_foreach_collection (QofBook * book,
253 	QofCollectionForeachCB cb, gpointer user_data)
254 {
255 	struct _iterate qiter;
256 
257 	g_return_if_fail (book);
258 	g_return_if_fail (cb);
259 	qiter.fn = cb;
260 	qiter.data = user_data;
261 	g_hash_table_foreach (book->hash_of_collections, foreach_cb, &qiter);
262 }
263 
264 void
qof_book_mark_closed(QofBook * book)265 qof_book_mark_closed (QofBook * book)
266 {
267 	if (!book)
268 	{
269 		return;
270 	}
271 	book->book_open = 'n';
272 }
273 
274 gchar
qof_book_get_open_marker(QofBook * book)275 qof_book_get_open_marker (QofBook * book)
276 {
277 	if (!book)
278 	{
279 		return 'n';
280 	}
281 	return book->book_open;
282 }
283 
284 gint32
qof_book_get_version(QofBook * book)285 qof_book_get_version (QofBook * book)
286 {
287 	if (!book)
288 	{
289 		return -1;
290 	}
291 	return book->version;
292 }
293 
294 guint32
qof_book_get_idata(QofBook * book)295 qof_book_get_idata (QofBook * book)
296 {
297 	if (!book)
298 	{
299 		return 0;
300 	}
301 	return book->idata;
302 }
303 
304 void
qof_book_set_version(QofBook * book,gint32 version)305 qof_book_set_version (QofBook * book, gint32 version)
306 {
307 	if (!book && version < 0)
308 	{
309 		return;
310 	}
311 	book->version = version;
312 }
313 
314 void
qof_book_set_idata(QofBook * book,guint32 idata)315 qof_book_set_idata (QofBook * book, guint32 idata)
316 {
317 	if (!book && idata == 0)
318 	{
319 		return;
320 	}
321 	book->idata = idata;
322 }
323 
324 gint64
qof_book_get_counter(QofBook * book,const gchar * counter_name)325 qof_book_get_counter (QofBook * book, const gchar * counter_name)
326 {
327 	QofBackend *be;
328 	KvpFrame *kvp;
329 	KvpValue *value;
330 	gint64 counter;
331 
332 	if (!book)
333 	{
334 		PWARN ("No book!!!");
335 		return -1;
336 	}
337 	if (!counter_name || *counter_name == '\0')
338 	{
339 		PWARN ("Invalid counter name.");
340 		return -1;
341 	}
342 	/* If we've got a backend with a counter method, call it */
343 	be = book->backend;
344 	if (be && be->counter)
345 		return ((be->counter) (be, counter_name));
346 	/* If not, then use the KVP in the book */
347 	kvp = qof_book_get_slots (book);
348 	if (!kvp)
349 	{
350 		PWARN ("Book has no KVP_Frame");
351 		return -1;
352 	}
353 	value = kvp_frame_get_slot_path (kvp, "counters", counter_name, NULL);
354 	if (value)
355 	{
356 		/* found it */
357 		counter = kvp_value_get_gint64 (value);
358 	}
359 	else
360 	{
361 		/* New counter */
362 		counter = 0;
363 	}
364 	/* Counter is now valid; increment it */
365 	counter++;
366 	/* Save off the new counter */
367 	value = kvp_value_new_gint64 (counter);
368 	kvp_frame_set_slot_path (kvp, value, "counters", counter_name, NULL);
369 	kvp_value_delete (value);
370 	/* and return the value */
371 	return counter;
372 }
373 
374 /* QofObject function implementation and registration */
375 gboolean
qof_book_register(void)376 qof_book_register (void)
377 {
378 	static QofParam params[] = {
379 		{QOF_PARAM_GUID, QOF_TYPE_GUID,
380 				(QofAccessFunc) qof_entity_get_guid,
381 			NULL, NULL},
382 		{QOF_PARAM_KVP, QOF_TYPE_KVP,
383 				(QofAccessFunc) qof_instance_get_slots,
384 			NULL, NULL},
385 		{NULL, NULL, NULL, NULL, NULL},
386 	};
387 
388 	qof_class_register (QOF_ID_BOOK, NULL, params);
389 
390 	return TRUE;
391 }
392 
393 /* ========================== END OF FILE =============================== */
394