• Non ci sono risultati.

Capitolo 7 Servizi Web

7.5 Il toolkit gSOAP

7.5.6 Plug-in per il toolkit gSOAP

Il Plug-in (o plugin) è un programma non autonomo che interagisce con un altro programma per ampliarne le funzioni. Il tipico esempio è un plugin per un software di grafica che permette l'utilizzo di un formato grafico non supportato in maniera nativa dal software principale. La capacità di un software di supportare i plugin è generalmente un'ottima caratteristica rendendo possibile l'ampliamento delle sue funzioni in maniera semplice e veloce.

Un Plug-In è quindi un componente aggiuntivo, normalmente sviluppato da terze parti, che permette di estendere le funzionalità di gSOAP. Il toolkit gSOAP consente di usare i Plug-in tramite l’operazione di registrazione che, come vedremo meglio in seguito, si realizza chiamando la funzione int

soap_register_plugin_arg(). Dopo la registrazione un Plug-in ha pieno

accesso alle impostazioni run-time e alle chiamate delle funzioni gSOAP, e i dati locali del plug-in sono associati all’ambiente run-time gSOAP. L’ambiente run-time è la struttura soap. Nella struttura soap fra le varie cose c’è infatti anche un puntatore alla lista delle strutture dati dei vari plug-in registrati in quel momento (in seguito chiameremo questa lista catena dei plugin). Attraverso l’overriding delle chiamate di funzioni gSOAP con le chiamate di funzioni del plug-in, il plug-in stesso estende le capacità di gSOAP.

La funzione che il toolkit mette a disposizione per registrare un plug-in è:

int soap_register_plugin_arg(struct soap *soap, int (*fcreate)

(struc soap *soap,

struct soap_plugin *p, void *arg),

void *arg)

Ai dati locali del plug-in si può accedere tramite una funzione di lookup:

void* soap_lookup_plugin(struct soap*, const char*)

La funzione soap_lookup_plugin() cerca un plugin registrato e restituisce i dati locali associati a quel plug-in. I dati locali del plug-in sono creati quando si registra un plug-in e possono essere usati per memorizzare informazioni che sono rilevanti solo per il plug-in.

La funzione soap_lookup_plugin() ha come argomenti la struttura soap e il nome (char*) del plugin. Restituisce NULL se il plugin non è stato registrato. Altre due funzioni utili possono essere:

7.5 Il toolkit gSOAP

int soap_copy(struct soap *soap); void soap_done(struct soap *soap);

La funzione soap_copy() restituisce un nuovo ambiente gSOAP allocato dinamicamente che è la copia di un altro, in modo che non ci siano dati condivisi fra l’ambiente originale e la copia. La funzione soap_copy() invoca le funzioni di copia del plug-in per copiare i dati locali al plug-in, quindi chi scrive il plug-in deve prevedere le chiamate per fare la copia. La funzione soap_copy()

restituisce un codice di errore gSOAP o SOAP_OK in caso di successo. La funzione soap_done de-registra tutti i plugin-in, quindi questa funzione va chiamata per terminare in modo pulito un ambiente run-time gSOAP. La

soap_done() chiama le funzioni di cancellazione definite nei vari plug-in, funzioni la cui scrittura e definizione è quindi compito di chi sviluppa il plug-in. Vediamo un esempio di definizione di un plug-in. Questo esempio fa l’ovveride delle chiamate send e receive per copiare sul terminale (stderr) tutti i messaggi che sono mandati e ricevuti.

Per prima cosa, scriviamo un file header plugin.h per definire le strutture dati locali al plug-in e definiamo un nome globale per identificare il plug-in:

//file plugin.h

#include "stdsoap2.h"

#define PLUGIN_ID "PLUGIN-1.0"

// some name to identify plugin struct plugin_data // local plugin data

{

int (*fsend)(struct soap*, const char*, size_t); /* to save and use send callback */ size_t (*frecv)(struct soap*, char*, size_t); /* to save and use recv callback*/ };

int plugin(struct soap *soap, struct soap_plugin *plugin,

Da osservare attentamente che nella struttura dei dati locali del plugin sono presenti dei puntatori a funzione per le funzioni di cui si vuole fare l’override. Altra cosa da notare è che in questo file va dichiarata anche la funzione

(plugin() in questo esempio) che sarà poi utilizzata dalla

soap_register_plugin().

Poi scriviamo la funzione per registrare il plugin e le chiamate alle altre funzioni:

//file plugin.c #include "plugin.h"

static const char plugin_id[] = PLUGIN_ID; static int plugin_init(struct soap *soap, struct plugin_data *data); static int plugin_copy(struct soap *soap, struct soap_plugin *dst, struct soap_plugin *src);

static void plugin_delete(struct soap *soap, struct soap_plugin *p);

static int plugin_send(struct soap *soap, const char *buf, size_t len); static size_t plugin_recv(struct soap *soap, char *buf, size_t len); // the registry function:

int plugin(struct soap *soap, struct soap_plugin *p, void *arg)

{

p->id = plugin_id;

7.5 Il toolkit gSOAP

/* optional: when set the plugin must copy its local data */

p->fdelete = plugin_delete; if (p->data)

if (plugin_init(soap, (struct plugin_data*)p->data)) {

free(p->data); // error: could not init return SOAP_EOM; // return error

}

return SOAP_OK; }

static int plugin_init(struct soap *soap,

struct plugin_data *data) {

data->fsend = soap->fsend; // save old recv callback data->frecv = soap->frecv; // save old send callback soap->fsend = plugin_send; /* replace send callback with new /

soap->frecv = plugin_recv; /* replace recv callback with new */

return SOAP_OK; }

// copy plugin data, called by soap_copy() // This is important: we need a deep copy to avoid data sharing by two run-time environments

static int plugin_copy(struct soap *soap,

struct soap_plugin *dst, struct soap_plugin *src) {

if (!(dst->data =

return SOAP_OK; }

// plugin deletion, called by soap_done() static void plugin_delete(struct soap *soap, struct soap_plugin *p) { free(p->data); // free allocated plugin data }

// the new send callback

static int plugin_send(struct soap *soap, const char *buf, size_t len) {

struct plugin_data *data =

(struct plugin_data*)soap_lookup_plugin(soap, plugin_id); /* fetch plugin's local data */ fwrite(buf, len, 1, stderr); // write message to stderr return data->fsend(soap, buf, len);

/* pass data on to old send callback */ }

// the new receive callback

static size_t plugin_recv(struct soap *soap, char *buf, size_t len) {

struct plugin_data *data =

(struct plugin_data*)soap_lookup_plugin(soap, plugin_id); /* fetch plugin's local data */ size_t res = data->frecv(soap, buf, len);

/* get data from old recv callback */ write(buf, res, 1, stderr);

return res; }

7.5 Il toolkit gSOAP

Osservare che nella funzione int plugin(struct soap *soap,

struct soap_plugin *p, void *arg) il campo fdelete della

struct soap_plugin deve contenere un puntatore a funzione. È infatti responsabilità del plug-in la gestione della registrazione (inizializzazione), copia, e cancellazione dei dati e delle funzioni del plug-in stesso.

Un’applicazione può copiare un ambiente runtime (per esempio per creare un nuovo thread) usando la funzione soap_copy(). Questa funzione deve, fra l’altro, copiare la catena dei plugin contenuta nell’ambiente. La copia di ciascun plug-in può avvenire in modo condiviso cioè tale che la nuova replica della catena dei plugin contenga dei puntatori ai dati originali, oppure in modo non condiviso, cioè tale che la replica contenga una nuova copia dei dati. Per usare la copia in modo condiviso, il campo fcopy() della struct soap_plugin() deve essere nullo, altrimenti deve contenere un puntatore a una funzione, scritta dallo sviluppatore del plugin, che provveda a copiare i dati.

Il plug-in appena definito può essere usato nel modo seguente:

struct soap soap; soap_init(&soap);

soap_register_plugin_arg(&soap, plugin, NULL); ...

Documenti correlati