Commit d0048a55 authored by Ronan's avatar Ronan

feat(core): provide a shareable data in ClonableObject, assignment operator is...

feat(core): provide a shareable data in ClonableObject, assignment operator is supported by events, ...
parent 1610aa41
......@@ -32,6 +32,9 @@ set(LINPHONE_CXX_OBJECTS_PRIVATE_HEADER_FILES
db/abstract/abstract-db-p.h
db/abstract/abstract-db.h
db/events-db.h
db/provider/db-session-p.h
db/provider/db-session-provider.h
db/provider/db-session.h
enums.h
event/call-event.h
event/event.h
......@@ -56,6 +59,8 @@ set(LINPHONE_CXX_OBJECTS_SOURCE_FILES
cpim/parser/cpim-parser.cpp
db/abstract/abstract-db.cpp
db/events-db.cpp
db/provider/db-session-provider.cpp
db/provider/db-session.cpp
event/call-event.cpp
event/event.cpp
event/message-event.cpp
......
......@@ -19,11 +19,8 @@
#ifndef _ABSTRACT_DB_P_H_
#define _ABSTRACT_DB_P_H_
#ifdef SOCI_ENABLED
#include <soci/soci.h>
#endif // ifdef SOCI_ENABLED
#include "abstract-db.h"
#include "db/provider/db-session.h"
#include "object/object-p.h"
// =============================================================================
......@@ -32,13 +29,10 @@ LINPHONE_BEGIN_NAMESPACE
class AbstractDbPrivate : public ObjectPrivate {
public:
#ifdef SOCI_ENABLED
soci::session session;
#endif // ifndef SOCI_ENABLED
DbSession dbSession;
private:
AbstractDb::Backend backend;
bool isConnected = false;
L_DECLARE_PUBLIC(AbstractDb);
};
......
......@@ -17,43 +17,34 @@
*/
#include "abstract-db-p.h"
#include "db/provider/db-session-provider.h"
#include "logger/logger.h"
#include "abstract-db.h"
using namespace std;
// =============================================================================
using namespace std;
LINPHONE_BEGIN_NAMESPACE
AbstractDb::AbstractDb (AbstractDbPrivate &p) : Object(*new AbstractDbPrivate) {}
bool AbstractDb::connect (Backend backend, const std::string &parameters) {
#ifdef SOCI_ENABLED
L_D(AbstractDb);
try {
if (d->isConnected) {
d->session.close();
d->isConnected = false;
}
d->session.open(backend == Mysql ? "mysql" : "sqlite3", parameters);
init();
} catch (const exception &e) {
return false;
}
return true;
#else
lWarning() << "Cannot use AbstractDb. Soci is not enabled.";
return false;
#endif // ifndef SOCI_ENABLED
bool AbstractDb::connect (Backend backend, const string &parameters) {
L_D(AbstractDb);
d->dbSession = DbSessionProvider::getInstance()->getSession(
(backend == Mysql ? "mysql://" : "sqlite3://") + parameters
);
if (d->dbSession)
init();
return d->dbSession;
}
bool AbstractDb::isConnected () const {
L_D(const AbstractDb);
return d->isConnected;
return d->dbSession;
}
AbstractDb::Backend AbstractDb::getBackend () const {
......
......@@ -20,6 +20,11 @@
#include "events-db.h"
// TODO: Remove me.
#ifdef SOCI_ENABLED
#undef SOCI_ENABLED
#endif
// =============================================================================
LINPHONE_BEGIN_NAMESPACE
......@@ -61,10 +66,10 @@ void EventsDb::init () {
d->session <<
"CREATE TABLE IF NOT EXISTS dialog ("
" local_sip_address_id BIGINT UNSIGNED NOT NULL," // Sip address used to communicate.
" remote_sip_address_id BIGINT UNSIGNED NOT NULL," // Server (for conference) or user sip address.
" creation_timestamp TIMESTAMP NOT NULL," // Dialog creation date.
" last_update_timestamp TIMESTAMP NOT NULL," // Last event timestamp (call, message...).
" local_sip_address_id BIGINT UNSIGNED NOT NULL," // Sip address used to communicate.
" remote_sip_address_id BIGINT UNSIGNED NOT NULL," // Server (for conference) or user sip address.
" creation_timestamp TIMESTAMP NOT NULL," // Dialog creation date.
" last_update_timestamp TIMESTAMP NOT NULL," // Last event timestamp (call, message...).
" FOREIGN KEY (local_sip_address_id)"
" REFERENCES sip_address(id)"
" ON DELETE CASCADE,"
......@@ -79,7 +84,7 @@ void EventsDb::init () {
" dialog_id BIGINT UNSIGNED NOT NULL,"
" status_id TINYINT UNSIGNED NOT NULL,"
" direction_id TINYINT UNSIGNED NOT NULL,"
" imdn_message_id VARCHAR(255) NOT NULL," // See: https://tools.ietf.org/html/rfc5438#section-6.3
" imdn_message_id VARCHAR(255) NOT NULL," // See: https://tools.ietf.org/html/rfc5438#section-6.3
" content_type VARCHAR(255) NOT NULL,"
" is_secured BOOLEAN NOT NULL,"
" app_data VARCHAR(2048),"
......
/*
* db-session-p.h
* Copyright (C) 2017 Belledonne Communications SARL
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*/
#ifndef _DB_SESSION_P_H_
#define _DB_SESSION_P_H_
#ifdef SOCI_ENABLED
#include <memory>
#endif // ifdef SOCI_ENABLED
#include "db-session.h"
#include "object/clonable-object-p.h"
// =============================================================================
#ifdef SOCI_ENABLED
namespace soci {
class session;
}
#endif // ifdef SOCI_ENABLED
LINPHONE_BEGIN_NAMESPACE
class DbSessionPrivate : public ClonableObjectPrivate {
friend class DbSessionProvider;
private:
bool isValid = false;
#ifdef SOCI_ENABLED
std::shared_ptr<soci::session> session;
#endif // ifndef SOCI_ENABLED
L_DECLARE_PUBLIC(DbSession);
};
LINPHONE_END_NAMESPACE
#endif // ifndef _DB_SESSION_P_H_
/*
* db-session-provider.cpp
* Copyright (C) 2017 Belledonne Communications SARL
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*/
#ifdef SOCI_ENABLED
#include <unordered_map>
#include <soci/soci.h>
#endif // ifdef SOCI_ENABLED
#include "db-session-p.h"
#include "object/object-p.h"
#include "db-session-provider.h"
#define CLEAN_COUNTER_MAX 1000
// =============================================================================
using namespace std;
LINPHONE_BEGIN_NAMESPACE
class DbSessionProviderPrivate : public ObjectPrivate {
public:
#ifdef SOCI_ENABLED
typedef pair<weak_ptr<soci::session>, DbSessionPrivate *> InternalSession;
unordered_map<string, InternalSession> sessions;
#endif // ifdef SOCI_ENABLED
int cleanCounter = 0;
};
DbSessionProvider::DbSessionProvider () : Singleton(*new DbSessionProviderPrivate) {}
DbSession DbSessionProvider::getSession (const string &uri) {
DbSession session;
#ifdef SOCI_ENABLED
L_D(DbSessionProvider);
try {
shared_ptr<soci::session> sociSession = d->sessions[uri].first.lock();
if (!sociSession) { // Create new session.
sociSession = make_shared<soci::session>(uri);
DbSessionPrivate *p = session.getPrivate();
p->session = sociSession;
p->isValid = true;
d->sessions[uri] = make_pair(sociSession, p);
} else // Share session.
session.setRef(*d->sessions[uri].second);
} catch (const exception &) {}
// Remove invalid weak ptrs.
if (++d->cleanCounter >= CLEAN_COUNTER_MAX) {
d->cleanCounter = 0;
for (auto it = d->sessions.begin(), itEnd = d->sessions.end(); it != itEnd;) {
if (it->second.first.expired())
it = d->sessions.erase(it);
else
++it;
}
}
#endif // ifndef SOCI_ENABLED
return session;
}
LINPHONE_END_NAMESPACE
/*
* db-session-provider.h
* Copyright (C) 2017 Belledonne Communications SARL
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*/
#ifndef _DB_SESSION_PROVIDER_H_
#define _DB_SESSION_PROVIDER_H_
#include <string>
#include "db-session.h"
#include "object/singleton.h"
// =============================================================================
LINPHONE_BEGIN_NAMESPACE
class DbSessionProviderPrivate;
class DbSessionProvider : public Singleton<DbSessionProvider> {
friend class Singleton<DbSessionProvider>;
public:
DbSession getSession (const std::string &uri);
private:
DbSessionProvider ();
L_DECLARE_PRIVATE(DbSessionProvider);
L_DISABLE_COPY(DbSessionProvider);
};
LINPHONE_END_NAMESPACE
#endif // ifndef _DB_SESSION_PROVIDER_H_
/*
* db-session.cpp
* Copyright (C) 2017 Belledonne Communications SARL
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*/
#include "db-session-p.h"
#include "db-session.h"
// =============================================================================
using namespace std;
LINPHONE_BEGIN_NAMESPACE
L_USE_DEFAULT_SHARE_IMPL(DbSession, ClonableObject);
DbSession::operator bool () const {
L_D(const DbSession);
return d->isValid;
}
LINPHONE_END_NAMESPACE
/*
* db-session.h
* Copyright (C) 2017 Belledonne Communications SARL
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*/
#ifndef _DB_SESSION_H_
#define _DB_SESSION_H_
#include <string>
#include "object/clonable-object.h"
// =============================================================================
LINPHONE_BEGIN_NAMESPACE
class DbSessionPrivate;
class DbSession : public ClonableObject {
friend class DbSessionProvider;
public:
DbSession ();
DbSession (const DbSession &src);
DbSession &operator= (const DbSession &src);
operator bool () const;
private:
L_DECLARE_PRIVATE(DbSession);
};
LINPHONE_END_NAMESPACE
#endif // ifndef _DB_SESSION_H_
......@@ -41,6 +41,16 @@ CallEvent::CallEvent (Type type, const shared_ptr<Call> &call) : Event(*new Call
CallEvent::CallEvent (const CallEvent &src) : CallEvent(src.getType(), src.getCall()) {}
CallEvent &CallEvent::operator= (const CallEvent &src) {
L_D(CallEvent);
if (this != &src) {
Event::operator=(src);
d->call = src.getPrivate()->call;
}
return *this;
}
shared_ptr<Call> CallEvent::getCall () const {
L_D(const CallEvent);
return d->call;
......
......@@ -35,6 +35,8 @@ public:
CallEvent (Type type, const std::shared_ptr<Call> &message);
CallEvent (const CallEvent &src);
CallEvent &operator= (const CallEvent &src);
std::shared_ptr<Call> getCall () const;
private:
......
......@@ -24,15 +24,24 @@
LINPHONE_BEGIN_NAMESPACE
// -----------------------------------------------------------------------------
Event::Event () : ClonableObject(*new EventPrivate) {}
Event::Event (const Event &) : ClonableObject(*new EventPrivate) {}
Event::Event (EventPrivate &p, Type type) : ClonableObject(p) {
Event::Event (EventPrivate &p, Type type) : ClonableObject(*new EventPrivate) {
L_D(Event);
d->type = type;
}
Event &Event::operator= (const Event &src) {
L_D(Event);
if (this != &src)
d->type = src.getPrivate()->type;
return *this;
}
Event::Type Event::getType () const {
L_D(const Event);
return d->type;
......
......@@ -40,6 +40,8 @@ public:
Event (const Event &src);
virtual ~Event () = default;
Event &operator= (const Event &src);
Type getType () const;
protected:
......
......@@ -41,6 +41,16 @@ MessageEvent::MessageEvent (const shared_ptr<Message> &message) : Event(*new Mes
MessageEvent::MessageEvent (const MessageEvent &src) : MessageEvent(src.getMessage()) {}
MessageEvent &MessageEvent::operator= (const MessageEvent &src) {
L_D(MessageEvent);
if (this != &src) {
Event::operator=(src);
d->message = src.getPrivate()->message;
}
return *this;
}
shared_ptr<Message> MessageEvent::getMessage () const {
L_D(const MessageEvent);
return d->message;
......
......@@ -35,6 +35,8 @@ public:
MessageEvent (const std::shared_ptr<Message> &message);
MessageEvent (const MessageEvent &src);
MessageEvent &operator= (const MessageEvent &src);
std::shared_ptr<Message> getMessage () const;
private:
......
......@@ -19,22 +19,27 @@
#ifndef _CLONABLE_OBJECT_P_H_
#define _CLONABLE_OBJECT_P_H_
#include <unordered_map>
#include "utils/general.h"
// =============================================================================
LINPHONE_BEGIN_NAMESPACE
class ClonableObject;
class ClonableObjectPrivate {
public:
virtual ~ClonableObjectPrivate () = default;
protected:
ClonableObject *mPublic = nullptr;
std::unordered_map<const ClonableObjectPrivate *, ClonableObject *> *mPublic = nullptr;
private:
void ref ();
void unref ();
int nRefs = 0;
L_DECLARE_PUBLIC(ClonableObject);
};
......
......@@ -20,16 +20,67 @@
#include "clonable-object.h"
// =============================================================================
using namespace std;
LINPHONE_BEGIN_NAMESPACE
// =============================================================================
// TODO: Use atomic counter?
void ClonableObjectPrivate::ref () {
++nRefs;
}
void ClonableObjectPrivate::unref () {
if (--nRefs == 0) {
delete mPublic;
delete this;
}
}
// -----------------------------------------------------------------------------
ClonableObject::ClonableObject (ClonableObjectPrivate &p) : mPrivate(&p) {
mPrivate->mPublic = this;
// Q-pointer must be empty. It's a constructor that takes a new private data.
L_ASSERT(!mPrivate->mPublic);
mPrivate->mPublic = new remove_pointer<decltype(mPrivate->mPublic)>::type;
(*mPrivate->mPublic)[mPrivate] = this;
mPrivate->ref();
}
ClonableObject::ClonableObject (const ClonableObjectPrivate &p) {
// Cannot access to Q-pointer. It's a copy constructor from private data.
L_ASSERT(!mPrivate);
setRef(p);
}
ClonableObject::~ClonableObject () {
delete mPrivate;
mPrivate->mPublic->erase(mPrivate);
mPrivate->unref();
}
void ClonableObject::setRef (const ClonableObjectPrivate &p) {
// Q-pointer must exist.
L_ASSERT(mPrivate);
L_ASSERT(mPrivate->mPublic);
// Nothing, same reference.
if (&p == mPrivate)
return;
// Unref previous private data.
if (mPrivate) {
mPrivate->mPublic->erase(mPrivate);
mPrivate->unref();
}
// Add and reference new private data.
mPrivate = const_cast<ClonableObjectPrivate *>(&p);
(*mPrivate->mPublic)[mPrivate] = this;
mPrivate->ref();
}
LINPHONE_END_NAMESPACE
......@@ -25,15 +25,20 @@
LINPHONE_BEGIN_NAMESPACE
class ClonableObjectPrivate;
class LINPHONE_PUBLIC ClonableObject {
public:
virtual ~ClonableObject ();
protected:
// Use a new ClonableObjectPrivate without owner.
explicit ClonableObject (ClonableObjectPrivate &p);
// If you want share an existing ClonableObjectPrivate, call this function.
explicit ClonableObject (const ClonableObjectPrivate &p);
// Change the ClonableObjectPrivate, it can be shared.
void setRef (const ClonableObjectPrivate &p);
ClonableObjectPrivate *mPrivate = nullptr;
private:
......
......@@ -25,8 +25,6 @@
LINPHONE_BEGIN_NAMESPACE
class Object;
class ObjectPrivate {
public:
virtual ~ObjectPrivate () = default;
......
......@@ -25,8 +25,6 @@
LINPHONE_BEGIN_NAMESPACE
class ObjectPrivate;
class LINPHONE_PUBLIC Object {
public:
virtual ~Object ();
......
......@@ -47,6 +47,14 @@ LINPHONE_BEGIN_NAMESPACE
// -----------------------------------------------------------------------------
void l_assert (const char *condition, const char *file, int line);
#ifdef DEBUG
#define L_ASSERT(CONDITION) static_cast<void>(false && (CONDITION))
#else
#define L_ASSERT(CONDITION) ((CONDITION) ? static_cast<void>(0) : l_assert(#CONDITION, __FILE__, __LINE__))
#endif
#define L_DECLARE_PRIVATE(CLASS) \
inline CLASS ## Private * getPrivate() { \
return reinterpret_cast<CLASS ## Private *>(mPrivate); \
......@@ -56,12 +64,41 @@ LINPHONE_BEGIN_NAMESPACE
} \
friend class CLASS ## Private;
class ClonableObject;
class ClonableObjectPrivate;
class Object;
class ObjectPrivate;
template<typename T>
inline ClonableObject *getPublicHelper (T *object, ClonableObjectPrivate *context) {
auto it = object->find(context);
L_ASSERT(it != object->end());
return it->second;
}
template<typename T>
inline const ClonableObject *getPublicHelper (const T *object, const ClonableObjectPrivate *context) {
auto it = object->find(context);
L_ASSERT(it != object->cend());
return it->second;
}
template<typename T>
inline Object *getPublicHelper (T *object, ObjectPrivate *) {
return object;
}
template<typename T>
inline const Object *getPublicHelper (const T *object, const ObjectPrivate *) {
return object;
}
#define L_DECLARE_PUBLIC(CLASS) \
inline CLASS * getPublic() { \
return static_cast<CLASS *>(mPublic); \
inline CLASS * getPublic () { \
return static_cast<CLASS *>(getPublicHelper(mPublic, this)); \
} \
inline const CLASS *getPublic() const { \
return static_cast<const CLASS *>(mPublic); \
inline const CLASS *getPublic () const { \
return static_cast<const CLASS *>(getPublicHelper(mPublic, this)); \
} \
friend class CLASS;
......@@ -72,13 +109,14 @@ LINPHONE_BEGIN_NAMESPACE
#define L_D(CLASS) CLASS ## Private * const d = getPrivate();
#define L_Q(CLASS) CLASS * const q = getPublic();
void l_assert (const char *condition, const char *file, int line);
#ifdef DEBUG
#define L_ASSERT(CONDITION) static_cast<void>(false && (CONDITION))
#else
#define L_ASSERT(CONDITION) ((CONDITION) ? static_cast<void>(0) : l_assert(#CONDITION, __FILE__, __LINE__))
#endif
#define L_USE_DEFAULT_SHARE_IMPL(CLASS, PARENT_CLASS) \
CLASS::CLASS () : PARENT_CLASS(*new CLASS ## Private) {} \
CLASS::CLASS (const CLASS &src) : ClonableObject(*src.getPrivate()) {} \
CLASS &CLASS::operator= (const CLASS &src) { \
if (this != &src) \
setRef(*src.getPrivate()); \
return *this; \
}
LINPHONE_END_NAMESPACE
......
......@@ -29,15 +29,15 @@
LINPHONE_BEGIN_NAMESPACE
namespace Utils {
LINPHONE_PUBLIC bool iequals (const std::string &a, const std::string &b);
LINPHONE_PUBLIC bool iequals (const std::string &a, const std::string &b);
LINPHONE_PUBLIC std::vector<std::string> split (const std::string &str, const std::string &delimiter);
LINPHONE_PUBLIC std::vector<std::string> split (const std::string &str, const std::string &delimiter);
LINPHONE_PUBLIC inline std::vector<std::string> split (const std::string &str, char delimiter) {