venerdì 15 luglio 2011

Realizzare Web Services in Java

In questo post vediamo come realizzare un Web Service in Java, deployarlo sotto un application server (in questo caso Jboss 5.1) e in seguito come costruire un client sempre in Java per interrogarlo.
Per realizzare il servizio Web sono stati utilizzati:
  • Jboss 5.1 (compilato per jdk 1.5);
  • JDK 1.5_019;
  • Eclipse Helios;


CREARE IL WEB SERVICE

Come prima cosa costruiamo il nostro servizio Web di esempio, che esporrà un solo metodo,  getFattoriale, che accetta in input un intero e restituisce il suo fattoriale.

Utilizziamo gli Ejb 3.0, che ci consentono di creare un servizio Web con delle semplici annotazioni.
Per prima cosa da Eclipse creiamo un semplice “Java Project”.
Si definisce quindi l’interfaccia di Business, che espone il metodo da implementare poi a livello di Ejb




package it.ws.test;

import javax.ejb.Remote;
@Remote
public interface FattorialeDao {
public long getFattoriale(int n);
}









L’implementazione dell’interfaccia è il nostro Ejb, che oltre all’annotazione @Stateless avrà anche l’annotazione @WebService


package it.ws.test;
import javax.ejb.*;
import javax.jws.WebService;
import javax.jws.soap.SOAPBinding;
import javax.jws.soap.SOAPBinding.Style;
@Stateless
@WebService(name="calcoloWs")
@SOAPBinding(style = Style.DOCUMENT)
public class FattorialeDaoImpl implements FattorialeDao {

     
      public long getFattoriale(int n) {
            if(n<0) throw new IllegalArgumentException("Il valore deve essere positivo");
            long retVal=1;
            for(int i=1;i<n;i++){
                  retVal+=i*retVal;
            }
            return retVal;
      }
}

L’annotazione @SOAPBinding  ci serve a specificare delle caratteristiche del messaggio SOAP.
In particolare l’attributo Style specifica come saranno specificati i tipi di campo coinvolti nel payload SOAP.

  • RPC (Remote Procedure Call)
  • Document (per gestire tipi di dato più complessi);

Nel caso in cui (come nell’esempio) si annoti con Document il type è espresso così nel WSDL:

<types>
<xs:schema targetNamespace="http://test.ws.it/" version="1.0">
<xs:element name="getFattoriale" type="tns:getFattoriale"/>
<xs:element name="getFattorialeResponse" type="tns:getFattorialeResponse"/>
<xs:element name="main" type="tns:main"/>

<xs:element name="mainResponse" type="tns:mainResponse"/>
<xs:complexType name="getFattoriale">
      <xs:sequence><xs:element name="arg0" type="xs:int"/></xs:sequence>
</xs:complexType>
<xs:complexType name="getFattorialeResponse">
<xs:sequence>
      <xs:element name="return" type="xs:long"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="main">
<xs:sequence>
      <xs:element maxOccurs="unbounded" minOccurs="0" name="arg0" type="xs:string"/>
      </xs:sequence>
</xs:complexType>
<xs:complexType name="mainResponse">
<xs:sequence/></xs:complexType>
</xs:schema>
</types>



Nel caso invece di Style RPC il nodo types è vuoto.
In questo caso trattandosi di dati “semplici” si potrebbe utilizzare anche lo style RPC.
Il default è comunque Style.DOCUMENT.

Una volta scritto il Ws per effettuare il deploy è sufficiente esportare il progetto come JAR file
dentro la directory di deploy di Jboss.

Per verificare che il servizio sia partito correttamente digitare l’url http://localhost:8080/jbossws , quindi cliccare su “View a list of deployed services” e poi cliccare sul link al WSDL (nel mio caso, poiché il jar si chiama wsTest l’url del Web Service è http://127.0.0.1:8080/wsTest/FattorialeDaoImpl?wsdl.

CREARE UN CLIENT DEL WEB SERVICE IN JAVA

Utilizzando la JDK 1.6 è a disposizione un comodo tool per generare il codice Java, wsimport.
Realizziamo quindi un altro progetto Java su Eclipse , e da MSDOS posizioniamoci nella directory src eseguento il comando wsimport con l’impostazione –keep (ci permette di vedere anche il codice generato e non solo il bytecode) passando come parametro il link al WSDL
Di seguito l’esempio



C:\temp>cd C:\workspaceTest\WsTestClient\src

C:\workspaceTest\WsTestClient\src>wsimport -keep -verbose http://127.0.0.1:8080/
wsTest/FattorialeDaoImpl?wsdl
parsing WSDL...


generating code...

it\ws\test\CalcoloWs.java
it\ws\test\FattorialeDaoImplService.java
it\ws\test\GetFattoriale.java
it\ws\test\GetFattorialeResponse.java
it\ws\test\ObjectFactory.java
it\ws\test\package-info.java

compiling code...

javac -d C:\workspaceTest\WsTestClient\src\. -classpath C:\Programmi\Java\jdk1.6
.0_25\lib\tools.jar;C:\Programmi\Java\jdk1.6.0_25\classes -Xbootclasspath/p:C:\P
rogrammi\Java\jdk1.6.0_25\jre\lib\rt.jar;C:\Programmi\Java\jdk1.6.0_25\jre\lib\r
t.jar C:\workspaceTest\WsTestClient\src\.\it\ws\test\CalcoloWs.java C:\workspace
Test\WsTestClient\src\.\it\ws\test\FattorialeDaoImplService.java........

























Facendo refresh sul progetto possiamo vedere che il tool ha costruito una serie di classi (in grassetto nella figura) che strutturano la chiamata.

Manca quindi soltanto un ultimo passaggio, ossia la scrittura di una classe con un main che richiami il servizio utilizzando le classi generate.

Di seguito il codice del main




      public static void main(String[] args) {
            try
            {
                  FattorialeDaoImplService f=new FattorialeDaoImplService();
                  CalcoloWs port=f.getCalcoloWsPort();
                  long fatt=port.getFattoriale(5);
                  System.out.println(fatt);
            }
            catch(Exception ex){
                  ex.printStackTrace();
            }
      }














INVOCARE IL SERVIZIO COME EJB REMOTO

Si noti come il nostro Web Service è anche un normale Ejb remoto, è quindi possibile anche invocarlo effettuando la lookup JNDI, come nel seguente esempio:

public static void main(String[] args) {
            try
            {
                  Properties p=new Properties();
                  p.put(Context.INITIAL_CONTEXT_FACTORY, "org.jnp.interfaces.NamingContextFactory");
              p.put(Context.URL_PKG_PREFIXES, "org.jboss.naming:org.jnp.interfaces");
              p.put(Context.PROVIDER_URL, "jnp://127.0.0.1:1099");
                  Context ctx=new InitialContext(p);
                  FattorialeDao f=(FattorialeDao)ctx.lookup("FattorialeDaoImpl/remote");
                  System.out.println(f.getFattoriale(5));
            }
            catch(Exception ex){
                  ex.printStackTrace();
            }
      }



PUBBLICARE IL SERVIZIO WEB USANDO SOLO LA JDK 1.6

Con la jdk 1.6 è possibile, nel caso di ambienti di test o di ambienti di produzione “light”, deployare un servizio Web con la jdk stessa.
E’ sufficiente creare una classe annotata con @WebService e poi per pubblicare il servizio effettuare in un main di una classe java (anche nella stessa classe annotata) :



public static void main(String[] args){
            Endpoint e=Endpoint.publish("http://localhost:7070/Test", new FattorialeDaoImpl());
            System.out.println("Ok");
      }








In questo modo digitando http://localhost:7070/Test?wsdl   si accede al WSDL.

1 commento:

  1. wsimport non viene riconosciuto come comando non essendo presente nella cartella bin del progetto Java che rappresenterà il Consumer del Servizio Web

    RispondiElimina