Services Web et SOAP Coulouris, Dollimore and Kindberg, Distributed Systems: Concepts and Design, Edition 4, © Addison-Wesley 2005 Tutoriel Sun sur SAAJ SOAP Initialement Simple Object Access Protocol, et dernièrement Service Oriented Architecture Protocol Protocole de communication Communication entre applications Format de transmission des messages Communication via Internet Indépendant des plate-formes Indépendant du langage XML Simple et extensible Traverse les pare-feux Un standard W3C Instructor’s Guide for Coulouris, Dollimore and Kindberg Distributed Systems: Concepts and Design Edn. 4 © Addison-Wesley Publishers 2005 Figure 19.3 SOAP message in an envelope envelope header header element header element body element body element body Instructor’s Guide for Coulouris, Dollimore and Kindberg Distributed Systems: Concepts and Design Edn. 4 © Addison-Wesley Publishers 2005 Figure 19.4 Example of a simple request without headers env:envelope xmlns:env =namespace URI for SOAP envelopes env:body m:exchange xmlns:m = namespace URI of the service description m:arg1 Hello m:arg2 World In this figure and the next, each XML element is represented by a shaded box with its name in italic followed by any attributes and its content Instructor’s Guide for Coulouris, Dollimore and Kindberg Distributed Systems: Concepts and Design Edn. 4 © Addison-Wesley Publishers 2005 Figure 19.5 Example of a reply corresponding to the request in Figure 19.4 env:envelope xmlns:env = namespace URI for SOAP envelope env:body m:exchangeResponse xmlns:m = namespace URI for the service description m:res1 World m:res2 Hello Instructor’s Guide for Coulouris, Dollimore and Kindberg Distributed Systems: Concepts and Design Edn. 4 © Addison-Wesley Publishers 2005 POST /examples/stringer endpoint address Host: www.cdk4.net Content-Type: application/soap+xml Action: http://www.cdk4.net/examples/stringer#exchange <env:envelope xmlns:env= namespace URI for SOAP envelope > <env:header> </env:header> <env:body> </env:body> </env:Envelope> Instructor’s Guide for Coulouris, Dollimore and Kindberg Distributed Systems: Concepts and Design Edn. 4 © Addison-Wesley Publishers 2005 action HTTP header Figure 19.6 Use of HTTP POST Request in SOAP client-server communication Règles syntaxiques En XML Doit utiliser SOAP Envelope namespace SOAP Encoding namespace namespace par défaut pour l’enveloppe SOAP : http://www.w3.org/2001/12/soap-envelope namespace par défaut pour encodage et les types de données SOAP : http://www.w3.org/2001/12/soap-encoding Un message SOAP ne doit pas contenir de référence à une DTD Instructions de traitement XML Instructor’s Guide for Coulouris, Dollimore and Kindberg Distributed Systems: Concepts and Design Edn. 4 © Addison-Wesley Publishers 2005 Squelette d’un message SOAP Instructor’s Guide for Coulouris, Dollimore and Kindberg Distributed Systems: Concepts and Design Edn. 4 © Addison-Wesley Publishers 2005 SAAJ SOAP with Attachments API for Java (SAAJ) Manière standard de transmettre des documents XML sur Internet en Java http://java.sun.com/j2ee/1.4/docs/api/index.html Instructor’s Guide for Coulouris, Dollimore and Kindberg Distributed Systems: Concepts and Design Edn. 4 © Addison-Wesley Publishers 2005 Messages Interfaces Node extends org.w3c.dom.Node SOAPEnvelope SOAPElement extends Node , org.w3c.dom.Element Classes SOAPMessage SOAPPart implements org.w3c.dom.Document Un document DOM Many SAAJ API interfaces extend DOM interfaces Instructor’s Guide for Coulouris, Dollimore and Kindberg Distributed Systems: Concepts and Design Edn. 4 © Addison-Wesley Publishers 2005 Messages avec et sans pièces jointes Instructor’s Guide for Coulouris, Dollimore and Kindberg Distributed Systems: Concepts and Design Edn. 4 © Addison-Wesley Publishers 2005 Invocation de la méthode getLastTradePrice sur un service Web REQUETE <SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"> <SOAP-ENV:Body> <m:GetLastTradePrice xmlns:m="http://wombat.ztrade.com"> <symbol>SUNW</symbol> </m:GetLastTradePrice> </SOAP-ENV:Body> </SOAP-ENV:Envelope> REPONSE Instructor’s Guide for Coulouris, Dollimore and Kindberg Distributed Systems: Concepts and Design Edn. 4 © Addison-Wesley Publishers 2005 Construction d’une requête SOAP import javax.xml.soap.*; import java.util.*; import java.net.URL; public class SoapRequest { public static void main(String[] args) { try { SOAPConnectionFactory soapConnectionFactory = SOAPConnectionFactory.newInstance(); SOAPConnection connection = soapConnectionFactory.createConnection(); SOAPFactory soapFactory = SOAPFactory.newInstance(); MessageFactory factory = MessageFactory.newInstance(); SOAPMessage message = factory.createMessage(); SOAPHeader header = message.getSOAPHeader(); SOAPBody body = message.getSOAPBody(); header.detachNode(); Instructor’s Guide for Coulouris, Dollimore and Kindberg Distributed Systems: Concepts and Design Edn. 4 © Addison-Wesley Publishers 2005 Construction d’une requête SOAP Name bodyName = soapFactory.createName("GetLastTradePrice", "m", "http://wombats.ztrade.com"); SOAPBodyElement bodyElement = body.addBodyElement(bodyName); Name name = soapFactory.createName("symbol"); SOAPElement symbol = bodyElement.addChildElement(name); symbol.addTextNode("SUNW"); URL endpoint = new URL("http://wombat.ztrade.com/quotes"); SOAPMessage response = connection.call(message, endpoint); connection.close(); SOAPBody soapBody = response.getSOAPBody(); Iterator iterator = soapBody.getChildElements(bodyName); bodyElement = (SOAPBodyElement) iterator.next(); String lastPrice = bodyElement.getValue(); System.out.print("The last price for SUNW is "); System.out.println(lastPrice); } catch (Exception ex) { ex.printStackTrace(); } } } Instructor’s Guide for Coulouris, Dollimore and Kindberg Distributed Systems: Concepts and Design Edn. 4 © Addison-Wesley Publishers 2005 Connexions Tous les messages SOAP sont transmis et reçus à l’aide d’une connexion. Messages de type request-response. méthode call, bloquantes en attente d’une réponse SOAPConnectionFactory soapConnectionFactory; SOAPConnection connection; URL endpoint; SOAPMessage response; soapConnectionFactory = SOAPConnectionFactory.newInstance(); connection = soapConnectionFactory.createConnection(); ...// create a request message and give it content endpoint = new URL("http://wombat.ztrade.com/quotes"); response = connection.call(message, endpoint); Instructor’s Guide for Coulouris, Dollimore and Kindberg Distributed Systems: Concepts and Design Edn. 4 © Addison-Wesley Publishers 2005 Création d’une connexion import javax.xml.soap.*; import java.util.*; import java.net.URL; public class SoapRequest { public static void main(String[] args) { SOAPConnectionFactory soapConnectionFactory; SOAPConnection connection; SOAPFactory soapFactory; try { soapConnectionFactory = SOAPConnectionFactory.newInstance(); connection = soapConnectionFactory.createConnection(); soapFactory = SOAPFactory.newInstance(); Instructor’s Guide for Coulouris, Dollimore and Kindberg Distributed Systems: Concepts and Design Edn. 4 © Addison-Wesley Publishers 2005 Création d’un message MessageFactory factory = MessageFactory.newInstance(); SOAPMessage message = factory.createMessage(); // header : données XML qui affecte la manière dont le contenu // spécifique à une application sera traité par le fournisseur du // message, par exemple : sémantique d’une transaction, information SOAPHeader header = message.getSOAPHeader(); SOAPBody body = message.getSOAPBody(); // l’en-tête n’est pas nécessaire header.detachNode(); Instructor’s Guide for Coulouris, Dollimore and Kindberg Distributed Systems: Concepts and Design Edn. 4 © Addison-Wesley Publishers 2005 Création d’un message L’instance de SOAPFactory permet de créer les différents objets qui seront dans l’arborescence XML SOAP createName(String localName, String prefix, String uri) Name bodyName = soapFactory.createName( "GetLastTradePrice", "m", "http://wombats.ztrade.com"); SOAPBodyElement bodyElement = body.addBodyElement(bodyName); Name name = soapFactory.createName("symbol"); SOAPElement symbol = bodyElement.addChildElement(name); symbol.addTextNode("SUNW"); Instructor’s Guide for Coulouris, Dollimore and Kindberg Distributed Systems: Concepts and Design Edn. 4 © Addison-Wesley Publishers 2005 Le message SOAP résultant <SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"> <SOAP-ENV:Body> <m:GetLastTradePrice xmlns:m="http://wombat.ztrade.com"> <symbol>SUNW</symbol> </m:GetLastTradePrice> </SOAP-ENV:Body> </SOAP-ENV:Envelope> Instructor’s Guide for Coulouris, Dollimore and Kindberg Distributed Systems: Concepts and Design Edn. 4 © Addison-Wesley Publishers 2005 Envoi du message URL endpoint ; SOAPMessage response; endpoint = new URL("http://wombat.ztrade.com/quotes"); response = connection.call(message, endpoint); connection.close(); Instructor’s Guide for Coulouris, Dollimore and Kindberg Distributed Systems: Concepts and Design Edn. 4 © Addison-Wesley Publishers 2005 Analyse de la réponse SOAPBody soapBody = response.getSOAPBody(); Iterator iterator = soapBody.getChildElements(bodyName); bodyElement = (SOAPBodyElement) iterator.next(); String lastPrice = bodyElement.getValue(); System.out.print("The last price for SUNW is "); System.out.println(lastPrice); Instructor’s Guide for Coulouris, Dollimore and Kindberg Distributed Systems: Concepts and Design Edn. 4 © Addison-Wesley Publishers 2005 Création d’une pièce jointe de type texte AttachmentPart attachment = message.createAttachmentPart(); String stringContent = "Update address for Sunny Skies " + "Inc., to 10 Upbeat Street, Pleasant Grove, CA 95439"; attachment.setContent(stringContent, "text/plain"); attachment.setContentId("update_address"); message.addAttachmentPart(attachment); Instructor’s Guide for Coulouris, Dollimore and Kindberg Distributed Systems: Concepts and Design Edn. 4 © Addison-Wesley Publishers 2005 Création d’une pièce jointe de type image URL url = new URL("http://greatproducts.com/gizmos/img.jpg"); DataHandler dataHandler = new DataHandler(url); AttachmentPart attachment = message.createAttachmentPart(dataHandler); attachment.setContentId("attached_image"); message.addAttachmentPart(attachment); Le DataHandler va s’occuper de déterminer le type MIME setContentID : déterminer le nom qui sera utilisé pour identifier la pièce jointe Instructor’s Guide for Coulouris, Dollimore and Kindberg Distributed Systems: Concepts and Design Edn. 4 © Addison-Wesley Publishers 2005 Accéder aux pièces jointes java.util.Iterator iterator = message.getAttachments(); while (iterator.hasNext()) { AttachmentPart attachment = (AttachmentPart)iterator.next(); String id = attachment.getContentId(); String type = attachment.getContentType(); System.out.print("Attachment " + id + " has content type " + type); if (type == "text/plain") { Object content = attachment.getContent(); System.out.println("Attachment " + "contains:\n" + content); } } Instructor’s Guide for Coulouris, Dollimore and Kindberg Distributed Systems: Concepts and Design Edn. 4 © Addison-Wesley Publishers 2005 Attributs de l’en-tête Détermine comment le destinataire doit traiter le message Façon d’étendre un message en donnant de l’information sur des éléments comme authentification, gestion des transactions, paiement etc. Attributs de l’en-tête (SOAP 1.1) actor mustUnderstand Instructor’s Guide for Coulouris, Dollimore and Kindberg Distributed Systems: Concepts and Design Edn. 4 © Addison-Wesley Publishers 2005 Attribut actor Indique le destinataire de l’élément header Par défaut, le destinataire ultime Un acteur est une application qui peut Recevoir des messages SOAP Les acheminer à un autre acteur Exemple : traitement d’un bon de commande Route: order desk, shipping desk, confirmation desk, billing department. Chaque application prend les actions nécessaires, retire les objets pertinents pour son travail, achemine le message à l’acteur suivant Instructor’s Guide for Coulouris, Dollimore and Kindberg Distributed Systems: Concepts and Design Edn. 4 © Addison-Wesley Publishers 2005 Chaîne d’acteurs SOAPHeader header = message.getSOAPHeader(); SOAPFactory soapFactory = SOAPFactory.newInstance(); String nameSpace = "ns"; String nameSpaceURI = "http://gizmos.com/NSURI"; Name order = soapFactory.createName("orderDesk", nameSpace, nameSpaceURI); SOAPHeaderElement orderHeader = header.addHeaderElement(order); orderHeader.setActor("http://gizmos.com/orders"); Name shipping = soapFactory.createName("shippingDesk",nameSpace, nameSpaceURI); SOAPHeaderElement shippingHeader = header.addHeaderElement(shipping); shippingHeader.setActor("http://gizmos.com/shipping"); Name confirmation = soapFactory.createName("confirmationDesk",nameSpace, nameSpaceURI); SOAPHeaderElement confirmationHeader = header.addHeaderElement(confirmation); confirmationHeader.setActor( "http://gizmos.com/confirmations"); Name billing = soapFactory.createName("billingDesk", nameSpace, nameSpaceURI); SOAPHeaderElement billingHeader = header.addHeaderElement(billing); billingHeader.setActor("http://gizmos.com/billing"); Instructor’s Guide for Coulouris, Dollimore and Kindberg Distributed Systems: Concepts and Design Edn. 4 © Addison-Wesley Publishers 2005 Attribut mustUnderstand Indique si oui ou non le destinataire doit savoir traiter les en-têtes SOAPHeader header = message.getSOAPHeader(); Name name = soapFactory.createName("Transaction", "t","http://gizmos.com/orders"); SOAPHeaderElement transaction = header.addHeaderElement(name); transaction.setMustUnderstand(true); transaction.addTextNode("5"); Fichier résultant <SOAP-ENV:Header> <t:Transaction xmlns:t="http://gizmos.com/orders" SOAP-ENV:mustUnderstand="1"> 5 </t:Transaction> </SOAP-ENV:Header> Instructor’s Guide for Coulouris, Dollimore and Kindberg Distributed Systems: Concepts and Design Edn. 4 © Addison-Wesley Publishers 2005 Fautes Si un message n’a pas réussi Un seul élément « faute » par message SOAP Doit être dans le corps (body) du message SOAP. Instructor’s Guide for Coulouris, Dollimore and Kindberg Distributed Systems: Concepts and Design Edn. 4 © Addison-Wesley Publishers 2005 SOAPFault fault = body.addFault(); Name faultName = soapFactory.createName("Client", "", SOAPConstants.URI_NS_SOAP_ENVELOPE); fault.setFaultCode(faultName); fault.setFaultString("Message does not have necessary info"); Detail detail = fault.addDetail(); Name entryName = soapFactory.createName("order", "PO", "http://gizmos.com/orders/"); DetailEntry entry = detail.addDetailEntry(entryName); entry.addTextNode("Quantity element does not have a value"); Name entryName2 = soapFactory.createName("confirmation", DetailEntry entry2 = detail.addDetailEntry(entryName2); entry2.addTextNode("Incomplete address: no zip code"); "PO", "http://gizmos.com/confirm"); Fichier résultant <SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"> <SOAP-ENV:Header/> <SOAP-ENV:Body> <SOAP-ENV:Fault> <faultcode>SOAP-ENV:Client</faultcode> <faultstring>Message does not have necessary info</faultstring> <faultactor>http://gizmos.com/order</faultactor> <detail> <PO:order xmlns:PO="http://gizmos.com/orders/"> Quantity element does not have a value </PO:order> <PO:confirmation xmlns:PO="http://gizmos.com/confirm"> Incomplete address: no zip code </PO:confirmation> </detail> </SOAP-ENV:Fault> </SOAP-ENV:Body> </SOAP-ENV:Envelope> Instructor’s Guide for Coulouris, Dollimore and Kindberg Distributed Systems: Concepts and Design Edn. 4 © Addison-Wesley Publishers 2005 Récupérer la faute SOAPBody body = newMessage.getSOAPBody(); if ( body.hasFault() ) { SOAPFault newFault = body.getFault(); Name code = newFault.getFaultCodeAsName(); String string = newFault.getFaultString(); String actor = newFault.getFaultActor(); System.out.println("SOAP fault contains: "); System.out.println(" Fault code = " + code.getQualifiedName()); System.out.println(" Fault string = " + string); if ( actor != null ) { System.out.println(" Fault actor = " + actor); } Detail newDetail = newFault.getDetail(); if (newDetail != null) { Iterator entries = newDetail.getDetailEntries(); while ( entries.hasNext() ) { DetailEntry newEntry = (DetailEntry)entries.next(); String value = newEntry.getValue(); System.out.println(" Detail entry = " + value); } } Output SOAP fault contains: Fault code = SOAP-ENV:Client Local name = Client Namespace prefix = SOAP-ENV, bound to http://schemas.xmlsoap.org/soap/envelope/ Fault string = Message does not have necessary info Fault actor = http://gizmos.com/order Instructor’s Guide for Coulouris, Dollimore and Kindberg Distributed Systems: Concepts and Design Detail entry = Quantity element does not ©have a value Addison-Wesley Publishers 2005 Detail entry = Incomplete address: no zip code Edn. 4 Références J2EE 1.5 tutorial Chapter 19 SOAP with Attachments API for Java http://java.sun.com/javaee/5/docs/tutorial/doc/bnbhf.html Instructor’s Guide for Coulouris, Dollimore and Kindberg Distributed Systems: Concepts and Design Edn. 4 © Addison-Wesley Publishers 2005