/*
 * Portions of this file Copyright 1999-2005 University of Chicago
 * Portions of this file Copyright 1999-2005 The University of Southern California.
 *
 * This file or a portion of this file is licensed under the
 * terms of the Globus Toolkit Public License, found at
 * http://www.globus.org/toolkit/download/license.html.
 * If you redistribute this file, with or without
 * modifications, you must include this notice in the file.
 */

#ifndef GLOBUS_WSRF_RESOURCE_H
#define GLOBUS_WSRF_RESOURCE_H 1

#include "globus_common.h"
#include "globus_soap_message_handle.h"

EXTERN_C_BEGIN

/**
 * Type of resource-specific data destroy function.
 * @ingroup resource
 *
 * @param data
 *     Resource-specific data object to destroy.
 */
typedef void (*globus_resource_destroy_t)(void * data);

/**
 * Resource handle
 * @ingroup resource
 */
typedef struct globus_resource_s * globus_resource_t;

extern globus_module_descriptor_t globus_i_wsrf_resource_module;
#define GLOBUS_WSRF_RESOURCE_MODULE (&globus_i_wsrf_resource_module)

/**
 * @defgroup resource_error_types Resource Error Types
 * This API uses the globus_result_t/globus_object_t error system defined
 * in the Globus Common module. Each function in this API returns a
 * globus_result_t.
 *
 * All functions will return either GLOBUS_SUCCESS or a non-0 result. In the
 * case of an error condition, the result can be converted into a
 * globus_object_t by calling globus_error_get() on that function. The
 * error can then be queried by calling globus_error_get_type(). This
 * function  will return one of the values in the
 * #globus_wsrf_resource_error_t enumeration. Once globus_error_get() is
 * called, it is the responsibility of the user to free the error by calling
 * globus_object_free().
 */

/**
 * Error Types
 * @ingroup resource_error_types
 */
typedef enum
{
    /** NULL parameter passed to function */
    GLOBUS_WSRF_RESOURCE_ERROR_TYPE_NULL_PARAM = 1024,
    /** Resource with the given name already exists */
    GLOBUS_WSRF_RESOURCE_ERROR_TYPE_DUPLICATE_RESOURCE,
    /** Resource Property with the given name already exists */
    GLOBUS_WSRF_RESOURCE_ERROR_TYPE_DUPLICATE_PROPERTY,
    /** Insufficient memory to perform function */
    GLOBUS_WSRF_RESOURCE_ERROR_TYPE_OUT_OF_MEMORY,
    /** Unknown resource name. */
    GLOBUS_WSRF_RESOURCE_ERROR_TYPE_UNKNOWN_RESOURCE,
    /** Unknown Resource Property name */
    GLOBUS_WSRF_RESOURCE_ERROR_TYPE_UNKNOWN_PROPERTY,
    /** Resource Already Destroyed */
    GLOBUS_WSRF_RESOURCE_ERROR_TYPE_ALREADY_DESTROYED,
    /** Finish on a resource without references */
    GLOBUS_WSRF_RESOURCE_ERROR_TYPE_NO_REFERENCES,
    /** Invalid type for any:any property */
    GLOBUS_WSRF_RESOURCE_ERROR_TYPE_INVALID_ANY
}
globus_wsrf_resource_error_t;

/**
 * @mainpage WSRF Resources
 *
 * A WSRF Resource encapsulates a stateful resource which can be associated
 * with a web service invocation. This library provides service implementors
 * with APIs for managing references to resources, resource-specific data, and
 * for manipulating Resource Properties.
 *
 * Users of this API must activate the @b GLOBUS_WSRF_RESOURCE_MODULE 
 * before caling any of the functions in this API.
 *
 * - @ref resource 
 * - @ref resource_property
 * - @ref resource_error_types
 */

/**
 * @defgroup resource Managing WSRF Resources
 *
 * WSRF Resources.
 *
 * <h2>Resource Management</h2>
 *
 * Services create resource instances using the #globus_resource_create()
 * function. Services can destroy these resources using either
 * globus_resource_destroy(), globus_resource_finish_and_destroy(), or
 * globus_resource_set_destroy_timeout().
 *
 * When a service is invoked, it can call globus_resource_find() with the
 * resource id to obtain a reference to the resource handle. The resource
 * ID is normally sent in a SOAP message in the ReferenceProperties of the
 * EndpointReference---see the globus_wsrf_core_tools API for functions
 * for dealing with Endpoint references.
 *
 * Resource references must be released by calling globus_resource_finish(),
 * or globus_resource_finish_and_destroy() when destroying a resource. All
 * of the * destroy functions will block if there are any outstanding
 * references to a resouce which haven't been finished.
 *
 * <h2>Resource-Specific Data</h2>
 * Resources contain a pointer to service-implementation-specific data.
 * Services may access this pointer via the
 * #globus_resource_get_resource_specific() and
 * #globus_resource_set_resource_specific() functions. The resource library
 * implementation automatically frees the pointer's value by calling the @a
 * destroy_func passed to #globus_resource_set_resource_specific() when the
 * service calls #globus_resource_set_resource_specific() again, or the
 * reference is destroyed.
 *
 * <h2>Type Registry</h2>
 * Resources can be configured to use a specific set of type mappings for
 * converting XML data into native data. Services may access this via the
 * #globus_resource_get_type_registry() and
 * #globus_resource_set_type_registry() functions.
 */
globus_result_t
globus_resource_create(
    const char *                        id,
    globus_resource_t *                 resource);

globus_result_t
globus_resource_find(
    const char *                        id,
    globus_resource_t *                 resource);

globus_result_t
globus_resource_finish(
    globus_resource_t                   resource);

globus_result_t
globus_resource_destroy(
    globus_resource_t                   resource);

globus_result_t
globus_resource_set_destroy_time(
    globus_resource_t                   resource,
    const globus_abstime_t *            timestamp);

globus_result_t
globus_resource_finish_and_destroy(
    globus_resource_t                   resource);

globus_result_t
globus_resource_get_resource_specific(
    globus_resource_t                   resource,
    void **                             data);

globus_result_t
globus_resource_set_resource_specific(
    globus_resource_t                   resource,
    void *                              data,
    globus_resource_destroy_t           destroy_func);

globus_result_t
globus_resource_set_type_registry(
    globus_resource_t                   resource,
    globus_xsd_type_registry_t          registry);

globus_result_t
globus_resource_get_type_registry(
    globus_resource_t                   resource,
    globus_xsd_type_registry_t *        registry);

/**
 * @defgroup resource_property Resource Properties
 *
 * <h2>Resource Property Management</h2>
 * <em>Resource properties</em> are publicly-visible data elements associated
 * with a resource. Functions in this section of the document concern
 * creating, destroying, and modifying the value of <em>resources
 * properties</em>.
 *
 * <em>Resource properties</em> are created by calling
 * globus_resource_create_property() or
 * globus_resource_create_property_callback(). Services should call
 * globus_resource_create_property() to create properties which have
 * relatively static values.  Services should call
 * globus_resource_create_property_callback() to create properties which have
 * dynamic values (for example, if the property is related to a sensor).
 *
 * Services can access property values by calling
 * globus_resource_get_property() and globus_resource_set_property(). The
 * latter will not work with callback-driven resource property values.
 *
 * Resource property values are freed when a new value is set. In the case
 * of a dynamic value, the value returned from globus_resource_get_property()
 * will become invalid the next time the property's value is acccessed.
 *
 * Resource properties can be removed from the resource by calling
 * globus_resource_delete_property() and can be freed and
 * removed from the property by calling globus_resource_destroy_property().
 * The difference between these two functions is that
 * globus_resource_delete_property() does not destroy the property's values
 * but globus_resource_destroy_property() does.
 *
 * When a resource is destroyed, all properties and their values will be
 * destroyed.
 *
 * <h2>Any-valued Resource Properties</h2>
 * Services which require <code>any</code> elements in their <em>resource
 * properties</em> document may create resource properties using the the
 * element QName pointer <code>globus_resource_properties_any_qname</code> to
 * implement them. The <code>type_info</code> associated with this element
 * must be either <code>&amp;xsd_any_info</code> or
 * <code>&amp;xsd_any_array_info</code>. Doing so will allow the
 * WS-ResourceProperties provider implementation to create and update
 * resource properties. Most services will not require this functionality.
 *
 * <h3>When to Use the Any QName</h3>
 * In general, services will not need to use the any element qname mentioned
 * above. It is typically only needed
 * if the resource property document contains an any element and the
 * service does not implement any restrictions on the contents of the
 * element. The SetResourceProperties provider will fail to insert
 * new elements for properties which haven't been explicitly created by
 * the service if the any element is not created. GetResourceProperties
 * and GetMultipleResourceProperties will Fault if the requested QName is not
 * present in the resource properties unless the any element is present.
 *
 * <h3>How to Manipulate any Elements</h3>
 *
 * <em>This subsection describes some low level resource property
 * manipulations which really aren't needed in most service
 * implementations. It is almost always simpler to explicitly create
 * resource properties that would be in an any and ignore the
 * globus_resource_properties_any_qname</em>.
 *
 * When an <code>any</code> resource property is present,
 * globus_resource_get_resource() will behave differently than
 * with normally created properties. Calls to globus_resource_get_property()
 * which would normally fail with a
 * GLOBUS_WSRF_RESOURCE_ERROR_TYPE_UNKNOWN_PROPERTY-type error 
 * may return an any and xsd_any_info.
 *
 * A service which wants to set the value of the any may modify the any's
 * any_info, element, and value fields. Calling
 * globus_resource_set_property() is not necessary unless a new any is
 * allocated because globus_resource_get_any() returned a NULL value.
 *
 * If the <code>any</code> property is created with the xsd_any_array_info
 * type, then sequential calls to globus_resource_get_property() after
 * setting the any's value with different names will return a newly-allocated
 * empty any. The default type of the any_info field for this any will
 * be xsd_any_array_info. If the any's any_info points to that and the
 * value and element are NULL, then the resource can be certain that the
 * any's any_info field can be set to hold an array of the type the element
 * will actually be.
 *
 * The particular elements associated with an any or any_array resource
 * property are most simply deleted by calling globus_resource_set_property()
 * with a NULL property value for the elemnt. This will cause the previous
 * value of the any to be removed, and if it's in an any_array, the any
 * holder for that element will be removed from the any_array as well.
 * Deleting or destroying the
 * <code>globus_resource_properties_any_qname</code> property will destroy
 * both the any and the element or elements it is holding.
 */

/**
 * QName for automatically-handled any resource properties.
 * @ingroup resource_property
 */
extern const xsd_QName * globus_resource_properties_any_qname;
/**
 * Callback type for dynamic resouce property values
 * @ingroup resource_property
 * This function is called when the value of a dynamic resource property is
 * requested. The implementation of this function must generated a new copy
 * of the resource property's value and return it in the @a property pointer.
 * This value will be freed by the caller when the property is destroyed
 * or globus_resource_get_property() is called again which will cause this
 * function to be called again
 *
 * @param arg
 *     Resource specific argument.
 * @param qname
 *     QName of the resource property 
 * @param property
 *     Pointer to a be initialized to the value of the resource property by
 *     this function.
 */
typedef void (*globus_resource_property_callback_t)(
    void *                              arg,
    const xsd_QName *                   qname,
    void **                             property);

globus_result_t
globus_resource_get_property(
    const globus_resource_t             resource,
    const xsd_QName *                   qname,
    void **                             property,
    globus_xsd_type_info_t *            type_info);

globus_result_t
globus_resource_set_property(
    globus_resource_t                   resource,
    const xsd_QName *                   qname,
    void *                              property);

globus_result_t
globus_resource_create_property(
    globus_resource_t                   resource,
    const xsd_QName *                   qname,
    const globus_xsd_type_info_t        type_info,
    void *                              property);

globus_result_t
globus_resource_create_property_callback(
    globus_resource_t                   resource,
    const xsd_QName *                   qname,
    const globus_xsd_type_info_t        type_info,
    globus_resource_property_callback_t callback,
    void *                              callback_arg);

globus_result_t
globus_resource_delete_property(
    globus_resource_t                   resource,
    const xsd_QName *                   qname,
    void **                             property,
    globus_xsd_type_info_t *            type_info);

globus_result_t
globus_resource_destroy_property(
    globus_resource_t                   resource,
    const xsd_QName *                   qname);

EXTERN_C_END

#endif /* GLOBUS_WSRF_RESOURCE_H */
