29/05/2010, Area Ricerca CNR, Pisa JAX-WS Java API for XML Web Services Massimo Martinelli [email protected] Consiglio Nazionale delle Ricerche - CNR Istituto di Scienza e Tecnologie della Informazione - ISTI Il corso di Java Web Services in 1 Minuto! import ... Scriviamo una classe Java con un metodo Aggiungiamo metainformazioni @WebService public class MioWebService { @WebMethod public String ciao(String nome) { } } return “Ciao “+ nome; Finito! ... RIPARTIAMO :-) JAX-WS Java API for XML Web Services Massimo Martinelli [email protected] Consiglio Nazionale delle Ricerche - CNR Istituto di Scienza e Tecnologie della Informazione - ISTI Sommario Cosa è JAX-WS? Implementazione di Web Service e di Client Tipi di dato supportati da JAX-WS JAXB Esercizi da svolgere durante il corso Secondo il W3C ... Un Web Service è un sistema software designato a supportare interazioni interoperabili macchina-macchina su una rete. Ha una interfaccia descritta in un formato elaborabile da una macchina (specificamente WSDL). Altri sistemi interagiscono con il Web Service in un modo prescritto dalla sua descrizione usando messaggi SOAP, tipicamente convogliati usando HTTP con una serializzazione XML insieme ad altri standard Web. Cosa è JAX-WS acronimo di “Java API for XML Web Services” Tecnologia per realizzare Web Service e client in Java che comunicano utilizzando messaggi SOAP-XML L’implementazione di riferimento (JAX-WS for Reference Implementation) è un progetto open source e fa parte del progetto GlassFish, un application server Java EE. Fa parte della distribuzione “Metro” Web Services semplificati Da Java 5 (Java 1.5) introdotte le annotazioni ovvero dei Metadati sul codice Java Esempio di annotazione: @Annotazione Annotazioni: – Possono essere trattate a livello di compilazione – Possono essere trattate anche tempo di esecuzione Annotazioni nei Web Service Per sviluppare un Web Service con JAX-WS è necessario utilizzare l'annotazione javax.jws.WebService Ovvero: la classe che implementa il Web Service deve essere annotata con la annotazione javax.jws.WebService (o con javax.jws.WebServiceProvider) Service Endpoint Interface (SEI) Una interfaccia service endpoint (SEI) è una interfaccia Java che dichiara i metodi che un client può invocare sul servizio SEI non necessaria quando si implementa un endpoint JAXWS: la classe di implementazione del Web Service (SIB Service Implementation Bean) definisce implicitamente una SEI può riferire esplicitamente una SEI tramite l’elemento endpointInterface dell’annotazione @Webservice Preparazione agli esercizi Creare una directory LINUX ~home/java-pgm/ C:/java-pgm/ dove installeremo i programmi che seguono... Strumenti che utilizzeremo: Java SE 6 Java Standard Development Kit versione 6 (Se non è già installata eseguire da terminale il comando java –version ) Scaricare da http://java.sun.com/javase/downloads/index.jsp Strumenti che utilizzeremo: Netbeans Netbeans è un ambiente di sviluppo realizzato da SUN ◦ Scaricare da http://netbeans.org/downloads/index.html (versione “Java” o “All”) Strumenti che utilizzeremo: Glassfish Application server open source realizzato da Sun di riferimento per Java EE 5/6. Incluso con NetBeans Supporta: EJB 3.1 JPA 2 JAXB 2.x JAX-WS 2.x Per utilizzare con Tomcat scaricare ant da http://ant.apache.org/ scaricare metro da http://metro.dev.java.net/ java -jar metro*.jar ant -Dtomcat.home=<DirectorydiTomcat> -f metro-ontomcat.xml install V Implementazione di un Web Service A partire da: una classe Java un documento WSDL Implementazione di un Web Service (classe Java): Passi Base 1. Codificare la classe che implementa il servizio 2. Compilare tale classe 3. Dispiegare (deploy) il file WAR 4. Codificare la classe per il client 5. Utilizzare wsimport per generare e compilare gli artefatti 6. Compilare la classe client 7. Eseguire il client Codifica della classe SIB (1/2) package serviziociao; import javax.jws.WebService; @WebService public class Ciao { private String messaggio = new String("Ciao, "); public void Ciao() {} @WebMethod public String saluto(String nome) { return messaggio + nome + "."; } } Codifica della classe SIB (2/2) • • • La classe implementata, Ciao, è annotata come web service utilizzando l'annotazione @WebService Ciao dichiara un singolo metodo chiamato saluto, annotato con l'annotazione @WebMethod La classe implementata deve anche definire un costruttore di default public senza argomenti JAX-WS Endpoint I metodi della classe che implementa il Web Service devono essere public, e non devono essere dichiarati ne static ne final I metodi di Business esposti ai client dei Web service devono: essere annotati con javax.jws.WebMethod avere tipi di parametri compatibili con JAX-B Le classi che implementano i Web Service Non devono essere dichiarate abstract Devono avere un costruttore di default public Non devono definire il metodo finalize Possono usare le annotazioni javax.annotation.PostConstruct o javax.annotation.PreDestroy sui propri metodi per gestire il loro ciclo di vita Il medoto @PostConstruct è chiamato dal container prima che la classe di implementazione inizi a rispondere ai client del Web Service Il metodo @PreDestroy è chiamato dal container prima che l'endpoint sia rimosso dall'operazione Esercizio (Guidato) • Realizzare un Web Service che fa la somma di due numeri interi • Da Netbeans creare un nuovo progetto Web • Creare un nuovo Web service • Dispiegare, eseguire e provare (Test) Non vi avevo detto che bisognava importare anche ... package serviziociao.endpoint; import javax.jws.WebService; import javax.jws.WebMethod; @WebService() public class Ciao { private String messaggio = new String("Ciao, "); public void Ciao() {} @WebMethod() public String saluto(String nome) { return messaggio + nome + "."; } } @WebService V Attributi ● name: nome del wsdl:portType (per difetto il nome della classe Java senza package) ● portName: nome del wsdl:portName (per difetto è il nome del WebService concatenato a Port) ● serviceName: nome del servizio (wsdl:service) (per difetto il nome della classe concatenato alla Stringa “Service”) ● endpointInterface: (es. endpointInterface = "package.MioWebServiceInterface") specifica il nome completo della SEI (per difetto la classe java,comprensiva del package, concatenata alla Stringa “ServicePortType”) ● targetNamespace: namespace di riferimento per il WSDL e gli XML generati (per difetto è il nome del package java) ● wsdlLocation: l'indirizzo documento WSDL del Web Service. L'indirizzo può essere relativo o assoluto. Esempio @javax.jws.WebService (serviceName = "NomeServizio", endpointInterface = "it.cnr.NomeServizioServicePortType", targetNamespace="http://..../", portName="NomeServizioServicePort") @WebMethod V Per difetto tutti i metodi public di una classe annotata con @WebService vengono esposti nel Web Service Per personalizzare un metodo esposto come operazione WS si utilizza @WebMethod Attributi − action definisce l'azione per l'operazione. (per difetto = al nome del metodo ) − exclude specifica se il metodo va escluso dalla pubblicazione del Web Service. (per difetto=”false”) (Booleano) − operationName specifica il nome di wsdl:operation per il metodo (per difetto = nome del metodo) @WebMethod(action="somma") public int somma(@WebParam(name = "i") int i, @WebParam(name = "j") int j) { int k = i + j; return k; } @WebParam e @WebResult V personalizzazione dei parametri di input(@WebParam) e di output(@WebResult) di un metodo del Web Service Attributi ● header: Specifica se il parametro si trova in un'intestazione di messaggio anziché nel corpo. Per difetto è false. (Booleano) ● mode: WebParam.mode.IN parametro, WebParam.mode.OUT, WebParam.mode.INOUT che rappresentano parametri in input, in output e parametri ripetuti sia in input che in output ● name: nome del parametro. ● targetNamespace: spazio dei nomi XML dell'elemento XML per il parametro @SOAPBinding In caso i metodi del Web Service utilizzino tipi semplici come String o int è possibile utilizzare la seguente annotazione @SOAPBinding(style=Style.RPC) In caso di utilizzo di tipi complessi lo stile da utilizzare corrisponde a quello di default: @SOAPBinding(style=Style.DOCUMENT) Nel secondo caso vedremo più avanti come utilizzare il mapping (da oggetti Java in XML e viceversa) con JAXB @SOAPBinding Indipendenza dal Protocollo e dal Trasporto @SOAPBinding specifica come avviene il mapping a livello SOAP Attributi – style stile di codifica per messaggi inviati e ricevuti. Valori: DOCUMENT (default), RPC. – use formattazione per messaggi inviati e ricevuti. Valori LITERAL(default). ENCODED (non WS-I standard) – parameterStyle valori Wrapped (default) o BARE (utilizzabile solo in stile DOCUMENT) Esempio: @WebService(targetNamespace = "http://.....", name = "MioServizio") @SOAPBinding(style = SOAPBinding.Style.DOCUMENT, use = SOAPBinding.Use.LITERAL) Personalizzazione tramite Annotazioni @WebService(name=”SistemaInformativoService”, targetNamespace=”http://esempio.it”) public class SistemaInformativo { ... @WebMethod(operationName=”getPersona”) public Persona getPersona(@WebParam(name=”codicefiscale”) String codicefiscale) { // ... codice di implementazione ... } } Implementazione del Servizio (da classe Java) Al momento dell'esecuzione Netbeans genera automaticamente gli artefatti, compila tutte le classi, dispiega il servizio e attiva l’application server Dietro le quinte il Web Service (endpoint) viene generato dal tool wsgen wsgen cp ./build -keep -s ./src -d ./build package.Class Artefatti Il tool “wsimport” a partire dal WSDL crea le classi di supporto (artefatti): • Service Endpoint Interface (SEI) • Service • Exception class a partire da wsdl:fault • Oggetti generati a partire dagli schemi XML (JAXB...) Per invocare una operazione WS è necessario istanziare la classe service ed ottenere il proxy mediante chiamata al metodo: get<ServiceName>Port CalculatorService svc = new CalculatorService(); Calculatorproxy = svc.getCalculatorPort( ) ; int answer = proxy.somma(35, 7); wsimport Parametri: wsdl: percorso del file wsdl (es: /home/massimo/servizio.wsdl, http://www..../servizio.wsdl, ...) destdir: destinazione dei compilati generati sourcedestdir: destinazione dei sorgenti generati keep: se indicata mantiene i sorgenti generati verbose: dettaglio verboso delle operazioni svolte binding: specifica il tipo di collegamento package: nome del package per le classi generate Prova del Servizio ...senza un Client • • • Aprire Admin Console collegandosi col browser all'indirizzo http://localhost:4848/ Fornire utente e password per effetturare il login Cliccare su “Web Services” nel panello a sinistra • Cliccare Hello • Cliccare Test (http://localhost:8080/EsempioWSCiao/CiaoService?Tester) Prova del metodo “sayHello” in “Methods”, scrivere un nome come parametro per il metodo “sayHello” •Cliccare il pulsante “sayHello” • Analisi dei Messaggi SOAP Client a partire da un WSDL Implementazione di un servizio a partire da un WSDL Netbeans genera un Web Service (bozza) a partire da un WSDL Dietro le quinte esegue per noi il comando wsimport wsimport -keep –s <directory_sorgenti> -d <classi_generate_compilate> <percorso_documento_WSDL> -keep non cancella i file sorgenti generati Il comando genera eventuali artefatti JAXB per gestire tipi non di base Codifica del Client 1. Utilizzare l’annotazione javax.xml.ws.WebServiceRef per riferire un Web Service • L’attributo wsdlLocation specifica l’ URI del documento WSDL @WebServiceRef{wsdlLocation=“http://localhost:8 080/EsempioWSCiao/CiaoService?wsdl} 2. Invocare il metodo del Web Service utilizzando il proxy (port) del service Hello port = service.getCiaoPort(); 3. Invocare il metodo (saluto ) del proxy (port) ClientCiao package simpleclient; import javax.xml.ws.WebServiceRef; import helloservice.endpoint.HelloService; import serviziociao.endpoint.Ciao; public class ClientCiao { @WebServiceRef(wsdlLocation="http://localhost:8080/EsempioWSCiao/CiaoService?wsdl") static CiaoService service = new CiaoService(); public static void main(String[] args) { try { ClientCiao client = new ClientCiao(); client.doTest(args); } catch(Exception e) { e.printStackTrace(); } } public void doTest(String[] args) { try { System.out.println(“Recupero il proxy (port) dal servizio: " + service); Ciao port = service.getCiaoPort(); System.out.println("Invoco l’operazione saluto sul proxy (port)"); String name; if (args.length > 0) { nome= args[0]; } else { nome = “Nessun nome"; } String response = port.saluto(nome); System.out.println(response); } catch(Exception e) { e.printStackTrace(); } } Esercizio • Preparare un client che chiami il metodo “registraNome” del Web Service “WSnominativo” descritto dal WSDL che trovate all’indirizzo • http://.......:8080/EsercizioWSserver/WSnominativoService?wsdl • il metodo richiede in input un parametro di tipo String • Test: http://....:8080/EsercizioWSserver/WSnominativoService?Tester • Controllo accessi: http://.....:8080/EsercizioWSserver/ Tipi Supportati da JAX-WS • Per essere indipendenti dal linguaggio i tipi supportati sono limitati a quelli descritti nelle specifiche: • tipi atomici (es. int, boolean, ecc.) • String • array e List • semplici JavaBean usati come strutture (con costruttore public) JAX-WS delega a JAXB il collegamento tra tipi Java e XML (e viceversa). Sviluppatori non devono preoccuparsi del collegamento (in generale) JAXB Java API XML Binding Librerie che consentono di collegare (binding) oggetti Java a documenti XML A partire da un documento XML schema si può creare una classe Java corrispondente le cui istanze possono leggere/scrivere documenti XML e viceversa Marshalling / Serializzazione Il procedimento detto marshalling si riferisce alla possibilità di serializzare (..trasformare..) oggetti Java in documenti XML. A partire da un oggetto Java, schemagen crea un documento XML corrispondente schemagen [-opzioni ...] [sorgenti_java] Le istanze di queste classi possono essere collegate ai relativi documenti XML Unmarshalling / Deserializzazione Il procedimento detto unmarshalling si riferisce alla possibilità di deserializzare (..trasformare..) documenti XML (schema) in oggetti Java. A partire da un documento xjc crea un oggetto Java corrispondente XML Schema xjc [-opzioni ...] <schema> xjc biblioteca.xsd Le istanze di questa classe possono essere collegate a documenti XML Esempio @XMLRootElement public class Persona () { private String nominativo; private String identificatore; public Persona() { } public void getNominativo(){ return nominativo; } public void setNominativo(String nominativo){ this.nominativo=nominativo; } public int getIdentificativo() { return identificativo; } @XmlAttribute // identificatore attributo dell'elemento radice public void setId(int identificatore) { this.identificatore = identificatore; } } JAXB Serializzare e Deserializzare // Serializzare un oggetto in XML Persona persona= new Persona(); persona.setNominativo("Salvo Montalbano"); persona.setIdentificatore(“slvmnt); // creiamo il contesto JAXB e un marshaller (serializzatore) JAXBContext contesto = JAXBContext.newInstance(Persona.class); Marshaller serializzatore = contesto.createMarshaller(); // Impostiamo un formato “pretty” serializzatore.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); // serializzaimo serializzatore.marshal(persona, new File("/output.xml")); // Deserializzare (Ottenere l'oggetto dall'XML // creiamo il contesto JAXB e un unmarshaller (deserializzatore) JAXBContext contesto = JAXBContext.newInstance(Persona.class); Unmarshaller deserializzatore = contesto.createUnmarshaller(); // otteniamo l'oggetto Message msg = (Persona)deserializzatore.unmarshal(new File("/persona.xml")); Personalizzazione @XMLType public class Persona () { private String nominativo; private String identificatore; .... } @XMLRootElement public Dipendente() { } Persona persona; } } Esempio public class Persona () { private String nominativo; private String identificatore; @XMLRootElement public Persona() { } public void getNominativo(){ return nominativo; } public void setNominativo(String nominativo){ this.nominativo=nominativo; } public int getIdentificativo() { return identificativo; } @XmlAttribute // identificatore attributo dell'elemento radice public void setId(int identificatore) { this.identificatore = identificatore; } } Gestire gli allegati (attachment): Server @MTOM(threshold = 4096) @WebService public class WSUpload { public void fileUpload(String nomeFile, @XmlMimeType("application/octet-stream") DataHandler data) { try { DataHandler dh = data; File file = new File(nomeFile); FileOutputStream outputStream = new FileOutputStream(file); dh.writeTo(outputStream); } catch (Exception e) { throw new WebServiceException(e); } } } Gestire gli allegati (attachment): Client WSUploadService service = new WSUploadService(); // classe generata MTOMFeature feature = new MTOMFeature(); WSUpload port = service.getWSUploadPort(feature); //classe generata URL url = new URL("file:///home/massimo/prova.png"); DataHandler dh = new DataHandler(url); String nomefile = "prova.png"; port.fileUpload(nomefile, dh); Esercizio • • • Preparare un client che chiami il metodo YYYYY del Web Service XXXX descritto dal WSDL che trovate all’indirizzo http://......:8080/EsempioWSUpload/WSUploadService?wsdl il metodo richiede in input un parametro di tipo String e un parametro file corrispondente ad una immagine jpg o gif o png che avete sul vostro disco Novità introdotta con in Java SE 6 //pubblicazione di un POJO (Plain Ordinary Java Object) @WebService public class Calcolatore { @Resource WebServiceContext context; // ottiene dal server il contesto dei WS public int somma(int a, int b) { return a+b; } } // crea e pubblica un endpoint Calcolator calculatore = new Calcolatore(); Endpoint endpoint=Endpoint.publish(“http://localhost/calcolatore”,Calcolatore); // WSDL creato e pubblicato al volo: http://localhost/calcolatore?WSDL // assegnazione di protocollo (per difetto è HTTP) // Endpoint endpoint=Endpoint.create(SOAPBinding.SOAP12HTTP_BINDING,calcolatore); //endpoint.publish(“http://localhost/calcolatore”); Client Asincroni (nonblocking) class AmazonAsyncClient { public static void main(String[ ] args) { // Usage if (args.length != 1) { System.err.println("Usage: java AmazonAsyncClient <access key>"); return; } final String access_key = args[0]; // Create service and get portType reference. AWSECommerceService service = new AWSECommerceService(); AWSECommerceServicePortType port = service.getAWSECommerceServicePort(); // Create request. ItemSearchRequest request = new ItemSearchRequest(); // Add details to request. request.setSearchIndex("Books"); request.setKeywords("quantum gravity"); ItemSearch item_search= new ItemSearch(); item_search.setAWSAccessKeyId(access_key); // The handler class implements handleResponse, which executes item_search.getRequest().add(request); // if and when there's a response. port.itemSearchAsync(item_search, new MyHandler()); static class MyHandler implements AsyncHandler<ItemSearchResponse> { // In this case, just sleep to give the search process time. public void handleResponse(Response<ItemSearchResponse> future) { // In a production application, other useful tasks could be try { // performed and the application could run indefinitely. ItemSearchResponse response = future.get(); try { List<Items> item_list = response.getItems(); Thread.sleep(400); for (Items next : item_list) } for (Item item : next.getItem()) catch(InterruptedException e) { System.err.println(e); } System.out.println(item.getItemAttributes().getTitle()); } } catch(InterruptedException e) { System.err.println(e); } catch(ExecutionException e) { System.err.println(e); } } } } Bibliografia Metro User Guide https://metro.dev.java.net/guide/index.html • Java Web Services Developer Pack 2.0 • http://java.sun.com/webservices/downloads/webservicespack.html • Java EE 5 Developing using Glassfish Application Server. David R. Heffelfinger Packt Publishing • Create stand-alone Web services applications with Eclipse and Java SE 6. Fiona Lam, John Robertson, IBM developerWorks • Documentazione di WebSphere Application Server http://publib.boulder.ibm.com/infocenter/wasinfo/v6r1/index.jsp? topic=/com.ibm.websphere.wsfep.multiplatform.doc/info/ae/ae/rwbs_jaxwsannotatio ns.html •RESTful Web services: The basics. Alex Rodriguez - IBM developerWorks •Web Services con Java5. MokaByte 127, 128 - Marzo Aprile 2008 (http://www.mokabyte.it/) • Java & XML. Brett McLaughlin – O'Reilly •Java Web Services Up adn Running – O'Reilly •Corso Comune Livorno “Web Services”. M.Martinelli •Corso Comune Livorno “AXIS 2.1”. M.Martinelli •Corso Comune Livorno “Java e XML”. M.Martinelli • Grazie !