Questa edizione si applica a:
e a tutte le release e modifiche successive, finché non verrà diversamente indicato nelle nuove edizioni.
Ordinare le pubblicazioni mediante il rappresentante IBM o gli uffici IBM del proprio paese.
In questa sezione vengono descritti lo scopo, l'organizzazione e le convenzioni di questo documento, la Guida alla programmazione di WebSphere Application Server per Edge Components.
In questa guida vengono analizzate le API (application programming interface) disponibili per la personalizzazione di Edge Components per WebSphere Application Server, Versione 6.1. Le informazioni sono rivolte ai programmatori che devono scrivere applicazioni plugin e che devono eseguire altre operazioni di personalizzazione. Anche i progettisti di rete e gli amministratori di sistema possono consultare queste informazioni per conoscere i tipi di personalizzazione possibili.
L'uso delle informazioni contenute in questa guida richiede la conoscenza delle procedure di programmazione tramite l'uso dei linguaggi di programmazione Java o C, a seconda dell'API che si intende utilizzare. Sono documentati sia i metodi che le strutture disponibili in ciascuna interfaccia esposta, ma il programmatore deve sapere come costruire la propria applicazione, come compilarla per il proprio sistema e, infine, come sottoporla a test. Il codice di esempio viene fornito per alcune interfacce, ma gli esempi sono forniti solo come esempi di creazione della propria applicazione.
Questa documentazione utilizza le seguenti convenzioni tipografiche e di definizione dei tasti.
Convenzione | Significato |
---|---|
Grassetto | Quando si fa riferimento alle interfacce utente grafiche (GUI, Graphical User Interfaces), il grassetto evidenzia menu, voci di menu, etichette, pulsanti, icone e cartelle. Inoltre, può essere utilizzato per enfatizzare i nomi di comandi che, altrimenti, verrebbero confusi con il testo circostante. |
A spaziatura fissa | Indica il testo da inserire davanti a un prompt di comandi. Inoltre, indica il testo su video, gli esempi di codice ed estratti di file. |
Corsivo | Indica i valori delle variabili che l'utente deve inserire (ad esempio, il nome per sostituire nomeFile con il nome effettivo di un file). Il corsivo viene inoltre utilizzato per enfatizzare un concetto ed evidenziare i titoli di manuali. |
Ctrl-x | Dove x è il nome di un tasto, indica una sequenza di caratteri di controllo. Ad esempio, Ctrl-c indica: tenere premuto il tasto Ctrl e contemporaneamente premere il tasto c. |
Return | Indica il tasto etichettato con la parola Invio, Enter, Return o con una freccia verso sinistra. |
% | Rappresenta il prompt della shell dei comandi in ambiente Linux e UNIX per un comando che non richiede privilegi root. |
# | Rappresenta il prompt della shell dei comandi in ambiente Linux e UNIX per un comando che richiede i privilegi root. |
C:\ | Rappresenta il prompt dei comandi in ambiente Windows. |
Immissione di comandi | Quando si invita l'utente a "immettere" o "inserire" un comando, digitare il comando e premere Invio. Ad esempio, l'istruzione "Immettere il comando ls" indica: digitare ls al prompt dei comandi e premere Invio. |
[ ] | Racchiude le voci facoltative nelle descrizioni della sintassi. |
{ } | Racchiude gli elenchi da cui è necessario scegliere una voce nelle descrizioni della sintassi. |
| | Separa le voci in un elenco di opzioni racchiuse tra parentesi { } nelle descrizioni della sintassi. |
... | I puntini di sospensione nelle descrizioni della sintassi indicano che è possibile ripetere la voce precedente una o più volte. Negli esempi, indicano che le informazioni sono state omesse dall'esempio per motivi di brevità. |
Le funzioni di accessibilità consentono ad un utente con un svantaggi fisici, quali una mobilità o una vista limitata, di utilizzare agevolmente prodotti software. Queste sono le principali funzioni di accessibilità in WebSphere Application Server, Versione 6.1:
I vostri commenti risultano di estrema importanza poiché consentono di fornire informazioni della massima accuratezza e qualità. In caso di commenti su questa guida o su altra documentazione relativa a Edge Components di WebSphere Application Server:
In questa guida vengono analizzate le API (application programming interfaces) fornite per Edge Components di WebSphere Application Server. (Edge Components di WebSphere Application Server include Caching Proxy e Load Balancer.) Vengono fornite diverse interfacce che consentono agli amministratori di personalizzare le loro installazioni, di cambiare il modo in cui gli Edge Components interagiscono tra loro o di abilitare l'interazione con altri sistemi software.
IMPORTANTE: Caching Proxy è disponibile su tutte le installazioni di Edge Component, con le seguenti eccezioni:
Le API contenute in questo documento indicano diverse categorie.
Caching Proxy dispone di diverse interfacce scritte nella propria sequenza di elaborazione, dove l'elaborazione personalizzata può essere aggiunta o sostituita da una standard. Le personalizzazioni che possono essere eseguite includono l'alterazione o l'aumento di attività, quali:
I programmi applicativi personalizzati, noti anche come plugin di Caching Proxy, vengono chiamati in punti predeterminati nella sequenza di elaborazione del server proxy.
L'API Caching Proxy è stata utilizzata per implementare determinate funzioni di sistema. Ad esempio, il supporto LDAP del server proxy viene implementato come un plugin.
API Caching Proxy descrive nei dettagli l'interfaccia e include le fasi di configurazione del server proxy per utilizzare i programmi del plugin.
Load Balancer può essere personalizzato scrivendo i propri advisor. Gli advisor eseguono la misurazione del carico effettivo sui server. Con un advisor personalizzato, è possibile utilizzare un metodo fornito dall'utente ed è rilevante per la misurazione del carico da parte del sistema. Risulta particolarmente importante se si dispone di sistemi del server Web personalizzati o proprietari.
Advisor personalizzati fornisce informazioni dettagliate sulla scrittura e l'utilizzo degli advisor personalizzati. Include il codice di esempio dell'advisor.
Il codice di esempio per queste API è incluso nel CD-ROM di Edge Components nella directory esempi. Ulteriori esempi di codice sono disponibili sul sito web di WebSphere Application Server, www.ibm.com/software/webservers/appserv/
In questa sezione si analizza l'API (application programming interface) Caching Proxy: di cosa si tratta, perché è utile e come funziona.
IMPORTANTE: Caching Proxy è disponibile su tutte le installazioni di Edge Component, con le seguenti eccezioni:
L'API è un'interfaccia del Caching Proxy che consente di estendere le funzioni di base del server proxy. Per effettuare un'elaborazione personalizzata, è possibile scrivere estensioni o plugin, che includono i seguenti esempi:
L'API Caching Proxy fornisce i seguenti vantaggi:
Prima di scrivere i programmi plugin del Caching Proxy, è necessario essere a conoscenza delle modalità di funzionamento del server proxy. Tale funzionamento del server proxy può essere suddiviso in diverse fasi di elaborazione distinte. Per ciascuna di queste fasi è possibile fornire le proprie funzioni personalizzate mediante l'utilizzo delle API. Ad esempio, si desidera effettuare un'operazione dopo aver letto una richiesta client e prima di eseguire un'altra elaborazione? Oppure si desidera eseguire routine speciali durante l'autenticazione e dopo l'invio del file richiesto?
Con l'API viene fornita una libreria di funzioni specifiche. I programmi di plugin possono chiamare le funzioni API predefinite affinché interagiscano con il processo del server proxy (ad esempio, per gestire le richieste, per leggere e scrivere le intestazioni della richiesta o per scrivere sui log del server proxy). Queste funzioni non devono essere confuse con quelle del plugin, scritte dall'utente, che vengono chiamate dal server proxy. Le funzioni predefinite vengono descritte in Funzioni e macro predefinite.
L'utente indica al server proxy di chiamare le funzioni di plugin nelle fasi appropriate utilizzando le direttive API Caching Proxy corrispondenti nel file di configurazione del server. Queste direttive vengono descritte in Direttive di configurazione del Caching Proxy per le fasi dell'API.
Questo documento include quanto segue:
Questi componenti e queste procedure possono essere utilizzati per scrivere i propri programmi di plugin del Caching Proxy.
L'operazione di base del server proxy può essere suddivisa in fasi in base al tipo di elaborazione eseguita dal server durante quella fase specifica. Ogni fase include un punto di collegamento in cui è possibile eseguire una parte specifica del proprio programma. Aggiungendo le direttive API al file di configurazione del Caching Proxy (ibmproxy.conf), si indica la funzione di plugin che si desidera venga chiamata durante una particolare operazione. È possibile chiamare diverse funzioni di plugin durante una fase particolare del processo, includendo più di una direttiva per quella fase.
Alcune operazioni fanno parte del processo di richiesta del server. In altri termini, il server proxy esegue queste operazioni ogni volta che elabora una richiesta. Vengono poi eseguite altre operazioni indipendentemente dall'elaborazione della richiesta; vale a dire, il server esegue queste operazioni a prescindere dal fatto che ci sia o no una richiesta in fase di elaborazione.
Il programma compilato si trova in un oggetto condiviso, ad esempio, un file DLL o .so, a seconda del sistema operativo. Man mano che il server procede con le operazioni del processo di richiesta, chiama le funzioni plugin associate a ciascuna operazione fino a quando una delle funzioni non indica che la richiesta è stata gestita. Se si specifica più di una funzione di plugin per una fase particolare, tali funzioni vengono definite nell'ordine in cui le relative direttive vengono visualizzate nel file di configurazione.
Se la richiesta non viene gestita da una funzione di plugin (o l'utente non ha incluso una direttiva API del Caching Proxy per quella fase o la funzione di plugin per quella fase ha restituito HTTP_NOACTION), il server esegue l'operazione predefinita.
Nota: ciò è valido per tutte le fasi, tranne per quella relativa al servizio; questa fase non prevede alcuna operazione predefinita.
Figura 1 illustra le fasi del processo del server proxy e definisce l'ordine di elaborazione delle fasi correlate all'elaborazione della richiesta.
Quattro delle fasi presenti nel diagramma vengono eseguite indipendentemente dall'elaborazione di qualsiasi richiesta client. Tali fasi sono correlate all'esecuzione e alla gestione del server proxy. Esse includono quanto segue:
L'elenco riportato di seguito spiega lo scopo di ciascuna fase illustrata nella Figura 1. Non tutte le fasi verranno, comunque, chiamate per una particolare richiesta.
Esegue l'elaborazione dopo la lettura di una richiesta ma prima di qualsiasi altra operazione.
Se si riceve un'indicazione che la richiesta è stata elaborata (HTTP_OK), il server ignora le altre fasi del processo di richiesta ed esegue solo le operazioni Transmogrifier, Log e PostExit.
Utilizza i token di sicurezza memorizzati per controllare il percorso fisico delle protezioni, degli ACL e di altri controlli di accesso, nonché crea le intestazioni WWW-Authenticate necessarie per l'autenticazione di base. Se si scrive la propria funzione di plugin per sostituire questa fase, è necessario creare autonomamente queste intestazioni.
Per ulteriori informazioni, consultare Autenticazione e autorizzazione.
Decodifica, verifica e memorizza i token di sicurezza.
Per ulteriori informazioni, consultare Autenticazione e autorizzazione.
Esegue l'elaborazione dopo l'autorizzazione e l'ubicazione dell'oggetto, ma prima che la richiesta venga soddisfatta.
Se si riceve un'indicazione che la richiesta è stata elaborata (HTTP_OK), il server ignora le altre fasi del processo di richiesta ed esegue solo le operazioni Transmogrifier, Log e PostExit.
Sui sistemi AIX, è necessario un file di esportazione (ad esempio, libmyapp.exp) che elenchi le funzioni di plugin a cui è necessario collegare un file di importazione API del Caching Proxy, libhttpdapi.exp.
Sui sistemi Linux, HP-UX e Solaris, è necessario effettuare un collegamento tra le librerie libhttpdapi e libc.
Sui sistemi Windows, è necessario un file di definizione modulo (.def) che elenchi le funzioni di plugin a cui è necessario collegare HTTPDAPI.LIB.
Accertarsi di includere HTAPI.h e di utilizzare la macro HTTPD_LINKAGE nelle proprie definizioni di funzione. Questa macro assicura che tutte le funzioni utilizzeranno le stesse convenzioni di chiamata.
Utilizzare i seguenti comandi di compilazione e collegamento come linea guida.
cc_r -c -qdbxextra -qcpluscmt foo.c
cc_r -bM:SRE -bnoentry -o libfoo.so foo.o -bI:libhttpdapi.exp -bE:foo.exp
(Questo comando viene illustrato su due righe solo per facilitarne la lettura.)
cc -Ae -c +Z +DAportable
aCC +Z -mt -c +DAportable
gcc -c foo.c
ld -G -Bsymbolic -o libfoo.so foo.o -lhttpdapi -lc
cc -mt -Bsymbolic -c foo.c
cc -mt -Bsymbolic -G -o libfoo.so foo.o -lhttpdapi -lc
cl /c /MD /DWIN32 foo.c
link httpdapi.lib foo.obj /def:foo.def /out:foo.dll /dll
Per specificare le esportazioni, utilizzare uno dei seguenti metodi:
Seguire la sintassi presentata in Prototipi della funzione del plugin per scrivere le proprie funzioni del programma per le fasi di elaborazione della richiesta definite.
Ciascuna delle funzioni deve completare il parametro del codice di ritorno con un valore che indica l'azione eseguita:
I prototipi della funzione per ogni fase del Caching Proxy mostrano il formato da utilizzare e illustrano il tipo di elaborazione da eseguire. Tenere presente che i nomi funzione non sono predefiniti. È necessario fornire nomi univoci alle funzioni utilizzando le proprie convenzioni di denominazione. Per rendere più semplice l'associazione, questo documento utilizza i nomi che si riferiscono alle fasi di elaborazione del server.
In ciascuna di queste funzioni del plugin, sono valide alcune funzioni API predefinite. Alcune delle funzioni predefinite non sono valide per tutte le fasi. Le funzioni API riportate di seguito sono valide se chiamate da tutte queste funzioni del plugin:
Nelle descrizioni relative al prototipo della funzione, vi sono ulteriori funzioni API valide o non valide.
Il valore del parametro handle inviato alle funzioni può essere inoltrato come primo argomento per le funzioni predefinite. Le funzioni API predefinite sono descritte in Funzioni e macro predefinite.
void HTTPD_LINKAGE ServerInitFunction ( unsigned char *handle, unsigned long *major_version, unsigned long *minor_version, long *return_code )
A function defined for this step is called once when your module is loaded during server initialization. It is your opportunity to perform initialization before any requests have been accepted.
Although all server initialization functions are called, a error return code from a function in this step causes the server to ignore all other functions configured in the same module as the function that returned the error code. (That is, any other functions contained in the same shared object as the function that returned the error are not called.)
The version parameters contain the server proxy's version number; these are supplied by the Caching Proxy.
void HTTPD_LINKAGE PreExitFunction ( unsigned char *handle, long *return_code )
A function defined for this step is called for each request after the request has been read but before any processing has occurred. A plug-in at this step can be used to access the client's request before it is processed by the Caching Proxy.
Valid return codes for the preExit function are the following:
Other return codes must not be used.
If this function returns HTTP_OK, the server proxy assumes that the request has been handled. All subsequent request processing steps are bypassed, and only the response steps (Transmogrifier, Log, and PostExit) are performed.
All predefined API functions are valid during this step.
void HTTPD_LINKAGE MidnightFunction ( unsigned char *handle, long *return_code )
A function defined for this step runs daily at midnight and contains no request context. For example, it can be used to invoke a child process to analyze logs. (Note that extensive processing during this step can interfere with logging.)
void HTTPD_LINKAGE AuthenticationFunction ( unsigned char *handle, long *return_code )
A function defined for this step is called for each request based on the request's authentication scheme. This function can be used to customize verification of the security tokens that are sent with a request.
void HTTPD_LINKAGE NameTransFunction ( unsigned char *handle, long *return_code )
Per ogni richiesta viene chiamata una funzione definita per questa fase. Se si desidera che la funzione plugin venga chiamata solo per le richieste che corrispondono alla maschera, è possibile specificare una maschera URL nella direttiva del file di configurazione. La fase di Conversione nome si verifica prima che la richiesta venga elaborata e fornisce un meccanismo per la mappatura degli URL sugli oggetti, quali nomi di file.
void HTTPD_LINKAGE AuthorizationFunction ( unsigned char *handle, long *return_code )
Per ogni richiesta viene chiamata una funzione definita per questa fase. Se si desidera che la funzione plugin venga chiamata solo per le richieste che corrispondono alla maschera, è possibile specificare una maschera URL nella direttiva del file di configurazione. La fase di Autorizzazione si verifica prima che la richiesta venga elaborata e può essere utilizzata per verificare se l'oggetto identificato possa essere restituito al client. Se si effettua l'autenticazione di base, è necessario creare le intestazioni WWW-Authenticate.
void HTTPD_LINKAGE ObjTypeFunction ( unsigned char *handle, long *return_code )
Per ogni richiesta viene chiamata una funzione definita per questa fase. Se si desidera che la funzione plugin venga chiamata solo per le richieste che corrispondono alla maschera, è possibile specificare una maschera URL nella direttiva del file di configurazione. La fase Tipo di oggetto si verifica prima che la richiesta venga elaborata e può essere utilizzata per controllare l'esistenza dell'oggetto e per immettere l'oggetto.
void HTTPD_LINKAGE PostAuthFunction ( unsigned char *handle, long *return_code )
Una funzione definita per questa fase viene richiamata dopo che la richiesta è stata autorizzata, ma prima di qualsiasi altra elaborazione. Se questa funzione restituisce HTTP_OK, il server proxy presume che la richiesta sia stata gestita. Tutte le successive fasi di richiesta vengono ignorate e verranno eseguite solo le fasi del processo di risposta (Transmogrifier, Log e PostExit).
In questa fase, sono valide tutte le funzioni predefinite del server.
void HTTPD_LINKAGE ServiceFunction ( unsigned char *handle, long *return_code )
Per ciascuna richiesta viene chiamata una funzione definita per questa fase. Se si desidera che la funzione del plugin venga chiamata solo per le richieste che corrispondono alla maschera, è possibile specificare una maschera URL nella direttiva del file di configurazione. La fase relativa al Servizio soddisfa la richiesta, nel caso non fosse stata soddisfatta nelle fasi PreExit o PostAuthorization.
In questa fase, sono valide tutte le funzioni predefinite del server.
Fare riferimento alla direttiva Enable nella Guida alla gestione per WebSphere Application Server Caching Proxy per informazioni sulla configurazione della funzione Servizio da eseguire in base al metodo HTTP piuttosto che in base all'URL.
In questa fase, è necessario implementare le seguenti quattro funzioni. (Non è necessario che i nomi delle funzioni corrispondano a questi nomi.)
void * HTTPD_LINKAGE openFunction ( unsigned char *handle, long *return_code )
La funzione open esegue qualsiasi inizializzazione (ad esempio l'assegnazione del buffer) necessaria per elaborare i dati di questo flusso. Qualsiasi codice di ritorno diverso da HTTP_OK causa l'interruzione dell'operazione di filtraggio (le funzioni write e close non vengono chiamate). La funzione può restituire un puntatore vuoto, in questo modo l'utente può assegnare spazio a una struttura e fare in modo che il puntatore gli venga restituito nel parametro correlator delle funzioni successive.
void HTTPD_LINKAGE writeFunction ( unsigned char *handle, unsigned char *data, /* dati di risposta inviati dal server di origine */ unsigned long *length, /* lunghezza dei dati di risposta */ void *correlator, /* puntatore restituito dalla funzione 'open' */ long *return_code )
La funzione write elabora i dati e può richiamare la funzione HTTPD_write() predefinita del server con i dati nuovi o modificati. Il plugin non tenta di liberare il buffer inviato al server o presuppone che il server liberi il buffer ricevuto.
Se, nell'ambito della funzione write, si decide di non modificare i dati, risulta ancora necessario chiamare la funzione HTTPD_write() nell'ambito della funzione open, write o close per inviare i dati della risposta al client. L'argomento correlator è il puntatore al buffer di dati restituito nella routine open.
void HTTPD_LINKAGE closeFunction ( unsigned char *handle, void *correlator, long *return_code )
La funzione close effettua tutte le operazioni di ripulitura (ad esempio, svuotare e liberare il buffer del correlatore) necessarie per completare l'elaborazione dei dati in questo flusso. L'argomento correlator è il puntatore al buffer di dati restituito nella routine open.
void HTTPD_LINKAGE errorFunction ( unsigned char *handle, void *correlator, long *return_code )
La funzione error abilita le prestazioni delle azioni di ripulitura, ad esempio lo svuotamento o la liberazione dei dati memorizzati nel buffer (o entrambe) prima che venga inviata una pagina di errore. A questo punto, vengono chiamate le funzioni open, write e close per elaborare la pagina di errore. L'argomento correlator è il puntatore al buffer di dati restituito nella routine open.
Note:
void HTTPD_LINKAGE GCAdvisorFunction ( unsigned char *handle, long *return_code )
Per ogni file presente nella cache durante la raccolta dei dati inutili, viene chiamata una funzione definita per questa fase. Tale funzione consente di influenzare i file che vengono conservati e quelli che vengono eliminati. Per ulteriori informazioni, consultare le variabili GC_*.
void HTTPD_LINKAGE ProxyAdvisorFunction ( unsigned char *handle, long *return_code )
Durante il servizio di ogni richiesta proxy, viene chiamata una funzione definita per questa fase. Tale funzione può essere utilizzata, ad esempio, per impostare la variabile USE_PROXY.
void HTTPD_LINKAGE LogFunction ( unsigned char *handle, long *return_code )
Dopo che ogni richiesta è stata elaborata e che la comunicazione con il client è stata interrotta viene chiamata una funzione definita per questa fase. Se si desidera che la funzione plugin venga chiamata solo per le richieste che corrispondono alla maschera, è possibile specificare una maschera URL nella direttiva del file di configurazione. Questa funzione viene chiamata indipendentemente dal fatto che la richiesta sia stata elaborata correttamente. Se non si desidera che il plugin di log sostituisca il meccanismo di log, impostare il codice di ritorno su HTTP_NOACTION invece che su HTTP_OK.
void HTTPD_LINKAGE ErrorFunction ( unsigned char *handle, long *return_code )
Per ogni richiesta che ha esito negativo viene chiamata una funzione definita per questa fase. Se si desidera che la funzione del plugin venga chiamata solo per le richieste non riuscite che corrispondono alla maschera, è possibile specificare una maschera URL nella direttiva del file di configurazione. La fase Error consente di personalizzare la risposta all'errore.
void HTTPD_LINKAGE PostExitFunction ( unsigned char *handle, long *return_code )
Per ogni richiesta, completata o non completata correttamente, viene chiamata una funzione definita per questa fase. Questa fase consente di deallocare tutte le risorse assegnate dal plugin per elaborare la richiesta.
void HTTPD_LINKAGE ServerTermFunction ( unsigned char *handle, long *return_code )
Quando si verifica una chiusura corretta del server, viene chiamata una funzione definita per questa fase. Essa consente di deallocare le risorse assegnate durante la fase di Inizializzazione del server. Non chiamare le funzioni HTTP_* in questa fase (i risultati sono imprevedibili). Se esiste più di una direttiva API del Caching Proxy nel file di configurazione per la fase Chiusura del server, verranno chiamate tutte.
Questi codici di ritorno seguono la specifica HTTP 1.1, RFC 2616, pubblicata dal World Wide Web Consortium (www.w3.org/pub/WWW/Protocols/). Le funzioni del plugin devono restituire uno di questi valori.
Valore | Codice di ritorno |
0 | HTTP_NOACTION |
100 | HTTP_CONTINUE |
101 | HTTP_SWITCHING_PROTOCOLS |
200 | HTTP_OK |
201 | HTTP_CREATED |
202 | HTTP_ACCEPTED |
203 | HTTP_NON_AUTHORITATIVE |
204 | HTTP_NO_CONTENT |
205 | HTTP_RESET_CONTENT |
206 | HTTP_PARTIAL_CONTENT |
300 | HTTP_MULTIPLE_CHOICES |
301 | HTTP_MOVED_PERMANENTLY |
302 | HTTP_MOVED_TEMPORARILY |
302 | HTTP_FOUND |
303 | HTTP_SEE_OTHER |
304 | HTTP_NOT_MODIFIED |
305 | HTTP_USE_PROXY |
307 | HTTP_TEMPORARY_REDIRECT |
400 | HTTP_BAD_REQUEST |
401 | HTTP_UNAUTHORIZED |
403 | HTTP_FORBIDDEN |
404 | HTTP_NOT_FOUND |
405 | HTTP_METHOD_NOT_ALLOWED |
406 | HTTP_NOT_ACCEPTABLE |
407 | HTTP_PROXY_UNAUTHORIZED |
408 | HTTP_REQUEST_TIMEOUT |
409 | HTTP_CONFLICT |
410 | HTTP_GONE |
411 | HTTP_LENGTH_REQUIRED |
412 | HTTP_PRECONDITION_FAILED |
413 | HTTP_ENTITY_TOO_LARGE |
414 | HTTP_URI_TOO_LONG |
415 | HTTP_BAD_MEDIA_TYPE |
416 | HTTP_BAD_RANGE |
417 | HTTP_EXPECTATION_FAILED |
500 | HTTP_SERVER_ERROR |
501 | HTTP_NOT_IMPLEMENTED |
502 | HTTP_BAD_GATEWAY |
503 | HTTP_SERVICE_UNAVAILABLE |
504 | HTTP_GATEWAY_TIMEOUT |
505 | HTTP_BAD_VERSION |
È possibile richiamare le funzioni e le macro predefinite del server dalle funzioni del plugin. A tal fine, utilizzare i relativi nomi predefiniti e rispettare il formato descritto di seguito. Nelle descrizioni relative al parametro, la lettera i indica un parametro di input, la lettera o indica un parametro di output e le lettere i/o indicano che un parametro viene utilizzato sia per l'input sia per l'output.
Ciascuna di queste funzioni restituisce uno dei codici di ritorno HTTPD, a seconda della corretta esecuzione della richiesta. Questi codici vengono descritti in Codici di ritorno delle funzioni e delle macro predefinite.
Quando vengono chiamate queste funzioni, utilizzare come primo parametro l'handle fornito al plugin. Altrimenti, la funzione restituisce un codice di errore HTTPD_PARAMETER_ERROR. NULL non è accettato come handle valido.
void HTTPD_LINKAGE HTTPD_authenticate ( unsigned char *handle, /* i; handle */ long *return_code /* o; codice di ritorno */ )
void HTTPD_LINKAGE HTTPD_cacheable_url ( unsigned char *handle, /* i; handle */ unsigned char *url, /* i; URL da controllare */ unsigned char *req_method, /* i; metodo di richiesta per l'URL */ long *retval /* o; codice di ritorno */ )
Il valore di ritorno HTTPD_SUCCESS indica che il contenuto dell'URL può essere memorizzato nella cache; mentre HTTPD_FAILURE indica il contrario. Anche HTTPD_INTERNAL_ERROR è un possibile codice di ritorno per questa funzione.
void HTTPD_LINKAGE HTTPD_close ( unsigned char *handle, /* i; handle */ long *return_code /* o; codice di ritorno */ )
void HTTPD_LINKAGE HTTPD_exec ( unsigned char *handle, /* i; handle */ unsigned char *name, /* i; nome dello script da eseguire */ unsigned long *name_length, /* i; lunghezza del nome */ long *return_code /* o; codice di ritorno */ )
void HTTPD_LINKAGE HTTPD_extract ( unsigned char *handle, /* i; handle */ unsigned char *name, /* i; nome della variabile da estrarre */ unsigned long *name_length, /* i; lunghezza del nome */ unsigned char *value, /* o; buffer in cui inserire il valore */ unsigned long *value_length, /* i/o; dimensione del buffer */ long *return_code /* o; codice di ritorno */ )
Se questa funzione restituisce il codice HTTPD_BUFFER_TOO_SMALL, significa che la dimensione del buffer richiesta non è sufficientemente grande per il valore estratto. In questo caso, la funzione non utilizza il buffer, ma aggiorna il parametro value_length con la dimensione del buffer necessaria per estrarre questo valore con esito positivo. Tentare nuovamente l'estrazione con un buffer che sia abbastanza grande da contenere il parametro value_length restituito.
void HTTPD_LINKAGE HTTPD_file ( unsigned char *handle, /* i; handle */ unsigned char *name, /* i; nome del file da inviare */ unsigned long *name_length, /* i; lunghezza del nome */ long *return_code /* o; codice di ritorno */ )
const unsigned char * /* o; valore della variabile */ HTTPD_LINKAGE httpd_getvar( unsigned char *handle, /* i; handle */ unsigned char *name, /* i; nome variabile */ unsigned long *n /* i; numero indice per la matrice contenente l'intestazione */ )
L'indice della matrice che contiene l'intestazione comincia con 0. Per ottenere la prima voce nella matrice, utilizzare il valore 0 al posto di n; per ottenere la quinta voce, utilizzare il valore 4 al posto di n.
void HTTPD_LINKAGE HTTPD_log_access ( unsigned char *handle, /* i; handle */ unsigned char *value, /* i; dati da scrivere */ unsigned long *value_length, /* i; lunghezza dei dati */ long *return_code /* o; codice di ritorno */ )
Si noti che i simboli escape non sono richiesti durante la scrittura del simbolo di percentuale (%) nei log di accesso del server.
void HTTPD_LINKAGE HTTPD_log_error ( unsigned char *handle, /* i; handle */ unsigned char *value, /* i; dati da scrivere */ unsigned long *value_length, /* i; lunghezza dei dati */ long *return_code /* o; codice di ritorno */ )
Si noti che i simboli escape non sono richiesti durante la scrittura del simbolo di percentuale (%) nei log degli errori del server.
void HTTPD_LINKAGE HTTPD_log_event ( unsigned char *handle, /* i; handle */ unsigned char *value, /* i; dati da scrivere */ unsigned long *value_length, /* i; lunghezza dei dati */ long *return_code /* o; codice di ritorno */ )
Si noti che i simboli escape non sono richiesti durante la scrittura del simbolo di percentuale (%) nei registri eventi del server.
void HTTPD_LINKAGE HTTPD_log_trace ( unsigned char *handle, /* i; handle */ unsigned char *value, /* i; dati da scrivere */ unsigned long *value_length, /* i; lunghezza dei dati */ long *return_code /* o; codice di ritorno */ )
Si noti che i simboli escape non sono richiesti durante la scrittura del simbolo di percentuale (%) nei registri di tracce del server.
void HTTPD_LINKAGE HTTPD_open ( unsigned char *handle, /* i; handle */ long *return_code /* o; codice di ritorno */ )
void HTTPD_LINKAGE HTTPD_proxy ( unsigned char *handle, /* i; handle */ unsigned char *url_name, /* i; URL per la richiesta proxy */ unsigned long *name_length, /* i; lunghezza dell'URL */ void *request_body, /* i; corpo della richiesta */ unsigned long *body_length, /* i; lunghezza del corpo */ long *return_code /* o; codice di ritorno */ )
void HTTPD_LINKAGE HTTPD_read ( unsigned char *handle, /* i; handle */ unsigned char *value, /* i; buffer dei dati */ unsigned long *value_length, /* i/o; dimensione del buffer (lunghezza dati) */ long *return_code /* o; codice di ritorno */ )
void HTTPD_LINKAGE HTTPD_restart ( long *return_code /* o; codice di ritorno */ )
Si noti che con questa funzione è anche possibile creare delle variabili. Le variabili create sono soggette alle convenzioni dei prefissi HTTP_ e PROXY_, descritti in Variabili. Se si crea una variabile che comincia con HTTP_, essa viene inviata come intestazione nella risposta al client, senza il prefisso HTTP_. Ad esempio, per impostare un'intestazione di ubicazione, utilizzare HTTPD_set() con il nome variabile HTTP_LOCATION. Le variabili create con un prefisso PROXY_ vengono inviate come intestazioni nella richiesta al server dei contenuti. Le variabili create con un prefisso CGI_ vengono inviate ai programmi CGI.
Questa funzione è valida in tutte le fasi; tuttavia, non tutte le variabili sono valide in tutte le fasi.
void HTTPD_LINKAGE HTTPD_set ( unsigned char *handle, /* i; handle */ unsigned char *name, /* i; nome del valore da impostare */ unsigned long *name_length, /* i; lunghezza del nome */ unsigned char *value, /* i; buffer con valore */ unsigned long *value_length, /* i; lunghezza del valore */ long *return_code /* o; codice di ritorno */ )
long /* o; codice di ritorno */ HTTPD_LINKAGE httpd_setvar ( unsigned char *handle, /* i; handle */ unsigned char *name, /* i; nome variabile */ unsigned char *value, /* i; nuovo valore */ unsigned long *addHdr /* i; aggiungere intestaz. o sostituirla */ )
Il parametro addHdr ha quattro valori possibili:
Questi valori vengono definiti in HTAPI.h.
void HTTPD_LINKAGE httpd_variant_insert ( unsigned char *handle, /* i; handle */ unsigned char *URI, /* i; URI di questo oggetto */ unsigned char *dimension, /* i; dimensione della variante */ unsigned char *variant, /* i; valore della variante */ unsigned char *filename, /* i; file contenente l'oggetto */ long *return_code /* o; codice di ritorno */ )
Note:
Mozilla 4.0 (compatible; BatBrowser 94.1.2; Bat OS)
void HTTPD_LINKAGE httpd_variant_lookup ( unsigned char *handle, /* i; handle */ unsigned char *URI, /* URI di questo oggetto */ unsigned char *dimension, /* i; dimensione della variante */ unsigned char *variant, /* i; valore della variante */ long *return_code); /* o; codice di ritorno */
Se la prima volta che si chiama questa funzione non viene impostato il tipo di contenuto, il server presume che si sta inviando un flusso di dati CGI.
void HTTPD_LINKAGE HTTPD_write ( unsigned char *handle, /* i; handle */ unsigned char *value, /* i; dati da inviare */ unsigned char *value_length, /* i; lunghezza dei dati */ long *return_code); /* o; codice di ritorno */
Il server imposterà il parametro del codice di ritorno su uno di questi valori, a seconda della riuscita della richiesta:
Valore | Codice stato | Spiegazione |
---|---|---|
-1 | HTTPD_UNSUPPORTED | La funzione non è supportata. |
0 | HTTPD_SUCCESS | La funzione ha avuto esito positivo e i campi di output sono validi. |
1 | HTTPD_FAILURE | La funzione ha avuto esito negativo. |
2 | HTTPD_INTERNAL_ERROR | È stato rilevato un errore interno, quindi non è possibile proseguire l'elaborazione di questa richiesta. |
3 | HTTPD_PARAMETER_ERROR | Sono stati inoltrati uno o più parametri non validi. |
4 | HTTPD_STATE_CHECK | La funzione non è valida in questa fase del processo. |
5 | HTTPD_READ_ONLY | (Restituito solo da HTTPD_set e httpd_setvar.) La variabile è in sola lettura e non può essere impostata dal plugin. |
6 | HTTPD_BUFFER_TOO_SMALL | (Restituito da HTTPD_set, httpd_setvar e HTTPD_read.) Il buffer fornito è troppo piccolo. |
7 | HTTPD_AUTHENTICATE_FAILED | (Restituito solo da HTTPD_authenticate.) L'autenticazione ha avuto esito negativo. Per ulteriori informazioni, esaminare le variabili HTTP_RESPONSE e HTTP_REASON. |
8 | HTTPD_EOF | (Restituito solo da HTTPD_read.) Indica la fine del corpo della richiesta. |
9 | HTTPD_ABORT_REQUEST | La richiesta è stata interrotta perché il client ha fornito una tag entità che non corrisponde alla condizione specificata dalla richiesta. |
10 | HTTPD_REQUEST_SERVICED | (Restituito da HTTPD_proxy.) La funzione chiamata ha completato la risposta per questa richiesta. |
11 | HTTPD_RESPONSE_ALREADY_COMPLETED | La funzione ha avuto esito negativo perché la risposta per quella richiesta è già stata completata. |
12 | HTTPD_WRITE_ONLY | La variabile è in sola scrittura e non può essere letta dal plug-in. |
Ogni fase di questo processo di richiesta ha una direttiva di configurazione che viene utilizzata per indicare quale delle funzioni dei plugin si desidera chiamare ed eseguire durante quella fase specifica. Tali direttive possono essere aggiunte al file di configurazione del server (ibmproxy.conf) modificandolo e aggiornandolo manualmente o utilizzando il modulo Elaborazione delle richieste API contenuto nei moduli Configurazione e gestione del Caching Proxy.
Ciò significa che il server elabora le direttive Service, NameTrans, Exec, Fail, Map, Pass, Proxy, ProxyWAS e Redirect nella relativa sequenza all'interno del file di configurazione. Se il server mappa con esito positivo un'URL su un file, esso non legge né elabora nessun altra direttiva. (La direttiva Map è un'eccezione. Per informazioni complete sulle regole di mappatura del server proxy, fare riferimento alla Guida alla gestione per WebSphere Application Server Caching Proxy.)
Queste direttive del file di configurazione devono essere visualizzate nel file ibmproxy.conf su un'unica riga, senza spazi se non quelli ivi specificati esplicitamente. Sebbene per agevolare la leggibilità, in alcuni esempi di sintassi potrebbero apparire delle interruzioni di riga, è necessario che in quei punti della direttiva reale non vi siano spazi.
Le variabili contenute in queste direttive hanno i seguenti significati:
Se si desidera accedere alle informazioni presenti sul percorso, la direttiva Servizio richiede un asterisco (*) dopo il nome della funzione.
Per ulteriori informazioni su queste direttive, inclusa la sintassi, consultare la Guida alla gestione per WebSphere Application Server Caching Proxy.
L'API del Caching Proxy è compatibile con le versioni precedenti di ICAPI e GWAPI, mediante la versione 4.6.1.
Utilizzare le seguenti linee guida per far sì che le applicazioni CGI scritte in C utilizzino l'API del Caching Proxy:
Durante la scrittura dei programmi API, è possibile utilizzare le variabili del Caching Proxy che forniscono informazioni sul sistema server e client remoto.
Note:
ACCEPT_RANGES BYTES CLIENT_ADDR 9.67.84.3
Questa variabile può essere utilizzata nelle fasi PostAuthorization, PostExit, ProxyAdvisor o Log.
http://www.anynet.com/~userk/main.htm
Mon, 01 Mar 2002 19:41:17 GMT
Mon, 01 Mar 1998 19:41:17 GMT
d:\wwwhome\foo
/wwwhome/foo
application/x-www-form-urlencoded
7034
NAME=Eugene+T%2E+Fox&ADDR=etfox%7Cibm.net&INTEREST=xyz
http://www.company.com/homepage
application/x-www-form-urlencoded
Breve riesame della terminologia:
Figura 3 illustra il processo di autorizzazione e autenticazione del server proxy.
Come dimostrato in Figura 3, l'avvio del processo di autorizzazione è il primo passo del processo di autorizzazione e autenticazione del server.
Nel Caching Proxy, l'autenticazione fa parte del processo di autorizzazione; si verifica solo quando viene richiesta l'autorizzazione.
Il server proxy segue queste fasi durante l'elaborazione di una richiesta che richiede l'autorizzazione.
Se il plugin del Caching Proxy fornisce il proprio processo di autorizzazione, questo sostituisce l'autorizzazione e l'autenticazione predefinita del server. Tuttavia, se nel file di configurazione sono presenti direttive di autorizzazione, è necessario che anche le funzioni del plugin ad esse associate gestiscano qualsiasi autorizzazione necessaria. A questo scopo viene fornita la funzione HTTPD_authenticate() predefinita.
Esistono tre metodi per fornire l'autenticazione nei plugin di autorizzazione:
Una volta effettuata l'operazione di autorizzazione, viene eseguita la funzione del plugin di autorizzazione, che a sua volta chiama la funzione del plugin di autenticazione.
Una volta effettuata l'operazione di autorizzazione, viene eseguita la funzione del plugin di autorizzazione che, a sua volta, chiama l'autenticazione predefinita del server.
Una volta eseguita l'operazione di autorizzazione, viene eseguita la funzione del plugin di autorizzazione, incluse eventuali autenticazioni.
Se il plugin del Caching Proxy non fornisce il processo di autorizzazione, è ancora possibile fornire un'autenticazione personalizzata utilizzando il seguente metodo:
Una volta effettuata l'operazione di Autorizzazione, viene eseguita l'autorizzazione predefinita del server che, a sua volta, chiama la funzione del plugin di autenticazione.
Tenere presenti i seguenti punti:
Utilizzare la funzione di memorizzazione nella cache della variante per memorizzare i dati, vale a dire un modulo modificato del documento originale (l'URI). Il Caching Proxy gestisce le varianti generate dall'API. Le varianti rappresentano versioni differenti di un documento di base.
In genere, quando i server di origine inviano delle varianti, la loro identificazione in quanto tali ha esito negativo. Il Caching Proxy supporta solo le varianti create dai plugin (ad esempio, la conversione della code page). Se un plugin crea una variante in base a criteri non presenti nell'intestazione HTTP, è necessario includere un funzione della fase PreExit o PostAuthorization per creare una pseudo intestazione in modo che il Caching Proxy possa identificare correttamente la variante esistente.
Ad esempio, utilizzare un programma API Transmogrifier per modificare i dati richiesti dagli utenti in base al valore dell'intestazione User-Agent inviato dal browser. Nella funzione close, salvare il contenuto modificato in un file o specificare una lunghezza del buffer e inoltrare il buffer come argomento dati. Quindi, utilizzare le funzioni di memorizzazione nella cache della variante, httpd_variant_insert() e httpd_variant_lookup(), per inserire il contenuto nella cache.
Per un'introduzione alle funzioni delle API del Caching Proxy, prendere in esame i programmi di esempio forniti nella directory esempi del CD-ROM di installazione di Edge Components. Altre informazioni sono disponibili sul sito web di WebSphere Application Server, www.ibm.com/software/webservers/appserv/.
Questa sezione analizza la scrittura degli advisor personalizzati per Load Balancer.
Gli advisor sono agenti software che operano all'interno di Load Balancer per fornire informazioni relative al carico su un server specifico. Esiste un advisor differente per ciascun protocollo standard (HTTP, SSL e altri). Periodicamente, il codice di base del Load Balancer esegue un ciclo di advisor, durante il quale valuta singolarmente lo stato di tutti i server della sua configurazione.
Scrivendo i propri advisor per il Load Balancer, è possibile personalizzare la modalità con cui viene ripartito il carico tra le macchine server.
Su sistemi Windows: Con le installazioni Load Balancer for IPv4 and IPv6, se si sta utilizzando il protocollo IPv6 e si desidera utilizzare gli advisor, è necessario modificare il file del protocollo che si trova nella directory C:\windows\system32\drivers\etc\.
Per IPv6, inserire la riga seguente nel file del protocollo:
ipv6-icmp 58 IPv6-ICMP # IPv6 interface control message protocol
In generale, gli advisor lavorano per consentire il bilanciamento del carico nel modo seguente.
Gli advisor standard forniti con Load Balancer includono advisor per le seguenti funzioni. Informazioni dettagliate su questi advisor sono disponibili nella Guida alla gestione per WebSphere Application Server Load Balancer
Per supportare i protocolli proprietari per cui non vengono forniti advisor standard è necessario scrivere advisor personalizzati.
Un advisor personalizzato è una piccola parte del codice Java, fornito come file di classe, definito dal codice di base del Load Balancer per determinare il carico su un server. Il codice di base fornisce tutti i servizi di gestione necessari, inclusi l'avvio e l'arresto di un'istanza dell'advisor personalizzato, l'indicazione di stato e report, la registrazione di informazioni cronologiche in un file di log e la registrazione dei risultati dell'advisor sul componente gestore.
Quando il codice di base del Load Balancer chiama un advisor personalizzato, avviene quanto segue.
Gli advisor personalizzati possono essere progettati per interagire con il Load Balancer in modalità normale o in modalità di sostituzione.
La scelta della modalità di funzionamento viene specificata nel file dell'advisor personalizzato come un parametro nel metodo del costruttore. (Ciascun advisor opera solo in una delle seguenti modalità, in base al proprio progetto.)
In modalità normale, l'advisor personalizzato scambia i dati con il server, il codice dell'advisor di base programma lo scambio e calcola il valore del carico. Il codice di base invia questo valore del carico al gestore. L'advisor personalizzato restituisce il valore zero per indicare la riuscita o un valore negativo per indicare un errore.
Per specificare la modalità normale, impostare l'indicatore di sostituzione nel costruttore su false.
In modalità di sostituzione, il codice di base non esegue nessuna misurazione temporizzata. Il codice dell'advisor personalizzato esegue qualsiasi operazione specificata, in base a requisiti univoci e restituisce un numero di carico effettivo. Il codice di base accetta il numero del carico e lo invia, inalterato, al gestore. Per ottenere risultati migliori, normalizzare i numeri del carico tra 10 e 1000; 10 indica un server veloce e 1000 indica un server lento.
Per specificare la modalità di sostituzione, impostare l'indicatore di sostituzione nel costruttore su true.
I nomi dei file dell'advisor personalizzato hanno il formato ADV_nome.java, dove nome è il nome scelto per il proprio advisor. Il nome completo deve cominciare con il prefisso ADV_ in lettere maiuscole, mentre tutti i caratteri successivi devono essere minuscoli. Le lettere minuscole assicurano che il comando di esecuzione dell'advisor non distingue tra maiuscole e al minuscole.
In base alle convenzioni Java, il nome classe definito all'interno del file deve corrispondere al nome del file.
Gli advisor personalizzati devono essere scritti in linguaggio Java e compilati con un compilatore Java installato sulla macchina di sviluppo. Durante la compilazione si fa riferimento ai seguenti file:
Durante la compilazione, la variabile d'ambiente classpath deve indicare il file dell'advisor personalizzato e il file delle classi di base. Un comando di compilazione potrebbe avere il seguente formato:
javac -classpath /opt/ibm/edge/lb/servers/lib/ibmnd.jar ADV_name.java
Questo esempio utilizza il percorso di installazione Linux e UNIX predefinito. Il file dell'advisor viene definito ADV_nome.java e viene memorizzato nella directory corrente.
L'output della compilazione è un file di classe, ad esempio, ADV_nome .class. Prima di avviare l'advisor, copiare il file di classe nella directory percorso_installazione/servers/lib/CustomAdvisors/.
Per eseguire l'advisor personalizzato, è necessario innanzitutto copiare il file di classe dell'advisor sulla directory secondaria lib/CustomAdvisors/ sulla macchina del Load Balancer. Ad esempio, per un advisor personalizzato definito myping, il percorso del file è percorso_installazione/servers/lib/CustomAdvisors/ADV_myping.class
Configurare il Load Balancer, avviare la funzione del gestore e immettere il comando per avviare l'advisor personalizzato. L'advisor personalizzato viene specificato tramite il nome, escludendo il prefisso ADV_ e l'estensione del file:
dscontrol advisor start myping numero_porta
Il numero porta specificato nel comando è la porta su cui verrà avviata una connessione con il server di destinazione.
Come tutti gli advisor, un advisor personalizzato estende la funzionalità della classe di base dell'advisor, definita ADV_Base. L'advisor di base esegue la maggior parte delle funzioni dell'advisor, come ad esempio l'invio dei carichi al gestore per essere utilizzati nell'algoritmo di valutazione del gestore. Inoltre, tale advisor effettua le operazioni di connessione e chiusura del socket e fornisce i metodi di invio e di ricezione per l'uso da parte dell'advisor. L'advisor viene utilizzato unicamente per l'invio e la ricezione dei dati sulla porta specifica del server esaminato. I metodi TCP forniti con l'advisor di base sono programmati per calcolare il carico. Se necessario, un'indicatore all'interno del costruttore dell'advisor di base sostituisce il carico esistente con il nuovo carico restituito dall'advisor.
Gli advisor dispongono dei seguenti metodi classe di base:
I dettagli relativi a queste routine necessarie sono riportati più avanti in questa stessa sezione.
Gli advisor personalizzati vengono chiamati dopo aver effettuato la ricerca di advisor nativi o standard. Se il Load Balancer non trova un advisor specificato nell'elenco di advisor standard, consulta l'elenco di advisor personalizzati. Nella Guida alla gestione per WebSphere Application Server Load Balancer sono disponibili ulteriori informazioni sull'utilizzo degli advisor.
Tenere presenti i seguenti requisiti per i nomi e i percorsi dell'advisor personalizzato.
void ADV_Base Constructor ( string sName; string sVersion; int iDefaultPort; int iInterval; string sDefaultLogFileName; boolean replace )
void ADV_AdvisorInitialize()
Questo metodo viene fornito per effettuare qualsiasi inizializzazione che potrebbe essere necessaria per l'advisor personalizzato. Tale metodo viene chiamato dopo l'avvio del modulo di base dell'advisor.
In molti casi, inclusi gli advisor standard, questo metodo non viene utilizzato e il relativo codice è composto unicamente da un'istruzione return. Questo metodo può essere utilizzato per chiamare il metodo suppressBaseOpeningSocket, valido solo dall'interno di questo metodo.
int getLoad( int iConnectTime; ADV_Thread *caller )
I metodi, o funzioni, descritti nelle seguenti sezioni possono essere chiamati dagli advisor personalizzati. Questi metodi sono supportati dal codice di base dell'advisor.
Alcune di queste chiamate di funzione possono essere effettuate direttamente, ad esempio nome_funzione(), ma altre necessitano del prefisso chiamante. Chiamante rappresenta l'istanza dell'advisor di base che supporta l'advisor personalizzato eseguito.
La funzione ADVLOG consente a un advisor personalizzato di scrivere un messaggio di testo sul file di log dell'advisor di base. Di seguito viene riportato il formato:
void ADVLOG (int logLevel, string message)
La funzione getAdvisorName restituisce una stringa Java con parte del suffisso del nome dell'advisor personalizzato. Ad esempio, per un advisor definito ADV_cdload.java, questa funzione restituisce il valore cdload.
Questa funzione non utilizza alcun parametro.
Si noti che non è possibile modificare questo valore durante la creazione di un'istanza di un advisor.
La funzione getAdviseOnPort restituisce il numero porta su cui è in esecuzione l'advisor personalizzato chiamante. Il valore di ritorno è un numero intero (int)Java e la funzione non utilizza alcun parametro.
Si noti che non è possibile modificare questo valore durante la creazione di un'istanza di un advisor.
La funzione getCurrentServer restituisce l'indirizzo IP del server corrente. Il valore di ritorno è una stringa Java in formato indirizzo IP, ad esempio 128.0.72.139
Generalmente, questo indirizzo viene modificato ogni volta che viene chiamato l'advisor personalizzato, in quanto il codice di base dell'advisor richiede tutte le macchine server in serie.
Questa funzione non utilizza alcun parametro.
La chiamata della funzione getCurrentCluster restituisce l'indirizzo IP del cluster di server corrente. Il valore di ritorno è una stringa Java in formato indirizzo IP, ad esempio 128.0.72.139
Generalmente, questo indirizzo viene modificato ogni volta che viene chiamato l'advisor personalizzato, in quanto il codice di base dell'advisor richiede tutti cluster di server in serie.
Questa funzione non utilizza alcun parametro.
La funzione getInterval restituisce l'intervallo dell'advisor, vale a dire, il numero di secondi trascorsi tra i cicli dell'advisor. Questo valore è uguale al valore predefinito impostato nel costruttore dell'advisor personalizzato, a meno che il valore non sia stato modificato durante il runtime utilizzando il comando dscontrol.
Il valore di ritorno è un numero intero (int) Java. La funzione non utilizza alcun parametro.
La funzione getLatestLoad consente a un advisor personalizzato di ottenere il valore del carico più recente per un determinato oggetto server. I valori del carico vengono gestiti in tabelle interne dal codice di base dell'advisor e dal daemon del gestore.
int caller.getLatestLoad (string cluster_IP, int port, string server_IP)
Tutti e tre gli argomenti definiscono un oggetto server.
Il valore di ritorno è un numero intero.
Questa chiamata di funzione è utile se si desidera che il funzionamento di un protocollo o di una porta dipenda dal funzionamento di un altro protocollo o porta. Ad esempio, si potrebbe utilizzare questa chiamata di funzione in un advisor personalizzato che ha disabilitato un particolare server delle applicazioni se su quella stessa macchina è stato disabilitato il server Telnet.
La funzione di ricezione ottiene informazioni dalla connessione socket.
caller.receive(stringbuffer *response)
Il parametro response è un buffer di stringhe in cui vengono introdotti i dati richiamati. Inoltre, la funzione restituisce un valore intero avente il seguente significato:
La funzione di invio utilizza la connessione socket stabilita per inviare un pacchetto di dati al server, utilizzando la porta specificata.
caller.send(string command)
Il parametro command è una stringa contenente i dati da inviare al server. La funzione restituisce un valore intero avente il seguente significato:
La funzione suppressBaseOpeningSocket consente a un advisor personalizzato di specificare se il codice dell'advisor di base apre un socket TCP sul server per conto dell'advisor personalizzato. Se l'advisor non utilizza la comunicazione diretta con il server per stabilire il suo stato, potrebbe essere necessario aprire questo socket.
Questa chiamata di funzione può essere emessa solo una volta e deve essere emessa dalla routine ADV_AdvisorInitialize.
La funzione non utilizza alcun parametro.
Gli esempi riportati di seguito mostrano come implementare gli advisor personalizzati.
Questo codice di origine di esempio è simile all'advisor HTTP del Load Balancer standard. Funziona nel modo seguente:
Questo advisor opera in modalità normale, quindi la misurazione del carico si basa sul tempo utilizzato, espresso in millisecondi, necessario per eseguire le operazioni di apertura, invio, ricezione e chiusura del socket.
package CustomAdvisors; import com.ibm.internet.lb.advisors.*; public class ADV_sample extends ADV_Base implements ADV_MethodInterface { static final String ADV_NAME ="Sample"; static final int ADV_DEF_ADV_ON_PORT = 80; static final int ADV_DEF_INTERVAL = 7; static final string ADV_SEND_REQUEST = "HEAD / HTTP/1.0\r\nAccept: */*\r\nUser-Agent: " + "IBM_Load_Balancer_HTTP_Advisor\r\n\r\n"; //-------- // Costruttore public ADV_sample() { super(ADV_NAME, "3.0.0.0-03.31.00", ADV_DEF_ADV_ON_PORT, ADV_DEF_INTERVAL, "", false); super.setAdvisor( this ); } //-------- // ADV_AdvisorInitialize public void ADV_AdvisorInitialize() { return; // generalmente una routine vuota } //-------- // getLoad public int getLoad(int iConnectTime, ADV_Thread caller) { int iRc; int iLoad = ADV_HOST_INACCESSIBLE; // inizializzare sull'inaccessibile iRc = caller.send(ADV_SEND_REQUEST); // inviare la richiesta HTTP al // server if (0 <= iRc) { // se l'invio riesce StringBuffer sbReceiveData = new StringBuffer(""); // assegnare un buffer // per la risposta iRc = caller.receive(sbReceiveData); // ricevere il risultato // se necessario, analizzare ora il risultato if (0 <= iRc) { // se la ricezione è riuscita iLoad = 0; // restituire 0 per indicare la riuscita } // (il valore del carico dell'advisor viene ignorato dalla } // base in modalità normale) return iLoad; } }
Questo esempio illustra l'eliminazione del socket standard aperto dall'advisor di base. Al contrario, questo advisor apre un socket Java flusso laterale per interrogare un server. Questa procedura può essere utile per i server che utilizzano una porta differente dal quella utilizzata dal traffico client normale per ricevere una query dell'advisor.
In questo esempio, un server è in ascolto sulla porta 11999 e quando viene interrogato restituisce un valore di carico con un int esadecimale pari a "4". Questo esempio viene eseguito in modalità di sostituzione, vale a dire, l'ultimo parametro del costruttore advisor viene impostato su true e il codice di base dell'advisor utilizza il valore del carico restituito piuttosto che il tempo trascorso.
Si noti la chiamata a supressBaseOpeningSocket() nella routine di inizializzazione. Non è richiesta l'eliminazione del socket di base se non verranno inviati dati. Ad esempio, è possibile che si desideri aprire il socket per verificare che l'advisor possa contattare il server. Esaminare attentamente le esigenze della propria applicazione prima di optare per questa scelta.
package CustomAdvisors; import java.io.*; import java.net.*; import java.util.*; import java.util.Date; import com.ibm.internet.lb.advisors.*; import com.ibm.internet.lb.common.*; import com.ibm.internet.lb.server.SRV_ConfigServer; public class ADV_sidea extends ADV_Base implements ADV_MethodInterface { static final String ADV_NAME = "sidea"; static final int ADV_DEF_ADV_ON_PORT = 12345; static final int ADV_DEF_INTERVAL = 7; // creare una matrice di byte con il messaggio di richiesta del carico static final byte[] abHealth = {(byte)0x00, (byte)0x00, (byte)0x00, (byte)0x04}; public ADV_sidea() { super(ADV_NAME, "3.0.0.0-03.31.00", ADV_DEF_ADV_ON_PORT, ADV_DEF_INTERVAL, "", true); // il parametro della modalità di sostituzione è true super.setAdvisor( this ); } //-------- // ADV_AdvisorInitialize public void ADV_AdvisorInitialize() { suppressBaseOpeningSocket(); // indicare al codice di base di non aprire // il socket standard return; } //-------- // getLoad public int getLoad(int iConnectTime, ADV_Thread caller) { int iRc; int iLoad = ADV_HOST_INACCESSIBLE; // -1 int iControlPort = 11999; // la porta su cui comunicare con il server string sServer = caller.getCurrentServer(); // indirizzo del server da interrogare try { socket soServer = new Socket(sServer, iControlPort); // aprire il socket sul // server DataInputStream disServer = new DataInputStream( soServer.getInputStream()); DataOutputStream dosServer = new DataOutputStream( soServer.getOutputStream()); int iRecvTimeout = 10000; // impostare il timeout (in millisecondi) // per la ricezione dei dati soServer.setSoTimeout(iRecvTimeout); dosServer.writeInt(4); // inviare un messaggio al server dosServer.flush(); iLoad = disServer.readByte(); // ricevere la risposta dal server } catch (exception e) { system.out.println("Caught exception " + e); } return iLoad; // restituire il carico registrato dal server } }
Questo esempio di advisor personalizzato mostra la capacità di rilevare l'errore di una porta di un server, sia in base al suo stato sia in base allo stato di un daemon server differente in esecuzione su un'altra porta sulla stessa macchina server. Ad esempio, se il daemon HTTP sulla porta 80 arresta la risposta, è possibile che si desideri arrestare il traffico di instradamento per il daemon SSL sulla porta 443.
Questo advisor è più aggressivo rispetto agli advisor standard, poiché considera non operativi tutti i server che non inviano una risposta e li contrassegna come inattivi. Gli advisor standard considerano i server inerti come molto lenti. Questo advisor contrassegna un server come inattivo sia per la porta HTTP sia per la porta SSL, in caso di mancata risposta da entrambe le porte.
Per utilizzare questo advisor personalizzato, l'amministratore avvia due istanze dell'advisor: una sulla porta HTTP e una sulla porta SSL. L'advisor crea le istanze di due tabelle hash globali statiche, una per HTTP e una per SSL. Ciascun advisor tenta di comunicare con il relativo daemon server e memorizza i risultati di questo evento nella tabella hash correlata. Il valore restituito da ciascun advisor alla classe dell'advisor di base dipende sia dalla capacità di comunicare con il server daemon sia dalla capacità dell'advisor partner di comunicare con il proprio daemon.
Vengono utilizzati i seguenti metodi personalizzati.
Vengono rilevate le seguenti condizioni di errore.
Questo esempio viene scritto per collegare la porta 80 per HTTP e la porta 443 per SSL, ma può essere adattato per qualsiasi combinazione di porte.
package CustomAdvisors; import java.io.*; import java.net.*; import java.util.*; import java.util.Date; import com.ibm.internet.lb.advisors.*; import com.ibm.internet.lb.common.*; import com.ibm.internet.lb.manager.*; import com.ibm.internet.lb.server.SRV_ConfigServer; //-------- // Defin. l'elemento tab. per le tab. hash utilizzate in questo advisor personalizzato class ADV_nte implements Cloneable { private string sCluster; private int iPort; private string sServer; private int iLoad; private Date dTimestamp; //-------- // costruttore public ADV_nte(string sClusterIn, int iPortIn, string sServerIn, int iLoadIn) { sCluster = sClusterIn; iPort = iPortIn; sServer = sServerIn; iLoad = iLoadIn; dTimestamp = new Date(); } //-------- // verificare se questo elemento è corrente o scaduto public boolean isCurrent(ADV_twop oThis) { boolean bCurrent; int iLifetimeMs = 3 * 1000 * oThis.getInterval(); // impostare la durata come // 3 cicli di advisor Date dNow = new Date(); Date dExpires = new Date(dTimestamp.getTime() + iLifetimeMs); if (dNow.after(dExpires)) { bCurrent = false; } else { bCurrent = true; } return bCurrent; } //-------- // accessori valore public int getLoadValue() { return iLoad; } //-------- // clone (evita la corruzione tra i thread) public synchronized Object Clone() { try { return super.clone(); } catch (cloneNotSupportedException e) { return null; } } } //-------- // definire l'advisor personalizzato public class ADV_twop extends ADV_Base implements ADV_MethodInterface, ADV_AdvisorVersionInterface { static final int ADV_TWOP_PORT_HTTP = 80; static final int ADV_TWOP_PORT_SSL = 443; //-------- // definire le tab. per conservare le info cronologiche specifiche della porta static HashTable htTwopHTTP = new Hashtable(); static HashTable htTwopSSL = new Hashtable(); static final String ADV_TWOP_NAME = "twop"; static final int ADV_TWOP_DEF_ADV_ON_PORT = 80; static final int ADV_TWOP_DEF_INTERVAL = 7; static final string ADV_HTTP_REQUEST_STRING = "HEAD / HTTP/1.0\r\nAccept: */*\r\nUser-Agent: " + "IBM_LB_Custom_Advisor\r\n\r\n"; //-------- // creare una matrice di byte con il messaggio hello del client SSL public static final byte[] abClientHello = { (byte)0x80, (byte)0x1c, (byte)0x01, // client hello (byte)0x03, (byte)0x00, // versione SSL (byte)0x00, (byte)0x03, // lunghezza specifica di codifica (byte) (byte)0x00, (byte)0x00, // lunghezza ID di sessione (byte) (byte)0x00, (byte)0x10, // lunghezza dati richiesta (byte) (byte)0x00, (byte)0x00, (byte)0x03, // specifica di codifica (byte)0x1A, (byte)0xFC, (byte)0xE5, (byte)Ox20, // dati richiesta (byte)0xFD, (byte)0x3A, (byte)0x3C, (byte)0x18, (byte)0xAB, (byte)0x67, (byte)0xB0, (byte)0x52, (byte)0xB1, (byte)0x1D, (byte)0x55, (byte)0x44, (byte)0x0D, (byte)0x0A }; //-------- // costruttore public ADV_twop() { super(ADV_TWOP_NAME, VERSION, ADV_TWOP_DEF_ADV_ON_PORT, ADV_TWOP_DEF_INTERVAL, "", false); // false = load balancer programma la risposta setAdvisor ( this ); } //-------- // ADV_AdvisorInitialize public void ADV_AdvisorInitialize() { return; } //-------- // routine di accesso PUT e GET sincronizzate per le tabelle hash synchronized ADV_nte getNte(Hashtable ht, String sName, String sHashKey) { ADV_nte nte = (ADV_nte)(ht.get(sHashKey)); if (null != nte) { nte = (ADV_nte)nte.clone(); } return nte; } synchronized void putNte(Hashtable ht, String sName, String sHashKey, ADV_nte nte) { ht.put(sHashKey,nte); return; } //-------- // getLoadHTTP - determinare il carico HTTP in base alla risposta del server int getLoadHTTP(int iConnectTime, ADV_Thread caller) { int iLoad = ADV_HOST_INACCESSIBLE; int iRc = caller.send(ADV_HTTP_REQUEST_STRING); // inviare il msg di richiesta // al server if (0 <= iRc) { // la richiesta ha restituito un errore? StringBuffer sbReceiveData = new StringBuffer("") // assegnare un buffer // per la risposta iRc = caller.receive(sbReceiveData); // ricevere la risposta dal server if (0 <= iRc) { // la ricezione ha restituito un errore? if (0 < sbReceiveData.length()) { // vi sono dati? iLoad = SUCCESS; // ignorare i dati richiamati e // restituire il codice di riuscita } } } return iLoad; } //-------- // getLoadSSL() - determinare il carico SSL in base alla risposta del server int getLoadSSL(int iConnectTime, ASV_Thread caller) { int iLoad = ADV_HOST_INACCESSIBLE; int iSocket = caller.getAdvisorSocket(); // inviare una rich. esadec. al server CMNByteArrayWrapper cbawClientHello = new CMNByteArrayWrapper( abClientHello); int iRc = SRV_ConfigServer.socketapi.sendBytes(iSocket, cbawClientHello); if (0 <= iRc) { // la richiesta ha restituito un errore? StringBuffer sbReceiveData = new StringBuffer(""); // assegnare un buffer // per la risposta iRc = caller.receive(sbReceiveData); // ottenere una risposta dal // server if (0 <= iRc) { // la ricezione ha restituito un errore? if (0 < sbReceiveData.length()) { // vi sono dati? iLoad = SUCCESS; // ignorare dati richiamati e restituire cod. riuscita } } } return iLoad; } //-------- // getLoad - associare i risultati dei metodi HTTP e SSL public int getLoad(int iConnectTime, ADV_Thread caller) { int iLoadHTTP; int iLoadSSL; int iLoad; int iRc; String sCluster = caller.getCurrentCluster(); // indirizzo corrente cluster int iPort = getAdviseOnPort(); String sServer = caller.getCurrentServer(); String sHashKey = sCluster = ":" + sServer; // chiave tabella hash if (ADV_TWOP_PORT_HTTP == iPort) { // gestire un server HTTP iLoadHTTP = getLoadHTTP(iConnectTime, caller); // richiamare carico per HTTP ADV_nte nteHTTP = newADV_nte(sCluster, iPort, sServer, iLoadHTTP); putNte(htTwopHTTP, "HTTP", sHashKey, nteHTTP); // salvare le info sul carico // su SSL ADV_nte nteSSL = getNte(htTwopSSL, "SSL", sHashKey); // richiamare le info // su SSL if (null != nteSSL) { if (true == nteSSL.isCurrent(this)) { // controllare data e ora if (ADV_HOST_INACCESSIBLE != nteSSL.getLoadValue()) { // l'SSL è // in funzione? iLoad = iLoadHTTP; } else { // SSL non funziona, quindi contras. srvr HTTP come inattivo iLoad= ADV_HOST_INACCESSIBLE; } } else { // le informazioni su SSL sono scadute, quindi contrassegnare // il server HTTP come inattivo iLoad = ADV_HOST_INACCESSIBLE; } } else { // nessuna informazione sul carico relativa all'SSL, registrare // i risultati di getLoadHTTP() iLoad = iLoadHTTP; } } else if (ADV_TWOP_PORT_SSL == iPort) { // gestire un server SSL iLoadSSL = getLoadSSL(iConnectTime, caller); // ricevere il carico per SSL ADV_nte nteSSL = new ADV_nte(sCluster, iPort, sServer, iLoadSSL); putNte(htTwopSSL, "SSL", sHashKey, nteSSL); // salvare info sul carico SSL. ADV_nte nteHTTP = getNte(htTwopHTTP, "SSL", sHashKey); // ottenere info su // su SSL if (null != nteHTTP) { if (true == nteHTTP.isCurrent(this)) { // controllare data e ora if (ADV_HOST_INACCESSIBLE != nteHTTP.getLoadValue()) { // HTTP è // in funzione? iLoad = iLoadSSL; } else { // srvr HTTP non in funzione, quindi contras. SSL come inattivo iLoad = ADV_HOST_INACCESSIBLE; } } else { // info da HTTP scadute, quindi contras. SSL come inattivo iLoad = ADV_HOST_INACCESSIBLE; } } else { // nessuna informazione su HTTP, registrare // i risultati di getLoadSSL() iLoad = iLoadSSL; } } //-------- // handler dell'errore else { iLoad = ADV_HOST_INACCESSIBLE; } return iLoad; } }
Un advisor personalizzato di esempio per WebSphere Application Server è incluso nella directory percorso_installazione/servers/samples/CustomAdvisors/. Il codice completo non viene duplicato in questo documento.
L'advisor completo è leggermente più complesso dell'esempio. Esso aggiunge una routine di analisi specializzata più compatta rispetto all'esempio StringTokenizer mostrato in precedenza.
La parte più complessa del codice di esempio è rappresentata dal servlet Java. Tra gli altri metodi, il servlet contiene due metodi richiesti dalla specifica del servlet: init() e service(), nonché un metodo, run(), richiesto dalla classe Java.lang.thread.
Di seguito vengono illustrati i frammenti rilevanti del codice servlet.
... public void init(ServletConfig config) throws ServletException { super.init(config); ... _checker = new Thread(this); _checker.start(); } public void run() { setStatus(GOOD); while (true) { if (!getKeepRunning()) return; setStatus(figureLoad()); setLastUpdate(new java.util.Date()); try { _checker.sleep(_interval * 1000); } catch (Exception ignore) { ; } } } public void service(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException { ServletOutputStream out = null; try { out = res.getOutputStream(); } catch (Exception e) { ... } ... res.setContentType("text/x-application-LBAdvisor"); out.println(getStatusString()); out.println(getLastUpdate().toString()); out.flush(); return; } ...
Nel caso in cui si utilizzi una chiamata standard a una parte esistente del server delle applicazioni o si aggiunga una nuova parte di codice alla controparte lato server del proprio advisor personalizzato, è possibile che si desideri esaminare i valori del carico restituiti e modificare il funzionamento del server. La classe Java StringTokenizer e i relativi metodi, rendono più semplice questo controllo.
Il contenuto di un comando HTTP tipico potrebbe essere GET /index.html HTTP/1.0
Una risposta tipica a questo comando potrebbe essere la seguente.
HTTP/1.1 200 OK Date: Mon, 20 November 2000 14:09:57 GMT Server: Apache/1.3.12 (Linux e UNIX) Content-Location: index.html.en Vary: negotiate TCN: choice Last-Modified: Fri, 20 Oct 2000 15:58:35 GMT ETag: "14f3e5-1a8-39f06bab;39f06a02" Accept-Ranges: bytes Content-Length: 424 Connection: close Content-Type: text/html Content-Language: en <!DOCTYPE HTML PUBLIC "-//w3c//DTD HTML 3.2 Final//EN"> <HTML><HEAD><TITLE>Test Page</TITLE></HEAD> <BODY><H1>Apache server</H1> <HR> <P><P>Questo server Web esegue Apache 1.3.12. <P><HR> <P><IMG SRC="apache_pb.gif" ALT=""> </BODY></HTML>
Gli elementi di interesse sono contenuti nella prima riga, in particolare il codice di ritorno HTTP.
La specifica HTTP classifica i codici di ritorno riepilogati nel modo seguente:
Se si conoscono perfettamente quali sono codici che il server può restituire, non è necessario che il codice sia così dettagliato come mostrato in questo esempio. Tuttavia, tenere presente che limitando i codici di ritorno che possono essere rilevati si potrebbe limitare la flessibilità futura del programma.
L'esempio riportato di seguito è un programma Java autonomo che contiene un client HTTP minimo. L'esempio richiama un programma di analisi semplice e generico per l'esame delle risposte HTTP.
import java.io.*; import java.util.*; import java.net.*; public class ParseTest { static final int iPort = 80; static final String sServer = "www.ibm.com"; static final String sQuery = "GET /index.html HTTP/1.0\r\n\r\n"; static final String sHTTP10 = "HTTP/1.0"; static final String sHTTP11 = "HTTP/1.1"; public static void main(String[] Arg) { String sHTTPVersion = null; String sHTTPReturnCode = null; String sResponse = null; int iRc = 0; BufferedReader brIn = null; PrintWriter psOut = null; Socket soServer= null; StringBuffer sbText = new StringBuffer(40); try { soServer = new Socket(sServer, iPort); brIn = new BufferedReader(new InputStreamReader( soServer.getInputStream())); psOut = new PrintWriter(soServer.getOutputStream()); psOut.println(sQuery); psOut.flush(); sResponse = brIn.readLine(); try { soServer.close(); } catch (Exception sc) {;} } catch (Exception swr) {;} StringTokenizer st = new StringTokenizer(sResponse, " "); if (true == st.hasMoreTokens()) { sHTTPVersion = st.nextToken(); if (sHTTPVersion.equals(sHTTP110) || sHTTPVersion.equals(sHTTP11)) { System.out.println("HTTP Version: " + sHTTPVersion); } else { System.out.println("Invalid HTTP Version: " + sHTTPVersion); } } else { System.out.println("Nothing was returned"); return; } if (true == st.hasMoreTokens()) { sHTTPReturnCode = st.nextToken(); try { iRc = Integer.parseInt(sHTTPReturnCode); } catch (NumberFormatException ne) {;} switch (iRc) { case(200): System.out.println("HTTP Response code: OK, " + iRc); break; case(400): case(401): case(402): case(403): case(404): System.out.println("HTTP Response code: Client Error, " + iRc); break; case(500): case(501): case(502): case(503): System.out.println("HTTP Response code: Server Error, " + iRc); break; default: System.out.println("HTTP Response code: Unknown, " + iRc); break; } } if (true == st.hasMoreTokens()) { while (true == st.hasMoreTokens()) { sbText.append(st.nextToken()); sbText.append(" "); } System.out.println("HTTP Response phrase: " + sbText.toString()); } } }