static gboolean __is_guid_valid(MidgardObject *self)
{
	if(MGD_OBJECT_GUID (self) == NULL) {

		midgard_set_error(MGD_OBJECT_CNC (self),
				MGD_GENERIC_ERROR,
				MGD_ERR_INVALID_PROPERTY_VALUE,
				" Guid property is NULL for %s. ", 
				G_OBJECT_TYPE_NAME(self));
		g_warning("%s", MGD_OBJECT_CNC (self)->err->message); 
		g_clear_error(&MGD_OBJECT_CNC (self)->err);
		return FALSE;
	}

	if(!midgard_is_guid(MGD_OBJECT_GUID (self))) {

		midgard_set_error(MGD_OBJECT_CNC (self),
				MGD_GENERIC_ERROR,
				MGD_ERR_INVALID_PROPERTY_VALUE,
				" Guid-property of %s has invalid value.", 
				G_OBJECT_TYPE_NAME(self));
		g_warning("%s", MGD_OBJECT_CNC (self)->err->message);
		g_clear_error(&MGD_OBJECT_CNC (self)->err);
		return FALSE;
	}

	return TRUE;
}
/**
 * midgard_transaction_begin:
 * @self: #MidgardTransaction instance
 * 
 * Begins new, underlying database provider's transaction.
 * In case of error, #MidgardConnection error is set to MGD_ERR_INTERNAL.
 *
 * Returns: %TRUE on success, %FALSE otherwise.
 * 
 * Since: 9.09
 */
gboolean
midgard_transaction_begin (MidgardTransaction *self)
{
	_ASSERT_T_MGD(self);

	gboolean rv = FALSE;
	GdaConnection *cnc = _T_CNC(self);
	MidgardConnection *mgd = self->priv->mgd;
	GError *error = NULL;

	g_debug("Begin named transaction '%s'", self->priv->name);

	rv = gda_connection_begin_transaction(cnc, self->priv->name, 
			GDA_TRANSACTION_ISOLATION_UNKNOWN, &error);

	if (!error && rv)
		return TRUE;

	midgard_set_error(mgd,
			MGD_GENERIC_ERROR,
			MGD_ERR_INTERNAL,
			error && error->message ? error->message : " Unknown error.");

	if (error)
		g_error_free(error);

	return FALSE;
}
Beispiel #3
0
/**
 * midgard_blob_write_content:
 * @self: #MidgardBlob self instance.
 * @content: content which should be written to file.
 * 
 * Write given @content to a file.
 * 
 * Returns: %TRUE if content has been written to file, %FALSE otherwise.
 */ 
gboolean  midgard_blob_write_content(MidgardBlob *self,	const gchar *content)
{
	g_assert(self != NULL);
	g_assert(content != NULL);

	MidgardConnection *mgd = self->priv->mgd;
	MIDGARD_ERRNO_SET(mgd, MGD_ERR_OK);

	__get_filepath(self);
	
	if(!self->priv->filepath) {
		midgard_set_error(self->priv->mgd,
				MGD_GENERIC_ERROR,
				MGD_ERR_USER_DATA,
				"Invalid attachment. "
				"Can not read file from empty location");
		return FALSE;
	}

	__get_channel(self, "w");
	if(!self->priv->channel)
		return FALSE;

	GIOChannel *channel = self->priv->channel;
	GIOStatus status;
	GError *err = NULL;

	status = g_io_channel_write_chars(channel, content,
			strlen(content), NULL, &err);

	g_io_channel_flush(channel, NULL);

	if(status != G_IO_STATUS_NORMAL) {
		midgard_set_error(self->priv->mgd,
				MGD_GENERIC_ERROR,
				MGD_ERR_INTERNAL,
				" %s ",
				err->message);
		g_clear_error(&err);

		return FALSE;
	}

	return TRUE;	
}
Beispiel #4
0
/* Create private channel */
static void __get_channel(MidgardBlob *self, const gchar *mode)
{
	if(self->priv->channel)
		return;

	GError *err = NULL;
	GIOChannel *channel = self->priv->channel;
	gchar *filepath = self->priv->filepath;
	if(channel == NULL)
		channel = g_io_channel_new_file(filepath, mode ? mode : "w", &err);
	/* Keep "binary" mode. It's useless on *nix but needed for WIN32 */
	
	if(!channel){
		midgard_set_error(self->priv->mgd,
				MGD_GENERIC_ERROR,
				MGD_ERR_USER_DATA,
				" %s ",
				err->message);
		g_clear_error(&err);
		return;
	}
	
	g_clear_error(&err);
	
	GIOStatus status = g_io_channel_set_encoding(channel,
			(const gchar *)self->priv->encoding, &err);
	
	if(status != G_IO_STATUS_NORMAL) {
		
		midgard_set_error(self->priv->mgd,
				MGD_GENERIC_ERROR,
				MGD_ERR_USER_DATA,
				" %s ",
				err->message);
		g_clear_error(&err);
		g_io_channel_shutdown(channel, TRUE, NULL);
		return;
	}

	self->priv->channel = channel;
}
/**
 * midgard_connection_open:	
 * @self: #MidgardConnection instance
 * @name: configuration file name
 * @error: pointer to store error 
 *
 * Opens a connection to the database, which is defined in named configuration. 
 * The configuration file is read from the system configuration directory
 * and is used as the configuration for the created connection. For example: `/etc`
 * directory is taken into account if library is compiled with `/usr' prefix, 
 * `/usr/local/etc` if compiled with `/usr/local` prefix, etc.
 *
 * Consider using midgard_connection_open_config(), if you need to open connection to 
 * database which is configured in user's home directory.
 *
 * If the named database configuration can not be read or the connection fails,
 * then %FALSE is returned and an error message is written to the global midgard
 * error state.
 *
 * It also initializes #MidgardSchema object (which is encapsulated by implementation )
 * and register all MgdSchema, #MidgardObjectClass derived classes defined by user.
 * This happens only when basic Midgard classes are not registered in GType system.
 * This is recommended way to initialize MgdSchema types.
 *  
 * Returns: %TRUE if the operation succeeded, %FALSE otherwise.
 */ 
gboolean 
midgard_connection_open (MidgardConnection *self, const char *name, GError **error)
{	
	g_assert(self != NULL);
	g_assert (name != NULL);
	g_return_val_if_fail (error == NULL || *error == NULL, FALSE);

	MIDGARD_ERRNO_SET (self, MGD_ERR_OK);
	gboolean rv = TRUE;
	
	__SELF_REOPEN (self, rv);
	if (!rv)
		return rv;	

	/* FIXME, it should be handled by GError */
	if(self->priv->config != NULL){
		midgard_set_error(self,
				MGD_GENERIC_ERROR,
				MGD_ERR_USER_DATA,
				"MidgardConfig already associated with "
				"MidgardConnection");
		return FALSE;
	}
	
	MidgardConfig *config = midgard_config_new();

	GError *rf_error = NULL;
	if(!midgard_config_read_file(config, name, FALSE, &rf_error)) {

		if(rf_error) 
			g_propagate_error(error, rf_error);	
		
		MIDGARD_ERRNO_SET (self, MGD_ERR_NOT_CONNECTED);
		return FALSE;
	}
	
	if(error)
		g_clear_error(&rf_error);

	self->priv->config = config;

	GHashTable *hash = NULL;

	if(!__midgard_connection_open(self, &hash, TRUE)) {

		MIDGARD_ERRNO_SET (self, MGD_ERR_NOT_CONNECTED);
		rv = FALSE;
	}

	g_hash_table_destroy(hash);
	
	return rv;
}
Beispiel #6
0
/* Build attachment's full path. 
 * Create new relative location for attachment if it's empty. 
 * WARNING! Keep in mind that attachment's location might be changed 
 * between midgard_blob method calls! */
static void __get_filepath(MidgardBlob *self)
{
	if(self->priv->filepath)
		return;

	gchar *fname = NULL;
	gchar *location = NULL;
	gchar *up_a, *up_b;
	MidgardObject *attachment = self->priv->attachment;

	GParamSpec *pspec =
		g_object_class_find_property(
				G_OBJECT_GET_CLASS(G_OBJECT(attachment)), "location");

	/* FIXME, we can not depend on just location property here.
	 * This must be defined in mgdschema file. */
	if(!pspec){
		midgard_set_error(self->priv->mgd,
				MGD_GENERIC_ERROR,
				MGD_ERR_USER_DATA,
				"Invalid Object. "
				"Blobs can not be attached to %s",
				G_OBJECT_TYPE_NAME(G_OBJECT(attachment)));
		return;
	}

	g_object_get(G_OBJECT(self->priv->attachment), "location", &location, NULL);

	if(location == NULL || *location == '\0') {
		
		fname = midgard_uuid_new();
		up_a = g_strdup(" ");
		up_a[0] = g_ascii_toupper(fname[0]);
		up_b = g_strdup(" ");
		up_b[0] = g_ascii_toupper(fname[1]);
		/* g_strdup is used to avoid filling every byte, which should be done with g_new(gchar, 2) */
		location = g_build_path(G_DIR_SEPARATOR_S, 
				up_a, up_b, fname, NULL);
	
		g_free(fname);
		g_free(up_a);
		g_free(up_b);

		g_object_set(G_OBJECT(self->priv->attachment), "location", location , NULL);

	}

	self->priv->location = location;

	self->priv->filepath = 
		g_build_path(G_DIR_SEPARATOR_S, 
				self->priv->blobdir, self->priv->location, NULL);
}
/**
 * midgard_connection_open_from_file:	
 * @mgd: #MidgardConnection instance
 * @filepath: configuration file path
 * @error: pointer to store error 
 *
 * Opens a connection to the database. 
 * The configuration file is read from given filepath. 
 * 
 * Take a look at midgard_connection_open() wrt #MidgardSchema.
 *  
 * Returns: %TRUE if the operation succeeded, %FALSE otherwise.
 */ 
gboolean midgard_connection_open_from_file(
		MidgardConnection *mgd, const char *filepath, GError **error)
{	
	g_assert(mgd != NULL);
	g_assert (filepath != NULL);
	g_return_val_if_fail (error == NULL || *error == NULL, FALSE);

	gboolean rv = TRUE;

	__SELF_REOPEN (mgd, rv);
	if (!rv) 
		return rv;
	
	/* FIXME, it should be handled by GError */
	if(mgd->priv->config != NULL){
		midgard_set_error(mgd,
				MGD_GENERIC_ERROR,
				MGD_ERR_USER_DATA,
				"MidgardConfig already associated with "
				"MidgardConnection");
		return FALSE;
	}
	
	MidgardConfig *config = midgard_config_new();

	GError *rf_error = NULL;
	if(!midgard_config_read_file_at_path(config, filepath, &rf_error)) {

		if(rf_error) 
			g_propagate_error(error, rf_error);	

		return FALSE;
	}
	
	if(error)
		g_clear_error(&rf_error);

	mgd->priv->config = config;

	GHashTable *hash = NULL;

	if(!__midgard_connection_open(mgd, &hash, TRUE)) 
		rv = FALSE;

	if(hash)
		g_hash_table_destroy(hash);
	
	return rv;
}
Beispiel #8
0
/**
 * midgard_blob_new: 
 * @attachment: #MidgardObject of MIDGARD_TYPE_ATTACHMENT type.
 * @encoding: file encoding
 * 
 * Default encoding is UTF-8. Set NULL @encoding if such is required. 
 *
 * Instatiate new Midgard Blob object for the given midgard_attachment object. 
 * This is almost the same constructor as g_object_new, but unlike that one,
 * midgard_blob_new requires MidgardObject (midgard_attachment) object's pointer.
 *
 * This constructor defines new relative path for attachment, if midgard_attachment 
 * is associated with midgard_blob and its location is empty. 
 * In any other case, location is not changed.
 * 
 * Returns: newly instatiated #MidgardBlob object or %NULL on failure
 */
MidgardBlob *midgard_blob_new (MidgardObject *attachment, const gchar *encoding)
{
	g_assert(attachment != NULL);
	
	MidgardConnection *mgd = MGD_OBJECT_CNC (attachment);

	if(mgd == NULL) {
		g_critical("MidgardConnection not found for given attachment");
		return NULL;
	}

	MIDGARD_ERRNO_SET(mgd, MGD_ERR_OK);

	const gchar *blobdir = MIDGARD_DBOBJECT (attachment)->dbpriv->mgd->priv->config->blobdir;
	if(!g_file_test(blobdir,G_FILE_TEST_EXISTS)) {
		midgard_set_error(mgd,
				MGD_GENERIC_ERROR,
				MGD_ERR_INTERNAL,
				" Blobs directory doesn't exist. %s", blobdir);
		return NULL;
	}

	if(!g_file_test(blobdir,G_FILE_TEST_IS_DIR)) {
		g_warning("Defined blobs directory is not directory");
		return NULL;
	}

	MidgardBlob *self = g_object_new(MIDGARD_TYPE_BLOB, NULL);
	self->priv->attachment = attachment;
	self->priv->mgd = mgd;
	self->priv->blobdir = g_strdup(blobdir);
	self->priv->channel = NULL;
	self->priv->encoding = NULL;
	if(encoding != NULL)
		self->priv->encoding = g_strdup(encoding);
	
	__get_filepath(self);

	if(self->priv->filepath == NULL) {		
		g_object_unref(self);
		return NULL;
	}
	
	return self;
}
Beispiel #9
0
/**
 * midgard_blob_exists:
 * @self: #MidgardBlob instance
 *
 * Check if file associated with midgard_blob exists.
 * This function will also return FALSE, if file is not yet associated.
 *
 * Returns: %TRUE if file exists, %FALSE otherwise
 */ 
gboolean midgard_blob_exists(MidgardBlob *self)
{
	g_assert(self != NULL);
	
	MidgardConnection *mgd = self->priv->mgd;
	MIDGARD_ERRNO_SET(mgd, MGD_ERR_OK);

	__get_filepath(self);    
	if(!self->priv->filepath)
		return FALSE; 

	if(g_file_test(self->priv->filepath, G_FILE_TEST_IS_DIR)){
		
		midgard_set_error(self->priv->mgd,
				MGD_GENERIC_ERROR,
				MGD_ERR_INTERNAL,
				" '%s' is a directory ", 
				self->priv->filepath);
		return FALSE;
	}


	return g_file_test(self->priv->filepath, G_FILE_TEST_IS_REGULAR);
}
Beispiel #10
0
/**
 * midgard_blob_read_content:
 * @self: MidgardBlob self instance
 * @bytes_read: number of bytes read
 *
 * Returned content should be freed when no longer needed.
 * @bytes_read holds size of returned content. 
 *
 * This function should be used to get content of small files.
 * For large and huge ones midgard_blob_get_handler should be used
 * to get file handle.
 * 
 * Returns: content of the file, or %NULL on failure
 */ 
gchar *midgard_blob_read_content(MidgardBlob *self, gsize *bytes_read)
{
	g_assert(self != NULL);

	MidgardConnection *mgd = self->priv->mgd;
	MIDGARD_ERRNO_SET(mgd, MGD_ERR_OK);

	__get_filepath(self);

	if(!self->priv->filepath) {
		 midgard_set_error(mgd,
				 MGD_GENERIC_ERROR,
				 MGD_ERR_USER_DATA,
				 "Invalid attachment. "
				 "Can not read file from empty location");
		 return NULL;
	}	

	__get_channel(self, "r");
	if(!self->priv->channel)
		return NULL;

	GIOChannel *channel = self->priv->channel;

	gchar *content = NULL;
	GError *err = NULL;
	GIOStatus status;
	const gchar *err_msg = "";

	/* Rewind. Channel could be already used for writing. */
	status = g_io_channel_seek_position(channel, 0, G_SEEK_SET, &err);
	if(status != G_IO_STATUS_NORMAL) {
		
		if(err != NULL) 
			err_msg = err->message;
		
		midgard_set_error(self->priv->mgd,
				MGD_GENERIC_ERROR,
				MGD_ERR_INTERNAL,
				" %s ",
				err_msg);

		return NULL;
	}
	g_clear_error(&err);

	g_io_channel_set_encoding (channel, NULL, NULL);
	status =
		g_io_channel_read_to_end(channel,
				&content,
				bytes_read,
				&err);
	
	/* FIXME, I have no idea how to determine file encoding */
	/* Let's set UTF-8 and try again */
	if(status == G_IO_STATUS_ERROR) {

		if(err && err->domain == G_CONVERT_ERROR){
			g_io_channel_set_encoding (channel, "UTF-8", NULL);
			g_clear_error(&err);
			status =
				g_io_channel_read_to_end(channel,
						&content,
						bytes_read,
						&err);
		}
	}	

	if(err) g_clear_error(&err);

	err_msg = "";

	if(status == G_IO_STATUS_NORMAL && *bytes_read == 0){	
		
		if(err != NULL)
			err_msg = err->message;

		midgard_set_error(self->priv->mgd,
				MGD_GENERIC_ERROR,
				MGD_ERR_INTERNAL,
				" %s ",
				err_msg);

		return NULL;
	}
	
	if(err) g_clear_error(&err);

	return content;
}
gboolean _nodes2object(GObject *object, xmlNode *node, gboolean force)
{
	g_assert(object);
	g_assert(node);

	xmlNode *cur = NULL;
	GObject *prop_object;
	gchar *nodeprop = NULL;
	xmlChar *decoded;
	xmlParserCtxtPtr parser;
	MidgardObject *mobject = NULL;
	MidgardObject *lobject = NULL;
	MidgardReflectionProperty *mrp = NULL;
	const gchar *linktype = NULL;

	if(MIDGARD_IS_OBJECT(object)) {
		mobject = MIDGARD_OBJECT(object);
		MidgardObjectClass *klass =
			MIDGARD_OBJECT_GET_CLASS(mobject);
		if(klass)
			mrp = midgard_reflection_property_new(
					MIDGARD_DBOBJECT_CLASS(klass));
	}

	gpointer set_from_xml_func = MIDGARD_DBOBJECT_GET_CLASS(object)->dbpriv->set_from_xml_node;
	if(set_from_xml_func != NULL) {
		MIDGARD_DBOBJECT_GET_CLASS(object)->dbpriv->set_from_xml_node(MIDGARD_DBOBJECT(object), node);
		return TRUE;
	}

	for (cur = node; cur; cur = cur->next) {
		if (cur->type == XML_ELEMENT_NODE) {
		
			linktype = NULL;
	
			GParamSpec *pspec = g_object_class_find_property(
					G_OBJECT_GET_CLASS(G_OBJECT(object)), 
					(const gchar *)cur->name);
			if(pspec) {
				GValue pval = {0, };
				g_value_init(&pval, pspec->value_type);
				
				if(nodeprop)
					g_free(nodeprop);

				nodeprop = (gchar *)xmlNodeGetContent(cur);

				if(mrp) {
					if(midgard_reflection_property_is_link(
								mrp, pspec->name)){
						linktype =
							midgard_reflection_property_get_link_name(
									mrp, pspec->name);
					}
				}

				/* moved out from mrp condition check to avoid nested indents */

				if(linktype && midgard_is_guid(
							(const gchar *) nodeprop)){

					/* Just set property quickly, if property holds a guid */
					GType mtype = midgard_reflection_property_get_midgard_type(mrp, pspec->name);
					if (mtype == MGD_TYPE_GUID) {
						
						g_value_unset(&pval);
						g_object_set(mobject, (const gchar *)cur->name, nodeprop, NULL);
						continue;	
					}

					/* we can use nodeprop directly */
					lobject = midgard_schema_object_factory_get_object_by_guid (
							MIDGARD_DBOBJECT (mobject)->dbpriv->mgd,
							(const gchar *) nodeprop);

					if(!lobject && !force){
						g_object_unref(mrp);
						g_value_unset(&pval);
						midgard_set_error(MGD_OBJECT_CNC (mobject), 
								MGD_GENERIC_ERROR, 
								MGD_ERR_MISSED_DEPENDENCE, 
								" Can not import %s. "
								"No '%s' object identified by '%s'",
								G_OBJECT_TYPE_NAME(object),
								linktype, nodeprop); 
						g_clear_error(&MIDGARD_DBOBJECT (mobject)->dbpriv->mgd->err);	
						return FALSE;
					}
					
					/* When force parameter is set we do not translate guids to ids */
					if(force && !lobject && midgard_is_guid(
								(const gchar *) nodeprop)) {
						
						switch(pspec->value_type) {
							
							case G_TYPE_UINT:
								g_value_set_uint(&pval, 0);
								break;
							
							case G_TYPE_INT:
								g_value_set_int(&pval, 0);
								break;
							
							default:
								goto set_property_unchecked;
								break;
						}
						
						g_object_set_property(
								G_OBJECT(object),
								(const gchar *) cur->name,
								&pval);
						g_value_unset(&pval);
						continue;
					}

					GValue tval = {0, };
					g_value_init(&tval, pspec->value_type);

					g_object_get_property(G_OBJECT(lobject),
							"id", &tval);

					if(G_VALUE_TYPE(&pval) == G_TYPE_INT)
						g_value_transform((const GValue *) &tval,
								&pval);
					else
						g_value_copy((const GValue*) &tval,
								&pval);

					g_object_set_property(
							G_OBJECT(object),
							(const gchar *) cur->name,
							&pval);
					g_value_unset(&pval);
					g_object_unref(lobject);
					g_value_unset(&tval);
					continue;					
				}

				set_property_unchecked:
				switch (G_TYPE_FUNDAMENTAL (pspec->value_type)) {
				
					case G_TYPE_STRING:
						parser = xmlNewParserCtxt();
						decoded = 
							xmlStringDecodeEntities(parser,
									(const xmlChar *) nodeprop, 	
									XML_SUBSTITUTE_REF, 
									0, 0, 0);
						g_value_set_string(&pval, 
								(gchar *)decoded);
						g_free(decoded);
						xmlFreeParserCtxt(parser);
						break;

					case G_TYPE_INT:
						if(nodeprop) 
							g_value_set_int(&pval, 
									(gint)atoi((gchar *)nodeprop));
						break;

					case G_TYPE_UINT:
						if(nodeprop)
							g_value_set_uint(&pval,
									(guint)atoi((gchar *)nodeprop));
						break;

					case G_TYPE_FLOAT:
						g_value_set_float(&pval,
								(gfloat)atof((gchar *)nodeprop));
						break;

					case G_TYPE_BOOLEAN:
						g_value_set_boolean(&pval,
								(gboolean)atoi((gchar*)nodeprop));
						break;

					case G_TYPE_OBJECT:
						g_object_get(G_OBJECT(object),
								(const gchar *) cur->name,
								&prop_object, NULL);
						if (prop_object) {
							_nodes2object(prop_object, cur->children, force);	
							g_value_set_object(&pval, prop_object);
						} else {
							g_warning ("Failed to unserialize '%s' object property. Expected to be initialized by given '%s' instance", (const gchar *) cur->name, G_OBJECT_TYPE_NAME (object));
						}

						break;

					default:
						/* do nothing */
						break;						
				}
				g_object_set_property(
						G_OBJECT(object), 
						(const gchar *) cur->name, 
						&pval);
				g_value_unset(&pval);
			} else {
				g_warning("Undefined property '%s' for '%s'",
						cur->name, G_OBJECT_TYPE_NAME(object));
			}
		}		
	}

	if(nodeprop)
		g_free(nodeprop);

	if(mrp)
		g_object_unref(mrp);

	return TRUE;
}