[libgovirt] collection: Add sync/async 'fetch' methods



commit 05d9f7a7223b034963b90160c8f6db0c886f2111
Author: Christophe Fergeau <cfergeau redhat com>
Date:   Thu Aug 22 15:06:52 2013 +0200

    collection: Add sync/async 'fetch' methods
    
    These methods use an OvirtProxy object to fetch data from the network
    and populate the collection with OvirtResource objects parsed
    from the XML that was fetched.
    This will remove the need for dedicated
    ovirt_proxy_fetch_xxx/ovirt_proxy_fetch_xxx_async for each resource
    type, which will in turn save quite some code ;)

 govirt/govirt.sym                 |    8 +
 govirt/ovirt-collection-private.h |    4 +
 govirt/ovirt-collection.c         |  340 ++++++++++++++++++++++++++++++++++---
 govirt/ovirt-collection.h         |   15 ++
 4 files changed, 345 insertions(+), 22 deletions(-)
---
diff --git a/govirt/govirt.sym b/govirt/govirt.sym
index 26af80c..ec4a8c4 100644
--- a/govirt/govirt.sym
+++ b/govirt/govirt.sym
@@ -49,4 +49,12 @@ GOVIRT_0.2.0 {
         *;
 };
 
+GOVIRT_0.2.1 {
+        ovirt_collection_fetch;
+        ovirt_collection_fetch_async;
+        ovirt_collection_fetch_finish;
+        ovirt_collection_lookup_resource;
+} GOVIRT_0.2.0;
+
+
 # .... define new API here using predicted next version number ....
diff --git a/govirt/ovirt-collection-private.h b/govirt/ovirt-collection-private.h
index da89900..5bc294f 100644
--- a/govirt/ovirt-collection-private.h
+++ b/govirt/ovirt-collection-private.h
@@ -31,6 +31,10 @@
 G_BEGIN_DECLS
 
 void ovirt_collection_set_resources(OvirtCollection *collection, GHashTable *resources);
+OvirtCollection *ovirt_collection_new(const char *href,
+                                      const char *collection_name,
+                                      GType resource_type,
+                                      const char *resource_name);
 OvirtCollection *ovirt_collection_new_from_xml(RestXmlNode *root_node,
                                                GType collection_type,
                                                const char *collection_name,
diff --git a/govirt/ovirt-collection.c b/govirt/ovirt-collection.c
index e4b7c45..287a6b5 100644
--- a/govirt/ovirt-collection.c
+++ b/govirt/ovirt-collection.c
@@ -32,11 +32,74 @@
         (G_TYPE_INSTANCE_GET_PRIVATE((obj), OVIRT_TYPE_COLLECTION, OvirtCollectionPrivate))
 
 struct _OvirtCollectionPrivate {
+    char *href;
+    char *collection_xml_name;
+    GType resource_type;
+    char *resource_xml_name;
+
     GHashTable *resources;
 };
 
 G_DEFINE_TYPE(OvirtCollection, ovirt_collection, G_TYPE_OBJECT);
 
+
+enum {
+    PROP_0,
+    PROP_HREF,
+    PROP_RESOURCE_TYPE,
+    PROP_COLLECTION_XML_NAME,
+    PROP_RESOURCE_XML_NAME,
+};
+
+
+static void ovirt_collection_get_property(GObject *object,
+                                          guint prop_id,
+                                          GValue *value,
+                                          GParamSpec *pspec)
+{
+    OvirtCollection *collection = OVIRT_COLLECTION(object);
+
+    switch (prop_id) {
+    case PROP_HREF:
+        g_value_set_string(value, collection->priv->href);
+        break;
+    case PROP_RESOURCE_TYPE:
+        g_value_set_gtype(value, collection->priv->resource_type);
+        break;
+    default:
+        G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
+        break;
+    }
+}
+
+
+static void ovirt_collection_set_property(GObject *object,
+                                          guint prop_id,
+                                          const GValue *value,
+                                          GParamSpec *pspec)
+{
+    OvirtCollection *collection = OVIRT_COLLECTION(object);
+
+    switch (prop_id) {
+    case PROP_HREF:
+        collection->priv->href = g_value_dup_string(value);
+        break;
+    case PROP_RESOURCE_TYPE:
+        collection->priv->resource_type = g_value_get_gtype(value);
+        break;
+    case PROP_COLLECTION_XML_NAME:
+        collection->priv->collection_xml_name = g_value_dup_string(value);
+        break;
+    case PROP_RESOURCE_XML_NAME:
+        collection->priv->resource_xml_name = g_value_dup_string(value);
+        break;
+    default:
+        G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
+        break;
+    }
+}
+
+
 static void ovirt_collection_finalize(GObject *object)
 {
     OvirtCollection *collection = OVIRT_COLLECTION(object);
@@ -44,18 +107,71 @@ static void ovirt_collection_finalize(GObject *object)
     if (collection->priv->resources != NULL) {
         g_hash_table_unref(collection->priv->resources);
     }
+    g_free(collection->priv->href);
+    g_free(collection->priv->collection_xml_name);
+    g_free(collection->priv->resource_xml_name);
+
     G_OBJECT_CLASS(ovirt_collection_parent_class)->finalize(object);
 }
 
+
 static void ovirt_collection_class_init(OvirtCollectionClass *klass)
 {
     GObjectClass *object_class = G_OBJECT_CLASS(klass);
+    GParamSpec *param_spec;
 
     g_type_class_add_private(klass, sizeof(OvirtCollectionPrivate));
 
     object_class->finalize = ovirt_collection_finalize;
+    object_class->get_property = ovirt_collection_get_property;
+    object_class->set_property = ovirt_collection_set_property;
+
+    param_spec = g_param_spec_string("href",
+                                     "Collection href",
+                                     "relative href for the collection",
+                                     NULL,
+                                     G_PARAM_READWRITE |
+                                     G_PARAM_CONSTRUCT_ONLY |
+                                     G_PARAM_STATIC_STRINGS);
+    g_object_class_install_property(object_class,
+                                    PROP_HREF,
+                                    param_spec);
+
+    param_spec = g_param_spec_gtype("resource-type",
+                                    "Resource Type",
+                                    "Type of resources held by this collection",
+                                    OVIRT_TYPE_RESOURCE,
+                                    G_PARAM_READWRITE |
+                                    G_PARAM_CONSTRUCT_ONLY |
+                                    G_PARAM_STATIC_STRINGS);
+    g_object_class_install_property(object_class,
+                                    PROP_RESOURCE_TYPE,
+                                    param_spec);
+
+    param_spec = g_param_spec_string("collection-xml-name",
+                                     "Collection XML Name",
+                                     "Name of the XML element for the collection",
+                                     NULL,
+                                     G_PARAM_WRITABLE |
+                                     G_PARAM_CONSTRUCT_ONLY |
+                                     G_PARAM_STATIC_STRINGS);
+    g_object_class_install_property(object_class,
+                                    PROP_COLLECTION_XML_NAME,
+                                    param_spec);
+
+    param_spec = g_param_spec_string("resource-xml-name",
+                                     "Resource XML Name",
+                                     "Name of the XML element for the resources stored in that collection",
+                                     NULL,
+                                     G_PARAM_WRITABLE |
+                                     G_PARAM_CONSTRUCT_ONLY |
+                                     G_PARAM_STATIC_STRINGS);
+    g_object_class_install_property(object_class,
+                                    PROP_RESOURCE_XML_NAME,
+                                    param_spec);
 }
 
+
 static void ovirt_collection_init(OvirtCollection *collection)
 {
     collection->priv = OVIRT_COLLECTION_GET_PRIVATE(collection);
@@ -91,33 +207,41 @@ void ovirt_collection_set_resources(OvirtCollection *collection, GHashTable *res
         collection->priv->resources = NULL;
     }
 }
-static OvirtResource *ovirt_collection_new_resource_from_xml(GType resource_type,
-                                                             RestXmlNode *node,
-                                                             GError **error)
+
+
+static OvirtResource *
+ovirt_collection_new_resource_from_xml(OvirtCollection *collection,
+                                       RestXmlNode *node,
+                                       GError **error)
 {
-    return OVIRT_RESOURCE(g_initable_new(resource_type, NULL, error,
+    return OVIRT_RESOURCE(g_initable_new(collection->priv->resource_type,
+                                         NULL, error,
                                          "xml-node", node , NULL));
 }
 
-OvirtCollection *ovirt_collection_new_from_xml(RestXmlNode *root_node,
-                                               GType collection_type,
-                                               const char *collection_name,
-                                               GType resource_type,
-                                               const char *resource_name,
-                                               GError **error)
+
+static gboolean
+ovirt_collection_refresh_from_xml(OvirtCollection *collection,
+                                  RestXmlNode *root_node,
+                                  GError **error)
 {
-    OvirtCollection *self;
     RestXmlNode *resources_node;
     RestXmlNode *node;
     GHashTable *resources;
-    const char *resource_key = g_intern_string(resource_name);
+    const char *resource_key;
 
-    if (strcmp(root_node->name, collection_name) != 0) {
+    g_return_val_if_fail(OVIRT_IS_COLLECTION(collection), FALSE);
+    g_return_val_if_fail(root_node != NULL, FALSE);
+    g_return_val_if_fail((error == NULL) || (*error == NULL), FALSE);
+
+    if (strcmp(root_node->name, collection->priv->collection_xml_name) != 0) {
         g_set_error(error, OVIRT_ERROR, OVIRT_ERROR_PARSING_FAILED,
-                    "Got '%s' node, expected '%s'", root_node->name, collection_name);
-        return NULL;
+                    "Got '%s' node, expected '%s'", root_node->name,
+                    collection->priv->collection_xml_name);
+        return FALSE;
     }
 
+    resource_key = g_intern_string(collection->priv->resource_xml_name);
     resources = g_hash_table_new_full(g_str_hash, g_str_equal,
                                       g_free, (GDestroyNotify)g_object_unref);
     resources_node = g_hash_table_lookup(root_node->children, resource_key);
@@ -125,13 +249,14 @@ OvirtCollection *ovirt_collection_new_from_xml(RestXmlNode *root_node,
         OvirtResource *resource;
         gchar *name;
 
-        resource = ovirt_collection_new_resource_from_xml(resource_type, node, error);
+        resource = ovirt_collection_new_resource_from_xml(collection, node, error);
         if (resource == NULL) {
             if ((error != NULL) && (*error != NULL)) {
                 g_message("Failed to parse '%s' node: %s",
-                          resource_name, (*error)->message);
+                          collection->priv->resource_xml_name, (*error)->message);
             } else {
-                g_message("Failed to parse '%s' node", resource_name);
+                g_message("Failed to parse '%s' node",
+                          collection->priv->resource_xml_name);
             }
             g_clear_error(error);
             continue;
@@ -139,22 +264,193 @@ OvirtCollection *ovirt_collection_new_from_xml(RestXmlNode *root_node,
         g_object_get(G_OBJECT(resource), "name", &name, NULL);
         if (name == NULL) {
             g_message("'%s' resource had no name in its XML description",
-                      resource_name);
+                      collection->priv->resource_xml_name);
             g_object_unref(G_OBJECT(resource));
             continue;
         }
         if (g_hash_table_lookup(resources, name) != NULL) {
             g_message("'%s' resource with the same name ('%s') already exists",
-                      resource_name, name);
+                      collection->priv->resource_xml_name, name);
             g_object_unref(resources);
             continue;
         }
         g_hash_table_insert(resources, name, resource);
     }
 
-    self = OVIRT_COLLECTION(g_object_new(collection_type, NULL));
-    ovirt_collection_set_resources(OVIRT_COLLECTION(self), resources);
+    ovirt_collection_set_resources(OVIRT_COLLECTION(collection), resources);
     g_hash_table_unref(resources);
 
+    return TRUE;
+}
+
+
+OvirtCollection *ovirt_collection_new(const char *href,
+                                      const char *collection_name,
+                                      GType resource_type,
+                                      const char *resource_name)
+{
+    OvirtCollection *self;
+
+    self = OVIRT_COLLECTION(g_object_new(OVIRT_TYPE_COLLECTION,
+                                         "href", href,
+                                         "collection-xml-name", collection_name,
+                                         "resource-type", resource_type,
+                                         "resource-xml-name", resource_name,
+                                         NULL));
+
+    return self;
+}
+
+
+OvirtCollection *ovirt_collection_new_from_xml(RestXmlNode *root_node,
+                                               GType collection_type,
+                                               const char *collection_name,
+                                               GType resource_type,
+                                               const char *resource_name,
+                                               GError **error)
+{
+    OvirtCollection *self;
+
+    self = OVIRT_COLLECTION(g_object_new(collection_type,
+                                         "collection-xml-name", collection_name,
+                                         "resource-type", resource_type,
+                                         "resource-xml-name", resource_name,
+                                         NULL));
+    ovirt_collection_refresh_from_xml(self, root_node, error);
+
     return self;
 }
+
+
+/**
+ * ovirt_collection_fetch:
+ * @collection: a #OvirtCollection
+ * @proxy: a #OvirtProxy
+ * @error: #GError to set on error, or NULL
+ */
+gboolean ovirt_collection_fetch(OvirtCollection *collection,
+                                OvirtProxy *proxy,
+                                GError **error)
+{
+    RestXmlNode *xml;
+
+    g_return_val_if_fail(OVIRT_IS_COLLECTION(collection), FALSE);
+    g_return_val_if_fail(OVIRT_IS_PROXY(proxy), FALSE);
+    g_return_val_if_fail(collection->priv->href != NULL, FALSE);
+
+    xml = ovirt_proxy_get_collection_xml(proxy, collection->priv->href, NULL);
+    if (xml == NULL)
+        return FALSE;
+
+    ovirt_collection_refresh_from_xml(collection, xml, error);
+
+    rest_xml_node_unref(xml);
+
+    return TRUE;
+}
+
+
+static gboolean ovirt_collection_fetch_async_cb(OvirtProxy* proxy,
+                                                RestXmlNode *root_node,
+                                                gpointer user_data,
+                                                GError **error)
+{
+    OvirtCollection *collection = OVIRT_COLLECTION(user_data);
+
+    g_return_val_if_fail(OVIRT_IS_COLLECTION(user_data), FALSE);
+
+    return ovirt_collection_refresh_from_xml(collection, root_node, error);
+}
+
+
+/**
+ * ovirt_collection_fetch_async:
+ * @collection: a #OvirtCollection
+ * @proxy: a #OvirtProxy
+ * @callback: (scope async): completion callback
+ * @user_data: (closure): opaque data for callback
+ */
+void ovirt_collection_fetch_async(OvirtCollection *collection,
+                                  OvirtProxy *proxy,
+                                  GCancellable *cancellable,
+                                  GAsyncReadyCallback callback,
+                                  gpointer user_data)
+{
+    GSimpleAsyncResult *result;
+
+    g_return_if_fail(OVIRT_IS_COLLECTION(collection));
+    g_return_if_fail(OVIRT_IS_PROXY(proxy));
+    g_return_if_fail((cancellable == NULL) || G_IS_CANCELLABLE(cancellable));
+
+    result = g_simple_async_result_new (G_OBJECT(collection), callback,
+                                        user_data,
+                                        ovirt_collection_fetch_async);
+    ovirt_proxy_get_collection_xml_async(proxy, collection->priv->href,
+                                         result, cancellable,
+                                         ovirt_collection_fetch_async_cb,
+                                         collection, NULL);
+}
+
+
+/**
+ * ovirt_collection_fetch_finish:
+ * @collection: a #OvirtCollection
+ * @result: (transfer none): async method result
+ *
+ * Return value: (transfer none) (element-type OvirtResource): the list of
+ * #OvirtResource contained in @collection. The elements stored in the list
+ * inherit from #OvirtResource, but their actual type is stored in the  The
+ * returned list should not be freed nor modified, and can become invalid
+ * any time a #OvirtCollection call completes.
+ */
+GList *
+ovirt_collection_fetch_finish(OvirtCollection *collection,
+                              GAsyncResult *result,
+                              GError **err)
+{
+    g_return_val_if_fail(OVIRT_IS_COLLECTION(collection), NULL);
+    g_return_val_if_fail(g_simple_async_result_is_valid(result, G_OBJECT(collection),
+                                                        ovirt_collection_fetch_async),
+                         NULL);
+
+    if (g_simple_async_result_propagate_error(G_SIMPLE_ASYNC_RESULT(result), err))
+        return NULL;
+
+    return g_hash_table_get_values(ovirt_collection_get_resources(collection));
+}
+
+
+/**
+ * ovirt_collection_lookup_resource:
+ * @collection: a #OvirtCollection
+ * @name: name of the resource to lookup
+ *
+ * Looks up a resource in @collection whose name is @name. If it cannot be
+ * found, NULL is returned. This method does not initiate any network
+ * activity, the remote collection content must have been fetched with
+ * ovirt_collection_fetch() or ovirt_collection_fetch_async() before
+ * calling this function.
+ *
+ * Return value: (transfer full): a #OvirtResource whose name is @name
+ * or NULL
+ */
+OvirtResource *ovirt_collection_lookup_resource(OvirtCollection *collection,
+                                                const char *name)
+{
+    OvirtResource *resource;
+
+    g_return_val_if_fail(OVIRT_IS_COLLECTION(collection), NULL);
+    g_return_val_if_fail(name != NULL, NULL);
+
+    if (collection->priv->resources == NULL) {
+        return NULL;
+    }
+
+    resource = g_hash_table_lookup(collection->priv->resources, name);
+
+    if (resource == NULL) {
+        return NULL;
+    }
+
+    return g_object_ref(resource);
+}
diff --git a/govirt/ovirt-collection.h b/govirt/ovirt-collection.h
index 79bc31e..a025820 100644
--- a/govirt/ovirt-collection.h
+++ b/govirt/ovirt-collection.h
@@ -25,6 +25,7 @@
 #include <gio/gio.h>
 #include <glib-object.h>
 #include <govirt/ovirt-types.h>
+#include <govirt/ovirt-resource.h>
 
 G_BEGIN_DECLS
 
@@ -58,6 +59,20 @@ struct _OvirtCollectionClass
 GType ovirt_collection_get_type(void);
 GHashTable *ovirt_collection_get_resources(OvirtCollection *collection);
 
+OvirtResource *ovirt_collection_lookup_resource(OvirtCollection *collection,
+                                                const char *name);
+gboolean ovirt_collection_fetch(OvirtCollection *collection,
+                                OvirtProxy *proxy,
+                                GError **error);
+void ovirt_collection_fetch_async(OvirtCollection *collection,
+                                  OvirtProxy *proxy,
+                                  GCancellable *cancellable,
+                                  GAsyncReadyCallback callback,
+                                  gpointer user_data);
+GList *ovirt_collection_fetch_finish(OvirtCollection *collection,
+                                     GAsyncResult *result,
+                                     GError **err);
+
 G_END_DECLS
 
 #endif /* __OVIRT_COLLECTION_H__ */


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]