Wstęp
WSF jest bazowym produktem open source (framework) pozwalającym na stworzenie własnego Web Service na podstawie którego opracowano szereg rozszerzeń. Cały pakiet jest dostępnych do ściągnięcia na stronie www.wso2.org.
Instalacja
Moje uwagi do instalacji na serwerze typu Linux dystrybucja Debian:
- Przed kompilacją upewnić się, że niezbędne pakiety są zainstalowane wywołując odpowiednie polecenia z shell wmoim porzypadku były to:
- apt-get install php5
- apt-get install php5-dev
- apt-get install pkg-config
- apt-get install libapache2-mod-php5
- apt-get install libxml2
- apt-get install libxml2-dev
- Ściągnąć i rozpakować do katalogu /tmp wersję tar.gz pliku a następnie mając uprawnienia pozwalające na kompilację pakietów wywołać kolejno polecenia z poziomu shell:
- ./configure
- make
- make install
- Jeżeli podczas wywołania jednej z powyższych operacji zwracany jest błąd przeanalizować wyświetlony komunikat i wrócić do punktu pierwszego doinstalowywując w razie potrzeby odpowiednie pakiety.
- Dopisać zgodnie ze wskazówkami umieszczonymi w pliku README.INSTALL odpowiednie komendy w pliku konfiguracyjnym /etc/php.ini
Uwagi do instalacji na serwerze w środowisku Windows typu WAMP:
- Sprawdzić, czy zainstalowane są wszystkie niezbędne biblioteki:
- axis2c.dll
- Po zainstalowaniu rozszerzenia WSF w środowisku Windows lub Linux możemy przejść do zasadniczej części napisania własnego Web Service.
Założenia
Mój przykład będzie polegał na utworzeniu usługi przypisującej do zmiennej in_id przekazaną wartość, oraz do zmiennej ob_nodes tablicę z zerowym indexem zawierającym pusty obiekt wyjściowego typu. W normalnym środowisku funkcje tego rodzaju powinny pobierać i odpowiednio przetwarzać rekordy z bazy danych wówczas web service służy do komunikacji z bazą, a właściwa aplikacja odpowiedzialna jest za wizualizację wyników.
Kod Web Service
- Definicja nagłówka
/**
* Web Service
*
* @package Example
* @author Michal Luberda luberda@iap.pl
* @version 0.1>
*/
- Definicja interfejsu klasy.
Zanim przystąpię do pisania właściwego kodu proponuję stworzenie bazowego interfejsu klasy w którym zadeklaruję funkcje wymagane do prawidłowego działania WS.
/**
* Menu
*/
interface Interface_Menu
{
/**
* getMenu
*
* get menu example
*
* @param int $in_id node's id
* @return array of object getMenuResponse $ob_nodes nodes' list
*/
public function getMenu ($in_id = 0);
}
Po co wogóle korzystać z interfajsów a tym bardziej z komentarzy, które zwykle w tym przypadku zajmują więcej miejsca niż sam kod?
Korzystając umiejętnie z interfejsów oraz komentarzy w PHP mamy możliwość tworzenia automatycznie generowanej dokumentacji API dla potencjalnych developerów korzystających z naszego WS ograniczając wynik tylko do wybranych funkcji. Polecam tutaj PHPdocumentor, jako narzędzie pozwalające na tworzenie dokumentacji na podstawie plików źródłowych projektu.
- Definicja obiektu wyjściowego.
/**
* @namespace myservice/menu
*/
class getMenuResponse
{
/**
* @var int $in_id record's id
* (maps to xs:nonNegativeInteger)
*/
public $in_id;
/**
* @var array of object getMenuResponse $ob_nodes nested nodes
* (maps to xs:anyType)
*/
public $ob_nodes;
}
Wymogiem WSF podczas tworzenia własnego kodu Web Service jest umiejętny sposób pisania komentarzy, na podstawie których rozszerzenie tworzy dynamicznie plik WSDL (Web Services Description Language).
- Definicja oraz oprogramowanie klasy wykonującej zadaną operację.
/**
* Menu
*/
class Menu implements Interface_Menu
{
/**
* __construct
*/
function __construct () {}
/**
* getMenu
*
* get menu example
*
* @param int $in_id node's id
* (maps to the xs:nonNegativeInteger XML schema type)
* @return array of object getMenuResponse $ob_nodes nodes' list
* (maps to the xs:anyType XML schema type)
*/
public function getMenu ($in_id = 0)
{
$ob = new getMenuResponse ();
$ob -> in_id = $in_id;
$ob -> ob_nodes = array ();
$ob -> ob_nodes[] = new getMenuResponse ();
return array ("ob_nodes" => $ob);
}
}
- Inicjalizacja Web Service.
// define classes
$ar_classes = array (
"Menu" => array (
"operations" => array (
"getMenu" => "getMenu"
)
)
);
// define parameters
$ar_parameters = array(
"getMenu" => "MIXED"
);
// create WS
$ob_service = new WSService (array (
"classes" => $ar_classes,
"bindingStyle" => "doclit",
"opParams" => $ar_parameters
));
$ob_service -> reply();
Cały utworzony plik proponuję zapisać na serwerze pod nazwą example.ws.php i uruchomić z poziomu przeglądarki. Jeśli wszystko przebiegnie zgodnie z planem uruchomienie pliku wyświetli komunikat o dostępnych operacjach. Uruchomienie pliku z parametrem, czyli example.ws.php?wsdl wyświetli z kolei wygenerowany WSDL.
Client
Teraz przejdę do części w której podam przykład strony klienta (client), która będzie w stanie wykorzystać wcześniej przygotowany Web Service.
Kod Client
- Na początek nagłówek:
/**
* Client
*
* @package Example
* @author Michal Luberda luberda@iap.pl
* @version 0.1
*/
- Definiowanie klas zapytania i odpowiedzi wraz z mapą:
// define request class
class getMenuRequest
{
public $in_id;
}
// define response class
class getMenuResponse
{
public $ob_nodes;
}
// define class map
$ar_classmap = array (
"getMenuRequest" => "getMenuRequest",
"getMenuResponse" => "getMenuResponse"
);
- Wywołanie Web Service
try {
$ob_wsclient = new WSClient (array (
// UWAGA! Tutaj należy podać pełny adres pod którym znajduje się utworzony poprzednio plik WSDL Web Service.
"wsdl" => "example.ws.php?wsdl",
"classmap" => $ar_classmap
));
$proxy = $ob_wsclient -> getProxy ();
$ob_input = new getMenuRequest ();
// set example value
$ob_input -> in_id = 99;
// get response object
$ob = $proxy-> getMenu ($ob_input);
// print result
print_r ($ob);
}
catch (Exception $e) {
if ($e instanceof WSFault) {
printf ("Soap Fault Reason: %s\n", $e -> Reason);
printf ("Soap Fault Code: %s \n", $e -> Code);
}
else {
printf ("Message = %s\n",$e -> getMessage ());
}
}
I to wszystko wystarczy teraz powyższy plik zapisać na serwerze pod nazwą client.php. Wywołując go z poziomu przeglądarki wyświetlony zostanie obiekt z rezultatem operacji. Należy pamiętać jedynie o podmianie ścieżki do wcześniej utworzonego pliku example.ws.php.
Podsumowanie
Tworząc umiejętnie Web Service można przygotować optymalny kod pod względem funkcjonalności oraz łatwości w modyfikacji, gdzie warstwa wizualizacyjna będzie odłączona od warstwy logicznej projektu i komunikacji z bazą danych.
W przypadku połączeń z bazą danych polecam stosowanie statycznych obiektów typu singletone, które będą dostępne jako zmienna globalna niezależnie od miejsca wywołania.
Jedną z wad korzystania z WSF (w momencie kiedy piszę te słowa) jest konieczność restartu Web Servera po modyfikacjach metod i klas WS. Czasmi zachodzi również konieczność skasowania z katalogu /tmp pliku wsdl-*, gdzie * oznacza niepowtarzalny alfanumeryczny ciąg znaków. Z tego co zdążyłem zauważyć problem jest dość świeży, znalazłem topik na forum WSO2 z końca marca 2009 roku w którym to autorzy systemu deklarują chęć usunięcia usterki.
Wenecja 2009 opracowany przez Michał Luberda