qofsession.h File Reference


Detailed Description

Encapsulates a connection to a backend (persistent store).

Author:
Copyright (c) 1998, 1999, 2001, 2002 Linas Vepstas <linas@linas.org>

Copyright (c) 2000 Dave Peticolas

Copyright (c) 2005 Neil Williams <linux@codehelp.co.uk>

Definition in file qofsession.h.

#include "qofbackend.h"
#include "qofbook.h"
#include "qofclass.h"
#include "qofobject.h"

Go to the source code of this file.

Session Errors

QofBackendError qof_session_get_error (QofSession *session)
const char * qof_session_get_error_message (QofSession *session)
QofBackendError qof_session_pop_error (QofSession *session)

Copying entities between sessions.

Only certain backends can cope with selective copying of entities and only fully defined QOF entities can be copied between sessions - see the QOF Serialisation Format (QSF) documentation (qsf_write_file) for more information.

The recommended backend for the new session is QSF or a future SQL backend. Using any of these entity copy functions sets a flag in the backend that this is now a partial QofBook. See Referring to entities outside a partial book.. When you save a session containing a partial QofBook, the session will check that the backend is able to handle the partial book. If not, the backend will be replaced by one that can handle partial books, preferably one using the same access_method. Currently, this means that a book using the GnuCash XML v2 file backend will be switched to QSF.

Copied entities are identical to the source entity, all parameters defined with QofAccessFunc and QofSetterFunc in QOF are copied and the GUID of the original QofEntity is set in the new entity. Sessions containing copied entities are intended for use as mechanisms for data export.

It is acceptable to add entities to new_session in batches. Note that any of these calls will fail if an entity already exists in new_session with the same GUID as any entity to be copied.

To merge a whole QofBook or where there is any possibility of collisions or requirement for user intervention, see Merging QofBook structures

gboolean qof_entity_copy_to_session (QofSession *new_session, QofEntity *original)
 Copy a single QofEntity to another session.
gboolean qof_entity_copy_list (QofSession *new_session, GList *entity_list)
 Copy a GList of entities to another session.
gboolean qof_entity_copy_coll (QofSession *new_session, QofCollection *entity_coll)
 Copy a QofCollection of entities.
gboolean qof_entity_copy_coll_r (QofSession *new_session, QofCollection *coll)
 Recursively copy a collection of entities to a session.
gboolean qof_entity_copy_one_r (QofSession *new_session, QofEntity *ent)
 Recursively copy a single entity to a new session.

Event Handling

gboolean qof_session_events_pending (QofSession *session)
gboolean qof_session_process_events (QofSession *session)

Defines

#define QOF_MOD_SESSION   "qof-session"
#define QOF_STDOUT   "file:"
 Allow session data to be printed to stdout.

Typedefs

typedef _QofSession QofSession
typedef void(* QofPercentageFunc )(const char *message, double percent)

Functions

QofSessionqof_session_new (void)
void qof_session_destroy (QofSession *session)
QofSessionqof_session_get_current_session (void)
void qof_session_set_current_session (QofSession *session)
void qof_session_swap_data (QofSession *session_1, QofSession *session_2)
void qof_session_begin (QofSession *session, const char *book_id, gboolean ignore_lock, gboolean create_if_nonexistent)
void qof_session_load (QofSession *session, QofPercentageFunc percentage_func)
void qof_session_add_book (QofSession *session, QofBook *book)
QofBookqof_session_get_book (QofSession *session)
const char * qof_session_get_file_path (QofSession *session)
const char * qof_session_get_url (QofSession *session)
gboolean qof_session_not_saved (QofSession *session)
gboolean qof_session_save_may_clobber_data (QofSession *session)
void qof_session_save (QofSession *session, QofPercentageFunc percentage_func)
void qof_session_end (QofSession *session)
void qof_session_add_close_hook (GFunc fn, gpointer data)
void qof_session_call_close_hooks (QofSession *session)


Define Documentation

#define QOF_STDOUT   "file:"
 

Allow session data to be printed to stdout.

book_id can't be NULL and we do need to have an access_method, so use one to solve the other.

To print a session to stdout, use qof_session_begin. Example:

qof_session_begin(session,QOF_STDOUT,TRUE,FALSE);

When you call qof_session_save(session, NULL), the output will appear on stdout and can be piped or redirected to other processes.

Currently, only the QSF backend supports writing to stdout, other backends may return a QofBackendError.

Definition at line 402 of file qofsession.h.


Function Documentation

gboolean qof_entity_copy_coll QofSession new_session,
QofCollection entity_coll
 

Copy a QofCollection of entities.

The QofBook in the new_session must not contain any entities with the same GUID as any entities in the collection - there is no support for handling collisions - instead, use Merging QofBook structures

Parameters:
new_session - the target session
entity_coll - a QofCollection of any QofIdType.
Returns:
FALSE, without copying, if new_session contains any entities with the same GUID. Otherwise TRUE.

Definition at line 706 of file qofsession.c.

00708 {
00709         struct recurse_s *store;
00710 
00711         if(user_data == NULL) { return; }
00712         store = (struct recurse_s*)user_data;
00713         if(!ent || !store) { return; }
00714         store->success = qof_entity_copy_to_session(store->session, ent);
00715         if(store->success) {
00716         store->ent_list = g_list_append(store->ent_list, ent);
00717         }
00718 }
00719 
00720 static void
00721 recurse_ent_cb(QofEntity *ent, gpointer user_data)
00722 {
00723         GList      *ref_list, *i, *j, *ent_list, *child_list;

gboolean qof_entity_copy_coll_r QofSession new_session,
QofCollection coll
 

Recursively copy a collection of entities to a session.

Note:
This function creates a partial QofBook. See qof_entity_copy_to_session for more information.
The QofBook in the new_session must not contain any entities with the same GUID as any entities to be copied - there is no support for handling collisions - instead, use Merging QofBook structures

Objects can be defined solely in terms of QOF data types or as a mix of data types and other objects, which may in turn include other objects. These references can be copied recursively down to the third level. See QofEntityReference.

Note:
This is a deep recursive copy - every referenced entity is copied to the new session, including all parameters. The starting point is all entities in the top level collection. It can take some time.
Parameters:
coll A QofCollection of entities that may or may not have references.
new_session The QofSession to receive the copied entities.
Returns:
TRUE on success; if any individual copy fails, returns FALSE. Note : Some entities may have been copied successfully even if one of the references fails to copy.

Definition at line 855 of file qofsession.c.

00856         { QOF_LIB_DIR, "libqof_backend_dwi", "dwiend_provider_init" },
00857 #endif
00858         { NULL, NULL, NULL }
00859 };
00860 
00861 static void
00862 qof_session_load_backend(QofSession * session, char * access_method)
00863 {
00864         GSList *p;
00865         GList *node;
00866         QofBackendProvider *prov;
00867         QofBook *book;
00868         char *msg;
00869         gint num;

gboolean qof_entity_copy_list QofSession new_session,
GList *  entity_list
 

Copy a GList of entities to another session.

The QofBook in the new_session must not contain any entities with the same GUID as any of the source entities - there is no support for handling collisions, instead use Merging QofBook structures

Note that the GList (e.g. from qof_sql_query_run) can contain QofEntity pointers of any QofIdType, in any sequence. As long as all members of the list are QofEntity*, and all GUID's are unique, the list can be copied.

Parameters:
new_session - the target session
entity_list - a GList of QofEntity pointers of any type(s).
Returns:
FALSE, without copying, if new_session contains any entities with the same GUID. Otherwise TRUE.

Definition at line 683 of file qofsession.c.

00684                          { return FALSE; }
00685         qof_event_suspend();
00686         qecd.param_list = NULL;
00687         qecd.new_session = new_session;
00688         qof_book_set_partial(qof_session_get_book(qecd.new_session));
00689         qof_collection_foreach(entity_coll, qof_entity_coll_foreach, &qecd);
00690         qof_class_param_foreach(qof_collection_get_type(entity_coll), 
00691                 qof_entity_param_cb, &qecd);
00692         qof_collection_foreach(entity_coll, qof_entity_coll_copy, &qecd);
00693         if(qecd.param_list != NULL) { g_slist_free(qecd.param_list); }
00694         qof_event_resume();
00695         return TRUE;
00696 }
00697 
00698 struct recurse_s
00699 {
00700         QofSession *session;
00701         gboolean   success;
00702         GList      *ref_list;
00703         GList      *ent_list;

gboolean qof_entity_copy_one_r QofSession new_session,
QofEntity ent
 

Recursively copy a single entity to a new session.

Copy the single entity and all referenced entities to the second level.

Only entities that are directly referenced by the top level entity are copied.

This is a deep copy - all parameters of all referenced entities are copied. If the top level entity has no references, this is identical to qof_entity_copy_to_session.

Parameters:
ent A single entity that may or may not have references.
new_session The QofSession to receive the copied entities.
Returns:
TRUE on success; if any individual copy fails, returns FALSE. Note : Some entities may have been copied successfully even if one of the references fails to copy.

Definition at line 871 of file qofsession.c.

00876         {
00877                 for (num = 0; backend_list[num].filename != NULL; num++) {
00878                         if(!qof_load_backend_library(backend_list[num].libdir,
00879                                 backend_list[num].filename, backend_list[num].init_fcn))
00880                         {
00881                                 PWARN (" failed to load %s from %s using %s",
00882                                 backend_list[num].filename, backend_list[num].libdir,
00883                                 backend_list[num].init_fcn);
00884                         }
00885                 }
00886         }
00887         p = g_slist_copy(provider_list);
00888         while(p != NULL)

gboolean qof_entity_copy_to_session QofSession new_session,
QofEntity original
 

Copy a single QofEntity to another session.

Checks first that no entity in the session book contains the GUID of the source entity.

Parameters:
new_session - the target session
original - the QofEntity* to copy
Returns:
FALSE without copying if the session contains an entity with the same GUID already, otherwise TRUE.

Definition at line 655 of file qofsession.c.

00657 {
00658         QofEntityCopyData *qecd;
00659 
00660         if(!new_session || !entity_list) { return FALSE; }
00661         ENTER (" list=%d", g_list_length(entity_list));
00662         qecd = g_new0(QofEntityCopyData, 1);
00663         qof_event_suspend();
00664         qecd->param_list = NULL;
00665         qecd->new_session = new_session;
00666         qof_book_set_partial(qof_session_get_book(new_session));
00667         g_list_foreach(entity_list, qof_entity_list_foreach, qecd);
00668         qof_event_resume();
00669         if(qecd->error) 
00670         { 
00671                 PWARN (" some/all entities in the list could not be copied.");
00672         }
00673         g_free(qecd);
00674         LEAVE (" ");
00675         return TRUE;
00676 }
00677 
00678 gboolean 
00679 qof_entity_copy_coll(QofSession *new_session, QofCollection *entity_coll)
00680 {
00681         QofEntityCopyData qecd;

void qof_session_add_book QofSession session,
QofBook book
 

The qof_session_add_book() allows additional books to be added to a session. XXX Under construction, clarify the following when done: XXX There must already be an open book in the session already!? XXX Only one open book at a time per session is allowed!? XXX each book gets its own unique backend ???

Definition at line 248 of file qofsession.c.

00249 {
00250   GList *node;
00251   if (!session) return;
00252 
00253   ENTER (" sess=%p book=%p", session, addbook);
00254 
00255   /* See if this book is already there ... */
00256   for (node=session->books; node; node=node->next)
00257   {
00258      QofBook *book = node->data;
00259      if (addbook == book) return;
00260   }
00261 
00262   if ('y' == addbook->book_open)
00263   {
00264     /* hack alert -- someone should free all the books in the list,
00265      * but it should probably not be us ... since the books backends
00266      * should be shutdown first, etc */
00267 /* XXX this should probably be an error XXX */
00268     g_list_free (session->books);
00269     session->books = g_list_append (NULL, addbook);
00270   }
00271   else 
00272   {
00273 /* XXX Need to tell the backend to add a book as well */
00274     session->books = g_list_append (session->books, addbook);
00275   }
00276 
00277   qof_book_set_backend (addbook, session->backend);
00278   LEAVE (" ");
00279 }

void qof_session_add_close_hook GFunc  fn,
gpointer  data
 

Register a function to be called just before a session is closed.

Parameters:
fn The function to be called. The function definition must be func(gpointer session, gpointer user_data);
data The data to be passed to the function.

Definition at line 69 of file qofsession.c.

00070 {
00071   GHook *hook;
00072 
00073   if (session_closed_hooks == NULL) {
00074       session_closed_hooks = malloc(sizeof(GHookList)); /* LEAKED */
00075     g_hook_list_init (session_closed_hooks, sizeof(GHook));
00076   }
00077 
00078   hook = g_hook_alloc(session_closed_hooks);
00079   if (!hook)
00080     return;
00081 
00082   hook->func = (GHookFunc)fn;
00083   hook->data = data;
00084   g_hook_append(session_closed_hooks, hook);
00085 }

void qof_session_call_close_hooks QofSession session  ) 
 

Call all registered session close hooks, informing them that the specified session is about to be closed.

Parameters:
session A pointer to the session being closed.

Definition at line 88 of file qofsession.c.

00089 {
00090   GHook *hook;
00091   GFunc fn;
00092 
00093   if (session_closed_hooks == NULL)
00094     return;
00095 
00096   hook = g_hook_first_valid (session_closed_hooks, FALSE);
00097   while (hook) {
00098     fn = (GFunc)hook->func;
00099     fn(session, hook->data);
00100     hook = g_hook_next_valid (session_closed_hooks, hook, FALSE);
00101   }
00102 }

void qof_session_end QofSession session  ) 
 

The qof_session_end() method will release the session lock. For the file backend, it will *not* save the data to a file. Thus, this method acts as an "abort" or "rollback" primitive. However, for other backends, such as the sql backend, the data would have been written out before this, and so this routines wouldn't roll-back anything; it would just shut the connection.

Definition at line 1368 of file qofsession.c.

01371 {
01372   GList *books_1, *books_2, *node;
01373 
01374   if (session_1 == session_2) return;
01375   if (!session_1 || !session_2) return;
01376 
01377   ENTER ("sess1=%p sess2=%p", session_1, session_2);
01378 
01379   books_1 = session_1->books;
01380   books_2 = session_2->books;
01381 
01382   session_1->books = books_2;
01383   session_2->books = books_1;
01384 
01385   for (node=books_1; node; node=node->next)
01386   {
01387     QofBook *book_1 = node->data;
01388     qof_book_set_backend (book_1, session_2->backend);

gboolean qof_session_events_pending QofSession session  ) 
 

The qof_session_events_pending() method will return TRUE if the backend has pending events which must be processed to bring the engine up to date with the backend.

Definition at line 1456 of file qofsession.c.

QofBackendError qof_session_get_error QofSession session  ) 
 

The qof_session_get_error() routine can be used to obtain the reason for any failure. Calling this routine returns the current error.

Definition at line 139 of file qofsession.c.

00140 {
00141   QofBackendError err;
00142 
00143   if (!session) return ERR_BACKEND_NO_BACKEND;
00144 
00145   /* if we have a local error, return that. */
00146   if (ERR_BACKEND_NO_ERR != session->last_err)
00147   {
00148     return session->last_err;
00149   }
00150 
00151   /* maybe we should return a no-backend error ??? */
00152   if (! session->backend) return ERR_BACKEND_NO_ERR;
00153 
00154   err = qof_backend_get_error (session->backend);
00155   session->last_err = err;
00156   return err;
00157 }

const char* qof_session_get_file_path QofSession session  ) 
 

The qof_session_get_file_path() routine returns the fully-qualified file path for the session. That is, if a relative or partial filename was for the session, then it had to have been fully resolved to open the session. This routine returns the result of this resolution. The path is always guaranteed to reside in the local file system, even if the session itself was opened as a URL. (currently, the filepath is derived from the url by substituting commas for slashes).

The qof_session_get_url() routine returns the url that was opened. URL's for local files take the form of file:/some/where/some/file.gml

Definition at line 289 of file qofsession.c.

00290 {
00291    if (!session) return NULL;
00292    if (!session->backend) return NULL;
00293    return session->backend->fullpath;
00294 }

gboolean qof_session_not_saved QofSession session  ) 
 

The qof_session_not_saved() subroutine will return TRUE if any data in the session hasn't been saved to long-term storage.

QofBackendError qof_session_pop_error QofSession session  ) 
 

The qof_session_pop_error() routine can be used to obtain the reason for any failure. Calling this routine resets the error value.

This routine allows an implementation of multiple error values, e.g. in a stack, where this routine pops the top value. The current implementation has a stack that is one-deep.

See qofbackend.h for a listing of returned errors.

Definition at line 175 of file qofsession.c.

00176 {
00177   QofBackendError err;
00178 
00179   if (!session) return ERR_BACKEND_NO_BACKEND;
00180 
00181   err = qof_session_get_error(session);
00182   qof_session_clear_error(session);
00183 
00184   return err;
00185 }

gboolean qof_session_process_events QofSession session  ) 
 

The qof_session_process_events() method will process any events indicated by the qof_session_events_pending() method. It returns TRUE if the engine was modified while engine events were suspended.

Definition at line 1466 of file qofsession.c.

void qof_session_save QofSession session,
QofPercentageFunc  percentage_func
 

Todo:
check the access_method too, not in scope here, yet.

Definition at line 1221 of file qofsession.c.

01222                         {*/
01223                                 if (NULL == prov->backend_new) continue;
01224                                 /* Use the providers creation callback */
01225                                 session->backend = (*(prov->backend_new))();
01226                                 session->backend->provider = prov;
01227                                 if (session->backend->session_begin)
01228                                 {
01229                                         /* Call begin - backend has been changed,
01230                                            so make sure a file can be written,
01231                                            use ignore_lock and create_if_nonexistent */
01232                                         g_free(session->book_id);
01233                                         session->book_id = NULL;
01234                                         (session->backend->session_begin)(session->backend, session,
01235                                                 book_id, TRUE, TRUE);
01236                                         PINFO("Done running session_begin on changed backend");
01237                                         err = qof_backend_get_error(session->backend);
01238                                         msg = qof_backend_get_message(session->backend);
01239                                         if (err != ERR_BACKEND_NO_ERR)
01240                                         {
01241                                                 g_free(session->book_id);
01242                                                 session->book_id = NULL;
01243                                                 qof_session_push_error (session, err, msg);
01244                                                 LEAVE("changed backend error %d", err);
01245                                                 return;
01246                                         }
01247                                         if (msg != NULL) 
01248                                         {
01249                                                 PWARN("%s", msg);
01250                                                 g_free(msg);
01251                                         }
01252                                 }
01253                                 /* Tell the books about the backend that they'll be using. */
01254                                 for (node=session->books; node; node=node->next)
01255                                 {
01256                                         book = node->data;
01257                                         qof_book_set_backend (book, session->backend);
01258                                 }
01259                                 p = NULL;
01260                         }
01261                         if(p) {
01262                                 p = p->next;
01263                         }
01264                 }
01265                 if(!session->backend) 
01266                 {
01267                         msg = g_strdup_printf("failed to load backend");
01268                         qof_session_push_error(session, ERR_BACKEND_NO_HANDLER, msg);
01269                         return;
01270                 }
01271         }
01272         /* If there is a backend, and the backend is reachable
01273         * (i.e. we can communicate with it), then synchronize with 
01274         * the backend.  If we cannot contact the backend (e.g.
01275         * because we've gone offline, the network has crashed, etc.)
01276         * then give the user the option to save to the local disk. 
01277         *
01278         * hack alert -- FIXME -- XXX the code below no longer
01279         * does what the words above say.  This needs fixing.
01280         */
01281         be = session->backend;
01282         if (be)
01283         {
01284                 for (node = session->books; node; node=node->next)
01285                 {
01286                         abook = node->data;
01287                         /* if invoked as SaveAs(), then backend not yet set */
01288                         qof_book_set_backend (abook, be);
01289                         be->percentage = percentage_func;
01290                         if (be->sync)
01291                         {
01292                                 (be->sync)(be, abook);
01293                                 if (save_error_handler(be, session)) return;
01294                         }
01295                 }
01296                 /* If we got to here, then the backend saved everything 
01297                 * just fine, and we are done. So return. */
01298                 /* Return the book_id to previous value. */
01299                 qof_session_clear_error (session);
01300                 LEAVE("Success");
01301                 return;
01302         }
01303         else
01304         {
01305                 msg = g_strdup_printf("failed to load backend");
01306                 qof_session_push_error(session, ERR_BACKEND_NO_HANDLER, msg);
01307         }
01308         LEAVE("error -- No backend!");
01309 }
01310 
01311 /* ====================================================================== */
01312 
01313 void
01314 qof_session_end (QofSession *session)
01315 {
01316   if (!session) return;
01317 
01318   ENTER ("sess=%p book_id=%s", session, session->book_id
01319          ? session->book_id : "(null)");
01320 
01321   /* close down the backend first */
01322   if (session->backend && session->backend->session_end)
01323   {
01324     (session->backend->session_end)(session->backend);
01325   }
01326 
01327   qof_session_clear_error (session);
01328 
01329   g_free (session->book_id);
01330   session->book_id = NULL;
01331 
01332   LEAVE ("sess=%p book_id=%s", session, session->book_id
01333          ? session->book_id : "(null)");
01334 }
01335 
01336 void 
01337 qof_session_destroy (QofSession *session) 
01338 {
01339   GList *node;
01340   if (!session) return;
01341 
01342   ENTER ("sess=%p book_id=%s", session, session->book_id
01343          ? session->book_id : "(null)");
01344 
01345   qof_session_end (session);
01346 
01347   /* destroy the backend */
01348   qof_session_destroy_backend(session);
01349 
01350   for (node = session->books; node; node = node->next)
01351   {
01352     QofBook *book = node->data;
01353     qof_book_set_backend (book, NULL);
01354     qof_book_destroy (book);
01355   }
01356 
01357   session->books  = NULL;
01358   if (session == current_session)
01359     current_session = NULL;
01360 
01361   g_free (session);
01362 
01363   LEAVE ("sess=%p", session);

gboolean qof_session_save_may_clobber_data QofSession session  ) 
 

Allows the backend to warn the user if a dataset already exists.

Definition at line 1197 of file qofsession.c.

01198                              { change_backend = TRUE; }
01199                 }
01200                 /* If provider is undefined, assume partial not supported. */
01201                 else { change_backend = TRUE; }
01202         }
01203         if(change_backend == TRUE)
01204         {


Generated on Fri May 12 17:57:21 2006 for QOF by  doxygen 1.4.4