Session: Backend connections.
[Backends: Permanent storage for QOF entities.]


Files

file  qofsession.h
 Encapsulates a connection to a backend (persistent store).

Defines

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

Typedefs

typedef struct _QofSession QofSession
typedef void(* QofPercentageFunc )(const gchar *message, gdouble percent)

Functions

QofSession * qof_session_new (void)
void qof_session_destroy (QofSession *session)
void qof_session_swap_data (QofSession *session_1, QofSession *session_2)
void qof_session_begin (QofSession *session, const gchar *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 gchar * qof_session_get_file_path (QofSession *session)
const gchar * 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)

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 Reference: 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 Merge: 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)

Detailed Description

The QOF Session encapsulates a connection to a storage backend. That is, it manages the connection to a persistant data store; whereas the backend is the thing that performs the actual datastore access.

This class provides several important services:

1) It resolves and loads the appropriate backend, based on the URL.

2) It reports backend errors (e.g. network errors, storage corruption errors) through a single, backend-independent API.

3) It reports non-error events received from the backend.

4) It helps manage global dataset locks. For example, for the file backend, the lock prevents multiple users from editing the same file at the same time, thus avoiding lost data due to race conditions. Thus, an open session implies that the associated file is locked.

5) Misc utilities, such as a search path for the file to be edited, and/or other URL resolution utilities. This should simplify install & maintenance problems for naive users who may not have a good grasp on what a file system is, or where they want to keep their data files.

6) In the future, this class is probably a good place to manage a portion of the user authentication process, and hold user credentials/cookies/keys/tokens. This is because at the coarsest level, authorization can happen at the datastore level: i.e. does this user even have the authority to connect to and open this datastore?

A brief note about books & sessions: A book encapsulates the datasets manipulated by QOF. A book holds the actual data. By contrast, the session mediates the connection between a book (the thing that lives in virtual memory in the local process) and the datastore (the place where book data lives permanently, e.g., file, database).

In the current design, a session may hold multiple books. For now, exactly what this means is somewhat vague, and code in various places makes some implicit assumptions: first, only one book is 'current' and open for editing. Next, its assumed that all of the books in a session are related in some way. i.e. that they are all earlier accounting periods of the currently open book. In particular, the backends probably make that assumption, in order to store the different accounting periods in a clump so that one can be found, given another.

If you want multiple books that are unrelated to each other, use multiple sessions.

The session now calls QofBackendProvider->check_data_type to check that the incoming path contains data that the backend provider can open. The backend provider should also check if it can contact it's storage media (disk, network, server, etc.) and abort if it can't. Malformed file URL's would be handled the same way.


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 386 of file qofsession.h.


Typedef Documentation

typedef void(* QofPercentageFunc)(const gchar *message, gdouble percent)

The qof_session_load() method causes the QofBook to be made ready to to use with this URL/datastore. When the URL points at a file, then this routine would load the data from the file. With remote backends, e.g. network or SQL, this would load only enough data to make the book actually usable; it would not cause *all* of the data to be loaded.

XXX the current design tries to accomodate multiple calls to 'load' for each session, each time wiping out the old books; this seems wrong to me, and should be restricted to allow only one load per session.

Definition at line 168 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 Merge: 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 685 of file qofsession.c.

00687 {
00688     QofEntityCopyData qecd;
00689 
00690     g_return_val_if_fail (new_session, FALSE);
00691     if (!entity_coll)
00692     {
00693         return FALSE;
00694     }
00695     qof_event_suspend ();
00696     qecd.param_list = NULL;
00697     qecd.new_session = new_session;
00698     qof_book_set_partial (qof_session_get_book (qecd.new_session));
00699     qof_collection_foreach (entity_coll, qof_entity_coll_foreach, &qecd);
00700     qof_class_param_foreach (qof_collection_get_type (entity_coll),
00701         qof_entity_param_cb, &qecd);
00702     qof_collection_foreach (entity_coll, qof_entity_coll_copy, &qecd);
00703     if (qecd.param_list != NULL)
00704     {
00705         g_slist_free (qecd.param_list);
00706     }
00707     qof_event_resume ();
00708     return TRUE;
00709 }

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 Merge: 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 859 of file qofsession.c.

00860 {
00861     struct recurse_s store;
00862     gboolean success;
00863 
00864     if ((!new_session) || (!coll))
00865     {
00866         return FALSE;
00867     }
00868     store.session = new_session;
00869     success = TRUE;
00870     store.success = success;
00871     store.ent_list = NULL;
00872     store.ref_list =
00873         qof_class_get_referenceList (qof_collection_get_type (coll));
00874     success = qof_entity_copy_coll (new_session, coll);
00875     if (success)
00876     {
00877         qof_collection_foreach (coll, recurse_ent_cb, &store);
00878     }
00879     return success;
00880 }

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 Merge: 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 663 of file qofsession.c.

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

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 883 of file qofsession.c.

00884 {
00885     struct recurse_s store;
00886     QofCollection *coll;
00887     gboolean success;
00888 
00889     if ((!new_session) || (!ent))
00890     {
00891         return FALSE;
00892     }
00893     store.session = new_session;
00894     success = TRUE;
00895     store.success = success;
00896     store.ref_list = qof_class_get_referenceList (ent->e_type);
00897     success = qof_entity_copy_to_session (new_session, ent);
00898     if (success == TRUE)
00899     {
00900         coll =
00901             qof_book_get_collection (qof_session_get_book (new_session),
00902             ent->e_type);
00903         if (coll)
00904         {
00905             qof_collection_foreach (coll, recurse_ent_cb, &store);
00906         }
00907     }
00908     return success;
00909 }

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 631 of file qofsession.c.

00632 {
00633     QofEntityCopyData qecd;
00634     QofInstance *inst;
00635     QofBook *book;
00636 
00637     if (!new_session || !original)
00638         return FALSE;
00639     if (qof_entity_guid_match (new_session, original))
00640         return FALSE;
00641     if (!qof_object_compliance (original->e_type, TRUE))
00642         return FALSE;
00643     qof_event_suspend ();
00644     qecd.param_list = NULL;
00645     book = qof_session_get_book (new_session);
00646     qecd.new_session = new_session;
00647     qof_book_set_partial (book);
00648     inst =
00649         (QofInstance *) qof_object_new_instance (original->e_type, book);
00650     qecd.to = &inst->entity;
00651     qecd.from = original;
00652     qof_entity_set_guid (qecd.to, qof_entity_get_guid (original));
00653     qof_class_param_foreach (original->e_type, qof_entity_param_cb, &qecd);
00654     if (g_slist_length (qecd.param_list) == 0)
00655         return FALSE;
00656     g_slist_foreach (qecd.param_list, qof_entity_foreach_copy, &qecd);
00657     g_slist_free (qecd.param_list);
00658     qof_event_resume ();
00659     return TRUE;
00660 }

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 145 of file qofsession.c.

00146 {
00147     GList *node;
00148     if (!session)
00149         return;
00150 
00151     ENTER (" sess=%p book=%p", session, addbook);
00152 
00153     /* See if this book is already there ... */
00154     for (node = session->books; node; node = node->next)
00155     {
00156         QofBook *book = node->data;
00157         if (addbook == book)
00158             return;
00159     }
00160 
00161     if ('y' == addbook->book_open)
00162     {
00163         /* hack alert -- someone should free all the books in the list,
00164          * but it should probably not be us ... since the books backends
00165          * should be shutdown first, etc */
00166 /* XXX this should probably be an error XXX */
00167         g_list_free (session->books);
00168         session->books = g_list_append (NULL, addbook);
00169     }
00170     else
00171     {
00172 /* XXX Need to tell the backend to add a book as well */
00173         session->books = g_list_append (session->books, addbook);
00174     }
00175 
00176     qof_book_set_backend (addbook, session->backend);
00177     LEAVE (" ");
00178 }

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     {
00075         session_closed_hooks = malloc (sizeof (GHookList)); /* LEAKED */
00076         g_hook_list_init (session_closed_hooks, sizeof (GHook));
00077     }
00078 
00079     hook = g_hook_alloc (session_closed_hooks);
00080     if (!hook)
00081         return;
00082 
00083     hook->func = (GHookFunc) fn;
00084     hook->data = data;
00085     g_hook_append (session_closed_hooks, hook);
00086 }

void qof_session_begin ( QofSession *  session,
const gchar *  book_id,
gboolean  ignore_lock,
gboolean  create_if_nonexistent 
)

The qof_session_begin () method begins a new session. It takes as an argument the book id. The book id must be a string in the form of a URI/URL. The access method specified depends on the loaded backends. In the absence of a customised backend, only QSF XML would be accepted). Paths may be relative or absolute. If the path is relative; that is, if the argument is "file:somefile.xml" then the current working directory is assumed. Customised backends can choose to search other, application-specific, directories as well.

The 'ignore_lock' argument, if set to TRUE, will cause this routine to ignore any global-datastore locks (e.g. file locks) that it finds. If set to FALSE, then file/database-global locks will be tested and obeyed.

If the datastore exists, can be reached (e.g over the net), connected to, opened and read, and a lock can be obtained then a lock will be obtained. Note that multi-user datastores (e.g. the SQL backend) typically will not need to get a global lock, and thus, the user will not be locked out. That's the whole point of 'multi-user'.

If the file/database doesn't exist, and the create_if_nonexistent flag is set to TRUE, then the database is created.

If an error occurs, it will be pushed onto the session error stack, and that is where it should be examined.

Definition at line 1032 of file qofsession.c.

01034 {
01035     gchar *p, *access_method;
01036 
01037     if (!session)
01038         return;
01039 
01040     ENTER (" sess=%p ignore_lock=%d, book-id=%s",
01041         session, ignore_lock, book_id ? book_id : "(null)");
01042 
01043     /* Clear the error condition of previous errors */
01044     qof_error_clear (session);
01045 
01046     /* Check to see if this session is already open */
01047     if (session->book_id)
01048     {
01049         qof_error_set (session, qof_error_register
01050         (_("This book appears to be open already."), FALSE));
01051         LEAVE (" push error book is already open ");
01052         return;
01053     }
01054 
01055     if (!book_id)
01056     {
01057         LEAVE (" using stdout");
01058         return;
01059     }
01060 
01061     /* Store the session URL  */
01062     session->book_id = g_strdup (book_id);
01063 
01064     /* destroy the old backend */
01065     qof_session_destroy_backend (session);
01066 
01067     /* Look for something of the form of "file:/", "http://" or
01068      * "postgres://". Everything before the colon is the access
01069      * method.  Load the first backend found for that access method.
01070      */
01071     p = strchr (book_id, ':');
01072     if (p)
01073     {
01074         access_method = g_strdup (book_id);
01075         p = strchr (access_method, ':');
01076         *p = 0;
01077         qof_session_load_backend (session, access_method);
01078         g_free (access_method);
01079     }
01080     else
01081     {
01082         /* If no colon found, assume it must be a file-path */
01083         qof_session_load_backend (session, "file");
01084     }
01085 
01086     /* No backend was found. That's bad. */
01087     if (NULL == session->backend)
01088     {
01089         gchar * msg;
01090 
01091         msg = g_strdup_printf (_("Unable to locate a "
01092         "suitable backend for '%s' - please check "
01093         "you have specified an access method "
01094         "like file: or sqlite:"), book_id);
01095         qof_error_set (session, qof_error_register
01096             (msg, FALSE));
01097         DEBUG (" msg=%s", msg);
01098         LEAVE (" BAD: no backend: sess=%p book-id=%s",
01099             session, book_id ? book_id : "(null)");
01100         g_free (msg);
01101         return;
01102     }
01103 
01104     /* If there's a begin method, call that. */
01105     if (session->backend->session_begin)
01106     {
01107         (session->backend->session_begin) (session->backend, session,
01108             session->book_id, ignore_lock, create_if_nonexistent);
01109         PINFO (" Done running session_begin on backend");
01110         if (qof_error_check(session) != QOF_SUCCESS)
01111         {
01112             g_free (session->book_id);
01113             session->book_id = NULL;
01114             LEAVE (" backend error ");
01115             return;
01116         }
01117     }
01118     qof_error_clear (session);
01119     LEAVE (" sess=%p book-id=%s", session, book_id ? book_id : "(null)");
01120 }

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 89 of file qofsession.c.

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

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 1374 of file qofsession.c.

01375 {
01376     if (!session)
01377         return;
01378 
01379     ENTER (" sess=%p book_id=%s", session, session->book_id
01380         ? session->book_id : "(null)");
01381 
01382     /* close down the backend first */
01383     if (session->backend && session->backend->session_end)
01384     {
01385         (session->backend->session_end) (session->backend);
01386     }
01387 
01388     qof_error_clear (session);
01389 
01390     g_free (session->book_id);
01391     session->book_id = NULL;
01392 
01393     LEAVE (" sess=%p book_id=%s", session, session->book_id
01394         ? session->book_id : "(null)");
01395 }

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 1463 of file qofsession.c.

01464 {
01465     if (!session)
01466         return FALSE;
01467     if (!session->backend)
01468         return FALSE;
01469     if (!session->backend->events_pending)
01470         return FALSE;
01471 
01472     return session->backend->events_pending (session->backend);
01473 }

const gchar* 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 189 of file qofsession.c.

00190 {
00191     if (!session)
00192         return NULL;
00193     if (!session->backend)
00194         return NULL;
00195     return session->backend->fullpath;
00196 }

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.

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 1476 of file qofsession.c.

01477 {
01478     if (!session)
01479         return FALSE;
01480     if (!session->backend)
01481         return FALSE;
01482     if (!session->backend->process_events)
01483         return FALSE;
01484 
01485     return session->backend->process_events (session->backend);
01486 }

void qof_session_save ( QofSession *  session,
QofPercentageFunc  percentage_func 
)

The qof_session_save() method will commit all changes that have been made to the session. For the file backend, this is nothing more than a write to the file of the current AccountGroup & etc. For the SQL backend, this is typically a no-op (since all data has already been written out to the database.

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

Definition at line 1220 of file qofsession.c.

01222 {
01223     GList *node;
01224     QofBackend *be;
01225     gboolean partial, change_backend;
01226     QofBackendProvider *prov;
01227     GSList *p;
01228     QofBook *book, *abook;
01229     gint num;
01230     gchar *msg, *book_id;
01231 
01232     if (!session)
01233         return;
01234     ENTER (" sess=%p book_id=%s",
01235         session, session->book_id ? session->book_id : "(null)");
01236     /* Partial book handling. */
01237     book = qof_session_get_book (session);
01238     partial =
01239         (gboolean)
01240         GPOINTER_TO_INT (qof_book_get_data (book, PARTIAL_QOFBOOK));
01241     change_backend = FALSE;
01242     msg = g_strdup_printf (" ");
01243     book_id = g_strdup (session->book_id);
01244     if (partial == TRUE)
01245     {
01246         if (session->backend && session->backend->provider)
01247         {
01248             prov = session->backend->provider;
01249             if (TRUE == prov->partial_book_supported)
01250             {
01251                 /* if current backend supports partial, leave alone. */
01252                 change_backend = FALSE;
01253             }
01254             else
01255             {
01256                 change_backend = TRUE;
01257             }
01258         }
01259         /* If provider is undefined, assume partial not supported. */
01260         else
01261         {
01262             change_backend = TRUE;
01263         }
01264     }
01265     if (change_backend == TRUE)
01266     {
01267         qof_session_destroy_backend (session);
01268         if (NULL == provider_list)
01269         {
01270             for (num = 0; backend_list[num].filename != NULL; num++)
01271             {
01272                 qof_load_backend_library (backend_list[num].libdir,
01273                     backend_list[num].filename,
01274                     backend_list[num].init_fcn);
01275             }
01276         }
01277         p = g_slist_copy (provider_list);
01278         while (p != NULL)
01279         {
01280             prov = p->data;
01281             if (TRUE == prov->partial_book_supported)
01282             {
01284                 /*  if((TRUE == prov->partial_book_supported) &&
01285                    (0 == strcasecmp (access_method, prov->access_method)))
01286                    { */
01287                 if (NULL == prov->backend_new)
01288                     continue;
01289                 /* Use the providers creation callback */
01290                 session->backend = (*(prov->backend_new)) ();
01291                 session->backend->provider = prov;
01292                 if (session->backend->session_begin)
01293                 {
01294                     /* Call begin - backend has been changed,
01295                        so make sure a file can be written,
01296                        use ignore_lock and create_if_nonexistent */
01297                     g_free (session->book_id);
01298                     session->book_id = NULL;
01299                     (session->backend->session_begin) (session->backend,
01300                         session, book_id, TRUE, TRUE);
01301                     PINFO
01302                         (" Done running session_begin on changed backend");
01303                     if (qof_error_check (session) != QOF_SUCCESS)
01304                     {
01305                         g_free (session->book_id);
01306                         session->book_id = NULL;
01307                         LEAVE (" changed backend error");
01308                         return;
01309                     }
01310                 }
01311                 /* Tell the books about the backend that they'll be using. */
01312                 for (node = session->books; node; node = node->next)
01313                 {
01314                     book = node->data;
01315                     qof_book_set_backend (book, session->backend);
01316                 }
01317                 p = NULL;
01318             }
01319             if (p)
01320             {
01321                 p = p->next;
01322             }
01323         }
01324         if (!session->backend)
01325         {
01326             msg = g_strdup_printf (" failed to load backend");
01327             qof_error_set (session, qof_error_register
01328             (_("Failed to load backend, no suitable handler."),
01329             FALSE));
01330             return;
01331         }
01332     }
01333     /* If there is a backend, and the backend is reachable
01334      * (i.e. we can communicate with it), then synchronize with
01335      * the backend.  If we cannot contact the backend (e.g.
01336      * because we've gone offline, the network has crashed, etc.)
01337      * then give the user the option to save to the local disk.
01338      *
01339      * hack alert -- FIXME -- XXX the code below no longer
01340      * does what the words above say.  This needs fixing.
01341      */
01342     be = session->backend;
01343     if (be)
01344     {
01345         for (node = session->books; node; node = node->next)
01346         {
01347             abook = node->data;
01348             /* if invoked as SaveAs(), then backend not yet set */
01349             qof_book_set_backend (abook, be);
01350             be->percentage = percentage_func;
01351             if (be->sync)
01352                 (be->sync) (be, abook);
01353         }
01354         /* If we got to here, then the backend saved everything
01355          * just fine, and we are done. So return. */
01356         /* Return the book_id to previous value. */
01357         qof_error_clear (session);
01358         LEAVE (" Success");
01359         return;
01360     }
01361     else
01362     {
01363         msg = g_strdup_printf (" failed to load backend");
01364         qof_error_set (session, qof_error_register
01365             (_("Failed to load backend, no suitable handler."),
01366             FALSE));
01367     }
01368     LEAVE (" error -- No backend!");
01369 }

gboolean qof_session_save_may_clobber_data ( QofSession *  session  ) 

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

Definition at line 1207 of file qofsession.c.

01208 {
01209     if (!session)
01210         return FALSE;
01211     if (!session->backend)
01212         return FALSE;
01213     if (!session->backend->save_may_clobber_data)
01214         return FALSE;
01215 
01216     return (*(session->backend->save_may_clobber_data)) (session->backend);
01217 }

void qof_session_swap_data ( QofSession *  session_1,
QofSession *  session_2 
)

The qof_session_swap_data () method swaps the book of the two given sessions. It is useful for 'Save As' type functionality.

Definition at line 1429 of file qofsession.c.

01430 {
01431     GList *books_1, *books_2, *node;
01432 
01433     if (session_1 == session_2)
01434         return;
01435     if (!session_1 || !session_2)
01436         return;
01437 
01438     ENTER (" sess1=%p sess2=%p", session_1, session_2);
01439 
01440     books_1 = session_1->books;
01441     books_2 = session_2->books;
01442 
01443     session_1->books = books_2;
01444     session_2->books = books_1;
01445 
01446     for (node = books_1; node; node = node->next)
01447     {
01448         QofBook *book_1 = node->data;
01449         qof_book_set_backend (book_1, session_2->backend);
01450     }
01451     for (node = books_2; node; node = node->next)
01452     {
01453         QofBook *book_2 = node->data;
01454         qof_book_set_backend (book_2, session_1->backend);
01455     }
01456 
01457     LEAVE (" ");
01458 }


Generated on Sat Aug 15 15:46:33 2009 for QOF by  doxygen 1.5.9