PIM Manager: initial D-Bus binding

Adds a subset of the D-Bus API to syncevo-dbus-server. Views are
resources that are attached to the client and thus get destroyed
automatically when the client disconnects from D-Bus.

In addition, failures for calls to the client's ViewAgent delete the
view. In this case, the client stays connected, because it might only
have destroyed one agent with others still active.
This commit is contained in:
Patrick Ohly 2012-09-05 11:17:40 +02:00
parent 7651b432c2
commit a8118eff89
5 changed files with 373 additions and 2 deletions

View file

@ -143,9 +143,13 @@ int main(int argc, char **argv, char **envp)
// make this object the main owner of the connection
boost::scoped_ptr<DBusObject> obj(new DBusObject(conn, "foo", "bar", true));
boost::scoped_ptr<SyncEvo::Server> server(new SyncEvo::Server(loop, shutdownRequested, restart, conn, duration));
boost::shared_ptr<SyncEvo::Server> server(new SyncEvo::Server(loop, shutdownRequested, restart, conn, duration));
server->activate();
#ifdef ENABLE_DBUS_PIM
boost::shared_ptr<GDBusCXX::DBusObjectHelper> manager(SyncEvo::CreateContactManager(server));
#endif
if (gdbus) {
unsetenv("G_DBUS_DEBUG");
}
@ -153,6 +157,9 @@ int main(int argc, char **argv, char **envp)
dbus_bus_connection_undelay(conn);
server->run();
SE_LOG_DEBUG(NULL, NULL, "cleaning up");
#ifdef ENABLE_DBUS_PIM
manager.reset();
#endif
server.reset();
obj.reset();
guard.reset();

View file

@ -0,0 +1,277 @@
/*
* Copyright (C) 2012 Intel Corporation
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) version 3.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301 USA
*/
#include "manager.h"
#include "../resource.h"
#include "../client.h"
SE_BEGIN_CXX
static const char * const MANAGER_SERVICE = "org._01.pim.contacts";
static const char * const MANAGER_PATH = "/org/01/pim/contacts";
static const char * const MANAGER_IFACE = "org._01.pim.contacts.Manager";
static const char * const AGENT_IFACE = "org._01.pim.contacts.ViewAgent";
static const char * const CONTROL_IFACE = "org._01.pim.contacts.ViewControl";
Manager::Manager(const boost::shared_ptr<Server> &server) :
DBusObjectHelper(server->getConnection(),
MANAGER_PATH,
MANAGER_IFACE),
m_server(server)
{
// TODO: claim MANAGER_SERVICE name on connection
// Prevent automatic shut down during idle times, because we need
// to keep our unified address book available.
m_server->autoTermRef();
}
void Manager::init()
{
// TODO: restore sort order
m_sortOrder = "first/last";
initFolks();
initSorting();
add(this, &Manager::start, "Start");
add(this, &Manager::stop, "Stop");
add(this, &Manager::setSortOrder, "SetSortOrder");
add(this, &Manager::getSortOrder, "GetSortOrder");
add(this, &Manager::search, "Search");
// Ready, make it visible via D-Bus.
activate();
}
void Manager::initFolks()
{
m_folks = IndividualAggregator::create();
}
void Manager::initSorting()
{
// TODO: mirror m_sortOrder in m_folks main view
}
Manager::~Manager()
{
m_server->autoTermUnref();
}
boost::shared_ptr<Manager> Manager::create(const boost::shared_ptr<Server> &server)
{
boost::shared_ptr<Manager> manager(new Manager(server));
manager->m_self = manager;
manager->init();
return manager;
}
boost::shared_ptr<GDBusCXX::DBusObjectHelper> CreateContactManager(const boost::shared_ptr<Server> &server)
{
return Manager::create(server);
}
void Manager::start()
{
m_folks->start();
}
void Manager::stop()
{
// TODO: if there are no active searches, then recreate aggregator
if (true) {
initFolks();
initSorting();
}
}
void Manager::setSortOrder(const std::string &order)
{
// TODO: check string and change order,
// store persistently
m_sortOrder = order;
initSorting();
}
/**
* Connects a normal IndividualView to a D-Bus client.
* Provides the org.01.pim.contacts.ViewControl API.
*/
class ViewResource : public Resource, public GDBusCXX::DBusObjectHelper
{
static unsigned int m_counter;
boost::weak_ptr<ViewResource> m_self;
GDBusCXX::DBusRemoteObject m_viewAgent;
boost::shared_ptr<IndividualView> m_view;
boost::weak_ptr<Client> m_owner;
GDBusCXX::DBusClientCall0 m_contactsModified,
m_contactsAdded,
m_contactsRemoved;
ViewResource(const boost::shared_ptr<IndividualView> view,
const boost::shared_ptr<Client> &owner,
GDBusCXX::connection_type *connection,
const GDBusCXX::Caller_t &ID,
const GDBusCXX::DBusObject_t &agentPath) :
GDBusCXX::DBusObjectHelper(connection,
StringPrintf("%s/view%d", MANAGER_PATH, m_counter++),
CONTROL_IFACE),
m_viewAgent(connection,
agentPath,
AGENT_IFACE,
ID),
m_view(view),
m_owner(owner),
// use ViewAgent interface
m_contactsModified(m_viewAgent, "ContactsModified"),
m_contactsAdded(m_viewAgent, "ContactsAdded"),
m_contactsRemoved(m_viewAgent, "ContactsRemoved")
{}
/**
* Invokes one of m_contactsModified/Added/Removed. A failure of
* the asynchronous call indicates that the client is dead and
* that its view can be purged.
*/
void sendChange(const GDBusCXX::DBusClientCall0 &call,
int start, int count)
{
call.start(boost::bind(ViewResource::sendDone,
m_self,
_1));
}
/**
* Used as callback for sending changes to the ViewAgent. Only
* holds weak references and thus does not prevent deleting view
* or client.
*/
static void sendDone(const boost::weak_ptr<ViewResource> &self,
const std::string &error)
{
if (!error.empty()) {
// remove view because it is no longer needed
SE_LOG_DEBUG(NULL, NULL, "ViewAgent method call failed, deleting view: %s", error.c_str());
boost::shared_ptr<ViewResource> r = self.lock();
if (r) {
r->close();
}
}
}
void init(boost::shared_ptr<ViewResource> self)
{
m_self = self;
// activate D-Bus interface
add(this, &ViewResource::readContacts, "ReadContacts");
add(this, &ViewResource::close, "Close");
add(this, &ViewResource::refineSearch, "RefineSearch");
activate();
// TODO: aggregate changes into batches
m_view->m_modifiedSignal.connect(IndividualView::ChangeSignal_t::slot_type(&ViewResource::sendChange,
this,
boost::cref(m_contactsModified),
_1,
1).track(self));
m_view->m_addedSignal.connect(IndividualView::ChangeSignal_t::slot_type(&ViewResource::sendChange,
this,
boost::cref(m_contactsAdded),
_1,
1).track(self));
m_view->m_removedSignal.connect(IndividualView::ChangeSignal_t::slot_type(&ViewResource::sendChange,
this,
boost::cref(m_contactsRemoved),
_1,
1).track(self));
}
public:
static boost::shared_ptr<ViewResource> create(const boost::shared_ptr<IndividualView> &view,
const boost::shared_ptr<Client> &owner,
GDBusCXX::connection_type *connection,
const GDBusCXX::Caller_t &ID,
const GDBusCXX::DBusObject_t &agentPath)
{
boost::shared_ptr<ViewResource> viewResource(new ViewResource(view, owner,
connection,
ID,
agentPath));
viewResource->init(viewResource);
return viewResource;
}
/** org.01.pim.contacts.ViewControl.ReadContacts() */
void readContacts(int start, int count, std::vector<FolksIndividualCXX> &contacts)
{
// TODO
SE_THROW("not implemented");
}
/** org.01.pim.contacts.ViewControl.Close() */
void close()
{
// Removing the resource from its owner will drop the last
// reference and delete it when we return.
boost::shared_ptr<ViewResource> r = m_self.lock();
if (r) {
boost::shared_ptr<Client> c = m_owner.lock();
if (c) {
c->detach(r.get());
}
}
}
/** ViewControl.RefineSearch() */
void refineSearch(const StringMap &filter)
{
// TODO
SE_THROW("not implemented");
}
};
unsigned int ViewResource::m_counter;
GDBusCXX::DBusObject_t Manager::search(const GDBusCXX::Caller_t &ID,
const boost::shared_ptr<GDBusCXX::Watch> &watch,
const StringMap &filter,
const GDBusCXX::DBusObject_t &agentPath)
{
// Create and track view which is owned by the caller.
boost::shared_ptr<Client> client = m_server->addClient(ID, watch);
boost::shared_ptr<IndividualView> view;
// TODO: parse filter
view = m_folks->getMainView();
boost::shared_ptr<ViewResource> viewResource(ViewResource::create(view,
client,
getConnection(),
ID,
agentPath));
client->attach(boost::shared_ptr<Resource>(viewResource));
// created local resource
return viewResource->getPath();
}
SE_END_CXX

View file

@ -0,0 +1,81 @@
/*
* Copyright (C) 2012 Intel Corporation
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) version 3.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301 USA
*/
/**
* The D-Bus IPC binding for folks.h and SyncEvolution's
* PBAP support.
*/
#ifndef INCL_SYNCEVO_DBUS_SERVER_PIM_MANAGER
#define INCL_SYNCEVO_DBUS_SERVER_PIM_MANAGER
#include "folks.h"
#include "../server.h"
#include <syncevo/declarations.h>
SE_BEGIN_CXX
/**
* Implementation of org._01.pim.contacts.Manager.
*/
class Manager : public GDBusCXX::DBusObjectHelper
{
boost::weak_ptr<Manager> m_self;
boost::shared_ptr<Server> m_server;
boost::shared_ptr<IndividualAggregator> m_folks;
std::string m_sortOrder;
Manager(const boost::shared_ptr<Server> &server);
void init();
void initFolks();
void initSorting();
/** Manager.Start() */
void start();
/** Manager.Stop() */
void stop();
/** Manager.SetSortOrder() */
void setSortOrder(const std::string &order);
/** Manager.GetSortOrder() */
std::string getSortOrder() { return m_sortOrder; }
/** Manager.Search() */
GDBusCXX::DBusObject_t search(const GDBusCXX::Caller_t &ID,
const boost::shared_ptr<GDBusCXX::Watch> &watch,
const StringMap &filter,
const GDBusCXX::DBusObject_t &agentPath);
public:
/**
* Creates an instance of the Manager which runs as part
* of the given server, using the same D-Bus connection
* and using the server's services (tracking clients,
* startup/shutdown).
*
* While the Manager exists, it blocks auto-termination
* of the server and serves method calls as part of the
* main event loop.
*/
static boost::shared_ptr<Manager> create(const boost::shared_ptr<Server> &server);
~Manager();
};
SE_END_CXX
#endif // INCL_SYNCEVO_DBUS_SERVER_PIM_MANAGER

View file

@ -51,7 +51,8 @@ src_dbus_server_libsyncevodbusserver_la_CXXFLAGS = $(SYNCEVOLUTION_CXXFLAGS) $(C
if COND_DBUS_PIM
src_dbus_server_server_cpp_files += \
src/dbus/server/pim/folks.cpp
src/dbus/server/pim/folks.cpp \
src/dbus/server/pim/manager.cpp
src_dbus_server_libsyncevodbusserver_la_LIBADD += $(FOLKS_LIBS)
src_dbus_server_libsyncevodbusserver_la_CXXFLAGS += $(FOLKS_CFLAGS)
endif

View file

@ -650,6 +650,11 @@ public:
virtual bool isProcessSafe() const { return false; }
};
// extensions to the D-Bus server, created dynamically by main()
#ifdef ENABLE_DBUS_PIM
boost::shared_ptr<GDBusCXX::DBusObjectHelper> CreateContactManager(const boost::shared_ptr<Server> &server);
#endif
SE_END_CXX
#endif // SYNCEVO_DBUS_SERVER_H