Remove close hook list; not used.

This commit is contained in:
John Ralls 2016-02-16 17:11:55 -08:00
parent 34e34334c7
commit 915a2930f3
21 changed files with 372 additions and 519 deletions

View File

@ -83,6 +83,7 @@ extern "C"
#include <boost/regex.hpp>
#include <string>
#include <gnc-backend-prov.hpp>
#include "gnc-backend-dbi.h"
#include "gnc-backend-dbi-priv.h"
@ -93,6 +94,46 @@ extern "C"
#endif
#endif
struct QofSQLITEBackendProvider : public QofBackendProvider
{
QofSQLITEBackendProvider (const char* name, const char* type) :
QofBackendProvider {name, type} {}
QofSQLITEBackendProvider(QofSQLITEBackendProvider&) = delete;
QofSQLITEBackendProvider operator=(QofSQLITEBackendProvider&) = delete;
QofSQLITEBackendProvider(QofSQLITEBackendProvider&&) = delete;
QofSQLITEBackendProvider operator=(QofSQLITEBackendProvider&&) = delete;
~QofSQLITEBackendProvider () = default;
QofBackend* create_backend(void);
bool type_check(const char* type);
};
struct QofMYSQLBackendProvider : public QofBackendProvider
{
QofMYSQLBackendProvider (const char* name, const char* type) :
QofBackendProvider {name, type} {}
QofMYSQLBackendProvider(QofMYSQLBackendProvider&) = delete;
QofMYSQLBackendProvider operator=(QofMYSQLBackendProvider&) = delete;
QofMYSQLBackendProvider(QofMYSQLBackendProvider&&) = delete;
QofMYSQLBackendProvider operator=(QofMYSQLBackendProvider&&) = delete;
~QofMYSQLBackendProvider () = default;
QofBackend* create_backend(void);
bool type_check(const char* type) { return true; }
};
struct QofPGSQLBackendProvider : public QofBackendProvider
{
QofPGSQLBackendProvider (const char* name, const char* type) :
QofBackendProvider {name, type} {}
QofPGSQLBackendProvider(QofPGSQLBackendProvider&) = delete;
QofPGSQLBackendProvider operator=(QofPGSQLBackendProvider&) = delete;
QofPGSQLBackendProvider(QofPGSQLBackendProvider&&) = delete;
QofPGSQLBackendProvider operator=(QofPGSQLBackendProvider&&) = delete;
~QofPGSQLBackendProvider () = default;
QofBackend* create_backend(void);
bool type_check(const char* type) { return true; }
};
#if LIBDBI_VERSION >= 900
#define HAVE_LIBDBI_R 1
static dbi_inst dbi_instance = NULL;
@ -297,7 +338,7 @@ gnc_dbi_sqlite3_session_begin (QofBackend* qbe, QofSession* session,
/* Remove uri type if present */
filepath = gnc_uri_get_path (book_id);
GFileTest ftest = static_cast<decltype (ftest)> (
G_FILE_TEST_IS_REGULAR | G_FILE_TEST_EXISTS) ;
G_FILE_TEST_IS_REGULAR | G_FILE_TEST_EXISTS) ;
file_exists = g_file_test (filepath, ftest);
if (!create && !file_exists)
{
@ -915,7 +956,7 @@ gnc_dbi_mysql_session_begin (QofBackend* qbe, QofSession* session,
/* Split the book-id
* Format is protocol://username:password@hostname:port/dbname
where username, password and port are optional) */
where username, password and port are optional) */
gnc_uri_get_components (book_id, &protocol, &host, &portnum,
&username, &password, &dbname);
@ -1270,7 +1311,7 @@ gnc_dbi_postgres_session_begin (QofBackend* qbe, QofSession* session,
/* Split the book-id
* Format is protocol://username:password@hostname:port/dbname
where username, password and port are optional) */
where username, password and port are optional) */
gnc_uri_get_components (book_id, &protocol, &host, &portnum,
&username, &password, &dbname);
if (portnum == 0)
@ -1595,7 +1636,7 @@ gnc_dbi_load (QofBackend* qbe, QofBook* book, QofBackendLoadType loadType)
qof_backend_set_error (qbe, ERR_SQL_DB_TOO_OLD);
}
else if (GNUCASH_RESAVE_VERSION < gnc_sql_get_table_version (&be->sql_be,
"Gnucash-Resave"))
"Gnucash-Resave"))
{
/* Worse, the database was created with a newer version. We
* can't safely write to this database, so the user will have
@ -1912,38 +1953,31 @@ new_backend (void (*session_begin) (QofBackend*, QofSession*, const gchar*,
return be;
}
static QofBackend*
gnc_dbi_backend_sqlite3_new (void)
QofBackend*
QofSQLITEBackendProvider::create_backend()
{
return new_backend (gnc_dbi_sqlite3_session_begin);
}
static QofBackend*
gnc_dbi_backend_mysql_new (void)
QofBackend*
QofMYSQLBackendProvider::create_backend()
{
return new_backend (gnc_dbi_mysql_session_begin);
}
static QofBackend*
gnc_dbi_backend_postgres_new (void)
QofBackend*
QofPGSQLBackendProvider::create_backend()
{
return new_backend (gnc_dbi_postgres_session_begin);
}
static void
gnc_dbi_provider_free (QofBackendProvider* prov)
{
g_return_if_fail (prov != NULL);
g_free (prov);
}
/*
* Checks to see whether the file is an sqlite file or not
*
*/
static gboolean
gnc_dbi_check_sqlite3_file (const gchar* uri)
bool
QofSQLITEBackendProvider::type_check(const char *uri)
{
FILE* f;
gchar buf[50];
@ -1986,7 +2020,6 @@ gnc_dbi_check_sqlite3_file (const gchar* uri)
void
gnc_module_init_backend_dbi (void)
{
QofBackendProvider* prov;
const gchar* driver_dir;
int num_drivers;
gboolean have_sqlite3_driver = FALSE;
@ -2062,51 +2095,25 @@ gnc_module_init_backend_dbi (void)
if (have_sqlite3_driver)
{
prov = g_new0 (QofBackendProvider, 1);
g_assert (prov != NULL);
prov->provider_name = "GnuCash Libdbi (SQLITE3) Backend";
prov->access_method = FILE_URI_TYPE;
prov->backend_new = gnc_dbi_backend_sqlite3_new;
prov->provider_free = gnc_dbi_provider_free;
prov->check_data_type = gnc_dbi_check_sqlite3_file;
qof_backend_register_provider (prov);
prov = g_new0 (QofBackendProvider, 1);
g_assert (prov != NULL);
prov->provider_name = "GnuCash Libdbi (SQLITE3) Backend";
prov->access_method = SQLITE3_URI_TYPE;
prov->backend_new = gnc_dbi_backend_sqlite3_new;
prov->provider_free = gnc_dbi_provider_free;
prov->check_data_type = gnc_dbi_check_sqlite3_file;
qof_backend_register_provider (prov);
const char* name = "GnuCash Libdbi (SQLITE3) Backend";
auto prov = QofBackendProvider_ptr(new QofSQLITEBackendProvider{name, FILE_URI_TYPE});
qof_backend_register_provider(std::move(prov));
prov = QofBackendProvider_ptr(new QofSQLITEBackendProvider{name, SQLITE3_URI_TYPE});
qof_backend_register_provider(std::move(prov));
}
if (have_mysql_driver)
{
prov = g_new0 (QofBackendProvider, 1);
g_assert (prov != NULL);
prov->provider_name = "GnuCash Libdbi (MYSQL) Backend";
prov->access_method = "mysql";
prov->backend_new = gnc_dbi_backend_mysql_new;
prov->provider_free = gnc_dbi_provider_free;
prov->check_data_type = NULL;
qof_backend_register_provider (prov);
const char *name = "GnuCash Libdbi (MYSQL) Backend";
auto prov = QofBackendProvider_ptr(new QofMYSQLBackendProvider{name, "mysql"});
qof_backend_register_provider(std::move(prov));
}
if (have_pgsql_driver)
{
prov = g_new0 (QofBackendProvider, 1);
g_assert (prov != NULL);
prov->provider_name = "GnuCash Libdbi (POSTGRESQL) Backend";
prov->access_method = "postgres";
prov->backend_new = gnc_dbi_backend_postgres_new;
prov->provider_free = gnc_dbi_provider_free;
prov->check_data_type = NULL;
qof_backend_register_provider (prov);
const char* name = "GnuCash Libdbi (POSTGRESQL) Backend";
auto prov = QofBackendProvider_ptr(new QofPGSQLBackendProvider{name, "postgres"});
qof_backend_register_provider(std::move(prov));
}
/* If needed, set log level to DEBUG so that SQl statements will be put into

View File

@ -593,7 +593,7 @@ test_gnc_sql_convert_timespec_to_string ()
GncSqlBackend be = {{
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
nullptr, nullptr, ERR_BACKEND_NO_ERR, nullptr, 0, nullptr, nullptr
nullptr, ERR_BACKEND_NO_ERR, nullptr, 0, nullptr, nullptr
},
nullptr, nullptr, FALSE, FALSE, FALSE, 0, 0, nullptr,
"%4d-%02d-%02d %02d:%02d:%02d"

View File

@ -78,7 +78,6 @@ extern "C"
#include "gnc-uri-utils.h"
#include "io-gncxml-v2.h"
#include "gnc-backend-xml.h"
#include "gnc-prefs.h"
#ifndef HAVE_STRPTIME
@ -86,6 +85,9 @@ extern "C"
#endif
}
#include <gnc-backend-prov.hpp>
#include "gnc-backend-xml.h"
#include <qofbackend-p.h>
#include "gnc-xml-helper.h"
#include "io-gncxml.h"
@ -105,6 +107,20 @@ static QofLogModule log_module = GNC_MOD_BACKEND;
static gboolean save_may_clobber_data (QofBackend* bend);
struct QofXmlBackendProvider : public QofBackendProvider
{
QofXmlBackendProvider (const char* name, const char* type) :
QofBackendProvider {name, type} {}
QofXmlBackendProvider(QofXmlBackendProvider&) = delete;
QofXmlBackendProvider operator=(QofXmlBackendProvider&) = delete;
QofXmlBackendProvider(QofXmlBackendProvider&&) = delete;
QofXmlBackendProvider operator=(QofXmlBackendProvider&&) = delete;
~QofXmlBackendProvider () = default;
QofBackend* create_backend(void);
bool type_check(const char* type);
};
/* ================================================================= */
static gboolean
@ -598,8 +614,8 @@ gnc_xml_be_determine_file_type (const char* path)
return GNC_BOOK_NOT_OURS;
}
static gboolean
gnc_determine_file_type (const char* uri)
bool
QofXmlBackendProvider::type_check (const char *uri)
{
struct stat sbuf;
int rc;
@ -1206,8 +1222,8 @@ gnc_xml_be_write_accounts_to_file (QofBackend* be, QofBook* book)
/* ================================================================= */
static QofBackend*
gnc_backend_new (void)
QofBackend*
QofXmlBackendProvider::create_backend(void)
{
FileBackend* gnc_be;
QofBackend* be;
@ -1268,14 +1284,6 @@ business_core_xml_init (void)
gnc_vendor_xml_initialize ();
}
static void
gnc_provider_free (QofBackendProvider* prov)
{
prov->provider_name = NULL;
prov->access_method = NULL;
g_free (prov);
}
#ifndef GNC_NO_LOADABLE_MODULES
G_MODULE_EXPORT void
qof_backend_module_init (void)
@ -1287,22 +1295,12 @@ qof_backend_module_init (void)
void
gnc_module_init_backend_xml (void)
{
QofBackendProvider* prov;
prov = g_new0 (QofBackendProvider, 1);
prov->provider_name = "GnuCash File Backend Version 2";
prov->access_method = "file";
prov->backend_new = gnc_backend_new;
prov->provider_free = gnc_provider_free;
prov->check_data_type = gnc_determine_file_type;
qof_backend_register_provider (prov);
const char* name {"GnuCash File Backend Version 2"};
auto prov = QofBackendProvider_ptr(new QofXmlBackendProvider{name, "xml"});
prov = g_new0 (QofBackendProvider, 1);
prov->provider_name = "GnuCash File Backend Version 2";
prov->access_method = "xml";
prov->backend_new = gnc_backend_new;
prov->provider_free = gnc_provider_free;
prov->check_data_type = gnc_determine_file_type;
qof_backend_register_provider (prov);
qof_backend_register_provider(std::move(prov));
prov = QofBackendProvider_ptr(new QofXmlBackendProvider{name, "file"});
qof_backend_register_provider(std::move(prov));
/* And the business objects */
business_core_xml_init ();

View File

@ -34,10 +34,9 @@
extern "C"
{
#endif
#include "qof.h"
#include <qof.h>
#include <gmodule.h>
#include "qofbackend-p.h"
#include <qofbackend-p.h>
typedef enum
{

View File

@ -64,8 +64,8 @@ struct timeval
#include "gnc-event.h"
#include <gnc-gdate-utils.h>
#include "SchedXaction.h"
#include "qofbackend-p.h"
#include "gncBusiness.h"
#include <qofinstance-p.h>
/* Notes about xaccTransBeginEdit(), xaccTransCommitEdit(), and
* xaccTransRollback():
@ -1815,7 +1815,7 @@ xaccTransRollbackEdit (Transaction *trans)
be = qof_book_get_backend(qof_instance_get_book(trans));
/** \todo Fix transrollbackedit in QOF so that rollback
is exposed via the API. */
if (be && be->rollback)
if (qof_backend_can_rollback (be))
{
QofBackendError errcode;
@ -1826,7 +1826,7 @@ xaccTransRollbackEdit (Transaction *trans)
}
while (ERR_BACKEND_NO_ERR != errcode);
(be->rollback) (be, &(trans->inst));
qof_backend_rollback_instance (be, &(trans->inst));
errcode = qof_backend_get_error (be);
if (ERR_BACKEND_MOD_DESTROY == errcode)

View File

@ -27,7 +27,7 @@
#include <glib.h>
#include <string.h>
#include "gnc-pricedb-p.h"
#include "qofbackend-p.h"
#include <qofinstance-p.h>
/* This static indicates the debugging module that this .o belongs to. */
static QofLogModule log_module = GNC_MOD_PRICE;

View File

@ -99,14 +99,6 @@ public:
{
qof_session_save(gobj(), percentage_func);
}
void call_close_hooks ()
{
qof_session_call_close_hooks (gobj());
}
};
std::pair<QString, QString> errorToStringPair(QofBackendError err);

View File

@ -375,7 +375,6 @@ void MainWindow::loadFile(const QString &fileName)
/* -------------- BEGIN CORE SESSION CODE ------------- */
/* -- this code is almost identical in FileOpen and FileSaveAs -- */
m_session.call_close_hooks();
gnc_hook_run(HOOK_BOOK_CLOSED, m_session.gobj());
qof_session_destroy(m_session.gobj());
m_session.reset();

View File

@ -577,7 +577,6 @@ void MainWindow::closeEvent(QCloseEvent *event)
* transactions during shutdown would cause massive redraws */
qof_event_suspend ();
qof_session_call_close_hooks(m_session.gobj());
gnc_hook_run(HOOK_BOOK_CLOSED, m_session.gobj());
qof_session_destroy(m_session.gobj());
@ -602,7 +601,6 @@ void MainWindow::newFile()
* disable events so we don't gobj spammed by redraws. */
qof_event_suspend ();
m_session.call_close_hooks();
gnc_hook_run(HOOK_BOOK_CLOSED, m_session.gobj());
qof_session_destroy(m_session.gobj());

View File

@ -527,7 +527,6 @@ gnc_file_new (void)
* disable events so we don't get spammed by redraws. */
qof_event_suspend ();
qof_session_call_close_hooks(session);
gnc_hook_run(HOOK_BOOK_CLOSED, session);
gnc_close_gui_component_by_session (session);
@ -706,7 +705,6 @@ RESTART:
if (gnc_current_session_exist())
{
current_session = gnc_get_current_session();
qof_session_call_close_hooks(current_session);
gnc_hook_run(HOOK_BOOK_CLOSED, current_session);
gnc_close_gui_component_by_session (current_session);
gnc_state_save (current_session);
@ -1605,7 +1603,6 @@ gnc_file_quit (void)
* transactions during shutdown would cause massive redraws */
qof_event_suspend ();
qof_session_call_close_hooks(session);
gnc_hook_run(HOOK_BOOK_CLOSED, session);
gnc_close_gui_component_by_session (session);
gnc_state_save (session);

View File

@ -35,6 +35,7 @@ SET (gnc_qof_HEADERS
qof/qof-string-cache.h
)
SET (gnc_qof_noinst_HEADERS
qof/gnc-backend-prov.hpp
qof/qofbook-p.h
qof/qofclass-p.h
qof/gnc-date-p.h

View File

@ -82,6 +82,7 @@ qofinclude_HEADERS = \
qof-gobject.h
noinst_HEADERS = \
gnc-backend-prov.hpp \
qofbook-p.h \
qofclass-p.h \
qofevent-p.h \

View File

@ -0,0 +1,81 @@
/********************************************************************\
* qofbackend-prov.hpp -- Manage creation of a QofBackend subclass. *
* *
* Copyright 2016 John Ralls <jralls@ceridwen.us> *
* *
* This program is free software; you can redistribute it and/or *
* modify it under the terms of the GNU General Public License as *
* published by the Free Software Foundation; either version 2 of *
* the License, or (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License*
* along with this program; if not, contact: *
* *
* Free Software Foundation Voice: +1-617-542-5942 *
* 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 *
* Boston, MA 02110-1301, USA gnu@gnu.org *
* *
\********************************************************************/
#ifndef __GNC_BACKEND_PROV_HPP__
#define __GNC_BACKEND_PROV_HPP__
#include <memory>
struct QofBackendProvider
{
QofBackendProvider(const char* name, const char* type) :
provider_name {name}, access_method {type} {}
QofBackendProvider(QofBackendProvider&) = delete;
QofBackendProvider(QofBackendProvider&&) = delete;
virtual ~QofBackendProvider() {}
/** Return a new, fully initialized backend.
*
* If the backend supports configuration, all configuration options
* should be initialised to usable values here.
* */
virtual QofBackend * create_backend(void) = 0;
/** \brief Distinguish two providers with same access method.
More than 1 backend can be registered under the same access_method,
so each one is passed the path to the data (e.g. a file) and
should return TRUE only:
-# if the backend recognises the type as one that it can load and write or
-# if the path contains no data but can be used (e.g. a new session).
\note If the backend can cope with more than one type, the backend
should not try to store or cache the sub-type for this data.
It is sufficient only to return TRUE if any ONE of the supported
types match the incoming data. The backend should not assume that
returning TRUE will mean that the data will naturally follow.
*/
/*@ null @*/
virtual bool type_check(const char*) = 0;
/** Some arbitrary name given for this particular backend provider */
const char * provider_name;
/** The access method that this provider provides, for example,
* file:// http:// postgres:// or sqlite://, but without the :// at the end
*/
const char * access_method;
};
using QofBackendProvider_ptr = std::unique_ptr<QofBackendProvider>;
/** Let the sytem know about a new provider of backends. This function
* is typically called by the provider library at library load time.
* This function allows the backend library to tell the QOF infrastructure
* that it can handle URL's of a certain type. Note that a single
* backend library may register more than one provider, if it is
* capable of handling more than one URL access method.
*/
void qof_backend_register_provider (QofBackendProvider_ptr&&);
#endif // __GNC_BACKEND_PROV_HPP__

View File

@ -235,45 +235,6 @@
* This should be done in the function called from backend_new.
*/
struct QofBackendProvider_s
{
/** Some arbitrary name given for this particular backend provider */
/*@ observer @*/
const char * provider_name;
/** The access method that this provider provides, for example,
* file:// http:// postgres:// or sqlite://, but without the :// at the end
*/
/*@ observer @*/
const char * access_method;
/** Return a new, fully initialized backend.
*
* If the backend supports configuration, all configuration options
* should be initialised to usable values here.
* */
QofBackend * (*backend_new) (void);
/** \brief Distinguish two providers with same access method.
More than 1 backend can be registered under the same access_method,
so each one is passed the path to the data (e.g. a file) and
should return TRUE only:
-# if the backend recognises the type as one that it can load and write or
-# if the path contains no data but can be used (e.g. a new session).
\note If the backend can cope with more than one type, the backend
should not try to store or cache the sub-type for this data.
It is sufficient only to return TRUE if any ONE of the supported
types match the incoming data. The backend should not assume that
returning TRUE will mean that the data will naturally follow.
*/
/*@ null @*/
gboolean (*check_data_type) (const char*);
/** Free this structure, unregister this backend handler. */
void (*provider_free) (/*@ only @*/ QofBackendProvider *);
};
typedef enum
{
@ -310,8 +271,6 @@ struct QofBackend_s
QofBePercentageFunc percentage;
QofBackendProvider *provider;
QofBackendError last_err;
char * error_msg;
@ -345,15 +304,6 @@ extern "C"
{
#endif
/** Let the sytem know about a new provider of backends. This function
* is typically called by the provider library at library load time.
* This function allows the backend library to tell the QOF infrastructure
* that it can handle URL's of a certain type. Note that a single
* backend library may register more than one provider, if it is
* capable of handling more than one URL access method.
*/
void qof_backend_register_provider (/*@ only @*/ QofBackendProvider *);
/** The qof_backend_set_message() assigns a string to the backend error message.
*/
void qof_backend_set_message(QofBackend *be, const char *format, ...);

View File

@ -79,6 +79,20 @@ qof_backend_check_error (QofBackend *be)
return be->last_err != ERR_BACKEND_NO_ERR;
}
gboolean
qof_backend_can_rollback (QofBackend* be)
{
if (be == nullptr) return FALSE;
return be->rollback != nullptr;
}
void
qof_backend_rollback_instance (QofBackend* be, QofInstance* inst)
{
if (be == nullptr || be->rollback == nullptr) return;
(be->rollback)(be, inst);
}
void
qof_backend_set_message (QofBackend *be, const char *format, ...)
{

View File

@ -127,15 +127,6 @@ typedef enum
ERR_RPC_FAILED, /**< Operation failed */
ERR_RPC_NOT_ADDED, /**< object not added */
} QofBackendError;
/**
* A structure that declares backend services that can be gotten.
* The Provider specifies a URL access method, and specifies the
* function to create a backend that can handle that URL access
* function.
*/
typedef struct QofBackendProvider_s QofBackendProvider;
/** \brief Pseudo-object providing an interface between the
* engine and a persistant data store (e.g. a server, a database,
* or a file).
@ -144,11 +135,45 @@ typedef struct QofBackendProvider_s QofBackendProvider;
* engine. The backend can, however, report errors to the GUI & other
* front-end users.
*/
typedef struct QofBackend_s QofBackend;
typedef struct QofBackend_s QofBackend;
/* The following functions are used in C files. */
/** Get the last backend error. */
QofBackendError qof_backend_get_error (QofBackend*);
/** Set the error on the specified QofBackend. */
void qof_backend_set_error (QofBackend*, QofBackendError);
/* Temporary wrapper so that we don't have to expose qofbackend-p.h to Transaction.c */
gboolean qof_backend_can_rollback (QofBackend*);
void qof_backend_rollback_instance (QofBackend*, QofInstance*);
/** \brief Load a QOF-compatible backend shared library.
\param directory Can be NULL if filename is a complete path.
\param module_name Name of the .la file that describes the
shared library. This provides platform independence,
courtesy of libtool.
\return FALSE in case or error, otherwise TRUE.
*/
gboolean
qof_load_backend_library(const gchar *directory, const gchar* module_name);
/** \brief Finalize all loaded backend sharable libraries. */
void qof_finalize_backend_libraries(void);
/** \brief Retrieve the backend used by this book */
QofBackend* qof_book_get_backend (const QofBook *book);
void qof_book_set_backend (QofBook *book, QofBackend *);
/** \brief DOCUMENT ME! */
typedef void (*QofBePercentageFunc) (/*@ null @*/ const char *message, double percent);
#ifdef __cplusplus
}
/** @name Allow access to the begin routine for this backend. */
//@{
@ -161,15 +186,6 @@ void qof_backend_run_commit(QofBackend *be, QofInstance *inst);
gboolean qof_backend_commit_exists(const QofBackend *be);
//@}
/** The qof_backend_set_error() routine pushes an error code onto the error
* stack. (FIXME: the stack is 1 deep in current implementation).
*/
void qof_backend_set_error (QofBackend *be, QofBackendError err);
/** The qof_backend_get_error() routine pops an error code off the error stack.
*/
QofBackendError qof_backend_get_error (QofBackend *be);
/** Report if the backend is in an error state.
* Since get_error resets the error state, its use for branching as the backend
* bubbles back up to the session would make the session think that there was
@ -179,28 +195,6 @@ QofBackendError qof_backend_get_error (QofBackend *be);
*/
gboolean qof_backend_check_error (QofBackend *be);
/** \brief Load a QOF-compatible backend shared library.
\param directory Can be NULL if filename is a complete path.
\param module_name Name of the .la file that describes the
shared library. This provides platform independence,
courtesy of libtool.
\return FALSE in case or error, otherwise TRUE.
*/
gboolean
qof_load_backend_library(const gchar *directory, const gchar* module_name);
/** \brief Finalize all loaded backend sharable libraries. */
void qof_finalize_backend_libraries(void);
/** \brief Retrieve the backend used by this book */
QofBackend* qof_book_get_backend (const QofBook *book);
void qof_book_set_backend (QofBook *book, QofBackend *);
#ifdef __cplusplus
}
#endif
#endif /* QOF_BACKEND_H */

View File

@ -31,6 +31,9 @@
@author Copyright (c) 2005 Neil Williams <linux@codehelp.co.uk>
*/
extern "C"
{
#include "config.h"
#include <platform.h>
@ -52,128 +55,71 @@
#include <glib.h>
#include "qof.h"
#include "qofbackend-p.h"
#include "qofbook-p.h"
#include "qofsession-p.h"
#include "qofobject-p.h"
static GHookList * session_closed_hooks = NULL;
static QofLogModule log_module = QOF_MOD_SESSION;
static GSList *provider_list = NULL;
static gboolean qof_providers_initialized = FALSE;
} //extern 'C'
#include "qofbackend-p.h"
#include "qofsession-p.h"
#include "gnc-backend-prov.hpp"
#include <vector>
#include <algorithm>
#include <string>
#include <sstream>
using ProviderVec = std::vector<QofBackendProvider_ptr>;
static ProviderVec s_providers;
/*
* These getters are used in tests to reach static vars from outside
* They should be removed when no longer needed
*/
#ifdef __cplusplus
extern "C"
{
#endif
GHookList* get_session_closed_hooks (void );
GSList* get_provider_list (void );
gboolean get_qof_providers_initialized (void );
ProviderVec& get_providers (void );
bool get_providers_initialized (void );
void unregister_all_providers (void );
#ifdef __cplusplus
}
#endif
GHookList*
get_session_closed_hooks (void)
ProviderVec&
get_providers (void)
{
return session_closed_hooks;
return s_providers;
}
GSList*
get_provider_list (void)
bool
get_providers_initialized (void)
{
return provider_list;
}
gboolean
get_qof_providers_initialized (void)
{
return qof_providers_initialized;
return !s_providers.empty();
}
void
unregister_all_providers (void)
{
if (provider_list)
{
g_slist_foreach (provider_list, (GFunc) g_free, NULL);
g_slist_free (provider_list);
provider_list = NULL;
}
s_providers.clear();
}
/* ====================================================================== */
void
qof_backend_register_provider (QofBackendProvider *prov)
qof_backend_register_provider (QofBackendProvider_ptr&& prov)
{
provider_list = g_slist_append (provider_list, prov);
s_providers.emplace_back(std::move(prov));
}
/* Called from C so we have to keep the GList for now. */
GList*
qof_backend_get_registered_access_method_list(void)
{
GList* list = NULL;
GSList* node;
for ( node = provider_list; node != NULL; node = node->next )
{
QofBackendProvider *prov = static_cast<QofBackendProvider*>(node->data);
list = g_list_append( list, (gchar*)prov->access_method );
}
std::for_each(s_providers.begin(), s_providers.end(),
[&list](QofBackendProvider_ptr& provider) {
gpointer method = reinterpret_cast<gpointer>(const_cast<char*>(provider->access_method));
list = g_list_prepend(list, method);
});
return list;
}
/* ====================================================================== */
/* hook routines */
void
qof_session_add_close_hook (GFunc fn, gpointer data)
{
GHook *hook;
if (session_closed_hooks == NULL)
{
session_closed_hooks = static_cast<GHookList*>(malloc(sizeof(GHookList))); /* LEAKED */
g_hook_list_init (session_closed_hooks, sizeof(GHook));
}
hook = g_hook_alloc(session_closed_hooks);
if (!hook)
return;
hook->func = reinterpret_cast<void*>(fn);
hook->data = data;
g_hook_append(session_closed_hooks, hook);
}
void
qof_session_call_close_hooks (QofSession *session)
{
GHook *hook;
GFunc fn;
if (session_closed_hooks == NULL)
return;
hook = g_hook_first_valid (session_closed_hooks, FALSE);
while (hook)
{
fn = (GFunc)hook->func;
fn(session, hook->data);
hook = g_hook_next_valid (session_closed_hooks, hook, FALSE);
}
}
/* ====================================================================== */
/* error handling routines */
@ -337,70 +283,38 @@ qof_session_ensure_all_data_loaded (QofSession *session)
/* ====================================================================== */
/** Programs that use their own backends also need to call
the default QOF ones. The backends specified here are
loaded only by applications that do not have their own. */
struct backend_providers
{
const char *libdir;
const char *filename;
};
static void
qof_session_load_backend(QofSession * session, const char * access_method)
{
GSList *p;
QofBackendProvider *prov;
char *msg;
gboolean prov_type;
gboolean (*type_check) (const char*);
ENTER (" list=%d, initted=%s", g_slist_length(provider_list),
qof_providers_initialized ? "true" : "false");
prov_type = FALSE;
if (!qof_providers_initialized)
ENTER (" list=%lu", s_providers.size());
for (QofBackendProvider_ptr& prov : s_providers)
{
qof_providers_initialized = TRUE;
}
p = provider_list;
while (p != NULL)
{
prov = static_cast<QofBackendProvider*>(p->data);
/* Does this provider handle the desired access method? */
if (0 == g_ascii_strcasecmp (access_method, prov->access_method))
if (0 != g_ascii_strcasecmp (access_method, prov->access_method))
continue;
/* More than one backend could provide this
access method, check file type compatibility. */
if (!prov->type_check(session->book_id))
{
/* More than one backend could provide this
access method, check file type compatibility. */
type_check = (gboolean (*)(const char*)) prov->check_data_type;
if (type_check)
{
prov_type = (type_check)(session->book_id);
if (!prov_type)
{
PINFO(" %s not usable", prov->provider_name);
p = p->next;
continue;
}
}
PINFO (" selected %s", prov->provider_name);
if (NULL == prov->backend_new)
{
p = p->next;
continue;
}
/* Use the providers creation callback */
session->backend = (*(prov->backend_new))();
session->backend->provider = prov;
/* Tell the book about the backend that they'll be using. */
qof_book_set_backend (session->book, session->backend);
LEAVE (" ");
return;
PINFO(" %s not usable", prov->provider_name);
continue;
}
p = p->next;
PINFO (" selected %s", prov->provider_name);
/* Use the providers creation callback */
session->backend = prov->create_backend();
/* Tell the book about the backend that they'll be using. */
qof_book_set_backend (session->book, session->backend);
LEAVE (" ");
return;
}
msg = g_strdup_printf("failed to load '%s' using access_method", access_method);
qof_session_push_error (session, ERR_BACKEND_NO_HANDLER, msg);
g_free(msg);
std::ostringstream msgstrm;
msgstrm << "Failed to load '" << access_method << "' using access_method";
qof_session_push_error (session, ERR_BACKEND_NO_HANDLER,
msgstrm.str().c_str());
LEAVE (" ");
}
@ -866,21 +780,12 @@ qof_session_export (QofSession *tmp_session,
/* ================= Static function access for testing ================= */
#ifdef __cplusplus
extern "C"
{
#endif
void init_static_qofsession_pointers (void);
void (*p_qof_session_load_backend) (QofSession * session, const char * access_method);
void (*p_qof_session_clear_error) (QofSession *session);
void (*p_qof_session_destroy_backend) (QofSession *session);
#ifdef __cplusplus
}
#endif
void
init_static_qofsession_pointers (void)
{

View File

@ -289,20 +289,6 @@ gboolean qof_session_events_pending (const QofSession *session);
gboolean qof_session_process_events (QofSession *session);
/** @} */
/** Register a function to be called just before a session is closed.
*
* @param fn The function to be called. The function definition must
* be func(gpointer session, gpointer user_data);
*
* @param data The data to be passed to the function. */
void qof_session_add_close_hook (GFunc fn, gpointer data);
/** Call all registered session close hooks, informing them that the
* specified session is about to be closed.
*
* @param session A pointer to the session being closed. */
void qof_session_call_close_hooks (QofSession *session);
gboolean qof_session_export (QofSession *tmp_session,
QofSession *real_session,
QofPercentageFunc percentage_func);

View File

@ -1,4 +1,3 @@
SET(TEST_QOF_INCLUDE_DIRS
${CMAKE_BINARY_DIR}/src # for config.h
${CMAKE_SOURCE_DIR}/src/test-core # for unittest-support.h
@ -17,7 +16,7 @@ SET(test_qof_SOURCES
test-qofinstance.cpp
# test-kvp-frame.cpp This now use Google Test
test-qofobject.c
test-qofsession.c
test-qofsession.cpp
test-qof-string-cache.c
test-gnc-guid.cpp
${CMAKE_SOURCE_DIR}/src/test-core/unittest-support.c

View File

@ -14,7 +14,7 @@ test_qof_SOURCES = \
test-qofbook.c \
test-qofinstance.cpp \
test-qofobject.c \
test-qofsession.c \
test-qofsession.cpp \
test-qof-string-cache.c \
test-gnc-guid.cpp \
${top_srcdir}/src/test-core/unittest-support.c

View File

@ -20,46 +20,33 @@
* Boston, MA 02110-1301, USA gnu@gnu.org *
\********************************************************************/
#ifdef __cplusplus
extern "C"
{
#endif
#include "config.h"
#include <glib.h>
#include <unittest-support.h>
#ifdef __cplusplus
}
#endif
#include "../qof.h"
#include "../qofbackend-p.h"
#include "../qofsession-p.h"
#include "../qofclass-p.h"
#include "../gnc-backend-prov.hpp"
#include <vector>
static const gchar *suitename = "/qof/qofsession";
void test_suite_qofsession ( void );
#ifdef __cplusplus
extern "C"
{
#endif
extern GHookList* get_session_closed_hooks (void);
extern GSList* get_provider_list (void);
extern gboolean get_qof_providers_initialized (void);
extern void unregister_all_providers (void);
extern "C" void test_suite_qofsession ( void );
extern void (*p_qof_session_load_backend) (QofSession * session, const char * access_method);
extern void (*p_qof_session_clear_error) (QofSession * session);
extern void (*p_qof_session_destroy_backend) (QofSession * session);
extern void init_static_qofsession_pointers (void);
void init_static_qofsession_pointers (void);
#ifdef __cplusplus
}
#endif
using ProviderVec = std::vector<QofBackendProvider_ptr>;
extern ProviderVec& get_providers (void);
extern bool get_providers_initialized (void);
extern void unregister_all_providers (void);
typedef struct
{
@ -136,22 +123,30 @@ test_session_safe_save( Fixture *fixture, gconstpointer pData )
static struct
{
QofBackend *be;
gboolean data_compatible;
gboolean check_data_type_called;
gboolean backend_new_called;
bool data_compatible;
bool check_data_type_called;
bool backend_new_called;
} load_backend_struct;
static gboolean
mock_check_data_type (const char* book_id)
struct QofMockLoadBackendProvider : public QofBackendProvider
{
QofMockLoadBackendProvider(const char *name, const char* type) :
QofBackendProvider{name, type} {}
QofBackend* create_backend(void);
bool type_check(const char* type);
};
bool
QofMockLoadBackendProvider::type_check (const char* book_id)
{
g_assert (book_id);
g_assert_cmpstr (book_id, == , "my book");
load_backend_struct.check_data_type_called = TRUE;
g_assert_cmpstr (book_id, ==, "my book");
load_backend_struct.check_data_type_called = true;
return load_backend_struct.data_compatible;
}
static QofBackend*
mock_backend_new (void)
QofBackend*
QofMockLoadBackendProvider::create_backend (void)
{
QofBackend *be = NULL;
@ -165,55 +160,44 @@ mock_backend_new (void)
static void
test_qof_session_load_backend (Fixture *fixture, gconstpointer pData)
{
QofBackendProvider *prov = NULL;
QofBook *book = NULL;
/* init */
prov = g_new0 (QofBackendProvider, 1);
g_test_message ("Test when no provider is registered");
g_assert (!get_qof_providers_initialized ());
g_assert (get_provider_list () == NULL);
g_assert (!get_providers_initialized ());
g_assert (get_providers ().empty());
p_qof_session_load_backend (fixture->session, "file");
g_assert (get_qof_providers_initialized ());
g_assert (!get_providers_initialized ());
g_assert_cmpint (qof_session_get_error (fixture->session), == , ERR_BACKEND_NO_HANDLER);
g_assert_cmpstr (qof_session_get_error_message (fixture->session), == , "failed to load 'file' using access_method");
g_assert_cmpstr (qof_session_get_error_message (fixture->session), == , "Failed to load 'file' using access_method");
p_qof_session_clear_error (fixture->session);
g_test_message ("Test with provider registered but access method not supported");
prov->access_method = "unsupported";
qof_backend_register_provider (prov);
g_assert (get_provider_list ());
g_assert_cmpint (g_slist_length (get_provider_list ()), == , 1);
auto prov = QofBackendProvider_ptr(new QofMockLoadBackendProvider("Mock Backend", "unsupported"));
qof_backend_register_provider (std::move(prov));
g_assert (!get_providers().empty());
g_assert_cmpint (get_providers().size(), == , 1);
p_qof_session_load_backend (fixture->session, "file");
g_assert_cmpint (qof_session_get_error (fixture->session), == , ERR_BACKEND_NO_HANDLER);
g_assert_cmpstr (qof_session_get_error_message (fixture->session), == , "failed to load 'file' using access_method");
g_assert_cmpstr (qof_session_get_error_message (fixture->session), == , "Failed to load 'file' using access_method");
p_qof_session_clear_error (fixture->session);
g_test_message ("Test with access method supported but type incompatible");
prov->access_method = "file";
prov->check_data_type = mock_check_data_type;
prov = QofBackendProvider_ptr(new QofMockLoadBackendProvider("Mock Backend",
"file"));
qof_backend_register_provider (std::move(prov));
load_backend_struct.data_compatible = FALSE;
load_backend_struct.check_data_type_called = FALSE;
fixture->session->book_id = g_strdup ("my book");
p_qof_session_load_backend (fixture->session, "file");
g_assert (load_backend_struct.check_data_type_called);
g_assert_cmpint (qof_session_get_error (fixture->session), == , ERR_BACKEND_NO_HANDLER);
g_assert_cmpstr (qof_session_get_error_message (fixture->session), == , "failed to load 'file' using access_method");
g_assert_cmpstr (qof_session_get_error_message (fixture->session), == , "Failed to load 'file' using access_method");
p_qof_session_clear_error (fixture->session);
g_test_message ("Test with type compatible but backend_new not set");
prov->backend_new = NULL;
load_backend_struct.data_compatible = TRUE;
load_backend_struct.check_data_type_called = FALSE;
p_qof_session_load_backend (fixture->session, "file");
g_assert (load_backend_struct.check_data_type_called);
g_assert_cmpint (qof_session_get_error (fixture->session), == , ERR_BACKEND_NO_HANDLER);
g_assert_cmpstr (qof_session_get_error_message (fixture->session), == , "failed to load 'file' using access_method");
p_qof_session_clear_error (fixture->session);
g_test_message ("Test with type compatible backend_new set");
prov->backend_new = mock_backend_new;
load_backend_struct.be = NULL;
load_backend_struct.data_compatible = TRUE;
load_backend_struct.check_data_type_called = FALSE;
@ -227,12 +211,11 @@ test_qof_session_load_backend (Fixture *fixture, gconstpointer pData)
g_assert (load_backend_struct.backend_new_called);
g_assert (load_backend_struct.be);
g_assert (load_backend_struct.be == fixture->session->backend);
g_assert (prov == fixture->session->backend->provider);
g_assert (qof_book_get_backend (book) == load_backend_struct.be);
g_assert_cmpint (qof_session_get_error (fixture->session), == , ERR_BACKEND_NO_ERR);
unregister_all_providers ();
g_assert_cmpint (g_slist_length (get_provider_list ()), == , 0);
g_assert_cmpint (get_providers().size(), == , 0);
}
static struct
@ -329,9 +312,23 @@ mock_session_begin (QofBackend *be, QofSession *session, const char *book_id,
}
session_begin_struct.session_begin_called = TRUE;
}
struct QofMockSessBackendProvider : public QofBackendProvider
{
QofMockSessBackendProvider(const char *name, const char* type) :
QofBackendProvider{name, type} {}
QofBackend* create_backend(void);
bool type_check(const char* type);
};
static QofBackend*
mock_backend_new_for_begin (void)
bool
QofMockSessBackendProvider::type_check (const char* book_id)
{
g_assert (book_id);
return true;
}
QofBackend*
QofMockSessBackendProvider::create_backend (void)
{
QofBackend *be = NULL;
@ -348,7 +345,6 @@ test_qof_session_begin (Fixture *fixture, gconstpointer pData)
{
gboolean ignore_lock, create, force;
QofBackend *be = NULL;
QofBackendProvider *prov = NULL;
/* setup */
ignore_lock = TRUE;
@ -357,9 +353,7 @@ test_qof_session_begin (Fixture *fixture, gconstpointer pData)
be = g_new0 (QofBackend, 1);
g_assert (be);
g_assert_cmpint (g_slist_length (get_provider_list ()), == , 0);
prov = g_new0 (QofBackendProvider, 1);
prov->backend_new = mock_backend_new_for_begin;
g_assert_cmpint (get_providers().size(), == , 0);
/* run tests */
g_test_message ("Test when book_id is set backend is not changed");
@ -383,14 +377,14 @@ test_qof_session_begin (Fixture *fixture, gconstpointer pData)
g_assert (fixture->session->backend == NULL);
g_assert (fixture->session->book_id == NULL);
g_assert_cmpint (qof_session_get_error (fixture->session), == , ERR_BACKEND_NO_HANDLER);
g_assert_cmpstr (qof_session_get_error_message (fixture->session), == , "failed to load 'file' using access_method");
g_assert_cmpstr (qof_session_get_error_message (fixture->session), == , "Failed to load 'file' using access_method");
g_test_message ("Test access_method parsing");
qof_session_begin (fixture->session, "postgres://localhost:8080", ignore_lock, create, force);
g_assert (fixture->session->backend == NULL);
g_assert (fixture->session->book_id == NULL);
g_assert_cmpint (qof_session_get_error (fixture->session), == , ERR_BACKEND_NO_HANDLER);
g_assert_cmpstr (qof_session_get_error_message (fixture->session), == , "failed to load 'postgres' using access_method");
g_assert_cmpstr (qof_session_get_error_message (fixture->session), == , "Failed to load 'postgres' using access_method");
g_test_message ("Test with valid backend returned and session begin set; error is produced");
session_begin_struct.session = fixture->session;
@ -398,8 +392,10 @@ test_qof_session_begin (Fixture *fixture, gconstpointer pData)
session_begin_struct.backend_new_called = FALSE;
session_begin_struct.session_begin_called = FALSE;
session_begin_struct.produce_error = TRUE;
prov->access_method = "postgres";
qof_backend_register_provider (prov);
auto prov = QofBackendProvider_ptr(new QofMockSessBackendProvider("Mock Backend",
"postgres"));
qof_backend_register_provider (std::move(prov));
qof_session_begin (fixture->session, "postgres://localhost:8080", ignore_lock, create, force);
g_assert (fixture->session->backend);
g_assert (session_begin_struct.be == fixture->session->backend);
@ -768,37 +764,6 @@ test_qof_session_data_loaded (Fixture *fixture, gconstpointer pData)
g_assert_cmpstr (qof_session_get_error_message (fixture->session), == , "");
}
static void
test_qof_backend_get_access_method_list (Fixture *fixture, gconstpointer pData)
{
GList *list = NULL;
const char *access_methods[4] = { "file", "http", "postgres", "sqlite" };
int i;
for (i = 0; i < 4; i++)
{
QofBackendProvider *prov = g_new0 (QofBackendProvider, 1);
g_assert (prov);
prov->access_method = access_methods[ i ];
qof_backend_register_provider (prov);
g_assert_cmpint (g_slist_length (get_provider_list ()), == , (i + 1));
}
g_assert_cmpint (g_slist_length (get_provider_list ()), == , 4);
g_test_message ("Test list of access methods is returned");
list = qof_backend_get_registered_access_method_list ();
g_assert (list);
g_assert_cmpint (g_list_length (list), == , 4);
g_assert_cmpstr (g_list_nth_data (list, 0), == , "file");
g_assert_cmpstr (g_list_nth_data (list, 1), == , "http");
g_assert_cmpstr (g_list_nth_data (list, 2), == , "postgres");
g_assert_cmpstr (g_list_nth_data (list, 3), == , "sqlite");
g_list_free (list);
unregister_all_providers ();
}
static void
test_qof_session_get_book (Fixture *fixture, gconstpointer pData)
{
@ -890,37 +855,6 @@ mock_hook_fn (gpointer data, gpointer user_data)
hooks_struct.call_count++;
}
static void
test_qof_session_close_hooks (Fixture *fixture, gconstpointer pData)
{
gint data1, data2, data3;
g_test_message ("Test hooks list is initialized and hooks are added");
g_assert (!get_session_closed_hooks ());
qof_session_add_close_hook (mock_hook_fn, (gpointer) &data1);
g_assert (get_session_closed_hooks ());
g_assert (g_hook_find_func_data (get_session_closed_hooks (), FALSE, mock_hook_fn, (gpointer) &data1));
qof_session_add_close_hook (mock_hook_fn, (gpointer) &data2);
g_assert (g_hook_find_func_data (get_session_closed_hooks (), FALSE, mock_hook_fn, (gpointer) &data2));
qof_session_add_close_hook (mock_hook_fn, (gpointer) &data3);
g_assert (g_hook_find_func_data (get_session_closed_hooks (), FALSE, mock_hook_fn, (gpointer) &data3));
g_test_message ("Test all close hooks are called");
hooks_struct.session = fixture->session;
hooks_struct.data1 = (gpointer) &data1;
hooks_struct.data2 = (gpointer) &data2;
hooks_struct.data3 = (gpointer) &data3;
hooks_struct.call_count = 0;
qof_session_call_close_hooks (fixture->session);
g_assert_cmpuint (hooks_struct.call_count, == , 3);
/* currently qofsession does not provide a way to clear hooks list
* g_hook_list_clear is used to destroy list and all of it's elements
* though i' not sure if it frees all the memory allocated
*/
g_hook_list_clear (get_session_closed_hooks ());
}
void
test_suite_qofsession ( void )
{
@ -936,9 +870,7 @@ test_suite_qofsession ( void )
GNC_TEST_ADD (suitename, "qof session swap data", Fixture, NULL, setup, test_qof_session_swap_data, teardown);
GNC_TEST_ADD (suitename, "qof session events", Fixture, NULL, setup, test_qof_session_events, teardown);
GNC_TEST_ADD (suitename, "qof session data loaded", Fixture, NULL, setup, test_qof_session_data_loaded, teardown);
GNC_TEST_ADD (suitename, "qof backend access method list", Fixture, NULL, setup, test_qof_backend_get_access_method_list, teardown);
GNC_TEST_ADD (suitename, "qof session get book", Fixture, NULL, setup, test_qof_session_get_book, teardown);
GNC_TEST_ADD (suitename, "qof session get error", Fixture, NULL, setup, test_qof_session_get_error, teardown);
GNC_TEST_ADD (suitename, "qof session clear error", Fixture, NULL, setup, test_qof_session_clear_error, teardown);
GNC_TEST_ADD (suitename, "qof session close hooks", Fixture, NULL, setup, test_qof_session_close_hooks, teardown);
}