JBoss Web Services


Po długiej batalii z EJB przyszedł czas na wyjazd do Wenecji. Chwila relaksu i oderwania od klawiatury – smażenie się na plaży w Lido, zwiedzanie wcale nie śmierdzących kanałów miasta, przejażdżka gondolą i niemal bójka w Padwie. Po tych jakże odprężających ćwiczeniach usiadłem na moment w domowym zaciszu przed komputerem i wpadła mi do głowy jedna myśl – jak skorzystać z Web Services w Jboss? Z technologią tą miałem sporo do czynienia w implementacji Oracle’owej na serwerze aplikacyjnym Weblogic. Tam jednak umysł programisty wyręcza myszka i JDeveloper. Generowany przez IDE kod jest nadmiarowy lecz o dziwo zazwyczaj działa :P.

Przystąpmy więc do części bardziej merytorycznej. Zacznę od krótkiego przypomnienia technologii Web Services, standardu SOAP oraz takich terminów jak np. WSDL. Web Service wykorzystuje jako warstwę transportu protokół HTTP (zazwyczaj, inne możliwości: SMTP, FTP, JMS) oraz język XML (w celu strukturyzacji przesyłanych danych). Komunikat SOAP ma formę XML’a składającego się z <Envelope>, oraz zagnieżdżonych w nim nagłówku <Header> i ciele <Body>.

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
                  xmlns:edu="edu.lantoniak.ws">
  <soapenv:Header/>
  <soapenv:Body>
    <edu:sayHello>Lukasz</edu:sayHello>
  </soapenv:Body>
</soapenv:Envelope>

Za opis udostępnianego przez Nas serwisu odpowiada WSDL. Jest on zwyczajowo umieszczony na serwerze aplikacyjnym i dostępny z poziomu przeglądarki internetowej. Klienci WS, na podstawie informacji zawartych w tym pliku, określić mogą typy wymaganych parametrów poszczególnych metod oraz wartości przez nich zwracanych. Jako deweloper Java rzadko piszę WSDL ręcznie. Deskryptor ów generowany jest automatycznie na podstawie klasy Java (implementacji Web Service’u) opatrzonej odpowiednimi adnotacjami. Poniżej zamieściłem przykładowy WSDL.

<definitions name="HelloService" targetNamespace="edu.lantoniak.ws">
  <types>
    <xs:schema targetNamespace="edu.lantoniak.ws" version="1.0">
      <xs:element name="sayHello" nillable="true" type="xs:string"/>
      <xs:element name="sayHelloResponse" nillable="true" type="xs:string"/>
    </xs:schema>
  </types>
  <message name="HelloWSRemote_sayHelloResponse">
    <part element="tns:sayHelloResponse" name="sayHelloResponse"/>
  </message>
  <message name="HelloWSRemote_sayHello">
    <part element="tns:sayHello" name="sayHello"/>
  </message>
  <portType name="HelloWSRemote">
    <operation name="sayHello" parameterOrder="sayHello">
      <input message="tns:HelloWSRemote_sayHello"/>
      <output message="tns:HelloWSRemote_sayHelloResponse"/>
    </operation>
  </portType>
  <binding name="HelloWSRemoteBinding" type="tns:HelloWSRemote">
    <soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
    <operation name="sayHello">
      <soap:operation soapAction=""/>
      <input>
        <soap:body use="literal"/>
      </input>
      <output>
        <soap:body use="literal"/>
      </output>
    </operation>
  </binding>
  <service name="HelloService">
    <port binding="tns:HelloWSRemoteBinding" name="HelloWSPort">
      <soap:address location="http://localhost:8080/Tutorial7/HelloWSImpl"/>
    </port>
  </service>
</definitions>

Wewnątrz tagu <types> określa się wszystkie typy danych stosowanych w serwisie (typy parametrów oraz wartości zwracanych wykorzystywanych w metodach). W Naszym przypadku, zdefiniowane są dwa proste typy klasy xs:string: sayHello oraz sayHelloResponse. Tag <message> specyfikuje wszystkie rodzaje wiadomości jakie obsługiwane są przez Web Service. Linijki 14 – 19 wiążą rodzaje wykorzystywanych wiadomości z poszczególnymi operacjami (metodami). Sekcja <binding> wyróżnia poszczególne operacje serwisu oraz definiuje szczegóły dotyczące stosowanego protokołu (w tym przypadku stylu document – por. RPC). Wreszcie, tag <service> specyfikuje nazwę serwisu oraz jego adres.

Implementacja prostego Web Service’u

W Eclipse, podobnie jak w JDeveloper, implementację Web Service’u oraz projektu proxy stosowanego przez klienta, można ponoć (mi się nie udało) w stosunkowo łatwy sposób wyklikać (rodzaje projektu: “Create a Sample Web Service” oraz “Web Service Client”). Zaprezentuję jednak drogą równie przyjemną metodę, nie opierającą się na kreatorach graficznych i klikologii, lecz na nieco bardziej przemyślanym użyciu klawiatury. Web Service tworzyć można na dwa sposoby: bottom up (najpierw klasy Java, a potem WSDL), lub top down (inaczej zwane contract first – najpierw WSDL, a następnie implementacja).

Stwórzmy nowy projekt EJB, a w nim bezstanowe (@Statefull nie jest wspierane, polecam zapoznać się z terminem conversational Web Service) ziarno EJB.

@Remote
@WebService(targetNamespace = "edu.lantoniak.ws")
@SOAPBinding(style = SOAPBinding.Style.DOCUMENT,
             parameterStyle = SOAPBinding.ParameterStyle.BARE)
public interface HelloWSRemote {
   public String sayHello(String name);
}

@Stateless
@WebService(serviceName = "HelloService", targetNamespace = "edu.lantoniak.ws",
            name = "HelloWS", endpointInterface = "edu.lantoniak.ws.HelloWSRemote")
@SOAPBinding(style = SOAPBinding.Style.DOCUMENT,
             parameterStyle = SOAPBinding.ParameterStyle.BARE)
public class HelloWSImpl implements HelloWSRemote {
   public String sayHello(String name) {
      return "Hello " + name + "!";
   }
}

Następnie deploy’ujemy aplikację. Uwaga: nazwa pod którą deploy’owana jest aplikacja nie może zawierać spacji! Aby upewnić się, że aplikacja wgrana została pomyślnie, przejdź do http://localhost:8080/jbossws/services i sprawdź, czy na liście serwisów widnieje Twoja nowo dodana usługa. Działanie samego Web Service’u weryfikujemy za pomocą narzędzia SoapUI.

W celu dalszej zabawy, polecam zapoznanie się z podstawowymi adnotacjami @WebMethod, @WebParam, @WebResult, oraz bardziej zaawansowanymi @OneWay i @HandlerChain.

Implementacja klienta standalone

Poniżej znajduje się kod prostego klienta, wywołującego wcześniej stworzony Web Service z poziomu Javy.

public class Main {
   public static void main(String[] args) {
      String endpointURI = "http://localhost:8080/Tutorial7/HelloWSImpl?wsdl";
      try {
         String hello = getPort(endpointURI).sayHello("Lukasz");
         System.out.println(hello);
      } catch (MalformedURLException e) {
         e.printStackTrace();
      }
   }

   private static HelloWSRemote getPort(String endpointURI) throws MalformedURLException {
      QName serviceName = new QName("edu.lantoniak.ws", "HelloService");
      URL wsdlURL = new URL(endpointURI);
      Service service = Service.create(wsdlURL, serviceName);
      return service.getPort(HelloWSRemote.class);
   }
}

Wstrzykiwanie proxy serwisu do ziaren EJB

W celu wywołania serwisu w ziarnie EJB, skorzystać należy z narzędzia wsconsume wchodzącego w skład serwera aplikacyjnego JBoss. Narzędzie to generuje klasy proxy Web Service’u, które następnie wepniemy za pomocą adnotacji @WebServiceRef. Stwórzmy nowy, pusty katalog w dowolnym miejscu na dysku twardym i wywołajmy polecenie: $JBOSS_HOME\bin\wsconsume.bat -p edu.lantoniak.ws.proxy http://localhost:8080/Tutorial7/HelloWSImpl?wsdl. Wygenerowane klasy (wraz z katalogami pakietu – w tym przypadku edu.lantoniak.ws.proxy) kopiujemy np. do katalogu generated w projekcie modułu EJB. Następnie w Eclipse klikamy prawym przyciskiem na projekt -> Properties -> Java Build Path -> Libraries -> Add Class Folder i wskazujemy na katalog generated. Pozostało Nam jedynie stworzenie nowego ziarna EJB korzystającego z Web Service’u:

@Stateless
public class StatelessSampleEJB implements StatelessSampleEJBRemote {
   @WebServiceRef(wsdlLocation = "http://localhost:8080/Tutorial7/HelloWSImpl?wsdl")
   private HelloService helloService;

   public String sayHello(String name) {
      return helloService.getHelloWSPort().sayHello(name);
   }
}

Źródła projektów: Tutorial 7 All.zip.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: