Nessun risultato. Prova con un altro termine.
Guide
Notizie
Software
Tutorial

WSDL d’esempio e organizzazione dei progetti

In questa lezione si descriveranno con un sufficiente livello di dettaglio i progetti di base allegati alla guida e relativo codice, privi di riferimenti alla sicurezza, progetti che faranno da base per gli esempi dei successivi capitoli dove andremo ad estendere quanto descritto.
In questa lezione si descriveranno con un sufficiente livello di dettaglio i progetti di base allegati alla guida e relativo codice, privi di riferimenti alla sicurezza, progetti che faranno da base per gli esempi dei successivi capitoli dove andremo ad estendere quanto descritto.
Link copiato negli appunti

In questa lezione introdurremo il WSDL alla base degli esempi che seguiranno nei prossimi capitoli, e i progetti Eclipse, allegati alla guida, lato client e server per esporre e invocare il servizio descritto nel WSDL. Si descriveranno inoltre nel dettaglio i progetti di base e relativo codice, privi di riferimenti alla sicurezza, essi faranno da base per gli esempi dei successivi capitoli. Il progetto di base sarà organizzato in modo da facilitare le operazioni di compilazione del WSDL.

Segue quindi la descrizione dei progetti allegati alla guida.

  1. PresentazioneServer: progetto contenente il WSDL di base e la relativa implementazione;
  2. PresentazioneClient: contenente sia invocazioni basiche del servizio che una classe che fa riferimento a keystores per eseguire accessi tramite HTTPS;
  3. PresentazioneServerWSSecurity: contenente il WSDL di base e diverse implementazioni di meccanismi di sicurezza che implementano lo standard WS-Security;
  4. PresentazioneClientCXF: contenente invocazioni del servizio che utilizzano lo stack CXF per implementare lo standard WS-Security;
  5. PresentazioneServerWSSecurityPolicy: contenente il WSDL modificato per esporre politiche di sicurezza secondo lo standard WS-SecurityPolicy e un’implementazione delle policies descritte.

Da osservare che il progetto PresentazioneClientCXF fa riferimento a librerie dello stack CXF che non sono contenute nei progetti allegati per motivi di dimensione dei file. E’ possibile reperirle nella cartella JBoss[vers]/client, eventualmente copiandole nella cartella predisposta lib dei progetti e poi importarle nel classpath.

WSDL e XSD

Segue il sorgente di documento.wsdl

<?xml version="1.0" encoding="ISO-8859-1" ?>
<definitions name="TestSicurezza1"
targetNamespace=http://www.prova.documento.test/
xmlns:tns=http://www.prova.documento.test/
xmlns:schema=http://www.prova.schema.test/
xmlns:xsd=http://www.w3.org/2001/XMLSchema
xmlns:soap=http://schemas.xmlsoap.org/wsdl/soap/
xmlns="http://schemas.xmlsoap.org/wsdl/">
<types>
<xsd:schema targetNamespace="http://www.prova.documento.test/">
<xsd:import namespace="http://www.prova.schema.test/" schemaLocation="schema.xsd" />
</xsd:schema>
</types>
<message name="PresentazioneReq">
<part name="parameter" element="schema:Presentazione" />
</message>
<message name="PresentazioneResp">
<part name="parameter" element="schema:PresentazioneRisposta" />
</message>
<portType name="ServizioPresentazioneIF">
<operation name="Presentazione">
<input message="tns:PresentazioneReq"/>
<output message="tns:PresentazioneResp"/>
</operation>
</portType>
<binding name="ServizioPresentazioneImplPortBinding" type="tns:ServizioPresentazioneIF">
<soap:binding transport="http://schemas.xmlsoap.org/soap/http"/>
<operation name="Presentazione">
<soap:operation soapAction=""/>
<input>
<soap:body use="literal"/>
</input>
<output>
<soap:body use="literal"/>
</output>
</operation>
</binding>
<service name="PresentazioneService">
<port name="ServizioPresentazioneImpl" binding="tns:ServizioPresentazioneImplPortBinding">
<soap:address location="http://localhost:8080/Presentazione/PresentazioneService/ServizioPresentazioneIF"/>
</port>
</service>
</definitions>

Mentre il codice seguente è quello relativo a schema.xsd:

targetNamespace="http://www.prova.schema.test/"
 >
 <xs:import namespace="http://www.w3.org/2001/XMLSchema" />
 <xs:element name="Presentazione">
 <xs:complexType>
 <xs:sequence>
 <xs:element name="Nome" type="xs:string" />
 <xs:element name="Cognome" type="xs:string" />
 </xs:sequence>
 </xs:complexType>
 </xs:element>
 <xs:element name="PresentazioneRisposta">
 <xs:complexType>
 <xs:sequence>
 <xs:element name="Risposta" type="xs:string" />
 </xs:sequence>
 </xs:complexType>
 </xs:element>
 </xs:schema>

Il WSDL e lo schema sono praticamente gli stessi usati in WSDL: stili e codifiche. Il WSDL si limita ad esporre un’operazione con in ingresso una coppia di attributi, due stringhe "nome – cognome", e in uscita un attributo anch’esso di tipo stringa. La compilazione la possiamo demandare ad uno script che inseriremo direttamente nel progetto Eclipse in un percorso apposito. L’immagine seguente mostra uno spaccato dei progetti.

Figura 1. Struttura dei progetti
Struttura dei progett

Da notare che nei progetti PresentazioneServer e PresentazioneClient sono presenti altri files, packages e classi che verranno descritti successivamente, non essendo parte necessaria per l’esecuzione degli esempi di base.

Server, implementazione e struttura del progetto

Lato server si è utilizzato un progetto Eclipse del tipo Dynamic Web Project. Come al solito, poniamo XSD e WSDL nella cartella WEB-INF, mentre nella cartella META-INF possiamo inserire il solo XSD. Alla struttura predeterminata si è aggiunta una cartella, support, con all'interno le cartelle build e generated. In build è presente uno script, un .bat per Windows, il cui compito è compilare il WSDL presente nel WEB-INF e posizionare gli stubs generati in generated:

@cd /D %~dp0
@wsimport -d ../generated -Xnocompile ../../WebContent/WEB-INF/wsdl/documento.wsdl

La prima riga serve a far sì che lo script venga lanciato direttamente dall’IDE, acquisendo il path nel quale è posizionato. Nella secondo troviamo l’invocazione del tool wsimport, con le richieste di posizionare i sorgenti nella cartella generated e di non compilarli. Per eseguire lo script direttamente da Eclipse tasto destro sul file e poi "Open With > Default Editor".

Per il progetto base stiamo utilizzando il tool wsimport con il quale si generano gli stubs relativi allo stack JAX-WS. Eseguito lo script, nella cartella generated (dopo il refresh) sarà possibile trovare la cartella test con l’organizzazione in package degli stubs. E’ possibile copiare quest'ultima così com’è in src. A questo punto manca solo l’implementazione da posizionare nel package prova.server. Di seguito la classe.

package prova.server;
import javax.ejb.Remote;
import javax.ejb.Stateless;
import javax.jws.WebMethod;
import javax.jws.WebService;
import javax.jws.soap.SOAPBinding;
import org.jboss.wsf.spi.annotation.WebContext;
import test.documento.prova.ServizioPresentazioneIF;
@WebService(targetNamespace="http://www.prova.documento.test/", serviceName="PresentazioneService",
wsdlLocation="WEB-INF/wsdl/documento.wsdl",
portName="ServizioPresentazioneImpl",
name="ServizioPresentazioneIF")
@WebContext(contextRoot="/Presentazione")
@Remote(ServizioPresentazioneIF.class)
@Stateless
@SOAPBinding
(
style = SOAPBinding.Style.DOCUMENT,
use = SOAPBinding.Use.LITERAL
)
public class ServizioPresentazione implements ServizioPresentazioneIF{
	@WebMethod
	public String presentazione(String nome, String cognome) {
		System.out.println("Web service, arrivata presentazione "+
                             "da parte di: "+nome+" "+cognome+"\n\n");
		String risposta = "Ciao "+nome+"!";
		return risposta;
	}
}

Dall’annotazione @Stateless posiamo vedere che andremo a deployare il servizio come EJB nell’Application Server. Con i JBossTools è possibile eseguire questo passaggio tramite comode interfacce grafiche. Per questi test, sarà sufficiente un server di tipo default.

Client, implementazione e struttura del progetto

Lato client, è sufficiente un normale progetto Java. Possiamo crearvi una cartella META-INF per ospitare WSDL e schemi, copiare e incollare direttamente nella cartella src gli stub creati in precedenza nel progetto lato server. Resta da implementare l’effettiva invocazione del servizio. A tal proposito, creiamo due classi nel package wsClient.

Classe ClientMETAInf.java:

package wsClient;
import java.net.MalformedURLException;
import java.net.URISyntaxException;
import java.net.URL;
import javax.xml.namespace.QName;
import javax.xml.ws.BindingProvider;
import test.documento.prova.PresentazioneService;
import test.documento.prova.ServizioPresentazioneIF;
public class ClientMETAInf {
	private ServizioPresentazioneIF port;
	public ClientMETAInf(String urlPath){
		if(urlPath==null) urlPath = "META-INF/wsdl/documento.wsdl";
		try {
			URL urlLocation = ClientMETAInf.class.getClassLoader().getResource(urlPath).toURI().toURL();
			QName serviceName = new QName("http://www.prova.documento.test/", "PresentazioneService");
			PresentazioneService srv = new PresentazioneService(urlLocation, serviceName);
			port = srv.getPort(ServizioPresentazioneIF.class);
		} catch (MalformedURLException e) {
			e.printStackTrace();
		} catch (URISyntaxException e) {
			e.printStackTrace();
		};
	}
	public ServizioPresentazioneIF getServicePort(String prothostport){
		BindingProvider bp = (BindingProvider)port;
		try {
			changeServiceEndPoint(prothostport, bp);
		} catch (MalformedURLException e) {
			e.printStackTrace();
		}
		return port;
	}
	private void changeServiceEndPoint(String prothostport, BindingProvider intservice) throws MalformedURLException {
		BindingProvider binding_bsn = (BindingProvider) intservice;
		java.lang.String endpoint_url = (java.lang.String) binding_bsn.getRequestContext().get(
				BindingProvider.ENDPOINT_ADDRESS_PROPERTY);
		URL url = new URL(endpoint_url);
		String fddexturl = prothostport + url.getPath();
		binding_bsn.getRequestContext().put(
				BindingProvider.ENDPOINT_ADDRESS_PROPERTY, fddexturl);
	}
}

Classe ServizioClient.java:

package wsClient;
import test.documento.prova.ServizioPresentazioneIF;
public class ServizioClient {
	public static void main(String[] args) {
		String prot = "http";
		String host = "localhost";
		String port = "8080";
		String protHostPort = prot+"://"+host+":"+port;
	              ClientMETAInf sensorClientSDM = new ClientMETAInf(null);
	              ServizioPresentazioneIF servicePort=sensorClientSDM.getServicePort(protHostPort);
	              String nome = "Micky";
		String cognome = "Mouse";
		System.out.println(nome+" "+cognome+" effettua la presentazione. ");
		String risposta=servicePort.presentazione(nome, cognome);
		System.out.println("Risposta ottenuta: "+risposta);
	}
}

Osserviamo che la classe ClientMETAInf mette a disposizione un metodo per restituire il porto del servizio dopo aver effettuato la modifica dell’end-point su cui eseguire l’effettiva invocazione del servizio, ciò anche all’esterno della macchina sulla quale viene operata l’invocazione. A tal fine, oltre alla possibilità di fornire il path al WSDL (viceversa viene cercato nella posizione di default, ossia quella relativa al momento in cui il WSDL è stato compilato), viene richiesta una stringa contenente la tripla di informazioni "protocollo-host-porto".

La classe ServizioClient contiene il main. Estremamente semplice, sarà la classe che utilizzeremo per eseguire l’invocazione del servizio. Individuati i parametri di connessione (nell’esempio la tripla "http-localhost-8080"), si utilizza la classe ClientMETAInf per ottenere il porto tramite il quale eseguire le operazioni, ossia si effettua il binding al servizio. Segue l’invocazione con semplici parametri d’esempio ("Micky - Mouse") e la stampa a video della risposta ottenuta. Nella prossima lezione le prove d'esecuzione osservando con Wireshark cosa viaggia su rete.

Ti consigliamo anche