|
Packit |
4b6dd7 |
/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
|
|
Packit |
4b6dd7 |
/*
|
|
Packit |
4b6dd7 |
* GData Client
|
|
Packit |
4b6dd7 |
* Copyright (C) Philip Withnall 2010 <philip@tecnocode.co.uk>
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* GData Client is free software; you can redistribute it and/or
|
|
Packit |
4b6dd7 |
* modify it under the terms of the GNU Lesser General Public
|
|
Packit |
4b6dd7 |
* License as published by the Free Software Foundation; either
|
|
Packit |
4b6dd7 |
* version 2.1 of the License, or (at your option) any later version.
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* GData Client is distributed in the hope that it will be useful,
|
|
Packit |
4b6dd7 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit |
4b6dd7 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Packit |
4b6dd7 |
* Lesser General Public License for more details.
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* You should have received a copy of the GNU Lesser General Public
|
|
Packit |
4b6dd7 |
* License along with GData Client. If not, see <http://www.gnu.org/licenses/>.
|
|
Packit |
4b6dd7 |
*/
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/**
|
|
Packit |
4b6dd7 |
* SECTION:gdata-batch-operation
|
|
Packit |
4b6dd7 |
* @short_description: GData batch operation object
|
|
Packit |
4b6dd7 |
* @stability: Stable
|
|
Packit |
4b6dd7 |
* @include: gdata/gdata-batch-operation.h
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* #GDataBatchOperation is a transient standalone class which represents and handles a single batch operation request to a service. To make a batch
|
|
Packit |
4b6dd7 |
* operation request: create a new #GDataBatchOperation; add the required queries, insertions, updates and deletions to the operation using
|
|
Packit |
4b6dd7 |
* gdata_batch_operation_add_query(), gdata_batch_operation_add_insertion(), gdata_batch_operation_add_update() and
|
|
Packit |
4b6dd7 |
* gdata_batch_operation_add_deletion(), respectively; run the request with gdata_batch_operation_run() or gdata_batch_operation_run_async(); and
|
|
Packit |
4b6dd7 |
* handle the results in the callback functions which are invoked by the operation as the results are received and parsed.
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* If authorization is required for any of the requests in the batch operation, the #GDataService set in #GDataBatchOperation:service must have
|
|
Packit |
4b6dd7 |
* a #GDataAuthorizer set as its #GDataService:authorizer property, and that authorizer must be authorized for the #GDataAuthorizationDomain set
|
|
Packit |
4b6dd7 |
* in #GDataBatchOperation:authorization-domain. It's not possible for requests in a single batch operation to be authorized under multiple domains;
|
|
Packit |
4b6dd7 |
* in that case, the requests must be split up across several batch operations using different authorization domains.
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* If all of the requests in the batch operation don't require authorization (i.e. they all operate on public data; see the documentation for the
|
|
Packit |
4b6dd7 |
* #GDataService subclass in question's operations for details of which require authorization), #GDataBatchOperation:authorization-domain can be set
|
|
Packit |
4b6dd7 |
* to %NULL to save the overhead of sending authorization data to the online service.
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* <example>
|
|
Packit |
4b6dd7 |
* <title>Running a Synchronous Operation</title>
|
|
Packit |
4b6dd7 |
* <programlisting>
|
|
Packit |
4b6dd7 |
* guint op_id, op_id2;
|
|
Packit |
4b6dd7 |
* GDataBatchOperation *operation;
|
|
Packit |
4b6dd7 |
* GDataContactsContact *contact;
|
|
Packit |
4b6dd7 |
* GDataService *service;
|
|
Packit |
4b6dd7 |
* GDataAuthorizationDomain *domain;
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* service = create_contacts_service ();
|
|
Packit |
4b6dd7 |
* domain = get_authorization_domain_from_service (service);
|
|
Packit |
4b6dd7 |
* contact = create_new_contact ();
|
|
Packit |
4b6dd7 |
* batch_link = gdata_feed_look_up_link (contacts_feed, GDATA_LINK_BATCH);
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* operation = gdata_batchable_create_operation (GDATA_BATCHABLE (service), domain, gdata_link_get_uri (batch_link));
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* /* Add to the operation to insert a new contact and query for another one */
|
|
Packit |
4b6dd7 |
* op_id = gdata_batch_operation_add_insertion (operation, GDATA_ENTRY (contact), insertion_cb, user_data);
|
|
Packit |
4b6dd7 |
* op_id2 = gdata_batch_operation_add_query (operation, gdata_entry_get_id (other_contact), GDATA_TYPE_CONTACTS_CONTACT, query_cb, user_data);
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* g_object_unref (contact);
|
|
Packit |
4b6dd7 |
* g_object_unref (domain);
|
|
Packit |
4b6dd7 |
* g_object_unref (service);
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* /* Run the operations in a blocking fashion. Ideally, check and free the error as appropriate after running the operation. */
|
|
Packit |
4b6dd7 |
* gdata_batch_operation_run (operation, NULL, &error);
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* g_object_unref (operation);
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* static void
|
|
Packit |
4b6dd7 |
* insertion_cb (guint operation_id, GDataBatchOperationType operation_type, GDataEntry *entry, GError *error, gpointer user_data)
|
|
Packit |
4b6dd7 |
* {
|
|
Packit |
4b6dd7 |
* /* operation_id == op_id, operation_type == GDATA_BATCH_OPERATION_INSERTION */
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* /* Process the new inserted entry, ideally after checking for errors. Note that the entry should be reffed if it needs to stay
|
|
Packit |
4b6dd7 |
* * alive after execution of the callback finishes. */
|
|
Packit |
4b6dd7 |
* process_inserted_entry (entry, user_data);
|
|
Packit |
4b6dd7 |
* }
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* static void
|
|
Packit |
4b6dd7 |
* query_cb (guint operation_id, GDataBatchOperationType operation_type, GDataEntry *entry, GError *error, gpointer user_data)
|
|
Packit |
4b6dd7 |
* {
|
|
Packit |
4b6dd7 |
* /* operation_id == op_id2, operation_type == GDATA_BATCH_OPERATION_QUERY */
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* /* Process the results of the query, ideally after checking for errors. Note that the entry should be reffed if it needs to
|
|
Packit |
4b6dd7 |
* * stay alive after execution of the callback finishes. */
|
|
Packit |
4b6dd7 |
* process_queried_entry (entry, user_data);
|
|
Packit |
4b6dd7 |
* }
|
|
Packit |
4b6dd7 |
* </programlisting>
|
|
Packit |
4b6dd7 |
* </example>
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* Since: 0.7.0
|
|
Packit |
4b6dd7 |
*/
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
#include <config.h>
|
|
Packit |
4b6dd7 |
#include <glib.h>
|
|
Packit |
4b6dd7 |
#include <glib/gi18n-lib.h>
|
|
Packit |
4b6dd7 |
#include <string.h>
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
#include "gdata-batch-operation.h"
|
|
Packit |
4b6dd7 |
#include "gdata-batch-feed.h"
|
|
Packit |
4b6dd7 |
#include "gdata-batchable.h"
|
|
Packit |
4b6dd7 |
#include "gdata-private.h"
|
|
Packit |
4b6dd7 |
#include "gdata-batch-private.h"
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
static void operation_free (BatchOperation *op);
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
static void gdata_batch_operation_dispose (GObject *object);
|
|
Packit |
4b6dd7 |
static void gdata_batch_operation_finalize (GObject *object);
|
|
Packit |
4b6dd7 |
static void gdata_batch_operation_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec);
|
|
Packit |
4b6dd7 |
static void gdata_batch_operation_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec);
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
struct _GDataBatchOperationPrivate {
|
|
Packit |
4b6dd7 |
GDataService *service;
|
|
Packit |
4b6dd7 |
GDataAuthorizationDomain *authorization_domain;
|
|
Packit |
4b6dd7 |
gchar *feed_uri;
|
|
Packit |
4b6dd7 |
GHashTable *operations;
|
|
Packit |
4b6dd7 |
guint next_id; /* next available operation ID */
|
|
Packit |
4b6dd7 |
gboolean has_run; /* TRUE if the operation has been run already (though it does not necessarily have to have finished running) */
|
|
Packit |
4b6dd7 |
gboolean is_async; /* TRUE if the operation was run with *_run_async(); FALSE if run with *_run() */
|
|
Packit |
4b6dd7 |
};
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
enum {
|
|
Packit |
4b6dd7 |
PROP_SERVICE = 1,
|
|
Packit |
4b6dd7 |
PROP_FEED_URI,
|
|
Packit |
4b6dd7 |
PROP_AUTHORIZATION_DOMAIN,
|
|
Packit |
4b6dd7 |
};
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
G_DEFINE_TYPE (GDataBatchOperation, gdata_batch_operation, G_TYPE_OBJECT)
|
|
Packit |
4b6dd7 |
#define GDATA_BATCH_OPERATION_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GDATA_TYPE_BATCH_OPERATION, GDataBatchOperationPrivate))
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
static void
|
|
Packit |
4b6dd7 |
gdata_batch_operation_class_init (GDataBatchOperationClass *klass)
|
|
Packit |
4b6dd7 |
{
|
|
Packit |
4b6dd7 |
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
g_type_class_add_private (klass, sizeof (GDataBatchOperationPrivate));
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
gobject_class->dispose = gdata_batch_operation_dispose;
|
|
Packit |
4b6dd7 |
gobject_class->finalize = gdata_batch_operation_finalize;
|
|
Packit |
4b6dd7 |
gobject_class->get_property = gdata_batch_operation_get_property;
|
|
Packit |
4b6dd7 |
gobject_class->set_property = gdata_batch_operation_set_property;
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/**
|
|
Packit |
4b6dd7 |
* GDataBatchOperation:service:
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* The service this batch operation is attached to.
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* Since: 0.7.0
|
|
Packit |
4b6dd7 |
*/
|
|
Packit |
4b6dd7 |
g_object_class_install_property (gobject_class, PROP_SERVICE,
|
|
Packit |
4b6dd7 |
g_param_spec_object ("service",
|
|
Packit |
4b6dd7 |
"Service", "The service this batch operation is attached to.",
|
|
Packit |
4b6dd7 |
GDATA_TYPE_SERVICE,
|
|
Packit |
4b6dd7 |
G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/**
|
|
Packit |
4b6dd7 |
* GDataBatchOperation:authorization-domain:
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* The authorization domain for the batch operation, against which the #GDataService:authorizer for the #GDataBatchOperation:service should be
|
|
Packit |
4b6dd7 |
* authorized. This may be %NULL if authorization is not needed for any of the requests in the batch operation.
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* All requests in the batch operation must be authorizable under this single authorization domain. If requests need different authorization
|
|
Packit |
4b6dd7 |
* domains, they must be performed in different batch operations.
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* Since: 0.9.0
|
|
Packit |
4b6dd7 |
*/
|
|
Packit |
4b6dd7 |
g_object_class_install_property (gobject_class, PROP_AUTHORIZATION_DOMAIN,
|
|
Packit |
4b6dd7 |
g_param_spec_object ("authorization-domain",
|
|
Packit |
4b6dd7 |
"Authorization domain", "The authorization domain for the batch operation.",
|
|
Packit |
4b6dd7 |
GDATA_TYPE_AUTHORIZATION_DOMAIN,
|
|
Packit |
4b6dd7 |
G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/**
|
|
Packit |
4b6dd7 |
* GDataBatchOperation:feed-uri:
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* The feed URI that this batch operation will be sent to.
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* Since: 0.7.0
|
|
Packit |
4b6dd7 |
*/
|
|
Packit |
4b6dd7 |
g_object_class_install_property (gobject_class, PROP_FEED_URI,
|
|
Packit |
4b6dd7 |
g_param_spec_string ("feed-uri",
|
|
Packit |
4b6dd7 |
"Feed URI", "The feed URI that this batch operation will be sent to.",
|
|
Packit |
4b6dd7 |
NULL,
|
|
Packit |
4b6dd7 |
G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
|
Packit |
4b6dd7 |
}
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
static void
|
|
Packit |
4b6dd7 |
gdata_batch_operation_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec)
|
|
Packit |
4b6dd7 |
{
|
|
Packit |
4b6dd7 |
GDataBatchOperationPrivate *priv = GDATA_BATCH_OPERATION_GET_PRIVATE (object);
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
switch (property_id) {
|
|
Packit |
4b6dd7 |
case PROP_SERVICE:
|
|
Packit |
4b6dd7 |
g_value_set_object (value, priv->service);
|
|
Packit |
4b6dd7 |
break;
|
|
Packit |
4b6dd7 |
case PROP_AUTHORIZATION_DOMAIN:
|
|
Packit |
4b6dd7 |
g_value_set_object (value, priv->authorization_domain);
|
|
Packit |
4b6dd7 |
break;
|
|
Packit |
4b6dd7 |
case PROP_FEED_URI:
|
|
Packit |
4b6dd7 |
g_value_set_string (value, priv->feed_uri);
|
|
Packit |
4b6dd7 |
break;
|
|
Packit |
4b6dd7 |
default:
|
|
Packit |
4b6dd7 |
/* We don't have any other property... */
|
|
Packit |
4b6dd7 |
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
|
Packit |
4b6dd7 |
break;
|
|
Packit |
4b6dd7 |
}
|
|
Packit |
4b6dd7 |
}
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
static void
|
|
Packit |
4b6dd7 |
gdata_batch_operation_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec)
|
|
Packit |
4b6dd7 |
{
|
|
Packit |
4b6dd7 |
GDataBatchOperationPrivate *priv = GDATA_BATCH_OPERATION_GET_PRIVATE (object);
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
switch (property_id) {
|
|
Packit |
4b6dd7 |
case PROP_SERVICE:
|
|
Packit |
4b6dd7 |
priv->service = g_value_dup_object (value);
|
|
Packit |
4b6dd7 |
break;
|
|
Packit |
4b6dd7 |
/* Construct only */
|
|
Packit |
4b6dd7 |
case PROP_AUTHORIZATION_DOMAIN:
|
|
Packit |
4b6dd7 |
priv->authorization_domain = g_value_dup_object (value);
|
|
Packit |
4b6dd7 |
break;
|
|
Packit |
4b6dd7 |
case PROP_FEED_URI:
|
|
Packit |
4b6dd7 |
priv->feed_uri = g_value_dup_string (value);
|
|
Packit |
4b6dd7 |
break;
|
|
Packit |
4b6dd7 |
default:
|
|
Packit |
4b6dd7 |
/* We don't have any other property... */
|
|
Packit |
4b6dd7 |
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
|
Packit |
4b6dd7 |
break;
|
|
Packit |
4b6dd7 |
}
|
|
Packit |
4b6dd7 |
}
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
static void
|
|
Packit |
4b6dd7 |
gdata_batch_operation_init (GDataBatchOperation *self)
|
|
Packit |
4b6dd7 |
{
|
|
Packit |
4b6dd7 |
self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, GDATA_TYPE_BATCH_OPERATION, GDataBatchOperationPrivate);
|
|
Packit |
4b6dd7 |
self->priv->next_id = 1; /* reserve ID 0 for error conditions */
|
|
Packit |
4b6dd7 |
self->priv->operations = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, (GDestroyNotify) operation_free);
|
|
Packit |
4b6dd7 |
}
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
static void
|
|
Packit |
4b6dd7 |
gdata_batch_operation_dispose (GObject *object)
|
|
Packit |
4b6dd7 |
{
|
|
Packit |
4b6dd7 |
GDataBatchOperationPrivate *priv = GDATA_BATCH_OPERATION_GET_PRIVATE (object);
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
if (priv->authorization_domain != NULL)
|
|
Packit |
4b6dd7 |
g_object_unref (priv->authorization_domain);
|
|
Packit |
4b6dd7 |
priv->authorization_domain = NULL;
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
if (priv->service != NULL)
|
|
Packit |
4b6dd7 |
g_object_unref (priv->service);
|
|
Packit |
4b6dd7 |
priv->service = NULL;
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/* Chain up to the parent class */
|
|
Packit |
4b6dd7 |
G_OBJECT_CLASS (gdata_batch_operation_parent_class)->dispose (object);
|
|
Packit |
4b6dd7 |
}
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
static void
|
|
Packit |
4b6dd7 |
gdata_batch_operation_finalize (GObject *object)
|
|
Packit |
4b6dd7 |
{
|
|
Packit |
4b6dd7 |
GDataBatchOperationPrivate *priv = GDATA_BATCH_OPERATION_GET_PRIVATE (object);
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
g_free (priv->feed_uri);
|
|
Packit |
4b6dd7 |
g_hash_table_destroy (priv->operations);
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/* Chain up to the parent class */
|
|
Packit |
4b6dd7 |
G_OBJECT_CLASS (gdata_batch_operation_parent_class)->finalize (object);
|
|
Packit |
4b6dd7 |
}
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/**
|
|
Packit |
4b6dd7 |
* gdata_batch_operation_get_service:
|
|
Packit |
4b6dd7 |
* @self: a #GDataBatchOperation
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* Gets the #GDataBatchOperation:service property.
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* Return value: (transfer none): the batch operation's attached service
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* Since: 0.7.0
|
|
Packit |
4b6dd7 |
*/
|
|
Packit |
4b6dd7 |
GDataService *
|
|
Packit |
4b6dd7 |
gdata_batch_operation_get_service (GDataBatchOperation *self)
|
|
Packit |
4b6dd7 |
{
|
|
Packit |
4b6dd7 |
g_return_val_if_fail (GDATA_IS_BATCH_OPERATION (self), NULL);
|
|
Packit |
4b6dd7 |
return self->priv->service;
|
|
Packit |
4b6dd7 |
}
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/**
|
|
Packit |
4b6dd7 |
* gdata_batch_operation_get_authorization_domain:
|
|
Packit |
4b6dd7 |
* @self: a #GDataBatchOperation
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* Gets the #GDataBatchOperation:authorization-domain property.
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* Return value: (transfer none) (allow-none): the #GDataAuthorizationDomain used to authorize the batch operation, or %NULL
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* Since: 0.9.0
|
|
Packit |
4b6dd7 |
*/
|
|
Packit |
4b6dd7 |
GDataAuthorizationDomain *
|
|
Packit |
4b6dd7 |
gdata_batch_operation_get_authorization_domain (GDataBatchOperation *self)
|
|
Packit |
4b6dd7 |
{
|
|
Packit |
4b6dd7 |
g_return_val_if_fail (GDATA_IS_BATCH_OPERATION (self), NULL);
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
return self->priv->authorization_domain;
|
|
Packit |
4b6dd7 |
}
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/**
|
|
Packit |
4b6dd7 |
* gdata_batch_operation_get_feed_uri:
|
|
Packit |
4b6dd7 |
* @self: a #GDataBatchOperation
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* Gets the #GDataBatchOperation:feed-uri property.
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* Return value: the batch operation's feed URI
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* Since: 0.7.0
|
|
Packit |
4b6dd7 |
*/
|
|
Packit |
4b6dd7 |
const gchar *
|
|
Packit |
4b6dd7 |
gdata_batch_operation_get_feed_uri (GDataBatchOperation *self)
|
|
Packit |
4b6dd7 |
{
|
|
Packit |
4b6dd7 |
g_return_val_if_fail (GDATA_IS_BATCH_OPERATION (self), NULL);
|
|
Packit |
4b6dd7 |
return self->priv->feed_uri;
|
|
Packit |
4b6dd7 |
}
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/* Add an operation to the list of operations to be executed when the #GDataBatchOperation is run, and return its operation ID */
|
|
Packit |
4b6dd7 |
static guint
|
|
Packit |
4b6dd7 |
add_operation (GDataBatchOperation *self, GDataBatchOperationType type, GDataEntry *entry, GDataBatchOperationCallback callback, gpointer user_data)
|
|
Packit |
4b6dd7 |
{
|
|
Packit |
4b6dd7 |
BatchOperation *op;
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/* Create the operation */
|
|
Packit |
4b6dd7 |
op = g_slice_new0 (BatchOperation);
|
|
Packit |
4b6dd7 |
op->id = (self->priv->next_id++);
|
|
Packit |
4b6dd7 |
op->type = type;
|
|
Packit |
4b6dd7 |
op->callback = callback;
|
|
Packit |
4b6dd7 |
op->user_data = user_data;
|
|
Packit |
4b6dd7 |
op->entry = g_object_ref (entry);
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/* Add the operation to the table */
|
|
Packit |
4b6dd7 |
g_hash_table_insert (self->priv->operations, GUINT_TO_POINTER (op->id), op);
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
return op->id;
|
|
Packit |
4b6dd7 |
}
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/**
|
|
Packit |
4b6dd7 |
* _gdata_batch_operation_get_operation:
|
|
Packit |
4b6dd7 |
* @self: a #GDataBatchOperation
|
|
Packit |
4b6dd7 |
* @id: the operation ID
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* Return the #BatchOperation for the given operation ID.
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* Return value: the relevant #BatchOperation, or %NULL
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* Since: 0.7.0
|
|
Packit |
4b6dd7 |
*/
|
|
Packit |
4b6dd7 |
BatchOperation *
|
|
Packit |
4b6dd7 |
_gdata_batch_operation_get_operation (GDataBatchOperation *self, guint id)
|
|
Packit |
4b6dd7 |
{
|
|
Packit |
4b6dd7 |
g_return_val_if_fail (GDATA_IS_BATCH_OPERATION (self), NULL);
|
|
Packit |
4b6dd7 |
g_return_val_if_fail (id > 0, NULL);
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
return g_hash_table_lookup (self->priv->operations, GUINT_TO_POINTER (id));
|
|
Packit |
4b6dd7 |
}
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/* Run a user-supplied callback for a #BatchOperation whose return value we've just processed. This is designed to be used in an idle handler, so
|
|
Packit |
4b6dd7 |
* that the callback is run in the main thread. It can be called if the user-supplied callback is %NULL (e.g. in the case that the callback's been
|
|
Packit |
4b6dd7 |
* called before). */
|
|
Packit |
4b6dd7 |
static gboolean
|
|
Packit |
4b6dd7 |
run_callback_cb (BatchOperation *op)
|
|
Packit |
4b6dd7 |
{
|
|
Packit |
4b6dd7 |
if (op->callback != NULL)
|
|
Packit |
4b6dd7 |
op->callback (op->id, op->type, op->entry, op->error, op->user_data);
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/* Unset the callback so that it can't be called again */
|
|
Packit |
4b6dd7 |
op->callback = NULL;
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
return FALSE;
|
|
Packit |
4b6dd7 |
}
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/**
|
|
Packit |
4b6dd7 |
* _gdata_batch_operation_run_callback:
|
|
Packit |
4b6dd7 |
* @self: a #GDataBatchOperation
|
|
Packit |
4b6dd7 |
* @op: the #BatchOperation which has been finished
|
|
Packit |
4b6dd7 |
* @entry: (allow-none): the entry representing the operation's result, or %NULL
|
|
Packit |
4b6dd7 |
* @error: the error from the operation, or %NULL
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* Run the callback for @op to notify the user code that the operation's result has been received and processed. Either @entry or @error should be
|
|
Packit |
4b6dd7 |
* set (and the other should be %NULL), signifying a successful operation or a failed operation, respectively.
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* The function will call @op's user-supplied callback, if available, in either the current or the main thread, depending on whether the
|
|
Packit |
4b6dd7 |
* #GDataBatchOperation was run with gdata_batch_operation_run() or gdata_batch_operation_run_async().
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* Since: 0.7.0
|
|
Packit |
4b6dd7 |
*/
|
|
Packit |
4b6dd7 |
void
|
|
Packit |
4b6dd7 |
_gdata_batch_operation_run_callback (GDataBatchOperation *self, BatchOperation *op, GDataEntry *entry, GError *error)
|
|
Packit |
4b6dd7 |
{
|
|
Packit |
4b6dd7 |
g_return_if_fail (GDATA_IS_BATCH_OPERATION (self));
|
|
Packit |
4b6dd7 |
g_return_if_fail (op != NULL);
|
|
Packit |
4b6dd7 |
g_return_if_fail (entry == NULL || GDATA_IS_ENTRY (entry));
|
|
Packit |
4b6dd7 |
g_return_if_fail (entry == NULL || error == NULL);
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/* We can free the request data, and replace it with the response data */
|
|
Packit |
4b6dd7 |
g_free (op->query_id);
|
|
Packit |
4b6dd7 |
op->query_id = NULL;
|
|
Packit |
4b6dd7 |
if (op->entry != NULL)
|
|
Packit |
4b6dd7 |
g_object_unref (op->entry);
|
|
Packit |
4b6dd7 |
if (entry != NULL)
|
|
Packit |
4b6dd7 |
g_object_ref (entry);
|
|
Packit |
4b6dd7 |
op->entry = entry;
|
|
Packit |
4b6dd7 |
op->error = error;
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/* Don't bother scheduling run_callback_cb() if there is no callback to run */
|
|
Packit |
4b6dd7 |
if (op->callback == NULL)
|
|
Packit |
4b6dd7 |
return;
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/* Only dispatch it in the main thread if the request was run with *_run_async(). This allows applications to run batch operations entirely in
|
|
Packit |
4b6dd7 |
* application-owned threads if desired. */
|
|
Packit |
4b6dd7 |
if (self->priv->is_async == TRUE) {
|
|
Packit |
4b6dd7 |
/* Send the callback; use G_PRIORITY_DEFAULT rather than G_PRIORITY_DEFAULT_IDLE
|
|
Packit |
4b6dd7 |
* to contend with the priorities used by the callback functions in GAsyncResult */
|
|
Packit |
4b6dd7 |
g_idle_add_full (G_PRIORITY_DEFAULT, (GSourceFunc) run_callback_cb, op, NULL);
|
|
Packit |
4b6dd7 |
} else {
|
|
Packit |
4b6dd7 |
run_callback_cb (op);
|
|
Packit |
4b6dd7 |
}
|
|
Packit |
4b6dd7 |
}
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/* Free a #BatchOperation */
|
|
Packit |
4b6dd7 |
static void
|
|
Packit |
4b6dd7 |
operation_free (BatchOperation *op)
|
|
Packit |
4b6dd7 |
{
|
|
Packit |
4b6dd7 |
g_free (op->query_id);
|
|
Packit |
4b6dd7 |
if (op->entry != NULL)
|
|
Packit |
4b6dd7 |
g_object_unref (op->entry);
|
|
Packit |
4b6dd7 |
if (op->error != NULL)
|
|
Packit |
4b6dd7 |
g_error_free (op->error);
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
g_slice_free (BatchOperation, op);
|
|
Packit |
4b6dd7 |
}
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/**
|
|
Packit |
4b6dd7 |
* gdata_batch_operation_add_query:
|
|
Packit |
4b6dd7 |
* @self: a #GDataBatchOperation
|
|
Packit |
4b6dd7 |
* @id: the ID of the entry being queried for
|
|
Packit |
4b6dd7 |
* @entry_type: the type of the entry which will be returned
|
|
Packit |
4b6dd7 |
* @callback: (scope async): a #GDataBatchOperationCallback to call when the query is finished, or %NULL
|
|
Packit |
4b6dd7 |
* @user_data: (closure): data to pass to the @callback function
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* Add a query to the #GDataBatchOperation, to be executed when the operation is run. The query will return a #GDataEntry (of subclass type
|
|
Packit |
4b6dd7 |
* @entry_type) representing the given entry @id. The ID is of the same format as that returned by gdata_entry_get_id().
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* Note that a single batch operation should not operate on a given #GDataEntry more than once, as there's no guarantee about the order in which the
|
|
Packit |
4b6dd7 |
* batch operation's operations will be performed.
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* @callback will be called when the #GDataBatchOperation is run with gdata_batch_operation_run() (in which case it will be called in the thread which
|
|
Packit |
4b6dd7 |
* ran the batch operation), or with gdata_batch_operation_run_async() (in which case it will be called in an idle handler in the main thread). The
|
|
Packit |
4b6dd7 |
* @operation_id passed to the callback will match the return value of gdata_batch_operation_add_query(), and the @operation_type will be
|
|
Packit |
4b6dd7 |
* %GDATA_BATCH_OPERATION_QUERY. If the query was successful, the resulting entry will be passed to the callback function as @entry, and @error will
|
|
Packit |
4b6dd7 |
* be %NULL. If, however, the query was unsuccessful, @entry will be %NULL and @error will contain a #GError detailing what went wrong.
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* Return value: operation ID for the added query, or 0
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* Since: 0.7.0
|
|
Packit |
4b6dd7 |
*/
|
|
Packit |
4b6dd7 |
guint
|
|
Packit |
4b6dd7 |
gdata_batch_operation_add_query (GDataBatchOperation *self, const gchar *id, GType entry_type,
|
|
Packit |
4b6dd7 |
GDataBatchOperationCallback callback, gpointer user_data)
|
|
Packit |
4b6dd7 |
{
|
|
Packit |
4b6dd7 |
BatchOperation *op;
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
g_return_val_if_fail (GDATA_IS_BATCH_OPERATION (self), 0);
|
|
Packit |
4b6dd7 |
g_return_val_if_fail (id != NULL, 0);
|
|
Packit |
4b6dd7 |
g_return_val_if_fail (g_type_is_a (entry_type, GDATA_TYPE_ENTRY), 0);
|
|
Packit |
4b6dd7 |
g_return_val_if_fail (self->priv->has_run == FALSE, 0);
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/* Create the operation manually, since it would be messy to special-case add_operation() to do this */
|
|
Packit |
4b6dd7 |
op = g_slice_new0 (BatchOperation);
|
|
Packit |
4b6dd7 |
op->id = (self->priv->next_id++);
|
|
Packit |
4b6dd7 |
op->type = GDATA_BATCH_OPERATION_QUERY;
|
|
Packit |
4b6dd7 |
op->callback = callback;
|
|
Packit |
4b6dd7 |
op->user_data = user_data;
|
|
Packit |
4b6dd7 |
op->query_id = g_strdup (id);
|
|
Packit |
4b6dd7 |
op->entry_type = entry_type;
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/* Add the operation to the table */
|
|
Packit |
4b6dd7 |
g_hash_table_insert (self->priv->operations, GUINT_TO_POINTER (op->id), op);
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
return op->id;
|
|
Packit |
4b6dd7 |
}
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/**
|
|
Packit |
4b6dd7 |
* gdata_batch_operation_add_insertion:
|
|
Packit |
4b6dd7 |
* @self: a #GDataBatchOperation
|
|
Packit |
4b6dd7 |
* @entry: the #GDataEntry to insert
|
|
Packit |
4b6dd7 |
* @callback: (scope async): a #GDataBatchOperationCallback to call when the insertion is finished, or %NULL
|
|
Packit |
4b6dd7 |
* @user_data: (closure): data to pass to the @callback function
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* Add an entry to the #GDataBatchOperation, to be inserted on the server when the operation is run. The insertion will return the inserted version
|
|
Packit |
4b6dd7 |
* of @entry. @entry is reffed by the function, so may be freed after it returns.
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* @callback will be called as specified in the documentation for gdata_batch_operation_add_query(), with an @operation_type of
|
|
Packit |
4b6dd7 |
* %GDATA_BATCH_OPERATION_INSERTION.
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* Return value: operation ID for the added insertion, or 0
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* Since: 0.7.0
|
|
Packit |
4b6dd7 |
*/
|
|
Packit |
4b6dd7 |
guint
|
|
Packit |
4b6dd7 |
gdata_batch_operation_add_insertion (GDataBatchOperation *self, GDataEntry *entry, GDataBatchOperationCallback callback, gpointer user_data)
|
|
Packit |
4b6dd7 |
{
|
|
Packit |
4b6dd7 |
g_return_val_if_fail (GDATA_IS_BATCH_OPERATION (self), 0);
|
|
Packit |
4b6dd7 |
g_return_val_if_fail (GDATA_IS_ENTRY (entry), 0);
|
|
Packit |
4b6dd7 |
g_return_val_if_fail (self->priv->has_run == FALSE, 0);
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
return add_operation (self, GDATA_BATCH_OPERATION_INSERTION, entry, callback, user_data);
|
|
Packit |
4b6dd7 |
}
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/**
|
|
Packit |
4b6dd7 |
* gdata_batch_operation_add_update:
|
|
Packit |
4b6dd7 |
* @self: a #GDataBatchOperation
|
|
Packit |
4b6dd7 |
* @entry: the #GDataEntry to update
|
|
Packit |
4b6dd7 |
* @callback: (scope async): a #GDataBatchOperationCallback to call when the update is finished, or %NULL
|
|
Packit |
4b6dd7 |
* @user_data: (closure): data to pass to the @callback function
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* Add an entry to the #GDataBatchOperation, to be updated on the server when the operation is run. The update will return the updated version of
|
|
Packit |
4b6dd7 |
* @entry. @entry is reffed by the function, so may be freed after it returns.
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* Note that a single batch operation should not operate on a given #GDataEntry more than once, as there's no guarantee about the order in which the
|
|
Packit |
4b6dd7 |
* batch operation's operations will be performed.
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* @callback will be called as specified in the documentation for gdata_batch_operation_add_query(), with an @operation_type of
|
|
Packit |
4b6dd7 |
* %GDATA_BATCH_OPERATION_UPDATE.
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* Return value: operation ID for the added update, or 0
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* Since: 0.7.0
|
|
Packit |
4b6dd7 |
*/
|
|
Packit |
4b6dd7 |
guint
|
|
Packit |
4b6dd7 |
gdata_batch_operation_add_update (GDataBatchOperation *self, GDataEntry *entry, GDataBatchOperationCallback callback, gpointer user_data)
|
|
Packit |
4b6dd7 |
{
|
|
Packit |
4b6dd7 |
g_return_val_if_fail (GDATA_IS_BATCH_OPERATION (self), 0);
|
|
Packit |
4b6dd7 |
g_return_val_if_fail (GDATA_IS_ENTRY (entry), 0);
|
|
Packit |
4b6dd7 |
g_return_val_if_fail (self->priv->has_run == FALSE, 0);
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
return add_operation (self, GDATA_BATCH_OPERATION_UPDATE, entry, callback, user_data);
|
|
Packit |
4b6dd7 |
}
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/**
|
|
Packit |
4b6dd7 |
* gdata_batch_operation_add_deletion:
|
|
Packit |
4b6dd7 |
* @self: a #GDataBatchOperation
|
|
Packit |
4b6dd7 |
* @entry: the #GDataEntry to delete
|
|
Packit |
4b6dd7 |
* @callback: (scope async): a #GDataBatchOperationCallback to call when the deletion is finished, or %NULL
|
|
Packit |
4b6dd7 |
* @user_data: (closure): data to pass to the @callback function
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* Add an entry to the #GDataBatchOperation, to be deleted on the server when the operation is run. @entry is reffed by the function, so may be freed
|
|
Packit |
4b6dd7 |
* after it returns.
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* Note that a single batch operation should not operate on a given #GDataEntry more than once, as there's no guarantee about the order in which the
|
|
Packit |
4b6dd7 |
* batch operation's operations will be performed.
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* @callback will be called as specified in the documentation for gdata_batch_operation_add_query(), with an @operation_type of
|
|
Packit |
4b6dd7 |
* %GDATA_BATCH_OPERATION_DELETION.
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* Return value: operation ID for the added deletion, or 0
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* Since: 0.7.0
|
|
Packit |
4b6dd7 |
*/
|
|
Packit |
4b6dd7 |
guint
|
|
Packit |
4b6dd7 |
gdata_batch_operation_add_deletion (GDataBatchOperation *self, GDataEntry *entry, GDataBatchOperationCallback callback, gpointer user_data)
|
|
Packit |
4b6dd7 |
{
|
|
Packit |
4b6dd7 |
g_return_val_if_fail (GDATA_IS_BATCH_OPERATION (self), 0);
|
|
Packit |
4b6dd7 |
g_return_val_if_fail (GDATA_IS_ENTRY (entry), 0);
|
|
Packit |
4b6dd7 |
g_return_val_if_fail (self->priv->has_run == FALSE, 0);
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
return add_operation (self, GDATA_BATCH_OPERATION_DELETION, entry, callback, user_data);
|
|
Packit |
4b6dd7 |
}
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/**
|
|
Packit |
4b6dd7 |
* gdata_batch_operation_run:
|
|
Packit |
4b6dd7 |
* @self: a #GDataBatchOperation
|
|
Packit |
4b6dd7 |
* @cancellable: (allow-none): a #GCancellable, or %NULL
|
|
Packit |
4b6dd7 |
* @error: a #GError, or %NULL
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* Run the #GDataBatchOperation synchronously. This will send all the operations in the batch operation to the server, and call their respective
|
|
Packit |
4b6dd7 |
* callbacks synchronously (i.e. before gdata_batch_operation_run() returns, and in the same thread that called gdata_batch_operation_run()) as the
|
|
Packit |
4b6dd7 |
* server returns results for each operation.
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* The callbacks for all of the operations in the batch operation are always guaranteed to be called, even if the batch operation as a whole fails.
|
|
Packit |
4b6dd7 |
* Each callback will be called exactly once for each time gdata_batch_operation_run() is called.
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* The return value of the function indicates whether the overall batch operation was successful, and doesn't indicate the status of any of the
|
|
Packit |
4b6dd7 |
* operations it comprises. gdata_batch_operation_run() could return %TRUE even if all of its operations failed.
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* @cancellable can be used to cancel the entire batch operation any time before or during the network activity. If @cancellable is cancelled
|
|
Packit |
4b6dd7 |
* after network activity has finished, gdata_batch_operation_run() will continue and finish as normal.
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* Return value: %TRUE on success, %FALSE otherwise
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* Since: 0.7.0
|
|
Packit |
4b6dd7 |
*/
|
|
Packit |
4b6dd7 |
gboolean
|
|
Packit |
4b6dd7 |
gdata_batch_operation_run (GDataBatchOperation *self, GCancellable *cancellable, GError **error)
|
|
Packit |
4b6dd7 |
{
|
|
Packit |
4b6dd7 |
GDataBatchOperationPrivate *priv = self->priv;
|
|
Packit |
4b6dd7 |
SoupMessage *message;
|
|
Packit |
4b6dd7 |
GDataFeed *feed;
|
|
Packit |
4b6dd7 |
GTimeVal updated;
|
|
Packit |
4b6dd7 |
gchar *upload_data;
|
|
Packit |
4b6dd7 |
guint status;
|
|
Packit |
4b6dd7 |
GHashTableIter iter;
|
|
Packit |
4b6dd7 |
gpointer op_id;
|
|
Packit |
4b6dd7 |
BatchOperation *op;
|
|
Packit |
4b6dd7 |
GError *child_error = NULL;
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
g_return_val_if_fail (GDATA_IS_BATCH_OPERATION (self), FALSE);
|
|
Packit |
4b6dd7 |
g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE);
|
|
Packit |
4b6dd7 |
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
|
|
Packit |
4b6dd7 |
g_return_val_if_fail (priv->has_run == FALSE, FALSE);
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/* Check for early cancellation. */
|
|
Packit |
4b6dd7 |
if (g_cancellable_set_error_if_cancelled (cancellable, error)) {
|
|
Packit |
4b6dd7 |
return FALSE;
|
|
Packit |
4b6dd7 |
}
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/* Check whether the service actually supports these kinds of
|
|
Packit |
4b6dd7 |
* operations. */
|
|
Packit |
4b6dd7 |
g_hash_table_iter_init (&iter, priv->operations);
|
|
Packit |
4b6dd7 |
while (g_hash_table_iter_next (&iter, &op_id, (gpointer*) &op) == TRUE) {
|
|
Packit |
4b6dd7 |
GDataBatchable *batchable = GDATA_BATCHABLE (priv->service);
|
|
Packit |
4b6dd7 |
GDataBatchableIface *batchable_iface;
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
batchable_iface = GDATA_BATCHABLE_GET_IFACE (batchable);
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
if (batchable_iface->is_supported != NULL &&
|
|
Packit |
4b6dd7 |
!batchable_iface->is_supported (op->type)) {
|
|
Packit |
4b6dd7 |
g_set_error (error, GDATA_SERVICE_ERROR,
|
|
Packit |
4b6dd7 |
GDATA_SERVICE_ERROR_WITH_BATCH_OPERATION,
|
|
Packit |
4b6dd7 |
_("Batch operations are unsupported by "
|
|
Packit |
4b6dd7 |
"this service."));
|
|
Packit |
4b6dd7 |
return FALSE;
|
|
Packit |
4b6dd7 |
}
|
|
Packit |
4b6dd7 |
}
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
message = _gdata_service_build_message (priv->service, priv->authorization_domain, SOUP_METHOD_POST, priv->feed_uri, NULL, TRUE);
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/* Build the request */
|
|
Packit |
4b6dd7 |
g_get_current_time (&updated);
|
|
Packit |
4b6dd7 |
feed = _gdata_feed_new (GDATA_TYPE_FEED, "Batch operation feed",
|
|
Packit |
4b6dd7 |
"batch1", updated.tv_sec);
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
g_hash_table_iter_init (&iter, priv->operations);
|
|
Packit |
4b6dd7 |
while (g_hash_table_iter_next (&iter, &op_id, (gpointer*) &op) == TRUE) {
|
|
Packit |
4b6dd7 |
if (op->type == GDATA_BATCH_OPERATION_QUERY) {
|
|
Packit |
4b6dd7 |
/* Queries are weird; build a new throwaway entry, and add it to the feed */
|
|
Packit |
4b6dd7 |
GDataEntry *entry;
|
|
Packit |
4b6dd7 |
GDataEntryClass *klass;
|
|
Packit |
4b6dd7 |
gchar *entry_uri;
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
klass = g_type_class_ref (op->entry_type);
|
|
Packit |
4b6dd7 |
g_assert (klass->get_entry_uri != NULL);
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
entry_uri = klass->get_entry_uri (op->query_id);
|
|
Packit |
4b6dd7 |
entry = gdata_entry_new (entry_uri);
|
|
Packit |
4b6dd7 |
g_free (entry_uri);
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
gdata_entry_set_title (entry, "Batch operation query");
|
|
Packit |
4b6dd7 |
_gdata_entry_set_updated (entry, updated.tv_sec);
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
_gdata_entry_set_batch_data (entry, op->id, op->type);
|
|
Packit |
4b6dd7 |
_gdata_feed_add_entry (feed, entry);
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
g_type_class_unref (klass);
|
|
Packit |
4b6dd7 |
g_object_unref (entry);
|
|
Packit |
4b6dd7 |
} else {
|
|
Packit |
4b6dd7 |
/* Everything else just dumps the entry's XML in the request */
|
|
Packit |
4b6dd7 |
_gdata_entry_set_batch_data (op->entry, op->id, op->type);
|
|
Packit |
4b6dd7 |
_gdata_feed_add_entry (feed, op->entry);
|
|
Packit |
4b6dd7 |
}
|
|
Packit |
4b6dd7 |
}
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
upload_data = gdata_parsable_get_xml (GDATA_PARSABLE (feed));
|
|
Packit |
4b6dd7 |
soup_message_set_request (message, "application/atom+xml", SOUP_MEMORY_TAKE, upload_data, strlen (upload_data));
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
g_object_unref (feed);
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/* Ensure that this GDataBatchOperation can't be run again */
|
|
Packit |
4b6dd7 |
priv->has_run = TRUE;
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/* Send the message */
|
|
Packit |
4b6dd7 |
status = _gdata_service_send_message (priv->service, message, cancellable, &child_error);
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
if (status != SOUP_STATUS_OK) {
|
|
Packit |
4b6dd7 |
/* Iff status is SOUP_STATUS_NONE or SOUP_STATUS_CANCELLED, child_error has already been set */
|
|
Packit |
4b6dd7 |
if (status != SOUP_STATUS_NONE && status != SOUP_STATUS_CANCELLED) {
|
|
Packit |
4b6dd7 |
/* Error */
|
|
Packit |
4b6dd7 |
GDataServiceClass *klass = GDATA_SERVICE_GET_CLASS (priv->service);
|
|
Packit |
4b6dd7 |
g_assert (klass->parse_error_response != NULL);
|
|
Packit |
4b6dd7 |
klass->parse_error_response (priv->service, GDATA_OPERATION_BATCH, status, message->reason_phrase, message->response_body->data,
|
|
Packit |
4b6dd7 |
message->response_body->length, &child_error);
|
|
Packit |
4b6dd7 |
}
|
|
Packit |
4b6dd7 |
g_object_unref (message);
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
goto error;
|
|
Packit |
4b6dd7 |
}
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/* Parse the XML; GDataBatchFeed will fire off the relevant callbacks */
|
|
Packit |
4b6dd7 |
g_assert (message->response_body->data != NULL);
|
|
Packit |
4b6dd7 |
feed = GDATA_FEED (_gdata_parsable_new_from_xml (GDATA_TYPE_BATCH_FEED, message->response_body->data, message->response_body->length,
|
|
Packit |
4b6dd7 |
self, &child_error));
|
|
Packit |
4b6dd7 |
g_object_unref (message);
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
if (feed == NULL)
|
|
Packit |
4b6dd7 |
goto error;
|
|
Packit |
4b6dd7 |
g_object_unref (feed);
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
return TRUE;
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
error:
|
|
Packit |
4b6dd7 |
/* Call the callbacks for each of our operations to notify them of the error */
|
|
Packit |
4b6dd7 |
g_hash_table_iter_init (&iter, priv->operations);
|
|
Packit |
4b6dd7 |
while (g_hash_table_iter_next (&iter, &op_id, (gpointer*) &op) == TRUE)
|
|
Packit |
4b6dd7 |
_gdata_batch_operation_run_callback (self, op, NULL, g_error_copy (child_error));
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
g_propagate_error (error, child_error);
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
return FALSE;
|
|
Packit |
4b6dd7 |
}
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
static void
|
|
Packit |
4b6dd7 |
run_thread (GTask *task, gpointer source_object, gpointer task_data, GCancellable *cancellable)
|
|
Packit |
4b6dd7 |
{
|
|
Packit |
4b6dd7 |
GDataBatchOperation *operation = GDATA_BATCH_OPERATION (source_object);
|
|
Packit |
4b6dd7 |
g_autoptr(GError) error = NULL;
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/* Run the batch operation and return */
|
|
Packit |
4b6dd7 |
if (!gdata_batch_operation_run (operation, cancellable, &error))
|
|
Packit |
4b6dd7 |
g_task_return_error (task, g_steal_pointer (&error));
|
|
Packit |
4b6dd7 |
else
|
|
Packit |
4b6dd7 |
g_task_return_boolean (task, TRUE);
|
|
Packit |
4b6dd7 |
}
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/**
|
|
Packit |
4b6dd7 |
* gdata_batch_operation_run_async:
|
|
Packit |
4b6dd7 |
* @self: a #GDataBatchOperation
|
|
Packit |
4b6dd7 |
* @cancellable: (allow-none): a #GCancellable, or %NULL
|
|
Packit |
4b6dd7 |
* @callback: a #GAsyncReadyCallback to call when the batch operation is finished, or %NULL
|
|
Packit |
4b6dd7 |
* @user_data: (closure): data to pass to the @callback function
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* Run the #GDataBatchOperation asynchronously. This will send all the operations in the batch operation to the server, and call their respective
|
|
Packit |
4b6dd7 |
* callbacks asynchronously (i.e. in idle functions in the main thread, usually after gdata_batch_operation_run_async() has returned) as the
|
|
Packit |
4b6dd7 |
* server returns results for each operation. @self is reffed when this function is called, so can safely be unreffed after this function returns.
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* For more details, see gdata_batch_operation_run(), which is the synchronous version of this function.
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* When the entire batch operation is finished, @callback will be called. You can then call gdata_batch_operation_run_finish() to get the results of
|
|
Packit |
4b6dd7 |
* the batch operation.
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* Since: 0.7.0
|
|
Packit |
4b6dd7 |
*/
|
|
Packit |
4b6dd7 |
void
|
|
Packit |
4b6dd7 |
gdata_batch_operation_run_async (GDataBatchOperation *self, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
|
|
Packit |
4b6dd7 |
{
|
|
Packit |
4b6dd7 |
g_autoptr(GTask) task = NULL;
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
g_return_if_fail (GDATA_IS_BATCH_OPERATION (self));
|
|
Packit |
4b6dd7 |
g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
|
|
Packit |
4b6dd7 |
g_return_if_fail (self->priv->has_run == FALSE);
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/* Mark the operation as async for the purposes of deciding where to call the callbacks */
|
|
Packit |
4b6dd7 |
self->priv->is_async = TRUE;
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
task = g_task_new (self, cancellable, callback, user_data);
|
|
Packit |
4b6dd7 |
g_task_set_source_tag (task, gdata_batch_operation_run_async);
|
|
Packit |
4b6dd7 |
g_task_run_in_thread (task, run_thread);
|
|
Packit |
4b6dd7 |
}
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/**
|
|
Packit |
4b6dd7 |
* gdata_batch_operation_run_finish:
|
|
Packit |
4b6dd7 |
* @self: a #GDataBatchOperation
|
|
Packit |
4b6dd7 |
* @async_result: a #GAsyncResult
|
|
Packit |
4b6dd7 |
* @error: a #GError, or %NULL
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* Finishes an asynchronous batch operation run with gdata_batch_operation_run_async().
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* Return values are as for gdata_batch_operation_run().
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* Return value: %TRUE on success, %FALSE otherwise
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* Since: 0.7.0
|
|
Packit |
4b6dd7 |
*/
|
|
Packit |
4b6dd7 |
gboolean
|
|
Packit |
4b6dd7 |
gdata_batch_operation_run_finish (GDataBatchOperation *self, GAsyncResult *async_result, GError **error)
|
|
Packit |
4b6dd7 |
{
|
|
Packit |
4b6dd7 |
GDataBatchOperationPrivate *priv = self->priv;
|
|
Packit |
4b6dd7 |
g_autoptr(GError) child_error = NULL;
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
g_return_val_if_fail (GDATA_IS_BATCH_OPERATION (self), FALSE);
|
|
Packit |
4b6dd7 |
g_return_val_if_fail (G_IS_ASYNC_RESULT (async_result), FALSE);
|
|
Packit |
4b6dd7 |
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
|
|
Packit |
4b6dd7 |
g_return_val_if_fail (g_task_is_valid (async_result, self), FALSE);
|
|
Packit |
4b6dd7 |
g_return_val_if_fail (g_async_result_is_tagged (async_result, gdata_batch_operation_run_async), FALSE);
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
if (!g_task_propagate_boolean (G_TASK (async_result), &child_error)) {
|
|
Packit |
4b6dd7 |
if (priv->has_run == FALSE) {
|
|
Packit |
4b6dd7 |
GHashTableIter iter;
|
|
Packit |
4b6dd7 |
gpointer op_id;
|
|
Packit |
4b6dd7 |
BatchOperation *op;
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/* Temporarily mark the operation as synchronous so that the callbacks get dispatched in this thread */
|
|
Packit |
4b6dd7 |
priv->is_async = FALSE;
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/* If has_run hasn't been set, the call to gdata_batch_operation_run() was never made in the thread, and so none of the
|
|
Packit |
4b6dd7 |
* operations' callbacks have been called. Call the callbacks for each of our operations to notify them of the error.
|
|
Packit |
4b6dd7 |
* If has_run has been set, gdata_batch_operation_run() has already done this for us. */
|
|
Packit |
4b6dd7 |
g_hash_table_iter_init (&iter, priv->operations);
|
|
Packit |
4b6dd7 |
while (g_hash_table_iter_next (&iter, &op_id, (gpointer*) &op) == TRUE)
|
|
Packit |
4b6dd7 |
_gdata_batch_operation_run_callback (self, op, NULL, g_error_copy (child_error));
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
priv->is_async = TRUE;
|
|
Packit |
4b6dd7 |
}
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
g_propagate_error (error, g_steal_pointer (&child_error));
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
return FALSE;
|
|
Packit |
4b6dd7 |
}
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
return TRUE;
|
|
Packit |
4b6dd7 |
}
|