To wydanie dotyczy wersji:
oraz wszystkich kolejnych wersji tego produktu, chyba że w nowym wydaniu zostanie stwierdzone inaczej.
Publikacje można zamówić za pośrednictwem przedstawiciela handlowego lub lokalnego oddziału firmy IBM.
W tej sekcji opisano przeznaczenie, organizację i konwencje stosowane w niniejszej publikacji (Podręcznik programowania dla produktu WebSphere Application Server Edge Components).
Ten podręcznik opisuje aplikacyjne interfejsy programistyczne (API) dostępne na potrzeby dostosowywania produktu Edge Components serwera WebSphere Application Server Wersja 6.1. Informacje te są przeznaczone dla programistów tworzących aplikacje wtyczek i wprowadzających inne modyfikacje. Korzystać z nich mogą również projektanci sieci i administratorzy systemów w celu uzyskania informacji o możliwych typach dostosowań.
Korzystanie z informacji zawartych w tym podręczniku wymaga zrozumienia procedur programistycznych w języku programowania Java lub C, w zależności od tego, jaki interfejs API będzie używany. Metody i struktury dostępne w każdym prezentowanym interfejsie są udokumentowane, ale czytelnik musi wiedzieć, w jaki sposób skonstruować własną aplikację, skompilować ją dla używanego systemu, a następnie przetestować. Dla niektórych interfejsów udostępniono kod przykładowy, ale stanowi on tylko przykład konstruowania własnej aplikacji.
W tej dokumentacji użyto następujących konwencji drukarskich i konwencji tworzenia kluczy.
Konwencja | Znaczenie |
---|---|
Pogrubienie | W przypadku odwołania do graficznego interfejsu użytkownika (GUI, graphical user interface) pogrubienie wskazuje menu, elementy menu, etykiety, przyciski, ikony i foldery. Może także zostać użyte do wyróżnienia nazw komend, które w przeciwnym razie mogłyby zostać pomylone z otaczającym tekstem. |
Czcionka o stałej szerokości | Wskazuje tekst, który należy wprowadzić w wierszu komend. Za pomocą czcionki o stałej szerokości oznaczono również tekst ekranowy, przykłady kodu oraz cytaty z plików. |
Kursywa | Wskazuje wartości zmiennych, które należy udostępnić (na przykład dla zmiennej fileName należy podać nazwę pliku). Kursywy użyto również jako wyróżnienia oraz oznaczono za jej pomocą tytuły podręczników. |
Ctrl-x | Gdzie x to nazwa klawisza. Wskazuje kombinację klawiszy control-znak. Na przykład Ctrl-c oznacza konieczność przytrzymania wciśniętego klawisza Ctrl i naciśnięcia klawisza c. |
Return | Odwołuje się do klawisza oznaczonego wyrazem Return, wyrazem Enter lub strzałką w lewo. |
% | Reprezentuje zachętę powłoki komend powłoki systemów Linux i UNIX dla komendy, która nie wymaga uprawnień administratora. |
# | Reprezentuje zachętę powłoki komend systemów Linux i UNIX dla komendy, która wymaga uprawnień administratora. |
C:\ | Reprezentuje zachętę wiersza komend systemu Windows. |
Wprowadzanie komend | Jeśli w instrukcji napisano "wprowadź" lub "wydaj" komendę, należy wpisać komendę i nacisnąć klawisz Return. Na przykład instrukcja "Wprowadź komendę ls" oznacza, że należy wpisać ls w wierszu komend i nacisnąć klawisz Return. |
[ ] | Oznaczają opcjonalne elementy w opisach składni. |
{ } | Oznaczają listy, z których należy wybrać pozycję w opisach składni. |
| | Oddziela pozycje na liście wyborów oznaczonych za pomocą znaków { } (nawias klamrowy) w opisach składni. |
... | Wielokropki w opisach składni wskazują możliwość powtórzenia poprzedniego elementu jeden lub większą liczbę razy. Wielokropki w przykładach oznaczają, że pominięto informacje w celu zachowania zwięzłości. |
Opcje ułatwień dostępu pomagają posługiwać się oprogramowaniem osobom niepełnosprawnym fizycznie, na przykład z ograniczeniami w zakresie ruchu lub z wadami wzroku. Poniżej przedstawiono najważniejsze opcje ułatwień dostępu produktu WebSphere Application Server Wersja 6.1:
Twoja opinia jest ważna i pomaga dostarczać najbardziej dokładne informacje o najwyższej jakości. Jeśli masz komentarze na temat tego podręcznika lub wszelkiej innej dokumentacji produktu Edge Components serwera WebSphere Application Server:
Ten podręcznik omawia aplikacyjne interfejsy programistyczne (API) udostępniane na potrzeby produktu Edge Components serwera WebSphere Application Server (produkt Edge Components serwera WebSphere Application Server zawiera komponent Buforujący serwer proxy i komponent System równoważenia obciążenia). Udostępniono kilka interfejsów, które umożliwiają administratorom dostosowywanie instalacji w celu modyfikowania sposobu współpracy komponentów Edge Components lub umożliwiania współpracy z innymi systemami oprogramowania.
Ważne: Komponent Buforujący serwer proxy jest dostępny we wszystkich instalacjach komponentów brzegowych, z następującymi wyjątkami:
Interfejsy API przedstawione w tym dokumencie należą do kilku kategorii.
Komponent Buforujący serwer proxy ma wbudowanych w sekwencję przetwarzania kilka interfejsów umożliwiających dodanie niestandardowego przetwarzania lub zastąpienie przetwarzania standardowego. Dostosowania, które mogą być wykonane, obejmują modyfikowanie lub rozszerzanie czynności takich jak następujące:
Niestandardowe aplikacje, nazywane też wtyczkami komponentu Buforujący serwer proxy, wywoływane są we wstępnie określonych punktach sekwencji przetwarzania serwera proxy.
Interfejs API komponentu Buforujący serwer proxy został wykorzystany do zaimplementowania pewnych funkcji systemu. Na przykład obsługa protokołu LDAP serwera proxy została zaimplementowana jako wtyczka.
Interfejs API komponentu Buforujący serwer proxy opisuje szczegółowo ten interfejs i zawiera kroki służące do konfiguracji serwera proxy do korzystania z programów wtyczek.
System równoważenia obciążenia można dostosowywać poprzez tworzenie własnych doradców. Doradcy wykonują pomiary bieżącego obciążenia na serwerach. W przypadku niestandardowego doradcy można użyć własnej metody pomiaru obciążenia, która będzie odpowiednia dla systemu użytkownika. Jest to szczególnie ważne w przypadku niestandardowych systemów serwerów WWW lub systemów innych firm.
Niestandardowi doradcy zawiera szczegółowe informacje na temat tworzenia i używania niestandardowych doradców. Zawiera też przykładowy kod doradcy.
Przykładowy kod dla tych interfejsów API jest zawarty na dysku CD-ROM o nazwie Edge Components, w katalogu samples. Dodatkowe przykłady kodu są dostępne w serwisie WWW serwera WebSphere Application Server: www.ibm.com/software/webservers/appserv/.
W tej sekcji omówiono interfejs API (application programming interface) komponentu Buforujący serwer proxy: co to jest, dlaczego jest użyteczny i w jaki sposób działa.
Ważne: Komponent Buforujący serwer proxy jest dostępny we wszystkich instalacjach komponentów brzegowych, z następującymi wyjątkami:
Ten API to interfejs komponentu Buforujący serwer proxy, który umożliwia rozszerzanie podstawowych funkcji serwera proxy. Możliwe jest pisanie rozszerzeń (wtyczek) służących do dostosowanego przetwarzania, w tym:
Interfejs API komponentu Buforujący serwer proxy ma następujące zalety:
Przed rozpoczęciem pisania programów wtyczek komponentu Buforujący serwer proxy należy zrozumieć zasadę działania serwera proxy. Zachowanie serwera proxy można podzielić na kilka osobnych kroków przetwarzania. Za pomocą tego interfejsu API można dostarczać własne, dostosowane funkcje dla każdego z tych kroków. Można na przykład dodać funkcję wykonywaną po odczytaniu żądania klienta, ale przed wykonaniem dalszego przetwarzania. Inną możliwością jest przeprowadzenie specjalnych procedur podczas uwierzytelniania, a także po wysłaniu żądanego pliku.
Wraz z interfejsem API udostępniana jest biblioteka predefiniowanych funkcji. Programy wtyczek mogą wywoływać predefiniowane funkcje API w celu nawiązania interakcji z procesem serwera proxy (na przykład aby operować na żądaniach, odczytywać lub zapisywać nagłówki żądań lub zapisywać dane w dziennikach serwera proxy). Nie należy mylić tych funkcji z funkcjami pisanej wtyczki, które są wywoływane przez serwer proxy. Te predefiniowane funkcje opisano w sekcji Predefiniowane funkcje i makra.
Aby serwer proxy wywoływał funkcje wtyczki w odpowiednich krokach, należy zawrzeć odpowiednie dyrektywy interfejsu API komponentu Buforujący serwer proxy w pliku konfiguracyjnym serwera. Dyrektywy te opisano w sekcji Dyrektywy konfiguracyjne komponentu Buforujący serwer proxy dla kroków interfejsu API.
W tym dokumencie zawarto:
Używając tych komponentów i procedur, można pisać własne programy wtyczek komponentu Buforujący serwer proxy.
Podstawowe działanie serwera proxy można podzielić na kroki na podstawie typu przetwarzania, które serwer wykonuje w czasie danej fazy. Każdy krok zawiera punkty, w których może być uruchomiona określona część programu. Dodając dyrektywy interfejsu API do pliku konfiguracyjnego komponentu Buforujący serwer proxy (ibmproxy.conf) można wskazać, która z funkcji wtyczki ma zostać wywołana podczas danego kroku. Można wywołać kilka funkcji wtyczki podczas danego kroku przetwarzania, dodając dla niego kilka dyrektyw.
Niektóre kroki są częścią procesu przetwarzania żądań przez serwer. Innymi słowy, serwer proxy wykonuje te kroki za każdym razem, gdy przetwarza żądanie. Inne kroki są wykonywane niezależnie od przetwarzania żądań, to znaczy serwer wykonuje je niezależnie od tego, czy przetwarzane jest żądanie.
Skompilowany program rezyduje w obiekcie współużytkowanym, na przykład w pliku DLL lub .so, w zależności od systemu operacyjnego. Wykonując kolejne kroki przetwarzania żądania, serwer wywołuje funkcje wtyczki powiązane z poszczególnymi krokami do momentu, gdy jedna z funkcji wskaże, że żądanie zostało obsłużone. Jeśli dla danego kroku zostanie określona więcej niż jedna funkcja wtyczki, będą one wywoływane w takim porządku, w jakim ich dyrektywy występują w pliku konfiguracyjnym.
Jeśli żądanie nie zostanie obsłużone przez funkcję wtyczki (dla danego kroku nie została dodana dyrektywa interfejsu API komponentu Buforujący serwer proxy lub funkcja wtyczki zwróciła dla tego kroku wartość HTTP_NOACTION), serwer wykona akcję domyślną.
Uwaga: Dzieje się tak dla wszystkich kroków poza krokiem Usługa. Ten krok nie ma akcji domyślnej.
Rysunek 1 ilustruje kroki wykonywane w procesie serwera proxy oraz porządek wykonywania kroków związanych z przetwarzaniem żądań.
Cztery z kroków przedstawionych na diagramie są wykonywane niezależnie od przetwarzania żądań klienta. Są one związane z działaniem i konserwacją serwera proxy. Te kroki to:
Na poniższej liście wyjaśniono cel każdego z kroków przedstawionych na Rysunek 1. Należy pamiętać, że nie wszystkie kroki muszą być wywoływane dla określonego żądania.
Przeprowadza przetwarzanie po odczytaniu żądania, lecz przed wykonaniem jakichkolwiek innych czynności.
Jeśli krok zwróci informacje o tym, że żądanie zostało przetworzone (HTTP_OK), serwer pominie inne kroki przetwarzania żądania i wykona tylko kroki Transmogryfikator, Dziennik oraz Po wyjściu.
Korzysta z przechowywanych elementów zabezpieczeń, aby sprawdzić ścieżkę fizyczną pod kątem wszelkich zabezpieczeń, list ACL oraz innych elementów kontroli dostępu, a także generuje nagłówki WWW-Authenticate, które są wymagane do podstawowego uwierzytelniania. Jeśli krok ten ma zostać zastąpiony funkcją wtyczki utworzoną przez użytkownika, podczas jej pisania należy pamiętać o konieczności wygenerowania tych nagłówków.
Więcej informacji można znaleźć w sekcji Uwierzytelnianie i autoryzacja.
Dekoduje, weryfikuje i zapisuje elementy zabezpieczeń.
Więcej informacji można znaleźć w sekcji Uwierzytelnianie i autoryzacja.
Przeprowadza przetwarzanie po autoryzacji i znalezieniu obiektu, lecz przed spełnieniem żądania.
Jeśli krok zwróci informacje o tym, że żądanie zostało przetworzone (HTTP_OK), serwer pominie inne kroki przetwarzania żądania i wykona tylko kroki Transmogryfikator, Dziennik oraz Po wyjściu.
W systemach AIX wymagany jest plik eksportu (na przykład libmyapp.exp), który zawiera wszystkie funkcje wtyczki. Podczas konsolidacji należy także uwzględnić plik importu interfejsu API komponentu Buforujący serwer proxy - libhttpdapi.exp.
W systemach Linux, HP-UX oraz Solaris należy podczas konsolidacji uwzględnić biblioteki libhttpdapi oraz libc.
W systemach Windows wymagany jest plik definicji modułów (.def), który zawiera informacje o wszystkich funkcjach wtyczki. Podczas konsolidacji należy uwzględnić plik HTTPDAPI.LIB.
W definicjach funkcji należy uwzględnić plik nagłówkowy HTAPI.h oraz użyć makra HTTPD_LINKAGE. Makro to gwarantuje, że wszystkie funkcje będą używały tych samych konwencji wywoływań.
Poniższe komendy kompilowania i konsolidowania należy traktować jako wytyczne.
cc_r -c -qdbxextra -qcpluscmt foo.c
cc_r -bM:SRE -bnoentry -o libfoo.so foo.o -bI:libhttpdapi.exp -bE:foo.exp
(Tę komendę zaprezentowano w dwóch wierszach jedynie z uwagi na czytelność).
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
Aby określić elementy do wyeksportowania, użyj jednej z poniższych metod:
Przy pisaniu funkcji programu dla określonych kroków przetwarzania żądań należy użyć składni zaprezentowanej w sekcji Prototypy funkcji wtyczki.
Każda z funkcji musi wypełnić parametr kodu powrotu wartością, która wskazuje jaka akcja została wykonana:
W prototypach funkcji dla każdego kroku komponentu Buforujący serwer proxy pokazano format, którego należy użyć, oraz wyjaśniono typ przetwarzania, które można za ich pomocą wykonać. Należy pamiętać, że nazwy funkcji nie są predefiniowane. Funkcjom należy nadać unikalne nazwy. Można stosować własne konwencje nazewnictwa. W tym dokumencie dla ułatwienia użyto nazw odpowiadających krokom przetwarzania serwera.
W każdej funkcji wtyczki można używać określonych predefiniowanych funkcji API. Niektóre predefiniowane funkcje nie są poprawne dla wszystkich kroków. Poniższe predefiniowane funkcje API mogą być poprawnie wywołane z poziomu wszystkich funkcji wtyczki:
Dodatkowe poprawne i niepoprawne funkcje API zostały podane w opisach prototypów funkcji.
Wartość parametru handle wysłanego do funkcji można przekazać do predefiniowanej funkcji jako pierwszy argument. Predefiniowane funkcje API opisano w sekcji Predefiniowane funkcje i makra.
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 serwer proxy's version number; these are supplied by the Buforujący serwer 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 Buforujący serwer 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 serwer 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 )
Funkcja zdefiniowana dla tego kroku jest wywoływana dla każdego żądania. Można określić szablon URL w dyrektywie pliku konfiguracyjnego, jeśli funkcja wtyczki ma być wywoływana tylko dla żądań zgodnych z szablonem. Krok Tłumaczenie nazwy jest wykonywany przed przetworzeniem żądania i udostępnia mechanizm odwzorowania adresów URL na obiekty, takie jak nazwy plików.
void HTTPD_LINKAGE AuthorizationFunction ( unsigned char *handle, long *return_code )
Funkcja zdefiniowana dla tego kroku jest wywoływana dla każdego żądania. Można określić szablon URL w dyrektywie pliku konfiguracyjnego, jeśli funkcja wtyczki ma być wywoływana tylko dla żądań zgodnych z szablonem. Krok Autoryzacja jest wykonywany przed przetworzeniem żądania i można go użyć w celu sprawdzenia, czy możliwe jest zwrócenie zidentyfikowanego obiektu do klienta. W przypadku przeprowadzania podstawowego uwierzytelniania należy wygenerować wymagane nagłówki WWW-Authenticate.
void HTTPD_LINKAGE ObjTypeFunction ( unsigned char *handle, long *return_code )
Funkcja zdefiniowana dla tego kroku jest wywoływana dla każdego żądania. Można określić szablon URL w dyrektywie pliku konfiguracyjnego, jeśli funkcja wtyczki ma być wywoływana tylko dla żądań zgodnych z szablonem. Krok Typ obiektu jest wykonywany przed przetworzeniem żądania i można go użyć do sprawdzenia, czy obiekt istnieje, a także do określenia typu obiektu.
void HTTPD_LINKAGE PostAuthFunction ( unsigned char *handle, long *return_code )
Funkcja zdefiniowana dla tego kroku jest wywoływana po autoryzacji żądania, lecz przed rozpoczęciem przetwarzania. Jeśli ta funkcja zwróci kod HTTP_OK, serwer proxy przyjmuje, że żądanie zostało obsłużone. Wszystkie kolejne kroki zostaną pominięte z wyjątkiem kroków odpowiedzi (Transmogryfikator, Dziennik i Po wyjściu).
Wszystkie predefiniowane funkcje serwera są poprawne w tym kroku.
void HTTPD_LINKAGE ServiceFunction ( unsigned char *handle, long *return_code )
Funkcja zdefiniowana dla tego kroku jest wywoływana dla każdego żądania. Można określić szablon URL w dyrektywie pliku konfiguracyjnego, jeśli funkcja wtyczki ma być wywoływana tylko dla żądań zgodnych z szablonem. W kroku Usługa żądanie jest spełniane, jeśli nie zostało ono spełnione w krokach Przed wyjściem lub Po autoryzacji.
Wszystkie predefiniowane funkcje serwera są poprawne w tym kroku.
Informacje na temat konfigurowania funkcji Usługa w taki sposób, aby była wykonywana na podstawie metody HTTP, a nie na podstawie adresu URL, można znaleźć w opisie dyrektywy Enable w publikacji Podręcznik administrowania komponentem Buforujący serwer proxy produktu WebSphere Application Server.
Dla tego kroku należy zaimplementować następujące cztery funkcje. (Nazwy funkcji nie muszą być zgodne z podanymi).
void * HTTPD_LINKAGE openFunction ( unsigned char *handle, long *return_code )
Funkcja otwierania przeprowadza inicjowanie (na przykład przydzielanie buforu) wymagane do przetworzenia danych z danego strumienia. Każdy kod powrotu z wyjątkiem HTTP_OK powoduje przerwanie działania filtru (funkcje zapisu i zamykania nie są wywoływane). Funkcja może zwrócić pusty wskaźnik, umożliwiając przydzielenie obszaru dla struktury i przekazanie wskaźnika z powrotem w parametrze correlator kolejnych funkcji.
void HTTPD_LINKAGE writeFunction ( unsigned char *handle, unsigned char *data, /* dane odpowiedzi wysłane przez serwer źródłowy */ unsigned long *length, /* długość danych odpowiedzi */ void *correlator, /* wskaźnik zwrócony przez funkcję otwierania */ long *return_code )
Funkcja zapisu przetwarza dane i może wywoływać predefiniowaną funkcję serwera HTTPD_write() z nowymi lub zmienionymi danymi. Wtyczka nie może próbować zwolnić buforu przekazanego do niej, ani oczekiwać, że serwer zwolni otrzymany bufor.
Nawet jeśli dane nie zostaną zmienione podczas wykonywania funkcji zapisu, należy wywołać funkcję HTTPD_write() w ramach funkcji otwierania, zapisu lub zamykania w celu przekazania danych odpowiedzi do klienta. Argument correlator to wskaźnik buforu danych, który został zwrócony w procedurze otwierania.
void HTTPD_LINKAGE closeFunction ( unsigned char *handle, void *correlator, long *return_code )
Funkcja zamykania przeprowadza akcje procedury czyszczącej (na przykład opróżnianie lub zwalnianie buforu korelatora) wymagane do zakończenia przetwarzania danych strumienia. Argument correlator to wskaźnik buforu danych, który został zwrócony w procedurze otwierania.
void HTTPD_LINKAGE errorFunction ( unsigned char *handle, void *correlator, long *return_code )
Funkcja błędu umożliwia przeprowadzenie akcji procedury czyszczącej, takich jak opróżnianie lub zwalnianie buforowanych danych (lub obu) przed wysłaniem strony błędu. W tym miejscu wywoływane są funkcje otwierania, zapisu i zamykania w celu przetworzenia strony błędu. Argument correlator to wskaźnik buforu danych, który został zwrócony w procedurze otwierania.
Uwagi:
void HTTPD_LINKAGE GCAdvisorFunction ( unsigned char *handle, long *return_code )
Funkcja zdefiniowana dla tego kroku jest wywoływana dla każdego pliku znajdującego się w pamięci podręcznej podczas czyszczenia pamięci. Za pomocą tej funkcji można wpływać na to, które pliki są zachowywane, a które są usuwane. Więcej informacji można znaleźć, przeglądając zmienne GC_*.
void HTTPD_LINKAGE ProxyAdvisorFunction ( unsigned char *handle, long *return_code )
Funkcja zdefiniowana dla tego kroku jest wywoływana podczas obsługiwania każdego żądania proxy. Można jej użyć na przykład do ustawienia zmiennej USE_PROXY.
void HTTPD_LINKAGE LogFunction ( unsigned char *handle, long *return_code )
Funkcja zdefiniowana dla tego kroku jest wywoływana dla każdego żądania po jego przetworzeniu i zakończeniu komunikacji z klientem. Można określić szablon URL w dyrektywie pliku konfiguracyjnego, jeśli funkcja wtyczki ma być wywoływana tylko dla żądań zgodnych z szablonem. Ta funkcja jest wywoływana niezależnie od tego, czy przetwarzanie żądania zakończyło się powodzeniem. Jeśli wtyczka dziennika nie ma przesłaniać domyślnego mechanizmu dziennika, należy ustawić kod powrotu HTTP_NOACTION zamiast kodu HTTP_OK.
void HTTPD_LINKAGE ErrorFunction ( unsigned char *handle, long *return_code )
Funkcja zdefiniowana dla tego kroku jest wywoływana dla każdego żądania, które się nie powiodło. Można określić szablon URL w dyrektywie pliku konfiguracyjnego, jeśli funkcja wtyczki ma być wywoływana tylko dla żądań, zgodnych z szablonem, które się nie powiodły. Krok Błąd umożliwia dostosowanie odpowiedzi dotyczącej błędu.
void HTTPD_LINKAGE PostExitFunction ( unsigned char *handle, long *return_code )
Funkcja zdefiniowana dla tego kroku jest wywoływana dla każdego żądania niezależnie od tego, czy zakończyło się ono powodzeniem. Ten krok umożliwia wykonanie czynności procedury czyszczącej dla zasobów przydzielonych przez wtyczkę na potrzeby przetworzenia żądania.
void HTTPD_LINKAGE ServerTermFunction ( unsigned char *handle, long *return_code )
Funkcja zdefiniowana dla tego kroku jest wywoływana przy poprawnym zamknięciu systemu serwera. Umożliwia przeprowadzenie procedury czyszczącej dla zasobów przydzielonych podczas kroku Inicjowanie serwera. Nie należy wywoływać żadnych funkcji HTTP_* w tym kroku (rezultaty są nieprzewidywalne). Jeśli w pliku konfiguracyjnym dla kroku Zakończenie działania serwera znajduje się więcej niż jedna dyrektywa interfejsu API komponentu Buforujący serwer proxy, zostanie wywołana każda z nich.
Poniższe kody powrotu są zgodne ze specyfikacją HTTP 1.1, RFC 2616, opublikowaną przez organizację World Wide Web Consortium (www.w3.org/pub/WWW/Protocols/). Funkcje wtyczki muszą zwracać jedną z podanych wartości.
Wartość | Kod powrotu |
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 |
Predefiniowane funkcje i makra serwera można wywoływać z poziomu własnych funkcji wtyczki. Należy używać ich predefiniowanych nazw oraz formatu opisanego poniżej. W opisach parametrów litery we wskazują parametr wejścia, litery wy parametr wyjścia, natomiast litery we/wy wskazują, że parametr jest zarówno parametrem wejścia, jak i wyjścia.
Każda z tych funkcji zwraca jeden z kodów powrotu HTTPD w zależności od tego, czy żądanie zakończy się powodzeniem. Kody te opisano w sekcji Kody powrotu z predefiniowanych funkcji i makr.
Podczas wywoływania tych funkcji jako pierwszego parametru należy użyć uchwytu wtyczki. W innym przypadku funkcja zwróci kod błędu HTTPD_PARAMETER_ERROR. Wartość NULL nie jest akceptowana jako poprawny uchwyt.
void HTTPD_LINKAGE HTTPD_authenticate ( unsigned char *handle, /* we; uchwyt */ long *return_code /* wy; kod powrotu */ )
void HTTPD_LINKAGE HTTPD_cacheable_url ( unsigned char *handle, /* we; uchwyt */ unsigned char *url, /* we; adres URL do sprawdzenia */ unsigned char *req_method, /* we; metoda żądania dla adresu URL */ long *retval /* wy; kod powrotu */ )
Zwrócona wartość HTTPD_SUCCESS wskazuje, że można buforować treść URL, natomiast wartość HTTPD_FAILURE wskazuje, że nie jest to możliwe. Dla tej funkcji możliwy jest także kod powrotu HTTPD_INTERNAL_ERROR.
void HTTPD_LINKAGE HTTPD_close ( unsigned char *handle, /* we; uchwyt */ long *return_code /* wy; kod powrotu */ )
void HTTPD_LINKAGE HTTPD_exec ( unsigned char *handle, /* we; uchwyt */ unsigned char *name, /* we; nazwa skryptu do uruchomienia */ unsigned long *name_length, /* we; długość nazwy */ long *return_code /* wy; kod powrotu */ )
void HTTPD_LINKAGE HTTPD_extract ( unsigned char *handle, /* we; uchwyt */ unsigned char *name, /* we; nazwa zmiennej do wyodrębnienia */ unsigned long *name_length, /* we; długość nazwy */ unsigned char *value, /* wy; bufor, w którym należy umieścić wartość */ unsigned long *value_length, /* we/wy; wielkość buforu */ long *return_code /* wy; kod powrotu */ )
Zwrócenie przez tę funkcję kodu HTTPD_BUFFER_TOO_SMALL oznacza, że żądana wielkość buforu nie była wystarczająca dla wyodrębnionej wartości. W takim przypadku funkcja nie użyje tego buforu, lecz nada parametrowi value_length wartość wielkości buforu, która jest konieczna do pomyślnego wyodrębnienia tej wartości. Należy ponowić ekstrakcję, używając buforu, który jest nie mniejszy niż zwrócona wartość value_length.
void HTTPD_LINKAGE HTTPD_file ( unsigned char *handle, /* we; uchwyt */ unsigned char *name, /* we; nazwa pliku do wysłania */ unsigned long *name_length, /* we; długość nazwy */ long *return_code /* wy; kod powrotu */ )
const unsigned char * /* wy; wartość zmiennej */ HTTPD_LINKAGE httpd_getvar( unsigned char *handle, /* we; uchwyt */ unsigned char *name, /* we; nazwa zmiennej */ unsigned long *n /* we; liczba indeksu tablicy zawierającej nagłówek */ )
Indeks tablicy zawierającej nagłówek zaczyna się od cyfry 0. Aby pobrać pierwszy element tablicy, należy użyć w parametrze n wartości 0, natomiast aby uzyskać piąty element, należy użyć wartości 4.
void HTTPD_LINKAGE HTTPD_log_access ( unsigned char *handle, /* we; uchwyt */ unsigned char *value, /* we; dane do zapisania */ unsigned long *value_length, /* we; długość danych */ long *return_code /* wy; kod powrotu */ )
Należy pamiętać, że symbole zmiany znaczenia nie są wymagane przy zapisywaniu symbolu procentów (%) w dziennikach dostępu serwera.
void HTTPD_LINKAGE HTTPD_log_error ( unsigned char *handle, /* we; uchwyt */ unsigned char *value, /* we; dane do zapisania */ unsigned long *value_length, /* we; długość danych */ long *return_code /* wy; kod powrotu */ )
Należy pamiętać, że symbole zmiany znaczenia nie są wymagane przy zapisywaniu symbolu procentów (%) w dziennikach błędów serwera.
void HTTPD_LINKAGE HTTPD_log_event ( unsigned char *handle, /* we; uchwyt */ unsigned char *value, /* we; dane do zapisania */ unsigned long *value_length, /* we; długość danych */ long *return_code /* wy; kod powrotu */ )
Należy pamiętać, że symbole zmiany znaczenia nie są wymagane przy zapisywaniu symbolu procentów (%) w dziennikach zdarzeń serwera.
void HTTPD_LINKAGE HTTPD_log_trace ( unsigned char *handle, /* we; uchwyt */ unsigned char *value, /* we; dane do zapisania */ unsigned long *value_length, /* we; długość danych */ long *return_code /* wy; kod powrotu */ )
Należy pamiętać, że symbole zmiany znaczenia nie są wymagane przy zapisywaniu symbolu procentów (%) w dziennikach śledzenia serwera.
void HTTPD_LINKAGE HTTPD_open ( unsigned char *handle, /* we; uchwyt */ long *return_code /* wy; kod powrotu */ )
void HTTPD_LINKAGE HTTPD_proxy ( unsigned char *handle, /* we; uchwyt */ unsigned char *url_name, /* we; adres URL dla żądania proxy */ unsigned long *name_length, /* we; długość adresu URL */ void *request_body, /* we; treść żądania */ unsigned long *body_length, /* we; długość treści */ long *return_code /* wy; kod powrotu */ )
void HTTPD_LINKAGE HTTPD_read ( unsigned char *handle, /* we; uchwyt */ unsigned char *value, /* we; bufor danych */ unsigned long *value_length, /* we/wy; wielkość buforu (długość danych) */ long *return_code /* wy; kod powrotu */ )
void HTTPD_LINKAGE HTTPD_restart ( long *return_code /* wy; kod powrotu */ )
Należy pamiętać, że za pomocą tej funkcji można także tworzyć zmienne. Zmienne te podlegają konwencjom tworzenia przedrostków HTTP_ oraz PROXY_, które zostały opisane w sekcji Zmienne. Jeśli zostanie utworzona zmienna, której nazwa rozpoczyna się od przedrostka HTTP_, będzie ona wysłana jako nagłówek w odpowiedzi do klienta bez przedrostka HTTP_. Na przykład aby ustawić nagłówek Location, należy użyć funkcji HTTPD_set() z nazwą zmiennej HTTP_LOCATION. Zmienne z przedrostkiem PROXY_ są wysyłane jako nagłówki żądania do serwera treści. Zmienne utworzone z przedrostkiem CGI_ są przekazywane do programów CGI.
Mimo że ta funkcja jest poprawna we wszystkich krokach, to niektóre zmienne mogą nie być poprawne w niektórych krokach.
void HTTPD_LINKAGE HTTPD_set ( unsigned char *handle, /* we; uchwyt */ unsigned char *name, /* we; nazwa wartości do ustawienia */ unsigned long *name_length, /* we; długość nazwy */ unsigned char *value, /* we; bufor z wartością */ unsigned long *value_length, /* we; długość wartości */ long *return_code /* wy; kod powrotu */ )
long /* wy; kod powrotu */ HTTPD_LINKAGE httpd_setvar ( unsigned char *handle, /* we; uchwyt */ unsigned char *name, /* we; nazwa zmiennej */ unsigned char *value, /* we; nowa wartość */ unsigned long *addHdr /* we; dodawanie lub zastępowanie nagłówka */ )
Parametr addHdr może przyjąć cztery wartości:
Wartości te zostały zdefiniowane w pliku nagłówków HTAPI.h.
void HTTPD_LINKAGE httpd_variant_insert ( unsigned char *handle, /* we; uchwyt */ unsigned char *URI, /* we; identyfikator URI obiektu */ unsigned char *dimension, /* we; wymiar różnicy */ unsigned char *variant, /* we; wartość wariantu */ unsigned char *filename, /* we; plik zawierający obiekt */ long *return_code /* wy; kod powrotu */ )
Uwagi:
Mozilla 4.0 (compatible; BatBrowser 94.1.2; Bat OS)
void HTTPD_LINKAGE httpd_variant_lookup ( unsigned char *handle, /* we; uchwyt */ unsigned char *URI, /* identyfikator URI obiektu */ unsigned char *dimension, /* we; wymiar różnicy */ unsigned char *variant, /* we; wartość wariantu */ long *return_code); /* wy; kod powrotu */
Jeśli typ treści nie zostanie ustawiony przed pierwszym wywołaniem tej funkcji, serwer zakłada, że wysyłany jest strumień danych CGI.
void HTTPD_LINKAGE HTTPD_write ( unsigned char *handle, /* we; uchwyt */ unsigned char *value, /* we; dane do wysłania */ unsigned char *value_length, /* we; długość danych */ long *return_code); /* wy; kod powrotu */
Serwer ustawi parametr kodu powrotu na jedną z poniższych wartości w zależności od tego, czy żądanie zakończyło się powodzeniem:
Wartość | Kod statusu | Wyjaśnienie |
---|---|---|
-1 | HTTPD_UNSUPPORTED | Funkcja nie jest obsługiwana. |
0 | HTTPD_SUCCESS | Funkcja została wykonana pomyślnie i pola wyjściowe są poprawne. |
1 | HTTPD_FAILURE | Funkcja nie powiodła się. |
2 | HTTPD_INTERNAL_ERROR | Napotkano błąd wewnętrzny i nie można kontynuować przetwarzania tego żądania. |
3 | HTTPD_PARAMETER_ERROR | Przekazano jeden lub większą liczbę niepoprawnych parametrów. |
4 | HTTPD_STATE_CHECK | Funkcja nie jest poprawna w tym kroku przetwarzania. |
5 | HTTPD_READ_ONLY | (Zwracany tylko przez funkcje HTTPD_set i httpd_setvar). Zmienna tylko do odczytu, nie może być ustawiana przez wtyczkę. |
6 | HTTPD_BUFFER_TOO_SMALL | (Zwracany przez funkcje HTTPD_set, httpd_setvar oraz HTTPD_read). Udostępniony bufor jest za mały. |
7 | HTTPD_AUTHENTICATE_FAILED | (Zwracany tylko przez funkcję HTTPD_authenticate). Uwierzytelnianie nie powiodło się. Aby uzyskać więcej informacji, należy sprawdzić zmienne HTTP_RESPONSE i HTTP_REASON. |
8 | HTTPD_EOF | (Zwracany tylko przez funkcję HTTPD_read). Wskazuje koniec treści żądania. |
9 | HTTPD_ABORT_REQUEST | Żądanie zostało przerwane, ponieważ klient udostępnił znacznik obiektu, który nie był zgodny z warunkiem określonym przez żądanie. |
10 | HTTPD_REQUEST_SERVICED | (Zwracany przez funkcję HTTPD_proxy.) Wywołana funkcja zakończyła proces odpowiadania na żądanie. |
11 | HTTPD_RESPONSE_ALREADY_COMPLETED | Funkcja nie powiodła się, ponieważ odpowiedź na to żądanie została już udzielona. |
12 | HTTPD_WRITE_ONLY | Zmienna tylko do zapisu, nie może być odczytywana przez wtyczkę. |
Dla każdego kroku w procesie przetwarzania żądania istnieje dyrektywa konfiguracyjna służącą do określania funkcji wtyczki, które mają zostać wywołane i wykonane w danym kroku. Dyrektywy można dodawać do pliku konfiguracyjnego serwera (ibmproxy.conf) ręcznie edytując i aktualizując go, lub używając formularza Przetwarzanie żądań interfejsu API znajdującego się na stronie Konfigurowanie i administrowanie komponentu Buforujący serwer proxy.
Oznacza to, że serwer przetwarza dyrektywy Service, NameTrans, Exec, Fail, Map, Pass, Proxy, ProxyWAS oraz Redirect w porządku, w którym występują w pliku konfiguracyjnym. Jeśli serwer pomyślnie odwzoruje adres URL na plik, nie czyta ani nie przetwarza kolejnych dyrektyw. (Dyrektywa Map jest wyjątkiem. Podręcznik administrowania komponentem Buforujący serwer proxy produktu WebSphere Application Server zawiera pełne informacje dotyczące reguł odwzorowywania serwera proxy).
Dyrektywy pliku konfiguracyjnego muszą występować w pliku ibmproxy.conf w jednym wierszu, bez odstępów innych niż te jawnie określone poniżej. Chociaż w niektórych przykładach umieszczone zostały znaczniki łamania wiersza w celu zachowania czytelności, w rzeczywistych dyrektywach w tych miejscach nie mogą pojawić się odstępy.
Zmienne w dyrektywach mają następujące znaczenie:
Dyrektywa Service wymaga podania znaku gwiazdki (*) po nazwie funkcji, aby możliwy był dostęp do informacji o ścieżce.
Więcej informacji dotyczących dyrektyw, w tym opisy składni, zawiera Podręcznik administrowania komponentem Buforujący serwer proxy produktu WebSphere Application Server.
Interfejs API komponentu Buforujący serwer proxy jest kompatybilny wstecz z interfejsami ICAPI i GWAPI do wersji 4.6.1.
Aby przenieść aplikacje CGI napisane w języku C tak, aby używały interfejsu API komponentu Buforujący serwer proxy, należy skorzystać z poniższych wytycznych:
Pisząc programy z zastosowaniem interfejsu API, można używać zmiennych komponentu Buforujący serwer proxy, które udostępniają informacje o zdalnym kliencie i systemie serwera.
Uwagi:
ACCEPT_RANGES BYTES CLIENT_ADDR 9.67.84.3
Zmienna ta może być używana w krokach PostAuthorization, PostExit, ProxyAdvisor i 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
Najpierw krótki przegląd terminologii:
Rysunek 3 ilustruje proces uwierzytelniania i autoryzacji serwera proxy.
Zgodnie z tym co zaprezentowano na diagramie Rysunek 3 inicjowanie procesu autoryzacji jest pierwszym krokiem w procesie autoryzacji i uwierzytelniania serwera.
W komponencie Buforujący serwer proxy uwierzytelnianie jest częścią procesu autoryzacji. Jest wykonywane tylko wtedy, gdy wymagana jest autoryzacja.
Podczas przetwarzania żądania, które wymaga autoryzacji, serwer proxy wykonuje następujące kroki.
Jeśli wtyczka komponentu Buforujący serwer proxy udostępnia własny proces autoryzacji, przesłania on domyślną autoryzację i uwierzytelnianie serwera. Jeśli w pliku konfiguracyjnym znajdują się dyrektywy autoryzacji, funkcje wtyczki powiązane z nimi muszą także obsługiwać niezbędne uwierzytelnianie. Można użyć udostępnionej predefiniowanej funkcji HTTPD_authenticate().
Obsługę uwierzytelniania we wtyczkach autoryzacji można zapewnić na trzy sposoby:
Podczas wykonywania kroku Autoryzacja wywoływana jest funkcja wtyczki autoryzacji, która z kolei wywołuje funkcję wtyczki uwierzytelniania.
Podczas wykonywania kroku Autoryzacja wywoływana jest funkcja wtyczki autoryzacji, która z kolei wywołuje domyślne uwierzytelnianie serwera.
Podczas wykonywania kroku Autoryzacja wywoływana jest funkcja wtyczki autoryzacji i wykonywane są zawarte w niej elementy uwierzytelniania.
Jeśli wtyczka komponentu Buforujący serwer proxy nie udostępnia własnego procesu autoryzacji, można udostępnić dostosowane uwierzytelnianie przy użyciu następującej metody:
Podczas wykonywania kroku Autoryzacja wywoływana jest domyślna autoryzacja serwera, która z kolei wywołuje funkcję wtyczki uwierzytelniania.
Należy pamiętać o następujących punktach:
Funkcji buforowania wariantów należy używać do buforowania danych, które są zmodyfikowaną wersją dokumentu oryginalnego (identyfikatora URI). Komponent Buforujący serwer proxy obsługuje warianty wygenerowane przez ten interfejs API. Warianty to różne wersje dokumentu podstawowego.
Zazwyczaj jeśli serwery źródłowe wysyłają warianty, nie identyfikują ich jako takich. Komponent Buforujący serwer proxy obsługuje tylko warianty utworzone przez wtyczki (na przykład w wyniku konwersji strony kodowej). Jeśli wtyczka tworzy wariant na podstawie kryteriów, które nie zostały podane w nagłówku HTTP, musi zawierać w kroku Przed wyjściem lub Po autoryzacji funkcję, która utworzy pseudonagłówek. Dzięki temu komponent Buforujący serwer proxy będzie mógł poprawnie zidentyfikować istniejący wariant.
Na przykład można użyć programu interfejsu API transmogryfikatora do modyfikowania żądanych przez użytkowników danych na podstawie wartości nagłówka User-Agent wysyłanego przez przeglądarkę. W funkcji zamykania należy zapisać zmodyfikowaną treść do pliku lub określić długość buforu i przekazać bufor jako argument danych. Następnie należy użyć funkcji buforowania wariantów, httpd_variant_insert() i httpd_variant_lookup(), aby umieścić treść w pamięci podręcznej.
Przed rozpoczęciem pisania własnych funkcji API komponentu Buforujący serwer proxy należy zapoznać się z programami przykładowymi udostępnionymi w katalogu samples instalacyjnego dysku CD produktu Edge Components. Dodatkowe informacje są dostępne w serwisie WWW produktu WebSphere Application Server, www.ibm.com/software/webservers/appserv/.
Ta sekcja omawia tworzenie niestandardowych doradców dla komponentu System równoważenia obciążenia.
Doradcy to programowe agenty, które działają w ramach komponentu System równoważenia obciążenia, udostępniając informacje o obciążeniu określonego serwera. Dla każdego standardowego protokołu (HTTP, SSL i innych) istnieje oddzielny doradca. Kod bazowy komponentu System równoważenia obciążenia wykonuje okresowo cykl doradcy, w czasie którego niezależnie sprawdzany jest status wszystkich serwerów znajdujących się w jego konfiguracji.
Możliwe jest tworzenie własnych doradców dla komponentu System równoważenia obciążenia w celu dostosowania sposobu określania obciążenia serwerów.
W systemach Windows: Jeśli używana jest instalacja komponentu System równoważenia obciążenia dla protokołów IPv4 i IPv6 oraz jeśli na danym komputerze używany jest protokół IPv6, w celu skorzystania z doradców należy zmodyfikować plik protocol znajdujący się w katalogu C:\windows\system32\drivers\etc\.
Należy wstawić następujący wiersz dla protokołu IPv6 w pliku protocol:
ipv6-icmp 58 IPv6-ICMP # Protokół komunikatów sterujących interfejsu IPv6
Ogólnie doradcy umożliwiają równoważnie obciążenia w następujący sposób.
Wraz z komponentem System równoważenia obciążenia dostarczani są standardowi doradcy dla następujących funkcji. Aby uzyskać szczegółowe informacje na temat tych doradców, patrz Podręcznik administrowania komponentem System równoważenia obciążenia produktu WebSphere Application Server.
Aby zapewnić obsługę protokołów, dla których nie istnieją standardowi doradcy, należy utworzyć doradców niestandardowych.
Niestandardowy doradca to mały fragment kodu Java udostępniany w postaci pliku klasy, który jest wywoływany przez kod bazowy komponentu System równoważenia obciążenia w celu określenia obciążenia serwera. Kod bazowy udostępnia wszystkie niezbędne usługi administracyjne, włącznie z uruchamianiem i zatrzymywaniem instancji niestandardowego doradcy, udostępnianiem statusu i raportów, rejestrowaniem informacji o historii w pliku dziennika oraz raportowaniem wyników doradcy do komponentu menedżera.
Kiedy kod bazowy komponentu System równoważenia obciążenia wywołuje niestandardowego doradcę, wykonywane są następujące czynności.
Niestandardowi doradcy mogą być zaprojektowani do interakcji z komponentem System równoważenia obciążenia w trybie normalnym lub w trybie zastępowania.
Wybór trybu działania jest określany w pliku niestandardowego doradcy jako parametr w metodzie konstruktora. Każdy doradca może działać tylko w jednym z tych trybów, co jest zależne od sposobu zaprojektowania tego doradcy.
W trybie normalnym niestandardowy doradca wymienia dane z serwerem, a kod bazowy doradcy mierzy czas wymiany i określa wartość obciążenia. Kod bazowy raportuje następnie tę wartość do menedżera. Niestandardowy doradca zwraca wartość 0, aby wskazać sukces, lub wartość -1, która oznacza błąd.
Aby określić tryb normalny, należy ustawić opcję zastępowania w konstruktorze na wartość false.
W trybie zastępowanie kod bazowy nie wykonuje żadnych pomiarów czasu. Kod niestandardowego doradcy wykonuje określone operacje na podstawie unikalnych wymagań, a następnie zwraca rzeczywistą wartość obciążenia. Kod bazowy akceptuje tę wartość i raportuje ją bez zmian do menedżera. Aby uzyskać najlepsze wyniki, należy znormalizować wartości obciążenia w zakresie od 10 do 1000, gdzie 10 oznacza szybki serwer, a 1000 - wolny serwer.
Aby określić tryb zastępowania, należy ustawić opcję zastępowania w konstruktorze na wartość true.
Nazwa pliku niestandardowego doradcy musi mieć formę ADV_nazwa.java, gdzie nazwa to nazwa wybrana dla doradcy. Pełna nazwa musi rozpoczynać się od przedrostka ADV_ z użyciem wielkich liter, a wszystkie pozostałe znaki muszą być wpisane z użyciem małych liter. Wymaganie użycia małych liter sprawia, że w komendzie służącej do uruchamiania doradcy nie jest rozróżniana wielkość liter.
Zgodnie z konwencjami języka Java, nazwa klasy zdefiniowanej w pliku musi być zgodna z nazwą tego pliku.
Tworzenie niestandardowych doradców musi odbywać się w języku Java. Ich kompilację należy wykonywać za pomocą kompilatora języka Java zainstalowanego na komputerze używanym do programowania. W czasie kompilacji przywoływane są następujące pliki:
W czasie kompilacji zmienna środowiskowa ścieżki klasy musi wskazywać zarówno plik niestandardowego doradcy, jak i plik klas bazowych. Komenda kompilacji może mieć następujący format:
javac -classpath /opt/ibm/edge/lb/servers/lib/ibmnd.jar ADV_nazwa.java
W tym przykładzie używana jest domyślna ścieżka instalacji w systemach Linux i UNIX. Plik doradcy nosi nazwę ADV_nazwa.java i jest zapisany w bieżącym katalogu.
Wynikiem kompilacji jest plik klasy, na przykład ADV_nazwa.class. Przed uruchomieniem doradcy należy skopiować ten plik klasy do katalogu ścieżka_instalacji/servers/lib/CustomAdvisors/.
Aby uruchomić niestandardowego doradcę, należy najpierw skopiować plik klasy doradcy do podkatalogu lib/CustomAdvisors/ na komputerze z komponentem System równoważenia obciążenia. Na przykład ścieżka do pliku niestandardowego doradcy o nazwie myping to ścieżka_instalacji/servers/lib/CustomAdvisors/ADV_myping.class.
Należy skonfigurować komponent System równoważenia obciążenia, uruchomić jego funkcję menedżera, a następnie wykonać komendę w celu uruchomienia niestandardowego doradcy. Niestandardowy doradca jest określany przez jego nazwę bez przedrostka ADV_ i rozszerzenia pliku:
dscontrol advisor start myping numer_portu
Numer portu określony w tej komendzie to port, który zostanie użyty przez doradcę do otwarcia połączenia z serwerem docelowym.
Podobnie jak wszyscy inni doradcy, również niestandardowy doradca rozszerza funkcje klasy bazowej doradcy o nazwie ADV_Base. Klasa bazowa doradcy wykonuje większość funkcji doradcy, takich jak raportowanie wartości obciążenia do menedżera w celu ich użycia w algorytmie wagi menedżera. Klasa bazowa doradcy jest także odpowiedzialna za operacje połączenia i zamknięcia gniazda, a także udostępnia metody wysyłania i odbioru używane przez doradcę. Doradca jest używany tylko do wysyłania i odbierania poprzez określony port danych dotyczących badanego serwera. Czas wykonywania metod TCP udostępnianych w ramach klasy bazowej doradcy jest mierzony, co pozwala na obliczanie obciążenia. Opcja konstruktora klasy bazowej doradcy umożliwia w razie konieczności zastąpienie istniejącej wartości obciążenia nową wartością zwróconą z doradcy.
Doradcy zawierają następujące metody klasy bazowej:
Szczegółowe informacje dotyczące wymaganych procedur są przedstawione w dalszej części tej sekcji.
Niestandardowi doradcy są wywoływani po zakończeniu wyszukiwania standardowych (rodzimych) doradców. Jeśli komponent System równoważenia obciążenia nie znajdzie określonego doradcy na liście standardowych doradców, sprawdza listę doradców niestandardowych. Aby uzyskać dodatkowe informacje na temat używania doradców, patrz Podręcznik administrowania komponentem System równoważenia obciążenia produktu WebSphere Application Server.
Poniżej przedstawiono wymagania wobec nazw i ścieżek doradców niestandardowych.
void ADV_Base Constructor ( string sName; string sVersion; int iDefaultPort; int iInterval; string sDefaultLogFileName; boolean replace )
void ADV_AdvisorInitialize()
Metoda ta jest udostępniana w celu wykonywania inicjowania, które może być wymagane przez niestandardowego doradcę. Jest ona wywoływana po uruchomieniu podstawowego modułu doradcy.
W wielu sytuacjach, także w przypadku standardowych doradców, metoda ta nie jest używana, a jej kod zawiera tylko instrukcję return. Metody tej można używać do wywoływania metody suppressBaseOpeningSocket, której wywołanie jest poprawne tylko w tej metodzie.
int getLoad( int iConnectTime; ADV_Thread *caller )
Metody lub funkcje opisane w kolejnych sekcjach mogą być wywoływane przez niestandardowych doradców. Metody te są obsługiwane przez kod bazowy doradcy.
Niektóre z tych wywołań funkcji można wykonywać bezpośrednio, na przykład nazwa_funkcji(), ale inne wymagają przedrostka caller. Przedrostek caller oznacza instancję klasy bazowej doradcy obsługującą doradcę niestandardowego, który jest wykonywany.
Funkcja ADVLOG pozwala niestandardowemu doradcy na zapisywanie komunikatów tekstowych w pliku dziennika klasy bazowej doradcy. Stosowany jest następujący format:
void ADVLOG (int logLevel, string message)
Funkcja getAdvisorName zwraca łańcuch języka Java zawierający przyrostek nazwy niestandardowego doradcy. Na przykład dla doradcy o nazwie ADV_cdload.java funkcja ta zwróci wartość cdload.
Funkcja ta nie ma żadnych parametrów.
Nie jest możliwa zmiana tej wartości w czasie jednego procesu tworzenia instancji doradcy.
Funkcja getAdviseOnPort zwraca numer portu, na którym działa wywołujący ją doradca niestandardowy. Kod powrotu ma wartość będącą liczbą całkowitą (int) języka Java, a funkcja ta nie ma żadnych parametrów.
Nie jest możliwa zmiana tej wartości w czasie jednego procesu tworzenia instancji doradcy.
Funkcja getCurrentServer zwraca adres IP bieżącego serwera. Kod powrotu ma wartość będącą łańcuchem języka Java w formacie adresu IP, na przykład 128.0.72.139.
Zwykle adres ten zmienia się przy każdym wywołaniu niestandardowego doradcy, ponieważ kod bazowy doradcy odpytuje kolejno wszystkie serwery.
Funkcja ta nie ma żadnych parametrów.
Wywołanie funkcji getCurrentCluster zwraca adres IP bieżącego klastra serwerów. Kod powrotu ma wartość będącą łańcuchem języka Java w formacie adresu IP, na przykład 128.0.72.139.
Zwykle adres ten zmienia się przy każdym wywołaniu niestandardowego doradcy, ponieważ kod bazowy doradcy odpytuje kolejno wszystkie klastry serwerów.
Funkcja ta nie ma żadnych parametrów.
Funkcja getInterval zwraca odstęp czasu dla doradcy, czyli liczbę sekund między kolejnymi cyklami doradcy. Wartość ta jest równa wartości domyślnej ustawionej w konstruktorze niestandardowego doradcy, chyba że wartość ta została zmodyfikowana w czasie wykonywania za pomocą komendy dscontrol.
Kod powrotu ma wartość będącą liczbą całkowitą (int) języka Java. Funkcja ta nie ma żadnych parametrów.
Funkcja getLatestLoad umożliwia niestandardowemu doradcy uzyskanie ostatniej wartości obciążenia dla danego obiektu serwera. Wartości obciążenia są przechowywane w wewnętrznych tabelach przez kod bazowy doradcy i demona menedżera.
int caller.getLatestLoad (string cluster_IP, int port, string server_IP)
Trzy argumenty definiują wspólnie jeden obiekt serwera.
Kod powrotu ma wartość będącą liczbą całkowitą.
To wywołanie funkcji jest przydatne w sytuacji, gdy zachowanie określonego protokołu lub portu powinno być zależne od zachowania innego protokołu lub portu. Tego wywołania funkcji można użyć na przykład w niestandardowym doradcy, który wyłącza określony serwer aplikacji, jeśli wyłączony jest serwer Telnet na tym samym komputerze.
Funkcja receive pobiera informacje z połączenia gniazda.
caller.receive(stringbuffer *response)
Parametr response jest buforem łańcuchowym, w którym umieszczane są pobrane dane. Dodatkowo funkcja ta zwraca liczbę całkowitą, która ma następujące znaczenie:
Funkcja send używa nawiązanego połączenia gniazda do wysłania pakietu danych do serwera poprzez określony port.
caller.send(string command)
Parametr command to łańcuch zawierający dane do wysłania do serwera. Funkcja ta zwraca liczbę całkowitą, która ma następujące znaczenie:
Wywołanie funkcji suppressBaseOpeningSocket umożliwia niestandardowemu doradcy określenie, czy kod bazowy doradcy otwiera gniazdo TCP do serwera w imieniu niestandardowego doradcy. Jeśli doradca nie korzysta z bezpośredniej komunikacji z serwerem w celu określenia jego statusu, otwarcie tego gniazda może nie być konieczne.
To wywołanie funkcji może być wykonane tylko raz i to tylko w procedurze ADV_AdvisorInitialize.
Funkcja ta nie ma żadnych parametrów.
Poniższe przykłady przedstawiają sposoby implementacji niestandardowych doradców.
Ten przykładowy kod źródłowy przypomina standardowego doradcę HTTP komponentu System równoważenia obciążenia. Poniżej przedstawiono sposób jego działania:
Ten doradca działa w trybie normalnym, przez co pomiar obciążenia jest oparty na ilości czasu (w milisekundach) wymaganego do wykonania operacji otwarcia gniazda, wysłania, odbioru i zamknięcia gniazda.
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"; //-------- // Konstruktor 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; // Zwykle pusta procedura } //-------- // getLoad public int getLoad(int iConnectTime, ADV_Thread caller) { int iRc; int iLoad = ADV_HOST_INACCESSIBLE; // Inicjowanie jako niedostępnego iRc = caller.send(ADV_SEND_REQUEST); // Wysłanie żądania HTTP // z serwera if (0 <= iRc) { // Jeśli wysyłanie powiodło się, StringBuffer sbReceiveData = new StringBuffer(""); // przydzielenie buforu // na odpowiedź iRc = caller.receive(sbReceiveData); // Odebranie wyniku // Analiza wyniku, jeśli jest to konieczne if (0 <= iRc) { // Jeśli odbieranie powiodło się, iLoad = 0; // zwrócenie wartości 0 oznaczającej sukces } // (wartość obciążenia doradcy jest ignorowana } // przez kod bazowy w trybie normalnym) return iLoad; } }
Ten przykład przedstawia sposób pominięcia standardowego gniazda otwartego przez klasę bazową doradcy. Doradca otwiera zamiast niego gniazdo strumienia bocznego Java w celu odpytania serwera. Ta procedura może być przydatna w przypadku serwerów używających do nasłuchu zapytań doradcy innego portu niż dla normalnego ruchu klientów.
W tym przykładzie serwer nasłuchuje na porcie 11999, a po zapytaniu zwraca wartość obciążenia w postaci szesnastkowej liczby całkowitej "4". Przykład ten działa w trybie zastępowania, co oznacza, że ostatni parametr konstruktora jest ustawiany na wartość "true", a kod bazowy doradcy używa zwróconej wartości obciążenia, a nie ilości czasu, jaki upłynął.
Należy zwrócić uwagę na wywołanie metody supressBaseOpeningSocket() w procedurze inicjowania. Pominięcie gniazda bazowego nie jest wymagane, jeśli nie będą wysyłane żadne dane. Gniazdo można otworzyć na przykład w celu upewnienia się, że doradca może skontaktować się z serwerem. Przed dokonaniem tego wyboru należy dokładnie zbadać wymagania aplikacji.
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; // Utworzenie tablicy bajtowej z komunikatem żądania ładowania 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); // Parametr trybu zastępowania ma wartość "true" super.setAdvisor( this ); } //-------- // ADV_AdvisorInitialize public void ADV_AdvisorInitialize() { suppressBaseOpeningSocket(); // Informacja dla kodu bazowego, aby nie otwierał // gniazda standardowego return; } //-------- // getLoad public int getLoad(int iConnectTime, ADV_Thread caller) { int iRc; int iLoad = ADV_HOST_INACCESSIBLE; // -1 int iControlPort = 11999; // Port służący do komunikacji z serwerem string sServer = caller.getCurrentServer(); // Adres serwera do odpytania try { socket soServer = new Socket(sServer, iControlPort); // Otwarcie gniazda // do serwera DataInputStream disServer = new DataInputStream( soServer.getInputStream()); DataOutputStream dosServer = new DataOutputStream( soServer.getOutputStream()); int iRecvTimeout = 10000; // Ustawienie limitu czasu (w milisekundach) // dla odbioru danych soServer.setSoTimeout(iRecvTimeout); dosServer.writeInt(4); // Wysłanie komunikatu do serwera dosServer.flush(); iLoad = disServer.readByte(); // Odebranie odpowiedzi z serwera } catch (exception e) { system.out.println("Wychwycono wyjątek " + e); } return iLoad; // Zwrócenie obciążenia zgłoszonego przez serwer } }
Ten przykład niestandardowego doradcy przedstawia możliwość wykrywania awarii portu serwera na podstawie jego statusu oraz statusu innego demona serwera, który działa na innym porcie na tym samym serwerze. Jeśli na przykład demon HTTP na porcie 80 przestaje odpowiadać, można również zatrzymać ruch związany z routingiem do demona SSL na porcie 443.
Ten doradca jest bardziej agresywny niż standardowi doradcy, ponieważ każdy serwer, który nie wysyła odpowiedzi, jest uznawany za niedziałający, a w konsekwencji oznaczany jako wyłączony. Standardowi doradcy przyjmują, że nie odpowiadające serwery są bardzo wolne. Ten doradca powoduje oznaczenie serwera jako wyłączonego zarówno dla portu HTTP, jak i dla portu SSL, na podstawie braku odpowiedzi z jednego z tych portów.
Aby użyć tego niestandardowego doradcy, administrator uruchamia jego dwie instancje - dla portu HTTP i dla portu SSL. Doradca tworzy instancje dwóch statycznych, globalnych tabel mieszających dla każdego z tych portów. Każdy doradca próbuje nawiązać komunikację z odpowiednim demonem serwera i umieszcza wyniki tego zdarzenia we własnej tabeli mieszającej. Wartość zwracana przez każdego doradcę do klasy bazowej doradcy jest zależna zarówno od możliwości komunikacji z własnym demonem serwera, jak i od możliwości komunikacji drugiego doradcy z jego demonem.
Użyte zostały następujące metody niestandardowe.
Wykrywane są następujące warunki błędu.
Przykład ten został utworzony w celu powiązania portu 80 dla protokołu HTTP i portu 443 dla protokołu SSL, ale można dostosować go do dowolnej kombinacji portów.
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; //-------- // Zdefiniowanie elementu tabeli dla tabel mieszających // używanych przez tego niestandardowego doradcę class ADV_nte implements Cloneable { private string sCluster; private int iPort; private string sServer; private int iLoad; private Date dTimestamp; //-------- // Konstruktor public ADV_nte(string sClusterIn, int iPortIn, string sServerIn, int iLoadIn) { sCluster = sClusterIn; iPort = iPortIn; sServer = sServerIn; iLoad = iLoadIn; dTimestamp = new Date(); } //-------- // Sprawdzenie, czy ten element jest aktualny czy też utracił ważność public boolean isCurrent(ADV_twop oThis) { boolean bCurrent; int iLifetimeMs = 3 * 1000 * oThis.getInterval(); // Ustawienie czasu życia // na trzy cykle doradcy Date dNow = new Date(); Date dExpires = new Date(dTimestamp.getTime() + iLifetimeMs); if (dNow.after(dExpires)) { bCurrent = false; } else { bCurrent = true; } return bCurrent; } //-------- // Akcesory wartości public int getLoadValue() { return iLoad; } //-------- // Klonowanie (pozwala uniknąć uszkodzenia między wątkami) public synchronized Object Clone() { try { return super.clone(); } catch (cloneNotSupportedException e) { return null; } } } //-------- // Zdefiniowanie niestandardowego doradcy 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; //-------- // Zdefiniowanie tabel do przechowywania informacji o historii // dla poszczególnych portów 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"; //-------- // Utworzenie tablicy bajtowej z komunikatem powitania klienta SSL public static final byte[] abClientHello = { (byte)0x80, (byte)0x1c, (byte)0x01, // Powitanie klienta (byte)0x03, (byte)0x00, // Wersja SSL (byte)0x00, (byte)0x03, // Długość specyfikacji szyfru (w bajtach) (byte)0x00, (byte)0x00, // Długość identyfikatora sesji (w bajtach) (byte)0x00, (byte)0x10, // Długość danych wezwania (w bajtach) (byte)0x00, (byte)0x00, (byte)0x03, // Specyfikacja szyfru (byte)0x1A, (byte)0xFC, (byte)0xE5, (byte)Ox20, // Dane wezwania (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 }; //-------- // Konstruktor public ADV_twop() { super(ADV_TWOP_NAME, VERSION, ADV_TWOP_DEF_ADV_ON_PORT, ADV_TWOP_DEF_INTERVAL, "", false); // false = komponent System równoważenia obciążenia // mierzy czas odpowiedzi setAdvisor ( this ); } //-------- // ADV_AdvisorInitialize public void ADV_AdvisorInitialize() { return; } //-------- // Zsynchronizowane procedury dostępu PUT i GET dla tabel mieszających 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 - określenie obciążenia serwera HTTP // na podstawie odpowiedzi serwera int getLoadHTTP(int iConnectTime, ADV_Thread caller) { int iLoad = ADV_HOST_INACCESSIBLE; int iRc = caller.send(ADV_HTTP_REQUEST_STRING); // Wysłanie komunikatu // żądania do serwera if (0 <= iRc) { // Czy żądanie zwróciło niepowodzenie? StringBuffer sbReceiveData = new StringBuffer("") // Przydzielenie buforu // na odpowiedź iRc = caller.receive(sbReceiveData); // Uzyskanie odpowiedzi z serwera if (0 <= iRc) { // Czy metoda receive zwróciła niepowodzenie? if (0 < sbReceiveData.length()) { // Czy istnieją dane? iLoad = SUCCESS; // Zignorowanie pobranych danych // i zwrócenie kodu sukcesu } } } return iLoad; } //-------- // getLoadSSL() - określenie obciążenia serwera SSL // na podstawie odpowiedzi serwera int getLoadSSL(int iConnectTime, ASV_Thread caller) { int iLoad = ADV_HOST_INACCESSIBLE; int iSocket = caller.getAdvisorSocket(); // Wysłanie żądania szesnastkowego // do serwera CMNByteArrayWrapper cbawClientHello = new CMNByteArrayWrapper( abClientHello); int iRc = SRV_ConfigServer.socketapi.sendBytes(iSocket, cbawClientHello); if (0 <= iRc) { // Czy żądanie zwróciło niepowodzenie? StringBuffer sbReceiveData = new StringBuffer(""); // Przydzielenie buforu // na odpowiedź iRc = caller.receive(sbReceiveData); // Uzyskanie odpowiedzi // z serwera if (0 <= iRc) { // Czy metoda receive zwróciła niepowodzenie? if (0 < sbReceiveData.length()) { // Czy istnieją dane? iLoad = SUCCESS; // Zignorowanie pobranych danych // i zwrócenie kodu sukcesu } } } return iLoad; } //-------- // getLoad - scalenie wyników metod HTTP i SSL public int getLoad(int iConnectTime, ADV_Thread caller) { int iLoadHTTP; int iLoadSSL; int iLoad; int iRc; String sCluster = caller.getCurrentCluster(); // Adres bieżącego klastra int iPort = getAdviseOnPort(); String sServer = caller.getCurrentServer(); String sHashKey = sCluster = ":" + sServer; // Klucz tabeli mieszającej if (ADV_TWOP_PORT_HTTP == iPort) { // Obsługa serwera HTTP iLoadHTTP = getLoadHTTP(iConnectTime, caller); // Uzyskanie obciążenia // serwera HTTP ADV_nte nteHTTP = newADV_nte(sCluster, iPort, sServer, iLoadHTTP); putNte(htTwopHTTP, "HTTP", sHashKey, nteHTTP); // Zapisanie informacji // o obciążeniu //serwera SSL ADV_nte nteSSL = getNte(htTwopSSL, "SSL", sHashKey); // Uzyskanie // informacji // dotyczących // serwera SSL if (null != nteSSL) { if (true == nteSSL.isCurrent(this)) { // Sprawdzenie znacznika czasu if (ADV_HOST_INACCESSIBLE != nteSSL.getLoadValue()) { // Czy serwer // SSL działa? iLoad = iLoadHTTP; } else { // Serwer SSL nie działa, należy więc oznaczyć // serwer HTTP jako wyłączony iLoad= ADV_HOST_INACCESSIBLE; } } else { // Informacje o serwerze SSL utraciły ważność, // należy więc oznaczyć serwer HTTP jako wyłączony iLoad = ADV_HOST_INACCESSIBLE; } } else { // Brak informacji o obciążeniu serwera SSL, // zgłoszenie wyników metody getLoadHTTP() iLoad = iLoadHTTP; } } else if (ADV_TWOP_PORT_SSL == iPort) { // Obsługa serwera SSL iLoadSSL = getLoadSSL(iConnectTime, caller); // Uzyskanie obciążenia // serwera SSL ADV_nte nteSSL = new ADV_nte(sCluster, iPort, sServer, iLoadSSL); putNte(htTwopSSL, "SSL", sHashKey, nteSSL); // Zapisanie informacji // o obciążeniu // serwera SSL ADV_nte nteHTTP = getNte(htTwopHTTP, "SSL", sHashKey); // Uzyskanie // informacji // dotyczących // serwera SSL if (null != nteHTTP) { if (true == nteHTTP.isCurrent(this)) { // Sprawdzenie znacznika czasu if (ADV_HOST_INACCESSIBLE != nteHTTP.getLoadValue()) { // Czy serwer // HTTP // działa? iLoad = iLoadSSL; } else { // Serwer HTTP nie działa, należy więc oznaczyć // serwer SSL jako wyłączony iLoad = ADV_HOST_INACCESSIBLE; } } else { // Informacje z serwera HTTP utraciły ważność, // należy więc oznaczyć serwer SSL jako wyłączony iLoad = ADV_HOST_INACCESSIBLE; } } else { // Brak informacji o obciążeniu serwera HTTP, // zgłoszenie wyników metody getLoadSSL() iLoad = iLoadSSL; } } //-------- // procedura obsługi błędów else { iLoad = ADV_HOST_INACCESSIBLE; } return iLoad; } }
Przykładowy doradca niestandardowy dla serwera WebSphere Application Server znajduje się w katalogu ścieżka_instalacji/servers/samples/CustomAdvisors/. Pełny kod tego doradcy nie zostanie powtórzony w niniejszym dokumencie.
Pełny doradca jest trochę bardziej złożony niż ten przykład. Doradca dodaje specjalną procedurę analizowania, która jest bardziej zwarta niż przedstawiony powyżej przykład StringTokenizer.
Bardziej skomplikowana część kodu przykładowego znajduje się w serwlecie Java. Oprócz innych metod, serwlet zawiera dwie metody wymagane przez specyfikację serwletu: init() i service(), a także metodę run() wymaganą przez klasę Java.lang.thread.
Odpowiednie fragmenty kodu serwletu zostały przedstawione poniżej.
... 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; } ...
Niezależnie od tego, czy używane jest standardowe wywołanie istniejącej części serwera aplikacji, czy też dodawany jest fragment kodu, który będzie odpowiednikiem niestandardowego doradcy po stronie serwera, prawdopodobnie konieczne będzie zbadanie zwróconych wartości obciążenia i zmodyfikowanie zachowania serwera. Klasa Java StringTokenizer i jej powiązane metody ułatwiają proces analizowania danych.
Typowa komenda HTTP może mieć postać GET /index.html HTTP/1.0
Typowa odpowiedź na tę komendę może mieć następującą postać.
HTTP/1.1 200 OK Date: Mon, 20 November 2000 14:09:57 GMT Server: Apache/1.3.12 (Linux and 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: pl <!DOCTYPE HTML PUBLIC "-//w3c//DTD HTML 3.2 Final//EN"> <HTML><HEAD><TITLE>Strona testowa</TITLE></HEAD> <BODY><H1>Serwer Apache</H1> <HR> <P><P>Na tym serwerze WWW działa program Apache 1.3.12. <P><HR> <P><IMG SRC="apache_pb.gif" ALT=""> </BODY></HTML>
Najbardziej interesujące informacje, a w szczególności kod powrotu HTTP, są zawarte w pierwszym wierszu.
Specyfikacja protokołu HTTP klasyfikuje kody powrotu w następujący sposób:
Jeśli dokładnie wiadomo, jakie kody mogą zostać zwrócone przez serwer, zastosowany kod nie musi być aż tak szczegółowy jak w tym przykładzie. Należy jednak pamiętać, że ograniczenie wykrywanych kodów powrotu może wpłynąć negatywnie na elastyczność programu w przyszłości.
Poniższy przykład przedstawia autonomiczny program Java zawierający podstawowego klienta HTTP. Przykład wywołuje prosty analizator składni ogólnego przeznaczenia służący do badania odpowiedzi 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("Wersja HTTP: " + sHTTPVersion); } else { System.out.println("Niepoprawna wersja HTTP: " + sHTTPVersion); } } else { System.out.println("Nic nie zwrócono"); return; } if (true == st.hasMoreTokens()) { sHTTPReturnCode = st.nextToken(); try { iRc = Integer.parseInt(sHTTPReturnCode); } catch (NumberFormatException ne) {;} switch (iRc) { case(200): System.out.println("Kod odpowiedzi HTTP: OK, " + iRc); break; case(400): case(401): case(402): case(403): case(404): System.out.println("Kod odpowiedzi HTTP: Błąd klienta, " + iRc); break; case(500): case(501): case(502): case(503): System.out.println("Kod odpowiedzi HTTP: Błąd serwera, " + iRc); break; default: System.out.println("Kod odpowiedzi HTTP: Nieznany, " + iRc); break; } } if (true == st.hasMoreTokens()) { while (true == st.hasMoreTokens()) { sbText.append(st.nextToken()); sbText.append(" "); } System.out.println("Fraza odpowiedzi HTTP: " + sbText.toString()); } } }