Camel.Service
From Evolution
Contents |
Camel.Service
CamelService is an abstract class which is the parent class of Camel.Store and Camel.Transport used to define common operations associated with a given mail service.
Services are resolved by URI using Camel.Session.get_service().
Base class
Class instances will always be instantiated by Camel.Session.get_service. It uses the class types in the Camel.Provider#struct CamelProvider to determine which type to create.
typedef enum { CAMEL_SERVICE_DISCONNECTED, CAMEL_SERVICE_CONNECTING, CAMEL_SERVICE_CONNECTED, CAMEL_SERVICE_DISCONNECTING } CamelServiceConnectionStatus; struct _CamelService { CamelObject parent_object; struct _CamelServicePrivate *priv; CamelSession *session; CamelProvider *provider; CamelServiceConnectionStatus status; CamelOperation *connect_op; CamelURL *url; };
Implementations can override this virtual construct
method, but should always chain the call up to the parent class. The url
parameter is the most important, it will contain all of the settings not only to uniquely identify this service, but also any options on it. It will be built using the information defined in the Camel.Provider module for this service. The construct method may parse the url
parameters to define service options, or leave it until connect time.
void camel_service_construct(CamelService *service, CamelSession *session, CamelProvider *provider, CamelURL *url, CamelException *ex);
Connection state
Although services may not necessarily deal with remote resources, CamelService contains a set of connection oriented functions. As a rule, services will always be connected to before they are used in a way which may imply the requirement to be connected. Functions requiring a connected state should just fail if they are not. Any local services should just use the default implementations of these virtual methods.
gboolean camel_service_connect(CamelService *service, CamelException *ex);
This is the time when a service should setup any remote resources, connect to sockets or servers, and so on, based on the url
set in the base CamelService object.
The connect
function will also setup a Camel.Operation for the current thread, that can be used to cancel the connection; since connections may take some time, failure or not.
Then there is a disconnect function. After this is called all remote resources should be closed down. If clean
is false then any connections must just be dropped, regardless of any failures involved. Otherwise the disconnect
may fail, if for example, it cannot synchronise local changes to the remote resource. Note that if clean
is false then this function must not fail.
gboolean camel_service_disconnect(CamelService *service, gboolean clean, CamelException *ex);
And finally a cancellation command. The default implementation for this will send a cancellation request to the connect_op
which will be registered appropriately. This will normally need to be called from another thread.
void camel_service_cancel_connect(CamelService *service);
Although the above scenario lists how the API expects things to work, it is up to the backend to implement this whichever way it sees fit.
For example, instead of the connect
function actually allocating the resources for the connection, it could merely switch the state of the service into a connected state. The service, via another thread or process, could then connect at will as required, silently failing if the server cannot be reached. It must just ensure that a disconnect
invocation closes down the remote connections and stops any more from occuring while in the disconnected state.
Note this will interact (often badly) with the online state of the Camel.Session and the Camel.DiscoStore. i.e. if you are onffline, then even a connect
must not access remote resources. Note that if the later implementation idea above is used, this additional offline state is easier to integrate.
This is complicated by the additional states of CONNECTING and DISCONNECTING. This has been the source of innumerable bugs; the states are probably not required, and the whole connect and disconnect interface is the entire cause of these bugs.
Accessors
Most of these are pointless accessors which access public structure fields, or they should be accessed using the object #Properties instead.
char *camel_service_get_url(CamelService *service); char *camel_service_get_name(CamelService *service, gboolean brief); char *camel_service_get_path(CamelService *service); CamelSession *camel_service_get_session(CamelService *service); CamelProvider *camel_service_get_provider(CamelService *service);
Auth types
The auth types complement the Camel.Provider.authtype
list, in that they will always be a sub-set of the provider authtypes. But unlike the provider authtypes, these will be the actual authentication types supported by the resource identified by the url
for this service.
typedef struct { char *name; char *description; char *authproto; gboolean need_password; } CamelServiceAuthType;
- name
- Is the short name of the authentication type. e.g. "Password". This will be translated based on the translation domain supplied in the Camel.Provider structure for this service.
- description
- Is a longer description of the authentication type. Might be used as a tool-tip or status bar help message, etc.
- authproto
- The string used to select this authentication type. It will be added as an 'authmech' option to the Camel.URL.
- need_password
- This authenication method uses and requires a password to be set. This is normally just used to fine-tune any configuration UI.
And to find the auth-types implemented by this service instance:
GList *camel_service_query_auth_types(CamelService *service, CamelException *ex);
Since this may need to make an implicit connection to the service it may fail, and set the Camel.Exception appropriately. It must also act appropriately if the Camel.Session is offline.
The caller must free the GList, but not its content.
Properties
In addition to the basic Camel.Object properties, CamelService provides additional properties accessors:
Note that these just access members of the url
. This is in preparation for the possibility that services will not be defined by a URI but by other means.
- CAMEL_SERVICE_USERNAME
- Get the username from the
url
for this service. - CAMEL_SERVICE_AUTH
- Retrieve the auth mechanism for this service.
- CAMEL_SERVICE_HOSTNAME
- Hostname.
- CAMEL_SERVICE_PORT
- Port.
- CAMEL_SERVICE_PATH
- Path.
Other properties should be added to replace the accessors above.
Notes
It is debatable whether Camel.Store and Camel.Transport really need to exist as separate object instances from Camel.Service. Infact it makes integrated providers like Exchange and Groupwise rather messy to implement since you must access the same resource using two independent objects.
What would be a cleaner approach is for each of Camel.Store and Camel.Transport to be changed into interfaces, say, CamelIStore and CamelITransport, which would optionally be present on any given CamelService class.
The connect
and disconnect
state machine is far too complex. With 4 states for that, 2 online states for the session and 3 states for the Camel.Store#Camel.DiscoStore that makes 24 potential states, most of which are invalid!! However it needs to properly handle concurrent threads trying to connect and disconnect simultaneously. Locking is used, but that is also complex. See also Camel.Store#Notes.