r6875 - in dumbhippo/trunk/client: common/ddm common/hippo linux linux/src
- From: commits mugshot org
- To: online-desktop-list gnome org
- Subject: r6875 - in dumbhippo/trunk/client: common/ddm common/hippo linux linux/src
- Date: Wed, 7 Nov 2007 11:41:19 -0600 (CST)
Author: otaylor
Date: 2007-11-07 11:41:12 -0600 (Wed, 07 Nov 2007)
New Revision: 6875
Added:
dumbhippo/trunk/client/linux/src/hippo-dbus-model-client.c
dumbhippo/trunk/client/linux/src/hippo-dbus-model-client.h
Modified:
dumbhippo/trunk/client/common/ddm/ddm-data-model-dbus.c
dumbhippo/trunk/client/common/ddm/ddm-data-model.c
dumbhippo/trunk/client/common/ddm/ddm-data-model.h
dumbhippo/trunk/client/common/ddm/ddm-data-query.c
dumbhippo/trunk/client/common/ddm/ddm-data-resource-internal.h
dumbhippo/trunk/client/common/ddm/ddm-data-resource.c
dumbhippo/trunk/client/common/ddm/ddm-data-resource.h
dumbhippo/trunk/client/common/ddm/ddm-work-item.c
dumbhippo/trunk/client/common/ddm/ddm.h
dumbhippo/trunk/client/common/hippo/hippo-data-model-backend.c
dumbhippo/trunk/client/linux/Makefile-mugshot.am
dumbhippo/trunk/client/linux/src/hippo-dbus-model.c
Log:
hippo-dbus-model-client.[ch] hippo-dbus-model.c: Rewrite export of data
model to D-BUS using DDMClient.
ddm-data-model.[ch]ddm-data-resource.c ddm-data-resource-internal.h
hippo-data-model-backend.c ddm-data-model-dbus.c: Reset the data
model when reconnecting to the server; discard all remote resources
and all local properties referencing remote resources.
ddm-data-resource.[ch]: Add refcounting for resources.
ddm-data-query.c: Add errored fetches into 'received_fetch'; this is needed
to to prevent infinite loops, especially in the disconnected state.
Modified: dumbhippo/trunk/client/common/ddm/ddm-data-model-dbus.c
===================================================================
--- dumbhippo/trunk/client/common/ddm/ddm-data-model-dbus.c 2007-11-07 00:45:26 UTC (rev 6874)
+++ dumbhippo/trunk/client/common/ddm/ddm-data-model-dbus.c 2007-11-07 17:41:12 UTC (rev 6875)
@@ -623,6 +623,8 @@
return;
}
+ if (is_connected)
+ ddm_data_model_reset(dbus_model->ddm_model);
ddm_data_model_set_connected(dbus_model->ddm_model, is_connected);
if (is_connected)
model_send_pending(dbus_model);
Modified: dumbhippo/trunk/client/common/ddm/ddm-data-model.c
===================================================================
--- dumbhippo/trunk/client/common/ddm/ddm-data-model.c 2007-11-07 00:45:26 UTC (rev 6874)
+++ dumbhippo/trunk/client/common/ddm/ddm-data-model.c 2007-11-07 17:41:12 UTC (rev 6875)
@@ -55,7 +55,9 @@
static void
ddm_data_model_init(DDMDataModel *model)
{
- model->resources = g_hash_table_new(g_str_hash, g_str_equal);
+ model->resources = g_hash_table_new_full(g_str_hash, g_str_equal,
+ NULL,
+ (GDestroyNotify)ddm_data_resource_unref);
model->changed_resources = g_hash_table_new(g_direct_hash, NULL);
model->work_items = g_queue_new();
@@ -446,7 +448,28 @@
return ensure_resource_internal(model, resource_id, class_id, TRUE);
}
+static gboolean
+model_reset_foreach (gpointer key,
+ gpointer value,
+ gpointer data)
+{
+ DDMDataResource *resource = value;
+
+ if (ddm_data_resource_is_local(resource)) {
+ _ddm_data_resource_reset(resource);
+ return FALSE;
+ } else {
+ return TRUE;
+ }
+}
+
void
+ddm_data_model_reset (DDMDataModel *model)
+{
+ g_hash_table_foreach_remove(model->resources, model_reset_foreach, NULL);
+}
+
+void
ddm_data_model_set_connected (DDMDataModel *model,
gboolean connected)
{
Modified: dumbhippo/trunk/client/common/ddm/ddm-data-model.h
===================================================================
--- dumbhippo/trunk/client/common/ddm/ddm-data-model.h 2007-11-07 00:45:26 UTC (rev 6874)
+++ dumbhippo/trunk/client/common/ddm/ddm-data-model.h 2007-11-07 17:41:12 UTC (rev 6875)
@@ -80,6 +80,13 @@
/* should only be called by backends */
void ddm_data_model_schedule_flush (DDMDataModel *model);
+
+/* Generally a backend will first reset() and then call set_connected(TRUE);
+ * the reason for the separation is to allow the backend to restablish
+ * local properties that reference remote properties.
+ */
+void ddm_data_model_reset (DDMDataModel *model);
+
void ddm_data_model_set_connected (DDMDataModel *model,
gboolean connected);
Modified: dumbhippo/trunk/client/common/ddm/ddm-data-query.c
===================================================================
--- dumbhippo/trunk/client/common/ddm/ddm-data-query.c 2007-11-07 00:45:26 UTC (rev 6874)
+++ dumbhippo/trunk/client/common/ddm/ddm-data-query.c 2007-11-07 17:41:12 UTC (rev 6875)
@@ -280,7 +280,24 @@
DDMWorkItem *item;
GSList *l;
- if (!local) {
+ /* It's possible that we succeeded in getting a list of results, but
+ * couldn't even find out the class_id for the results (particularly
+ * for getResource, where a simple failed query shows this way)
+ * In this case, treat the whole thing as a failure.
+ */
+ for (l = results; l; l = l->next) {
+ if (ddm_data_resource_get_class_id(l->data) == NULL) {
+ g_debug("%s: resource %s has no class ID, failing query",
+ query->id_string, ddm_data_resource_get_resource_id(l->data));
+
+ ddm_data_query_error(query,
+ DDM_DATA_ERROR_ITEM_NOT_FOUND,
+ "Couldn't get details of result items");
+ return;
+ }
+ }
+
+ if (!local) {
g_debug("%s: Received response", query->id_string);
for (l = results; l; l = l->next) {
@@ -370,6 +387,31 @@
g_debug("%s: Got error response: %s (%d)", query->id_string, message != NULL ? message : "<null>", error);
+ /* For a getResource query for a particular resource, we want to mark the
+ * fetch as 'received', so that we don't try to fetch it again. This is
+ * especially important for keeping our multi-part fetch code from going
+ * into an infinite loop; if we make a fetch, and it returns an error,
+ * don't try again.
+ *
+ * FIXME: This isn't really right; a 404 on a getResource shouldn't
+ * keep us from successfully trying to getResource again later if that
+ * resource appears. Possibly we want to track errored fetches separately
+ * with a timeout for retrying the errored fetch.
+ */
+ if (query->qname == ddm_qname_get("http://mugshot.org/p/system", "getResource")) {
+ const char *resource_id = g_hash_table_lookup(query->params, "resourceId");
+ if (resource_id == NULL) {
+ /* Shouldn't happen; we validate application-supplied getResource queries */
+ g_warning("%s: Null resource_id for getresource query when marking error response", query->id_string);
+ } else {
+ DDMDataResource *resource = ddm_data_model_lookup_resource(query->model, resource_id);
+ if (resource != NULL) {
+ g_debug("%s: marking fetch 'received' on errored getResource for %s'", query->id_string, resource_id);
+ _ddm_data_resource_fetch_received(resource, query->fetch);
+ }
+ }
+ }
+
_ddm_data_model_query_answered(query->model, query);
if (query->error_handler)
Modified: dumbhippo/trunk/client/common/ddm/ddm-data-resource-internal.h
===================================================================
--- dumbhippo/trunk/client/common/ddm/ddm-data-resource-internal.h 2007-11-07 00:45:26 UTC (rev 6874)
+++ dumbhippo/trunk/client/common/ddm/ddm-data-resource-internal.h 2007-11-07 17:41:12 UTC (rev 6875)
@@ -14,6 +14,8 @@
const char *class_id,
gboolean local);
+void _ddm_data_resource_reset (DDMDataResource *resource);
+
GSList *_ddm_data_resource_get_default_properties (DDMDataResource *resource);
DDMDataFetch *_ddm_data_resource_get_received_fetch (DDMDataResource *resource);
Modified: dumbhippo/trunk/client/common/ddm/ddm-data-resource.c
===================================================================
--- dumbhippo/trunk/client/common/ddm/ddm-data-resource.c 2007-11-07 00:45:26 UTC (rev 6874)
+++ dumbhippo/trunk/client/common/ddm/ddm-data-resource.c 2007-11-07 17:41:12 UTC (rev 6875)
@@ -44,6 +44,8 @@
struct _DDMDataResource
{
+ guint refcount;
+
DDMDataModel *model;
char *resource_id;
char *class_id;
@@ -129,6 +131,17 @@
g_warning("Type value '%d' not valid", DDM_DATA_BASE(value->type));
}
+static void
+ddm_data_property_free(DDMDataProperty *property)
+{
+ ddm_data_value_clear(&property->value);
+
+ if (property->default_children)
+ ddm_data_fetch_unref(property->default_children);
+
+ g_free(property);
+}
+
DDMQName *
ddm_data_property_get_qname(DDMDataProperty *property)
{
@@ -178,6 +191,13 @@
return property->default_children;
}
+static void
+data_client_free(DataClient *data_client)
+{
+ ddm_data_fetch_unref(data_client->fetch);
+ g_free(data_client);
+}
+
DDMDataResource *
_ddm_data_resource_new(DDMDataModel *model,
const char *resource_id,
@@ -186,6 +206,8 @@
{
DDMDataResource *resource = g_new0(DDMDataResource, 1);
+ resource->refcount = 1;
+
resource->model = model;
resource->resource_id = g_strdup(resource_id);
ddm_data_resource_set_class_id(resource, class_id);
@@ -198,7 +220,125 @@
return resource;
}
+typedef gboolean (*ForeachRemoveFunc) (gpointer data,
+ gpointer user_data);
+
+static GSList *
+slist_foreach_remove(GSList *list,
+ ForeachRemoveFunc func,
+ gpointer user_data)
+{
+ GSList *l = list;
+ GSList *prev = NULL;
+
+ while (l) {
+ GSList *next = l->next;
+ if ((*func)(l->data, user_data)) {
+ if (prev != NULL)
+ prev->next = next;
+ else
+ list = next;
+ } else {
+ prev = l;
+ }
+
+ l = next;
+ }
+
+ return list;
+}
+
+static gboolean
+reset_resource_value_foreach(gpointer data,
+ gpointer user_data)
+{
+ DDMDataResource *resource = data;
+
+ return !resource->local;
+}
+
+static gboolean
+reset_property_foreach(gpointer data,
+ gpointer user_data)
+{
+ DDMDataProperty *property = data;
+
+ if (DDM_DATA_BASE(property->value.type) != DDM_DATA_RESOURCE)
+ return FALSE;
+
+ if (DDM_DATA_IS_LIST(property->value.type)) {
+ property->value.u.list = slist_foreach_remove(property->value.u.list, reset_resource_value_foreach, NULL);
+ reset_resource_value_foreach(data, user_data);
+ return FALSE;
+ } else {
+ if (!property->value.u.resource->local) {
+ ddm_data_property_free(property);
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+ }
+}
+
void
+_ddm_data_resource_reset (DDMDataResource *resource)
+{
+ g_return_if_fail(resource != NULL);
+ g_return_if_fail(resource->local);
+
+ resource->properties = slist_foreach_remove(resource->properties, reset_property_foreach, NULL);
+
+ if (resource->requested_fetch != NULL) {
+ ddm_data_fetch_unref(resource->requested_fetch);
+ resource->requested_fetch = NULL;
+ }
+
+ if (resource->received_fetch != NULL) {
+ ddm_data_fetch_unref(resource->received_fetch);
+ resource->received_fetch = NULL;
+ }
+
+ resource->requested_serial = -1;
+}
+
+DDMDataResource *
+ddm_data_resource_ref (DDMDataResource *resource)
+{
+ g_return_val_if_fail(resource != NULL, NULL);
+ g_return_val_if_fail(resource->refcount > 0, NULL);
+
+ resource->refcount++;
+
+ return resource;
+}
+
+void
+ddm_data_resource_unref (DDMDataResource *resource)
+{
+ g_return_if_fail(resource != NULL);
+ g_return_if_fail(resource->refcount > 0);
+
+ resource->refcount--;
+ if (resource->refcount == 0) {
+ g_free(resource->resource_id);
+ g_free(resource->class_id);
+
+ g_slist_foreach(resource->clients, (GFunc)data_client_free, NULL);
+ g_slist_foreach(resource->connections, (GFunc)g_free, NULL);
+ g_slist_foreach(resource->properties, (GFunc)ddm_data_property_free, NULL);
+
+ g_slist_free(resource->changed_properties);
+
+ if (resource->received_fetch != NULL)
+ ddm_data_fetch_unref(resource->received_fetch);
+ if (resource->requested_fetch != NULL)
+ ddm_data_fetch_unref(resource->requested_fetch);
+
+ g_free(resource);
+ }
+}
+
+void
ddm_data_resource_set_class_id(DDMDataResource *resource,
const char *class_id)
{
@@ -543,30 +683,47 @@
for (l = resource->clients; l; l = l->next) {
data_client = l->data;
if (data_client->client == client) {
- if (fetch)
+ if (fetch) {
ddm_data_fetch_ref(fetch);
+ ddm_data_fetch_unref(data_client->fetch);
- ddm_data_fetch_unref(data_client->fetch);
- if (fetch) {
data_client->fetch = fetch;
} else {
resource->clients = g_slist_remove(resource->clients, data_client);
- g_free(data_client);
+ data_client_free(data_client);
}
return;
}
}
- data_client = g_new(DataClient, 1);
- data_client->client = client;
- data_client->fetch = ddm_data_fetch_ref(fetch);
+ if (fetch) {
+ data_client = g_new(DataClient, 1);
+ data_client->client = client;
+ data_client->fetch = ddm_data_fetch_ref(fetch);
+ }
}
+DDMDataFetch *
+ddm_data_resource_get_client_fetch (DDMDataResource *resource,
+ DDMClient *client)
+{
+ GSList *l;
+ DataClient *data_client;
+
+ for (l = resource->clients; l; l = l->next) {
+ data_client = l->data;
+ if (data_client->client == client)
+ return data_client->fetch;
+ }
+
+ return NULL;
+}
+
void
ddm_data_resource_disconnect (DDMDataResource *resource,
DDMDataFunction function,
- gpointer user_data)
+ gpointer user_data)
{
GSList *l;
@@ -802,12 +959,7 @@
DDMDataProperty *property)
{
resource->properties = g_slist_remove(resource->properties, property);
- ddm_data_value_clear(&property->value);
- if (property->default_children) {
- ddm_data_fetch_unref(property->default_children);
- }
-
- g_free(property);
+ ddm_data_property_free(property);
}
/* return value is whether something changed (we need to emit notification) */
Modified: dumbhippo/trunk/client/common/ddm/ddm-data-resource.h
===================================================================
--- dumbhippo/trunk/client/common/ddm/ddm-data-resource.h 2007-11-07 00:45:26 UTC (rev 6874)
+++ dumbhippo/trunk/client/common/ddm/ddm-data-resource.h 2007-11-07 17:41:12 UTC (rev 6875)
@@ -86,6 +86,9 @@
} u;
};
+DDMDataResource *ddm_data_resource_ref (DDMDataResource *resource);
+void ddm_data_resource_unref (DDMDataResource *resource);
+
void ddm_data_value_get_element(DDMDataValue *value,
GSList *element_node,
DDMDataValue *element);
@@ -107,10 +110,13 @@
DDMQName *property,
DDMDataFunction function,
gpointer user_data);
-void ddm_data_resource_set_client_fetch (DDMDataResource *resource,
- DDMClient *client,
- DDMDataFetch *fetch);
+void ddm_data_resource_set_client_fetch (DDMDataResource *resource,
+ DDMClient *client,
+ DDMDataFetch *fetch);
+DDMDataFetch *ddm_data_resource_get_client_fetch (DDMDataResource *resource,
+ DDMClient *client);
+
void ddm_data_resource_disconnect (DDMDataResource *resource,
DDMDataFunction function,
gpointer user_data);
Modified: dumbhippo/trunk/client/common/ddm/ddm-work-item.c
===================================================================
--- dumbhippo/trunk/client/common/ddm/ddm-work-item.c 2007-11-07 00:45:26 UTC (rev 6874)
+++ dumbhippo/trunk/client/common/ddm/ddm-work-item.c 2007-11-07 17:41:12 UTC (rev 6875)
@@ -347,8 +347,10 @@
}
break;
case ITEM_QUERY_RESPONSE:
- _ddm_data_query_run_response(item->u.query_response.query);
- break;
+ {
+ _ddm_data_query_run_response(item->u.query_response.query);
+ break;
+ }
}
} else {
g_debug("%s: have unsatisfied fetches; need responses; min_serial=%" G_GINT64_MODIFIER "d", item->id_string,
Modified: dumbhippo/trunk/client/common/ddm/ddm.h
===================================================================
--- dumbhippo/trunk/client/common/ddm/ddm.h 2007-11-07 00:45:26 UTC (rev 6874)
+++ dumbhippo/trunk/client/common/ddm/ddm.h 2007-11-07 17:41:12 UTC (rev 6875)
@@ -14,6 +14,7 @@
#define DDM_INSIDE_DDM_H 1
+#include <ddm/ddm-client.h>
#include <ddm/ddm-data-fetch.h>
#include <ddm/ddm-data-model.h>
#include <ddm/ddm-data-model-backend.h>
Modified: dumbhippo/trunk/client/common/hippo/hippo-data-model-backend.c
===================================================================
--- dumbhippo/trunk/client/common/hippo/hippo-data-model-backend.c 2007-11-07 00:45:26 UTC (rev 6874)
+++ dumbhippo/trunk/client/common/hippo/hippo-data-model-backend.c 2007-11-07 17:41:12 UTC (rev 6875)
@@ -79,6 +79,13 @@
const char *self_id;
DDMQName *self_id_prop;
DDMDataValue value;
+
+ /* We first "reset" - deleting all non-local resources from the model, and all property
+ * values that reference non-local properties; then we add back the "self" property, which
+ * references the local resource, *then* we signal that we are reconnected, so that the
+ * self property is already there.
+ */
+ ddm_data_model_reset(hippo_model->ddm_model);
global_resource = ddm_data_model_ensure_local_resource(hippo_model->ddm_model,
DDM_GLOBAL_RESOURCE, DDM_GLOBAL_RESOURCE_CLASS);
@@ -88,8 +95,7 @@
self_id = NULL;
}
- self_id_prop = ddm_qname_get(DDM_GLOBAL_RESOURCE_CLASS,
- "self");
+ self_id_prop = ddm_qname_get(DDM_GLOBAL_RESOURCE_CLASS, "self");
if (self_id) {
value.type = DDM_DATA_RESOURCE;
value.u.resource = ddm_data_model_ensure_resource(hippo_model->ddm_model,
@@ -167,9 +173,15 @@
if (hippo_model == NULL)
return FALSE; /* in case model was nuked before getting to idle */
-
+
+ if (hippo_model->disk_cache == NULL) {
+ ddm_data_query_error(query,
+ DDM_DATA_ERROR_INTERNAL,
+ "No connection and query is not cached");
+ return FALSE;
+ }
+
_hippo_disk_cache_do_query(hippo_model->disk_cache, query);
-
return FALSE;
}
Modified: dumbhippo/trunk/client/linux/Makefile-mugshot.am
===================================================================
--- dumbhippo/trunk/client/linux/Makefile-mugshot.am 2007-11-07 00:45:26 UTC (rev 6874)
+++ dumbhippo/trunk/client/linux/Makefile-mugshot.am 2007-11-07 17:41:12 UTC (rev 6875)
@@ -40,6 +40,8 @@
src/hippo-dbus-local.h \
src/hippo-dbus-model.c \
src/hippo-dbus-model.h \
+ src/hippo-dbus-model-client.c \
+ src/hippo-dbus-model-client.h \
src/hippo-dbus-mugshot.c \
src/hippo-dbus-mugshot.h \
src/hippo-dbus-pidgin.c \
Added: dumbhippo/trunk/client/linux/src/hippo-dbus-model-client.c
===================================================================
--- dumbhippo/trunk/client/linux/src/hippo-dbus-model-client.c 2007-11-07 00:45:26 UTC (rev 6874)
+++ dumbhippo/trunk/client/linux/src/hippo-dbus-model-client.c 2007-11-07 17:41:12 UTC (rev 6875)
@@ -0,0 +1,658 @@
+/* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil; -*- */
+
+#include "hippo-dbus-model-client.h"
+#include "hippo-dbus-server.h"
+#include "hippo-dbus-model.h"
+
+typedef struct _DataClientConnection DataClientConnection;
+typedef struct _DataClientQueryClosure DataClientQueryClosure;
+
+static void hippo_dbus_model_client_iface_init(DDMClientIface *iface);
+
+static void add_resource_to_message (HippoDBusModelClient *client,
+ DBusMessageIter *resource_array_iter,
+ DDMDataResource *resource,
+ DDMDataFetch *fetch,
+ gboolean indirect,
+ gboolean is_notification,
+ GSList *changed_properties);
+
+struct _HippoDBusModelClient {
+ GObject parent;
+
+ DBusConnection *connection;
+ DDMDataModel *model;
+
+ char *bus_name;
+ char *path;
+
+ GHashTable *connections;
+ gboolean disconnected;
+};
+
+struct _HippoDBusModelClientClass {
+ GObjectClass parent_class;
+};
+
+struct _DataClientConnection {
+ HippoDBusModelClient *client;
+ DDMDataResource *resource;
+ DDMDataFetch *fetch;
+};
+
+struct _DataClientQueryClosure {
+ HippoDBusModelClient *client;
+ DBusMessage *message;
+ DDMDataFetch *fetch;
+};
+
+G_DEFINE_TYPE_WITH_CODE(HippoDBusModelClient, hippo_dbus_model_client, G_TYPE_OBJECT,
+ G_IMPLEMENT_INTERFACE(DDM_TYPE_CLIENT, hippo_dbus_model_client_iface_init);)
+
+static DataClientConnection *
+data_client_connection_new (HippoDBusModelClient *client,
+ DDMDataResource *resource)
+{
+ DataClientConnection *connection = g_new0(DataClientConnection, 1);
+
+ connection->client = client;
+ connection->resource = resource;
+ connection->fetch = NULL;
+
+ return connection;
+}
+
+static void
+data_client_connection_set_fetch (DataClientConnection *connection,
+ DDMDataFetch *fetch)
+{
+ if (fetch)
+ ddm_data_fetch_ref(fetch);
+
+ ddm_data_resource_set_client_fetch(connection->resource, DDM_CLIENT(connection->client), fetch);
+
+ if (connection->fetch)
+ ddm_data_fetch_unref(connection->fetch);
+
+ connection->fetch = fetch;
+}
+
+static void
+data_client_connection_destroy(DataClientConnection *connection)
+{
+ ddm_data_resource_set_client_fetch(connection->resource, DDM_CLIENT(connection->client), NULL);
+ g_free(connection);
+}
+
+/*****************************************************************/
+
+static DataClientQueryClosure *
+data_client_query_closure_new (HippoDBusModelClient *client,
+ DBusMessage *message,
+ DDMDataFetch *fetch)
+{
+ DataClientQueryClosure *closure = g_new0(DataClientQueryClosure, 1);
+ closure->client = client ? g_object_ref(client) : NULL;
+ closure->message = dbus_message_ref(message);
+ closure->fetch = fetch ? ddm_data_fetch_ref(fetch) : NULL;
+
+ return closure;
+}
+
+static void
+data_client_query_closure_destroy (DataClientQueryClosure *closure)
+{
+ if (closure->client)
+ g_object_unref(closure->client);
+ if (closure->fetch)
+ ddm_data_fetch_unref(closure->fetch);
+ dbus_message_unref(closure->message);
+ g_free(closure);
+}
+
+/*****************************************************************/
+
+static void
+add_property_value_to_message(DBusMessageIter *property_array_iter,
+ DDMQName *property_qname,
+ DDMDataUpdate update,
+ DDMDataValue *value,
+ DDMDataCardinality cardinality)
+{
+ DBusMessageIter property_iter;
+ DBusMessageIter value_iter;
+ char update_byte;
+ char type_byte;
+ char cardinality_byte;
+ const char *value_signature = NULL;
+
+ switch (update) {
+ case DDM_DATA_UPDATE_ADD:
+ update_byte = 'a';
+ break;
+ case DDM_DATA_UPDATE_REPLACE:
+ update_byte = 'r';
+ break;
+ case DDM_DATA_UPDATE_DELETE:
+ update_byte = 'd';
+ break;
+ case DDM_DATA_UPDATE_CLEAR:
+ update_byte = 'c';
+ break;
+ }
+
+ switch (value->type) {
+ case DDM_DATA_BOOLEAN:
+ type_byte = 'b';
+ value_signature = "b";
+ break;
+ case DDM_DATA_INTEGER:
+ type_byte = 'i';
+ value_signature = "i";
+ break;
+ case DDM_DATA_LONG:
+ type_byte = 'l';
+ value_signature = "x";
+ break;
+ case DDM_DATA_FLOAT:
+ type_byte = 'f';
+ value_signature = "d";
+ break;
+ case DDM_DATA_NONE: /* Empty list, type doesn't matter */
+ case DDM_DATA_STRING:
+ type_byte = 's';
+ value_signature = "s";
+ break;
+ case DDM_DATA_RESOURCE:
+ type_byte = 'r';
+ value_signature = "s";
+ break;
+ case DDM_DATA_URL:
+ type_byte = 'u';
+ value_signature = "s";
+ break;
+ case DDM_DATA_LIST:
+ break;
+ }
+
+ g_assert(value_signature != NULL);
+
+ switch (cardinality) {
+ case DDM_DATA_CARDINALITY_01:
+ cardinality_byte = '?';
+ break;
+ case DDM_DATA_CARDINALITY_1:
+ cardinality_byte = '.';
+ break;
+ case DDM_DATA_CARDINALITY_N:
+ cardinality_byte = '*';
+ break;
+ }
+
+ dbus_message_iter_open_container(property_array_iter, DBUS_TYPE_STRUCT, NULL, &property_iter);
+ dbus_message_iter_append_basic(&property_iter, DBUS_TYPE_STRING, &property_qname->uri);
+ dbus_message_iter_append_basic(&property_iter, DBUS_TYPE_STRING, &property_qname->name);
+ dbus_message_iter_append_basic(&property_iter, DBUS_TYPE_BYTE, &update_byte);
+ dbus_message_iter_append_basic(&property_iter, DBUS_TYPE_BYTE, &type_byte);
+ dbus_message_iter_append_basic(&property_iter, DBUS_TYPE_BYTE, &cardinality_byte);
+
+ dbus_message_iter_open_container(&property_iter, DBUS_TYPE_VARIANT, value_signature, &value_iter);
+
+ switch (value->type) {
+ case DDM_DATA_BOOLEAN:
+ {
+ dbus_bool_t v = value->u.boolean;
+ dbus_message_iter_append_basic(&value_iter, DBUS_TYPE_BOOLEAN, &v);
+ }
+ break;
+ case DDM_DATA_INTEGER:
+ dbus_message_iter_append_basic(&value_iter, DBUS_TYPE_INT32, &value->u.integer);
+ break;
+ case DDM_DATA_LONG:
+ dbus_message_iter_append_basic(&value_iter, DBUS_TYPE_INT64, &value->u.long_);
+ break;
+ case DDM_DATA_FLOAT:
+ dbus_message_iter_append_basic(&value_iter, DBUS_TYPE_DOUBLE, &value->u.float_);
+ break;
+ case DDM_DATA_NONE:
+ {
+ const char *v = "";
+ dbus_message_iter_append_basic(&value_iter, DBUS_TYPE_STRING, &v);
+ }
+ break;
+ case DDM_DATA_STRING:
+ case DDM_DATA_URL:
+ dbus_message_iter_append_basic(&value_iter, DBUS_TYPE_STRING, &value->u.string);
+ break;
+ case DDM_DATA_RESOURCE:
+ {
+ const char *v = ddm_data_resource_get_resource_id(value->u.resource);
+
+ dbus_message_iter_append_basic(&value_iter, DBUS_TYPE_STRING, &v);
+
+ }
+ break;
+ case DDM_DATA_LIST:
+ break;
+ }
+
+ dbus_message_iter_close_container(&property_iter, &value_iter);
+ dbus_message_iter_close_container(property_array_iter, &property_iter);
+}
+
+static void
+add_property_children_to_message(HippoDBusModelClient *client,
+ DBusMessageIter *resource_array_iter,
+ DDMDataProperty *property,
+ DDMDataFetch *children)
+{
+ DDMDataValue value;
+
+ ddm_data_property_get_value(property, &value);
+
+ if (value.type == DDM_DATA_RESOURCE) {
+ add_resource_to_message(client, resource_array_iter, value.u.resource, children, TRUE, FALSE, NULL);
+ } else if (value.type == (DDM_DATA_RESOURCE | DDM_DATA_LIST)) {
+ GSList *l;
+ for (l = value.u.list; l; l = l->next)
+ add_resource_to_message(client, resource_array_iter, l->data, children, TRUE, FALSE, NULL);
+ }
+}
+
+static void
+add_property_to_message(DBusMessageIter *property_array_iter,
+ DDMDataProperty *property)
+{
+ DDMDataCardinality cardinality;
+ DDMDataValue value;
+ DDMQName *property_qname;
+
+ ddm_data_property_get_value(property, &value);
+ cardinality = ddm_data_property_get_cardinality(property);
+ property_qname = ddm_data_property_get_qname(property);
+
+ if (value.type == DDM_DATA_NONE) {
+ add_property_value_to_message(property_array_iter, property_qname,
+ DDM_DATA_UPDATE_CLEAR,
+ &value, cardinality);
+ } else if (DDM_DATA_IS_LIST(value.type)) {
+ GSList *l;
+
+ for (l = value.u.list; l; l = l->next) {
+ DDMDataValue element;
+ ddm_data_value_get_element(&value, l, &element);
+
+ add_property_value_to_message(property_array_iter, property_qname,
+ l == value.u.list ? DDM_DATA_UPDATE_REPLACE : DDM_DATA_UPDATE_ADD,
+ &element, cardinality);
+ }
+ } else {
+ add_property_value_to_message(property_array_iter, property_qname,
+ DDM_DATA_UPDATE_REPLACE,
+ &value, cardinality);
+ }
+}
+
+static void
+add_resource_to_message(HippoDBusModelClient *client,
+ DBusMessageIter *resource_array_iter,
+ DDMDataResource *resource,
+ DDMDataFetch *fetch,
+ gboolean indirect,
+ gboolean is_notification,
+ GSList *changed_properties)
+{
+ DDMDataFetchIter fetch_iter;
+ DataClientConnection *connection;
+ DDMDataFetch *new_fetch;
+ DDMDataFetch *total_fetch;
+ DBusMessageIter resource_iter;
+ DBusMessageIter property_array_iter;
+ const char *resource_id;
+ const char *class_id;
+ dbus_bool_t indirect_bool;
+
+ connection = g_hash_table_lookup(client->connections, ddm_data_resource_get_resource_id(resource));
+ if (connection == NULL) {
+ connection = data_client_connection_new(client, resource);
+ g_hash_table_insert(client->connections, (char *)ddm_data_resource_get_resource_id(resource), connection);
+ }
+
+ if (is_notification) {
+ new_fetch = ddm_data_fetch_ref(fetch);
+ total_fetch = ddm_data_fetch_ref(fetch);
+ } else {
+ if (connection->fetch)
+ new_fetch = ddm_data_fetch_subtract(fetch, connection->fetch);
+ else
+ new_fetch = ddm_data_fetch_ref(fetch);
+
+ if (new_fetch == NULL && indirect)
+ return;
+
+ if (connection->fetch)
+ total_fetch = ddm_data_fetch_merge(fetch, connection->fetch);
+ else
+ total_fetch = ddm_data_fetch_ref(fetch);
+
+ data_client_connection_set_fetch(connection, total_fetch);
+ }
+
+ if (new_fetch) {
+ ddm_data_fetch_iter_init(&fetch_iter, resource, new_fetch);
+ while (ddm_data_fetch_iter_has_next(&fetch_iter)) {
+ DDMDataProperty *property;
+ DDMDataFetch *children;
+
+ ddm_data_fetch_iter_next(&fetch_iter, &property, &children);
+
+ /* FIXME: This check on children isn't really right ... if we have a resource-value
+ * property that is default-fetched without default-children, then we should
+ * send an empty resource element for it, because the recipient needs at least
+ * the classId. */
+ if (!children)
+ continue;
+
+ if (is_notification && g_slist_find(changed_properties, ddm_data_property_get_qname(property)) == NULL)
+ continue;
+
+ add_property_children_to_message(client, resource_array_iter, property, children);
+ }
+ ddm_data_fetch_iter_clear(&fetch_iter);
+ }
+
+ resource_id = ddm_data_resource_get_resource_id(resource);
+ class_id = ddm_data_resource_get_class_id(resource);
+ indirect_bool = indirect;
+
+ dbus_message_iter_open_container(resource_array_iter, DBUS_TYPE_STRUCT, NULL, &resource_iter);
+ dbus_message_iter_append_basic(&resource_iter, DBUS_TYPE_STRING, &resource_id);
+ dbus_message_iter_append_basic(&resource_iter, DBUS_TYPE_STRING, &class_id);
+ dbus_message_iter_append_basic(&resource_iter, DBUS_TYPE_BOOLEAN, &indirect_bool);
+
+ dbus_message_iter_open_container(&resource_iter, DBUS_TYPE_ARRAY, "(ssyyyv)", &property_array_iter);
+
+ if (new_fetch) {
+ ddm_data_fetch_iter_init(&fetch_iter, resource, new_fetch);
+ while (ddm_data_fetch_iter_has_next(&fetch_iter)) {
+ DDMDataProperty *property;
+
+ ddm_data_fetch_iter_next(&fetch_iter, &property, NULL);
+
+ if (is_notification && g_slist_find(changed_properties, ddm_data_property_get_qname(property)) == NULL)
+ continue;
+
+ add_property_to_message(&property_array_iter, property);
+ }
+
+ ddm_data_fetch_iter_clear(&fetch_iter);
+ }
+
+ dbus_message_iter_close_container(&resource_iter, &property_array_iter);
+ dbus_message_iter_close_container(resource_array_iter, &resource_iter);
+
+ if (new_fetch)
+ ddm_data_fetch_unref(new_fetch);
+ ddm_data_fetch_unref(total_fetch);
+}
+
+/*****************************************************************/
+
+static void
+hippo_dbus_model_client_dispose (GObject *object)
+{
+ HippoDBusModelClient *dbus_client = HIPPO_DBUS_MODEL_CLIENT(object);
+ if (!dbus_client->disconnected) {
+ dbus_client->disconnected = TRUE;
+
+ hippo_dbus_unwatch_for_disconnect(hippo_app_get_dbus(hippo_get_app()),
+ dbus_client->bus_name);
+
+ g_hash_table_destroy(dbus_client->connections);
+ dbus_client->connections = NULL;
+ }
+}
+
+static void
+hippo_dbus_model_client_finalize (GObject *object)
+{
+ HippoDBusModelClient *dbus_client = HIPPO_DBUS_MODEL_CLIENT(object);
+
+ g_free(dbus_client->bus_name);
+ g_free(dbus_client->path);
+}
+
+static void
+hippo_dbus_model_client_init (HippoDBusModelClient *dbus_client)
+{
+ dbus_client->connections = g_hash_table_new_full(g_str_hash, g_str_equal,
+ NULL, (GDestroyNotify)data_client_connection_destroy);
+ dbus_client->disconnected = FALSE;
+}
+
+static void
+hippo_dbus_model_client_class_init (HippoDBusModelClientClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->dispose = hippo_dbus_model_client_dispose;
+ object_class->finalize = hippo_dbus_model_client_finalize;
+}
+
+static gpointer
+hippo_dbus_model_client_begin_notification (DDMClient *client)
+{
+ return NULL;
+}
+
+static void
+hippo_dbus_model_client_notify (DDMClient *client,
+ DDMDataResource *resource,
+ GSList *changed_properties,
+ gpointer notification_data)
+{
+ HippoDBusModelClient *dbus_client = HIPPO_DBUS_MODEL_CLIENT(client);
+ DataClientConnection *client_connection = g_hash_table_lookup(dbus_client->connections,
+ ddm_data_resource_get_resource_id(resource));
+ DBusMessage *message;
+ DBusMessageIter iter;
+ DBusMessageIter array_iter;
+
+ message = dbus_message_new_method_call(dbus_client->bus_name, dbus_client->path,
+ HIPPO_DBUS_MODEL_CLIENT_INTERFACE, "Notify");
+
+ dbus_message_iter_init_append(message, &iter);
+
+ dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(ssba(ssyyyv))", &array_iter);
+
+ add_resource_to_message(dbus_client, &array_iter,
+ resource, client_connection->fetch,
+ FALSE,
+ TRUE, changed_properties);
+
+ dbus_message_iter_close_container(&iter, &array_iter);
+
+ dbus_connection_send(dbus_client->connection, message, NULL);
+
+ /* FIXME: We should catch errors, and kick the client connection on error */
+
+ dbus_message_unref(message);
+}
+
+static void
+hippo_dbus_model_client_end_notification (DDMClient *client,
+ gpointer notification_data)
+{
+}
+
+static void
+hippo_dbus_model_client_iface_init(DDMClientIface *iface)
+{
+ iface->begin_notification = hippo_dbus_model_client_begin_notification;
+ iface->notify = hippo_dbus_model_client_notify;
+ iface->end_notification = hippo_dbus_model_client_end_notification;
+}
+
+/*****************************************************************/
+
+HippoDBusModelClient *
+hippo_dbus_model_client_new (DBusConnection *connection,
+ DDMDataModel *model,
+ const char *bus_name,
+ const char *path)
+{
+ HippoDBusModelClient *dbus_client;
+
+ g_return_val_if_fail(DDM_IS_DATA_MODEL(model), NULL);
+ g_return_val_if_fail(bus_name != NULL, NULL);
+ g_return_val_if_fail(path != NULL, NULL);
+
+ dbus_client = g_object_new(HIPPO_TYPE_DBUS_MODEL_CLIENT, NULL);
+
+ dbus_client->connection = connection;
+ dbus_client->model = model;
+ dbus_client->bus_name = g_strdup(bus_name);
+ dbus_client->path = g_strdup(path);
+
+ hippo_dbus_watch_for_disconnect(hippo_app_get_dbus(hippo_get_app()),
+ bus_name);
+
+ return dbus_client;
+}
+
+const char *
+hippo_dbus_model_client_get_bus_name (HippoDBusModelClient *dbus_client)
+{
+ g_return_val_if_fail(HIPPO_IS_DBUS_MODEL_CLIENT(dbus_client), NULL);
+
+ return dbus_client->bus_name;
+}
+
+void
+hippo_dbus_model_client_disconnected (HippoDBusModelClient *dbus_client)
+{
+ g_return_if_fail(HIPPO_IS_DBUS_MODEL_CLIENT(dbus_client));
+
+ g_object_run_dispose(G_OBJECT(dbus_client));
+}
+
+/*****************************************************************/
+
+static void
+on_query_success (GSList *results,
+ gpointer data)
+{
+ DataClientQueryClosure *closure = data;
+ DBusMessageIter iter;
+ DBusMessageIter array_iter;
+ DBusMessage *reply;
+ GSList *l;
+
+ reply = dbus_message_new_method_return(closure->message);
+ dbus_message_iter_init_append(reply, &iter);
+
+ dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(ssba(ssyyyv))", &array_iter);
+
+ for (l = results; l; l = l->next) {
+ add_resource_to_message(closure->client, &array_iter, l->data, closure->fetch, FALSE, FALSE, NULL);
+ }
+
+ dbus_message_iter_close_container(&iter, &array_iter);
+
+ dbus_connection_send(closure->client->connection, reply, NULL);
+ dbus_message_unref(reply);
+
+ data_client_query_closure_destroy(closure);
+}
+
+static void
+on_query_error (DDMDataError error,
+ const char *message,
+ gpointer data)
+{
+ DataClientQueryClosure *closure = data;
+ DBusMessage *reply;
+ DBusMessageIter iter;
+ dbus_int32_t code = (dbus_int32_t)error;
+
+ reply = dbus_message_new_error(closure->message,
+ HIPPO_DBUS_MODEL_ERROR,
+ message);
+
+ dbus_message_iter_init_append(reply, &iter);
+ dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &code);
+
+ dbus_connection_send(closure->client->connection, reply, NULL);
+ dbus_message_unref(reply);
+
+ data_client_query_closure_destroy(closure);
+}
+
+gboolean
+hippo_dbus_model_client_do_query (HippoDBusModelClient *client,
+ DBusMessage *message,
+ const char *method_uri,
+ DDMDataFetch *fetch,
+ GHashTable *params)
+{
+ DataClientQueryClosure *closure;
+ DDMDataQuery *query;
+ char *fetch_string;
+
+ g_return_val_if_fail(HIPPO_IS_DBUS_MODEL_CLIENT(client), FALSE);
+ g_return_val_if_fail(!client->disconnected, FALSE);
+
+ closure = data_client_query_closure_new(client, message, fetch);
+
+ fetch_string = ddm_data_fetch_to_string(fetch);
+ query = ddm_data_model_query_params(client->model, method_uri, fetch_string, params);
+ g_free(fetch_string);
+
+ if (query == NULL) {
+ data_client_query_closure_destroy(closure);
+ return FALSE;
+ }
+
+ ddm_data_query_set_multi_handler(query, on_query_success, closure);
+ ddm_data_query_set_error_handler(query, on_query_error, closure);
+
+ return TRUE;
+}
+
+/*****************************************************************/
+
+static void
+on_update_success (gpointer data)
+{
+ DataClientQueryClosure *closure = data;
+ DBusMessage *reply;
+
+ reply = dbus_message_new_method_return(closure->message);
+ dbus_connection_send(closure->client->connection, reply, NULL);
+ dbus_message_unref(reply);
+
+ data_client_query_closure_destroy(closure);
+}
+
+gboolean
+hippo_dbus_model_client_do_update (DDMDataModel *model,
+ DBusMessage *message,
+ const char *method_uri,
+ GHashTable *params)
+{
+ DataClientQueryClosure *closure;
+ DDMDataQuery *query;
+
+ closure = data_client_query_closure_new(NULL, message, NULL);
+
+ query = ddm_data_model_update_params(model, method_uri, params);
+ if (query == NULL) {
+ data_client_query_closure_destroy(closure);
+ return FALSE;
+ }
+
+ ddm_data_query_set_update_handler(query, on_update_success, closure);
+ ddm_data_query_set_error_handler(query, on_query_error, closure);
+
+ return TRUE;
+}
Added: dumbhippo/trunk/client/linux/src/hippo-dbus-model-client.h
===================================================================
--- dumbhippo/trunk/client/linux/src/hippo-dbus-model-client.h 2007-11-07 00:45:26 UTC (rev 6874)
+++ dumbhippo/trunk/client/linux/src/hippo-dbus-model-client.h 2007-11-07 17:41:12 UTC (rev 6875)
@@ -0,0 +1,52 @@
+/* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil; -*- */
+
+#ifndef __HIPPO_DBUS_MODEL_CLIENT_H__
+#define __HIPPO_DBUS_MODEL_CLIENT_H__
+
+#include <ddm/ddm.h>
+#include "hippo-dbus-helper.h"
+
+G_BEGIN_DECLS
+
+/* Client object representing an incoming D-BUS connection to the data model
+ */
+
+typedef struct _HippoDBusModelClient HippoDBusModelClient;
+typedef struct _HippoDBusModelClientClass HippoDBusModelClientClass;
+typedef struct _HippoDBusModelClientId HippoDBusModelClientId;
+
+#define HIPPO_TYPE_DBUS_MODEL_CLIENT (hippo_dbus_model_client_get_type ())
+#define HIPPO_DBUS_MODEL_CLIENT(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), HIPPO_TYPE_DBUS_MODEL_CLIENT, HippoDBusModelClient))
+#define HIPPO_DBUS_MODEL_CLIENT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), HIPPO_TYPE_DBUS_MODEL_CLIENT, HippoDBusModelClientClass))
+#define HIPPO_IS_DBUS_MODEL_CLIENT(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), HIPPO_TYPE_DBUS_MODEL_CLIENT))
+#define HIPPO_IS_DBUS_MODEL_CLIENT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), HIPPO_TYPE_DBUS_MODEL_CLIENT))
+#define HIPPO_DBUS_MODEL_CLIENT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), HIPPO_TYPE_DBUS_MODEL_CLIENT, HippoDBusModelClientClass))
+
+GType hippo_dbus_model_client_get_type (void) G_GNUC_CONST;
+
+HippoDBusModelClient *hippo_dbus_model_client_new (DBusConnection *connection,
+ DDMDataModel *model,
+ const char *bus_name,
+ const char *path);
+
+const char *hippo_dbus_model_client_get_bus_name (HippoDBusModelClient *client);
+void hippo_dbus_model_client_disconnected (HippoDBusModelClient *client);
+
+gboolean hippo_dbus_model_client_do_query (HippoDBusModelClient *client,
+ DBusMessage *message,
+ const char *method_uri,
+ DDMDataFetch *fetch,
+ GHashTable *params);
+
+/* Since the update() method doesn't take a notification path, we don't
+ * know or need to know the client it corresponds to. But we put it in
+ * here because of it's close connection to do_query()
+ */
+gboolean hippo_dbus_model_client_do_update (DDMDataModel *model,
+ DBusMessage *message,
+ const char *method_uri,
+ GHashTable *params);
+
+G_END_DECLS
+
+#endif /* __HIPPO_DBUS_MODEL_CLIENT_H__ */
Modified: dumbhippo/trunk/client/linux/src/hippo-dbus-model.c
===================================================================
--- dumbhippo/trunk/client/linux/src/hippo-dbus-model.c 2007-11-07 00:45:26 UTC (rev 6874)
+++ dumbhippo/trunk/client/linux/src/hippo-dbus-model.c 2007-11-07 17:41:12 UTC (rev 6875)
@@ -6,6 +6,7 @@
#include "hippo-dbus-helper.h"
#include <ddm/ddm.h>
#include "hippo-dbus-model.h"
+#include "hippo-dbus-model-client.h"
#include "main.h"
/* FIXME it's probably a broken layering whenever we need
@@ -17,97 +18,22 @@
#include <hippo/hippo-data-cache.h>
typedef struct _DataClientId DataClientId;
-typedef struct _DataClientConnection DataClientConnection;
-typedef struct _DataClient DataClient;
typedef struct _DataClientMap DataClientMap;
-typedef struct _DataClientQueryClosure DataClientQueryClosure;
-struct _DataClientFetch
-{
- guint ref_count;
-
- char **properties;
- char **fetch_children;
-};
-
struct _DataClientId {
char *bus_name;
char *path;
};
-struct _DataClientConnection {
- DataClient *client;
- DDMDataResource *resource;
- DDMDataFetch *fetch;
-};
-
-struct _DataClient {
- guint ref_count;
-
- DataClientId id;
-
- GHashTable *connections;
-
- gboolean disconnected;
-};
-
struct _DataClientMap {
+ DDMDataModel *model;
GHashTable *clients;
};
-struct _DataClientQueryClosure {
- DataClient *client;
- DBusMessage *message;
- DDMDataFetch *fetch;
-};
-
-static DataClient *data_client_ref (DataClient *client);
-static void data_client_unref (DataClient *client);
-static void add_resource_to_message (DataClient *client,
- DBusMessageIter *resource_array_iter,
- DDMDataResource *resource,
- DDMDataFetch *fetch,
- gboolean indirect,
- gboolean is_notification,
- GSList *changed_properties);
static void on_connected_changed (DDMDataModel *ddm_model,
gboolean connected,
void *data);
-
-static void
-on_resource_changed(DDMDataResource *resource,
- GSList *changed_properties,
- gpointer data)
-{
- DBusConnection *connection = hippo_dbus_get_connection(hippo_app_get_dbus(hippo_get_app()));
- DataClientConnection *client_connection = data;
- DataClient *client = client_connection->client;
- DBusMessage *message;
- DBusMessageIter iter;
- DBusMessageIter array_iter;
-
- message = dbus_message_new_method_call(client->id.bus_name, client->id.path,
- HIPPO_DBUS_MODEL_CLIENT_INTERFACE, "Notify");
-
- dbus_message_iter_init_append(message, &iter);
-
- dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(ssba(ssyyyv))", &array_iter);
-
- add_resource_to_message(client, &array_iter,
- client_connection->resource, client_connection->fetch,
- FALSE,
- TRUE, changed_properties);
-
- dbus_message_iter_close_container(&iter, &array_iter);
-
- dbus_connection_send(connection, message, NULL);
-
- /* FIXME: We should catch errors, and kick the client connection on error */
-
- dbus_message_unref(message);
-}
-
static guint
data_client_id_hash(const DataClientId *id)
{
@@ -121,114 +47,26 @@
return strcmp(a->bus_name, b->bus_name) == 0 && strcmp(a->path, b->path) == 0;
}
-static DataClientConnection *
-data_client_connection_new(DataClient *client,
- DDMDataResource *resource)
+static DataClientId *
+data_client_id_copy(const DataClientId *other)
{
- DataClientConnection *connection = g_new0(DataClientConnection, 1);
+ DataClientId *id = g_new(DataClientId, 1);
+ id->bus_name = g_strdup(other->bus_name);
+ id->path = g_strdup(other->path);
- connection->client = client;
- connection->resource = resource;
- connection->fetch = NULL;
-
- ddm_data_resource_connect(connection->resource, NULL,
- on_resource_changed, connection);
-
- return connection;
+ return id;
}
static void
-data_client_connection_set_fetch(DataClientConnection *connection,
- DDMDataFetch *fetch)
+data_client_id_free(DataClientId *id)
{
- if (fetch)
- ddm_data_fetch_ref(fetch);
-
- if (connection->fetch)
- ddm_data_fetch_unref(connection->fetch);
+ g_free(id->bus_name);
+ g_free(id->path);
- connection->fetch = fetch;
+ g_free(id);
}
static void
-data_client_connection_destroy(DataClientConnection *connection)
-{
- ddm_data_resource_disconnect(connection->resource,
- on_resource_changed, connection);
-
- ddm_data_fetch_unref(connection->fetch);
- g_free(connection);
-}
-
-static DataClientQueryClosure *
-data_client_query_closure_new(DataClient *client,
- DBusMessage *message,
- DDMDataFetch *fetch)
-{
- DataClientQueryClosure *closure = g_new0(DataClientQueryClosure, 1);
- closure->client = client ? data_client_ref(client) : NULL;
- closure->message = dbus_message_ref(message);
- closure->fetch = fetch ? ddm_data_fetch_ref(fetch) : NULL;
-
- return closure;
-}
-
-static void
-data_client_query_closure_destroy(DataClientQueryClosure *closure)
-{
- if (closure->client)
- data_client_unref(closure->client);
- if (closure->fetch)
- ddm_data_fetch_unref(closure->fetch);
- dbus_message_unref(closure->message);
- g_free(closure);
-}
-
-static DataClient *
-data_client_new(DataClientId *id)
-{
- DataClient *client = g_new(DataClient, 1);
-
- client->ref_count = 1;
-
- client->id.bus_name = g_strdup(id->bus_name);
- client->id.path = g_strdup(id->path);
- client->connections = g_hash_table_new_full(g_str_hash, g_str_equal,
- NULL, (GDestroyNotify)data_client_connection_destroy);
-
- client->disconnected = FALSE;
-
- hippo_dbus_watch_for_disconnect(hippo_app_get_dbus(hippo_get_app()),
- client->id.bus_name);
-
- return client;
-}
-
-static DataClient *
-data_client_ref(DataClient *client)
-{
- client->ref_count++;
-
- return client;
-}
-
-static void
-data_client_unref(DataClient *client)
-{
- client->ref_count--;
-
- if (client->ref_count == 0) {
- hippo_dbus_unwatch_for_disconnect(hippo_app_get_dbus(hippo_get_app()),
- client->id.bus_name);
-
- g_free(client->id.bus_name);
- g_free(client->id.path);
- g_hash_table_destroy(client->connections);
- g_free(client);
- }
-}
-
-static void
data_client_map_destroy(DataClientMap *map)
{
g_hash_table_destroy(map->clients);
@@ -241,8 +79,9 @@
DataClientMap *map = g_object_get_data(G_OBJECT(ddm_model), "hippo-client-map");
if (map == NULL) {
map = g_new0(DataClientMap, 1);
+ map->model = ddm_model;
map->clients = g_hash_table_new_full((GHashFunc)data_client_id_hash, (GEqualFunc)data_client_id_equal,
- NULL, (GDestroyNotify)data_client_unref);
+ (GDestroyNotify)data_client_id_free, (GDestroyNotify)g_object_unref);
g_object_set_data_full(G_OBJECT(ddm_model), "hippo-client-map",
map, (GDestroyNotify)data_client_map_destroy);
}
@@ -250,20 +89,22 @@
return map;
}
-static DataClient *
+static HippoDBusModelClient *
data_client_map_get_client(DataClientMap *map,
const char *bus_name,
const char *path)
{
- DataClient *client;
+ HippoDBusModelClient *client;
DataClientId id;
id.bus_name = (char *)bus_name;
id.path = (char *)path;
client = g_hash_table_lookup(map->clients, &id);
if (client == NULL) {
- client = data_client_new(&id);
- g_hash_table_insert(map->clients, &client->id, client);
+ DBusConnection *connection = hippo_dbus_get_connection(hippo_app_get_dbus(hippo_get_app()));
+
+ client = hippo_dbus_model_client_new(connection, map->model, bus_name, path);
+ g_hash_table_insert(map->clients, data_client_id_copy(&id), client);
}
return client;
@@ -312,348 +153,11 @@
return NULL;
}
-static void
-add_property_value_to_message(DBusMessageIter *property_array_iter,
- DDMQName *property_qname,
- DDMDataUpdate update,
- DDMDataValue *value,
- DDMDataCardinality cardinality)
-{
- DBusMessageIter property_iter;
- DBusMessageIter value_iter;
- char update_byte;
- char type_byte;
- char cardinality_byte;
- const char *value_signature = NULL;
-
- switch (update) {
- case DDM_DATA_UPDATE_ADD:
- update_byte = 'a';
- break;
- case DDM_DATA_UPDATE_REPLACE:
- update_byte = 'r';
- break;
- case DDM_DATA_UPDATE_DELETE:
- update_byte = 'd';
- break;
- case DDM_DATA_UPDATE_CLEAR:
- update_byte = 'c';
- break;
- }
-
- switch (value->type) {
- case DDM_DATA_BOOLEAN:
- type_byte = 'b';
- value_signature = "b";
- break;
- case DDM_DATA_INTEGER:
- type_byte = 'i';
- value_signature = "i";
- break;
- case DDM_DATA_LONG:
- type_byte = 'l';
- value_signature = "x";
- break;
- case DDM_DATA_FLOAT:
- type_byte = 'f';
- value_signature = "d";
- break;
- case DDM_DATA_NONE: /* Empty list, type doesn't matter */
- case DDM_DATA_STRING:
- type_byte = 's';
- value_signature = "s";
- break;
- case DDM_DATA_RESOURCE:
- type_byte = 'r';
- value_signature = "s";
- break;
- case DDM_DATA_URL:
- type_byte = 'u';
- value_signature = "s";
- break;
- case DDM_DATA_LIST:
- break;
- }
-
- g_assert(value_signature != NULL);
-
- switch (cardinality) {
- case DDM_DATA_CARDINALITY_01:
- cardinality_byte = '?';
- break;
- case DDM_DATA_CARDINALITY_1:
- cardinality_byte = '.';
- break;
- case DDM_DATA_CARDINALITY_N:
- cardinality_byte = '*';
- break;
- }
-
- dbus_message_iter_open_container(property_array_iter, DBUS_TYPE_STRUCT, NULL, &property_iter);
- dbus_message_iter_append_basic(&property_iter, DBUS_TYPE_STRING, &property_qname->uri);
- dbus_message_iter_append_basic(&property_iter, DBUS_TYPE_STRING, &property_qname->name);
- dbus_message_iter_append_basic(&property_iter, DBUS_TYPE_BYTE, &update_byte);
- dbus_message_iter_append_basic(&property_iter, DBUS_TYPE_BYTE, &type_byte);
- dbus_message_iter_append_basic(&property_iter, DBUS_TYPE_BYTE, &cardinality_byte);
-
- dbus_message_iter_open_container(&property_iter, DBUS_TYPE_VARIANT, value_signature, &value_iter);
-
- switch (value->type) {
- case DDM_DATA_BOOLEAN:
- {
- dbus_bool_t v = value->u.boolean;
- dbus_message_iter_append_basic(&value_iter, DBUS_TYPE_BOOLEAN, &v);
- }
- break;
- case DDM_DATA_INTEGER:
- dbus_message_iter_append_basic(&value_iter, DBUS_TYPE_INT32, &value->u.integer);
- break;
- case DDM_DATA_LONG:
- dbus_message_iter_append_basic(&value_iter, DBUS_TYPE_INT64, &value->u.long_);
- break;
- case DDM_DATA_FLOAT:
- dbus_message_iter_append_basic(&value_iter, DBUS_TYPE_DOUBLE, &value->u.float_);
- break;
- case DDM_DATA_NONE:
- {
- const char *v = "";
- dbus_message_iter_append_basic(&value_iter, DBUS_TYPE_STRING, &v);
- }
- break;
- case DDM_DATA_STRING:
- case DDM_DATA_URL:
- dbus_message_iter_append_basic(&value_iter, DBUS_TYPE_STRING, &value->u.string);
- break;
- case DDM_DATA_RESOURCE:
- {
- const char *v = ddm_data_resource_get_resource_id(value->u.resource);
-
- dbus_message_iter_append_basic(&value_iter, DBUS_TYPE_STRING, &v);
-
- }
- break;
- case DDM_DATA_LIST:
- break;
- }
-
- dbus_message_iter_close_container(&property_iter, &value_iter);
- dbus_message_iter_close_container(property_array_iter, &property_iter);
-}
-
-static void
-add_property_children_to_message(DataClient *client,
- DBusMessageIter *resource_array_iter,
- DDMDataProperty *property,
- DDMDataFetch *children)
-{
- DDMDataValue value;
-
- ddm_data_property_get_value(property, &value);
-
- if (value.type == DDM_DATA_RESOURCE) {
- add_resource_to_message(client, resource_array_iter, value.u.resource, children, TRUE, FALSE, NULL);
- } else if (value.type == (DDM_DATA_RESOURCE | DDM_DATA_LIST)) {
- GSList *l;
- for (l = value.u.list; l; l = l->next)
- add_resource_to_message(client, resource_array_iter, l->data, children, TRUE, FALSE, NULL);
- }
-}
-
-static void
-add_property_to_message(DBusMessageIter *property_array_iter,
- DDMDataProperty *property)
-{
- DDMDataCardinality cardinality;
- DDMDataValue value;
- DDMQName *property_qname;
-
- ddm_data_property_get_value(property, &value);
- cardinality = ddm_data_property_get_cardinality(property);
- property_qname = ddm_data_property_get_qname(property);
-
- if (value.type == DDM_DATA_NONE) {
- add_property_value_to_message(property_array_iter, property_qname,
- DDM_DATA_UPDATE_CLEAR,
- &value, cardinality);
- } else if (DDM_DATA_IS_LIST(value.type)) {
- GSList *l;
-
- for (l = value.u.list; l; l = l->next) {
- DDMDataValue element;
- ddm_data_value_get_element(&value, l, &element);
-
- add_property_value_to_message(property_array_iter, property_qname,
- l == value.u.list ? DDM_DATA_UPDATE_REPLACE : DDM_DATA_UPDATE_ADD,
- &element, cardinality);
- }
- } else {
- add_property_value_to_message(property_array_iter, property_qname,
- DDM_DATA_UPDATE_REPLACE,
- &value, cardinality);
- }
-}
-
-static void
-add_resource_to_message(DataClient *client,
- DBusMessageIter *resource_array_iter,
- DDMDataResource *resource,
- DDMDataFetch *fetch,
- gboolean indirect,
- gboolean is_notification,
- GSList *changed_properties)
-{
- DDMDataFetchIter fetch_iter;
- DataClientConnection *connection;
- DDMDataFetch *new_fetch;
- DDMDataFetch *total_fetch;
- DBusMessageIter resource_iter;
- DBusMessageIter property_array_iter;
- const char *resource_id;
- const char *class_id;
- dbus_bool_t indirect_bool;
-
- connection = g_hash_table_lookup(client->connections, ddm_data_resource_get_resource_id(resource));
- if (connection == NULL) {
- connection = data_client_connection_new(client, resource);
- g_hash_table_insert(client->connections, (char *)ddm_data_resource_get_resource_id(resource), connection);
- }
-
- if (is_notification) {
- new_fetch = ddm_data_fetch_ref(fetch);
- total_fetch = ddm_data_fetch_ref(fetch);
- } else {
- if (connection->fetch)
- new_fetch = ddm_data_fetch_subtract(fetch, connection->fetch);
- else
- new_fetch = ddm_data_fetch_ref(fetch);
-
- if (new_fetch == NULL && indirect)
- return;
-
- if (connection->fetch)
- total_fetch = ddm_data_fetch_merge(fetch, connection->fetch);
- else
- total_fetch = ddm_data_fetch_ref(fetch);
-
- data_client_connection_set_fetch(connection, total_fetch);
- }
-
- if (new_fetch) {
- ddm_data_fetch_iter_init(&fetch_iter, resource, new_fetch);
- while (ddm_data_fetch_iter_has_next(&fetch_iter)) {
- DDMDataProperty *property;
- DDMDataFetch *children;
-
- ddm_data_fetch_iter_next(&fetch_iter, &property, &children);
-
- /* FIXME: This check on children isn't really right ... if we have a resource-value
- * property that is default-fetched without default-children, then we should
- * send an empty resource element for it, because the recipient needs at least
- * the classId. */
- if (!children)
- continue;
-
- if (is_notification && g_slist_find(changed_properties, ddm_data_property_get_qname(property)) == NULL)
- continue;
-
- add_property_children_to_message(client, resource_array_iter, property, children);
- }
- ddm_data_fetch_iter_clear(&fetch_iter);
- }
-
- resource_id = ddm_data_resource_get_resource_id(resource);
- class_id = ddm_data_resource_get_class_id(resource);
- indirect_bool = indirect;
-
- dbus_message_iter_open_container(resource_array_iter, DBUS_TYPE_STRUCT, NULL, &resource_iter);
- dbus_message_iter_append_basic(&resource_iter, DBUS_TYPE_STRING, &resource_id);
- dbus_message_iter_append_basic(&resource_iter, DBUS_TYPE_STRING, &class_id);
- dbus_message_iter_append_basic(&resource_iter, DBUS_TYPE_BOOLEAN, &indirect_bool);
-
- dbus_message_iter_open_container(&resource_iter, DBUS_TYPE_ARRAY, "(ssyyyv)", &property_array_iter);
-
- if (new_fetch) {
- ddm_data_fetch_iter_init(&fetch_iter, resource, new_fetch);
- while (ddm_data_fetch_iter_has_next(&fetch_iter)) {
- DDMDataProperty *property;
-
- ddm_data_fetch_iter_next(&fetch_iter, &property, NULL);
-
- if (is_notification && g_slist_find(changed_properties, ddm_data_property_get_qname(property)) == NULL)
- continue;
-
- add_property_to_message(&property_array_iter, property);
- }
-
- ddm_data_fetch_iter_clear(&fetch_iter);
- }
-
- dbus_message_iter_close_container(&resource_iter, &property_array_iter);
- dbus_message_iter_close_container(resource_array_iter, &resource_iter);
-
- if (new_fetch)
- ddm_data_fetch_unref(new_fetch);
- ddm_data_fetch_unref(total_fetch);
-}
-
-static void
-on_query_success(GSList *results,
- gpointer data)
-{
- DBusConnection *connection = hippo_dbus_get_connection(hippo_app_get_dbus(hippo_get_app()));
- DataClientQueryClosure *closure = data;
- DBusMessageIter iter;
- DBusMessageIter array_iter;
- DBusMessage *reply;
- GSList *l;
-
- reply = dbus_message_new_method_return(closure->message);
- dbus_message_iter_init_append(reply, &iter);
-
- dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(ssba(ssyyyv))", &array_iter);
-
- for (l = results; l; l = l->next) {
- add_resource_to_message(closure->client, &array_iter, l->data, closure->fetch, FALSE, FALSE, NULL);
- }
-
- dbus_message_iter_close_container(&iter, &array_iter);
-
- dbus_connection_send(connection, reply, NULL);
- dbus_message_unref(reply);
-
- data_client_query_closure_destroy(closure);
-}
-
-static void
-on_query_error(DDMDataError error,
- const char *message,
- gpointer data)
-{
- DBusConnection *connection = hippo_dbus_get_connection(hippo_app_get_dbus(hippo_get_app()));
- DataClientQueryClosure *closure = data;
- DBusMessage *reply;
- DBusMessageIter iter;
- dbus_int32_t code = (dbus_int32_t)error;
-
- reply = dbus_message_new_error(closure->message,
- HIPPO_DBUS_MODEL_ERROR,
- message);
-
- dbus_message_iter_init_append(reply, &iter);
- dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &code);
-
- dbus_connection_send(connection, reply, NULL);
- dbus_message_unref(reply);
-
- data_client_query_closure_destroy(closure);
-}
-
static DBusMessage*
handle_query (void *object,
DBusMessage *message,
DBusError *error)
{
- DBusConnection *connection;
DDMDataModel *model;
const char *notification_path;
const char *method_uri;
@@ -661,12 +165,9 @@
DDMDataFetch *fetch;
GHashTable *params = NULL;
DBusMessageIter iter;
- DDMDataQuery *query;
DataClientMap *client_map;
- DataClient *client;
- DataClientQueryClosure *closure;
+ HippoDBusModelClient *client;
- connection = hippo_dbus_get_connection(hippo_app_get_dbus(hippo_get_app()));
model = hippo_app_get_data_model(hippo_get_app());
dbus_message_iter_init (message, &iter);
@@ -716,86 +217,33 @@
client_map = data_client_map_get(model);
client = data_client_map_get_client(client_map, dbus_message_get_sender(message), notification_path);
- closure = data_client_query_closure_new(client, message, fetch);
-
- /* We short-circuit m:getResource requests for resources with the local
- * online-desktop scheme and handle them against the current contents of the cache.
- */
- if (strcmp(method_uri, "http://mugshot.org/p/system#getResource") == 0) {
- const char *resource_id = g_hash_table_lookup(params, "resourceId");
- if (resource_id == NULL) {
- data_client_query_closure_destroy(closure);
- return dbus_message_new_error(message,
- DBUS_ERROR_INVALID_ARGS,
- _("resourceId parameter is mandatory for m:getResource query"));
- }
-
- if (g_str_has_prefix(resource_id, "online-desktop:")) {
- DDMDataResource *resource = ddm_data_model_lookup_resource(model, resource_id);
- GSList *results;
-
- if (resource == NULL) {
- data_client_query_closure_destroy(closure);
- return dbus_message_new_error(message,
- DBUS_ERROR_FAILED,
- _("Couldn't find local resource"));
- }
-
- results = g_slist_prepend(NULL, resource);
- on_query_success(results, closure);
- g_slist_free(results);
-
- return NULL;
- }
- }
-
- query = ddm_data_model_query_params(model, method_uri, fetch_string, params);
- g_hash_table_destroy(params);
-
- if (query == NULL) {
- data_client_query_closure_destroy(closure);
+ if (!hippo_dbus_model_client_do_query(client, message, method_uri, fetch, params)) {
+ /* We've already validated most arguments, so don't worry too much about getting a
+ * good error message if something goes wrong at this point
+ */
return dbus_message_new_error(message,
DBUS_ERROR_FAILED,
_("Couldn't send query"));
}
- ddm_data_query_set_multi_handler(query, on_query_success, closure);
- ddm_data_query_set_error_handler(query, on_query_error, closure);
+ g_hash_table_destroy(params);
ddm_data_fetch_unref(fetch);
return NULL;
}
-static void
-on_update_success(gpointer data)
-{
- DBusConnection *connection = hippo_dbus_get_connection(hippo_app_get_dbus(hippo_get_app()));
- DataClientQueryClosure *closure = data;
- DBusMessage *reply;
-
- reply = dbus_message_new_method_return(closure->message);
- dbus_connection_send(connection, reply, NULL);
- dbus_message_unref(reply);
-
- data_client_query_closure_destroy(closure);
-}
-
static DBusMessage*
handle_update (void *object,
DBusMessage *message,
DBusError *error)
{
- DBusConnection *connection;
DDMDataModel *model;
const char *method_uri;
GHashTable *params = NULL;
DBusMessageIter iter;
- DDMDataQuery *query;
- DataClientQueryClosure *closure;
- connection = hippo_dbus_get_connection(hippo_app_get_dbus(hippo_get_app()));
- model = hippo_app_get_data_model(hippo_get_app());
+ model = hippo_app_get_data_model(hippo_get_app());
dbus_message_iter_init (message, &iter);
@@ -818,20 +266,17 @@
DBUS_ERROR_INVALID_ARGS,
_("Too many arguments"));
- closure = data_client_query_closure_new(NULL, message, NULL);
- query = ddm_data_model_update_params(model, method_uri, params);
- g_hash_table_destroy(params);
-
- if (query == NULL) {
- data_client_query_closure_destroy(closure);
+ if (!hippo_dbus_model_client_do_update(model, message, method_uri, params)) {
+ /* We've already validated most arguments, so don't worry too much about getting a
+ * good error message if something goes wrong at this point
+ */
return dbus_message_new_error(message,
DBUS_ERROR_FAILED,
- _("Couldn't send query"));
+ _("Couldn't send update"));
}
- ddm_data_query_set_update_handler(query, on_update_success, closure);
- ddm_data_query_set_error_handler(query, on_query_error, closure);
-
+ g_hash_table_destroy(params);
+
return NULL;
}
@@ -840,13 +285,10 @@
DBusMessage *message,
DBusError *error)
{
- DBusConnection *connection;
const char *notification_path;
const char *resource_id;
DBusMessageIter iter;
- connection = hippo_dbus_get_connection(hippo_app_get_dbus(hippo_get_app()));
-
dbus_message_iter_init (message, &iter);
if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_OBJECT_PATH) {
@@ -1079,11 +521,11 @@
gpointer value,
gpointer data)
{
- DataClient *client = value;
+ HippoDBusModelClient *client = value;
const char *name = data;
- if (strcmp(client->id.bus_name, name) == 0) {
- client->disconnected = TRUE;
+ if (strcmp(hippo_dbus_model_client_get_bus_name(client), name) == 0) {
+ hippo_dbus_model_client_disconnected(client);
return TRUE;
} else {
return FALSE;
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]