XML SOAP Services Web et JAVA Me SOAP
XML, SOAP, Services Web et JAVA Me SOAP Web Services on Smart Clients
Plan z Services Web y XML over http y SOAP - RPC
Avantages de SOAP z Support pour le typage y Plus de 40 types de données avec les schémas XML y Permet aux usagers de se définir des types de données complexes z Messagerie flexible et répandue y Supporte plusieurs schémas de messagerie dont x x RPC synchrone, messages asynchrones, multicast (souscription), routage complexe des messages avec plusieurs intermédiaires z Standardisation y Adhérence répandue à SOAP par les services web y Profiter des standards XML qui peuvent être intégrés à SOAP ou utiliser SOAP x WSDL (Web Services Description Language), UDDI (Universal Description, Discovery, and Integration), et la plupart des registres XML; x XML Digital Signature, XML Encryption, SAML (Security Assertion Markup Language) z Rem: sérialisation d’objets Java y En vecteur d’octets en tant qu’élément Base 64 pour les transporter par SOAP y Par contre, si on sait que tout se passe en Java, il vaut mieux utiliser RMI ou JMS
Architecture des services web SOAP z J 2 ME Web Services API (WSA) y Pour tout profil J 2 ME CDC ou CLDC y remote invocation API x Sous-ensemble strict de J 2 SE Java API for XML-Based RPC (JAX-RPC 1. 1), x + quelques classes Remote Method Invocation (RMI) classes ajoutées pour satisfaire les dépendances de JAX-RPC x Un sous-ensemble strict de SAX, version 2
Organisation d’une application fondée sur JSR
JSR 172 run-time et stubs z runtime y Permet aux stubs de réaliser toutes les tâches associées à l’invocation d’un RPC à service web x. Déterminer les propriétés spécifiques à une invocation RPC x. Décrire les valeurs d’entrée et le résultat d’une invocation RPC x. Encoder les valeurs d’entrée x. Invoquer le RPC au point de livraison du service web x. Décoder et rendre à l’application tout résultat rendu par le service
k. SOAP z Construit au-dessus de l’analyseur k. XML yhttp: //ksoap 2. sourceforge. net/ y. Empreinte petite : 41 K pour v 2. 1. 2 y. Ne supporte pas la spécification entière de SOAP z L’exemple qui suit est réalisé avec k. SOAP v 1. 2
Analyseur SOAP z Extraire directement les objets Java d’un document SOAP y Type-mapping y Mashalling via un encodage sous forme de chaîne de caractères y Comprends les informations de typage dans un document SOAP y Convertit automatiquement les éléments SOAP en objets Java z Serialisation / désérialisation devient transparente
Exemple simple z Préparer les arguments à transmettre à la méthode distante y Instancier un objet SOAP (Soap. Object) y Ajouter les arguments de l’appel add. Property() z Préparer le transport y objet Http. Transport + URL destination z Invoquer la méthode distante y Invocation de la méthode call() sur l’objet Http. Transport y Le résultat est rendu par cette invocation
private String license. Key = "f. Vq. Hy. SRr. Xuf"; private String end. Point. URL ="http: //api. google. com/search/beta 2"; /** * Simple spell check using convenience class Http. Transport * This function returns the Google suggested spell. * @param query the string to be spell corrected. */ public String spell. Check (String query) throws Exception { // Prepare request SOAP message in a memory object Soap. Object method = new Soap. Object("urn: Google. Search", "do. Spelling. Suggestion"); method. add. Property("key", license. Key); method. add. Property("phrase", query); // Prepare SOAP RPC call object. Http. Transport rpc = new Http. Transport(end. Point. URL); // Google uses 1999 SOAP standards. Class. Map cm = new Class. Map(Soap. VER 10); rpc. set. Class. Map (cm); // Conduct RPC call through HTTP and directly get results String spell. Sugg = (String) rpc. call (method); System. out. println(rpc. request. Dump); System. out. println(rpc. response. Dump); return spell. Sugg; }
Fonctionnement de la méthode ‘call’ 1 - Sérialisation de l’objet Soap. Object sous forme de message de requête avec les bons espaces de noms <? xml version='1. 0' encoding='UTF-8'? > <SOAP-ENV: Envelope xmlns: SOAP-ENV="http: //schemas. xmlsoap. org/soap/envelope/" xmlns: xsi="http: //www. w 3. org/1999/XMLSchema-instance" xmlns: xsd="http: //www. w 3. org/1999/XMLSchema"> <SOAP-ENV: Body> <ns 1: do. Spelling. Suggestion xmlns: ns 1="urn: Google. Search" SOAP-ENV: encoding. Style= "http: //schemas. xmlsoap. org/soap/encoding/"> <key xsi: type="xsd: string">QLg. FCb. GCQD 6710 Pl. S</key> <phrase xsi: type="xsd: string">phon</phrase> </ns 1: do. Spelling. Suggestion> </SOAP-ENV: Body> </SOAP-ENV: Envelope>
Fonctionnement de la méthode ‘call’ z 2. soumission de la requête au point de livraison à travers HTTP z 3. récupération du message de réponse SOAP <? xml version='1. 0' encoding='UTF-8'? > <SOAP-ENV: Envelope xmlns: SOAP-ENV="http: //schemas. xmlsoap. org/soap/envelope/" xmlns: xsi="http: //www. w 3. org/1999/XMLSchema-instance" xmlns: xsd="http: //www. w 3. org/1999/XMLSchema"> <SOAP-ENV: Body> <ns 1: do. Spelling. Suggestion. Response xmlns: ns 1="urn: Google. Search" SOAP-ENV: encoding. Style= "http: //schemas. xmlsoap. org/soap/encoding/"> <return xsi: type="xsd: string">phone</return> </ns 1: do. Spelling. Suggestion. Response> </SOAP-ENV: Body> </SOAP-ENV: Envelope> z 4. transformer la réponse en objet Java et rendre cet objet y La chaîne « phone » de type String
Transport des message en k. SOAP package org. ksoap. transport; import java. io. *; import javax. microedition. io. *; import org. kxml. parser. *; import org. ksoap. *; public class Http. Transport { String url; String soap. Action = """"; Soap. Envelope request. Envelope = new Soap. Envelope (); Soap. Envelope response. Envelope = new Soap. Envelope (); Http. Connection connection; Output. Stream os; Input. Stream is; Input. Stream. Reader reader;
Transport des message en k. SOAP /** Sends the request. Envelope and fills the response. Envelope @exception Interrupted. IOException if transport was closed async. @exception IOException if an error occurs */ public void call () throws IOException { Byte. Array. Output. Stream bos = new Byte. Array. Output. Stream (); Xml. Writer xw = new Xml. Writer (new Output. Stream. Writer (bos)); request. Envelope. write (xw); xw. flush (); bos. write ('r'); bos. write ('n'); byte [] request. Data = bos. to. Byte. Array (); bos = null; xw = null; request. Dump = debug ? new String (request. Data) : null; response. Dump = null;
try { connected = true; connection = (Http. Connection) Connector. open (url, Connector. READ_WRITE, true); connection. set. Request. Property ("SOAPAction", soap. Action); connection. set. Request. Property ("Content-Type", "text/xml"); connection. set. Request. Property ("Content-Length", ""+request. Data. length); connection. set. Request. Property ("User-Agent", "k. SOAP/1. 0"); connection. set. Request. Method (Http. Connection. POST); os = connection. open. Output. Stream (); os. write (request. Data, 0, request. Data. length); os. close (); request. Data = null; is = connection. open. Input. Stream (); reader = new Input. Stream. Reader (is); Xml. Parser xp = new Xml. Parser (reader); response. Envelope. parse (xp); } finally { if (!connected) throw new Interrupted. IOException (); reset (); } }
Génération des stubs z. IBM Web. Sphere Studio Device Developer z. Sun. One Studio z. Code. Warrior Wireless Studio
Fonctionnement interne de k. SOAP v 1. 2 z Lorsque l’analyseur k. SOAP rencontre un élément SOAP, l’analyseur lit l’élément XML dans un objet Java selon les règles suivantes: y Si l’élément SOAP est un des type primitifs prédéfini du tableau, il est converti dans un objet Java du type correspondant y Si l’élément SOAP n’a pas de fils, mais n’est pas un des types prédéfini, il est converti en un objet Soap. Primitive x On peut récupérer les informations de typage de l’élément originel SOAP via les méthodes Soap. Primitive. get. Name. Space() et Soap. Primitive. get. Name() x On peut accéder la valeur de la chaîne de caractères via la méthode Soap. Primitive. to. String() y Si l’élément SOAP a des fils, i. e. c’est un élément complexe, il est converti en objet implémentant l’interface Kvm. Serializable x La classe utilitaire Soap. Object implémente cet interface x On peut récupérer les information s typages via les méthodes Soap. Object. get. Name. Space() et Soap. Object. get. Name() y Les fils d’un élément complexe sont convertis en propriétés de leur parent Soap. Object selon les règles précédentes. x Chaque propriété possède se voit aussi associé un objet Property. Info qui contient les informations comme le nom de l’élément SOAP et son type Java
Structure des Soap. Object z Parce qu’un objet Soap. Object peut avoir des propriétés Soap. Object, on peut l’utiliséer pour représenter des structures hiérarchiques complexes
Sérialiser un objet z Pour sérialiser un objet y Construire une représentaiton hiérarchique où x Toutes les feuilles doivent être soit un objet Soap. Primitive, soit un des quatre types prédéfinis x La racine par contre ne possède pas de paires (Soap. Object, Property. Info), on a donc perdu en principe le nom de la racine lors de l’analyse y Utiliser un objet « writer » k. SOAP pour sérialiser l’objet en mémoire dans un flot XML
// Soap. Object "method" is the calling construct // // the "" and "Stock. Order. Parameters" here are // element name/namespace rather than SOAP type name/namespace Soap. Object method = new Soap. Object("", "Stock. Order. Parameters"); method. add. Property("Symbol", "XYZ"); method. add. Property("From", "Michael Yuan"); method. add. Property("Shares", new Integer (1000)); method. add. Property("Buy", new Boolean (true)); method. add. Property("Limit. Price", new Soap. Primitive ("http: //www. w 3. org/2001/XMLSchema", "float", "123. 4")); // Assemble "method" into an enveloped SOAP message // and then export to a String Byte. Array. Output. Stream bos = new Byte. Array. Output. Stream (); Xml. Writer xw = new Xml. Writer (new Output. Stream. Writer (bos)); // Use default mapping between Java objects and Soap elements Soap. Envelope envelope = new Soap. Envelope (new Class. Map (Soap. VER 12)); envelope. set. Body (method); envelope. write (xw); xw. flush (); bos. write ('r'); bos. write ('n'); byte [] request. Data = bos. to. Byte. Array (); String request. SOAPmesg = new String (request. Data);
Requête <SOAP-ENV: Envelope xmlns: SOAP-ENC="http: //www. w 3. org/2001/12/soap-encoding" xmlns: SOAP-ENV="http: //www. w 3. org/2001/12/soap-envelope" xmlns: xsi="http: //www. w 3. org/2001/XMLSchema-instance" xmlns: xsd="http: //www. w 3. org/2001/XMLSchema"> <SOAP-ENV: Body SOAP-ENV: encoding. Style="http: //www. w 3. org/2001/12/soapencoding"> <Stock. Order. Parameters id="o 0" SOAP-ENC: root="1"> <Symbol xsi: type="xsd: string">XYZ</Symbol> <From xsi: type="xsd: string">Michael Yuan</From> <Shares xsi: type="xsd: int">1000</Shares> <Buy xsi: type="xsd: boolean">true</Buy> <Limit. Price xsi: type="xsd: float">123. 45</Limit. Price> </Stock. Order. Parameters> </SOAP-ENV: Body> </SOAP-ENV: Envelope>
Réponse
Récupérer les éléments de la réponse Byte. Array. Input. Stream bis = new Byte. Array. Input. Stream (soap. Resp. Mesg. get. Bytes ()); Input. Stream. Reader reader = new Input. Stream. Reader (bis); Xml. Parser xp = new Xml. Parser (reader); // Use default mapping between Java objects and Soap elements. Soap. Envelope envelope = new Soap. Envelope (new Class. Map (Soap. VER 12)); envelope. parse (xp); // Get the parsed structure. Soap. Object order. Status = (Soap. Object) envelope. get. Result(); // Retrieve the values as appropriate Java objects. String customer. Name = (String) order. Status. get. Property ("Customer. Name"); String symbol = (String) order. Status. get. Property ("Symbol"); Integer share = (Integer) order. Status. get. Property ("Share"); Boolean buy = (Boolean) order. Status. get. Property ("Buy"); // Since the default mapping table has no "Float" type, there is no corresponding // Java object type for "xsd: float". So, as any unknown type, // this element is mapped to a "Soap. Primitive". Soap. Primitive price = (Soap. Primitive) order. Status. get. Property ("Price"); Soap. Primitive exec. Time = (Soap. Primitive) order. Status. get. Property ("Exec. Time");
Automatiser la sérialisation / désérialisation z Indiquer à l’analyseur la relation entre les type SOAP et les types Java y Compléter la table de base z Indiquer à l’analyseur comment convertir les chaînes de caractères en objet Java y Enregistrer dans la table un objet Marshal qui sait faire la conversion public interface Marshal { public Object read. Instance ( Soap. Parser parser, String namespace, String name, Element. Type expected) throws IOException; public void write. Instance (Soap. Writer writer, Object instance) throws IOException; public void register (Class. Map cm); }
La classe utilitaire org. ksoap. marshal. Marshal. Date Public class Marshal. Date implements Marshal public Object read. Instance ( Soap. Parser parser, String namespace, String name, Element. Type expected) throws IOException { parser. read (); // Start tag Object result = Iso. Date. string. To. Date ( parser. read. Text (), Iso. Date. DATE_TIME); parser. read (); // End tag return result; } public void register (Class. Map cm) { cm. add. Mapping (cm. xsd, "date. Time", Marshal. Date. DATE_CLASS, this); }
Class. Map. add. Mapping /** Defines a direct mapping from a namespace and name to a Java class (and vice versa), using the given marshal mechanism */ public void add. Mapping (String namespace, String name, Class clazz, Marshal marshal) { q. Name. To. Class. put ( new Soap. Primitive (namespace, name, null), marshal == null ? (Object) clazz : marshal); class. To. QName. put ( clazz. get. Name (), new Object [] {namespace, name, null, marshal}); if (prefix. Map. get. Prefix (namespace) == null) prefix. Map = new Prefix. Map (prefix. Map, "n"+(cnt++), namespace); }
Ajout à la table des mappings avant de désérialiser la réponse Byte. Array. Input. Stream bis = new Byte. Array. Input. Stream (mesg. get. Bytes ()); Input. Stream. Reader reader = new Input. Stream. Reader (bis); Xml. Parser xp = new Xml. Parser (reader); // Register Marshal for "xsd: date. Time" type Class. Map cm = new Class. Map (Soap. VER 12); Marshal md = new Marshal. Date (); md. register (cm); Soap. Envelope envelope = new Soap. Envelope (cm); envelope. parse (xp); Soap. Object order. Status =(Soap. Object)envelope. get. Result(); Date exec. Time = (Date) order. Status. get. Property ("Exec. Time");
La sérialisation des « array »
La désérialisation sous forme de Vector // Register Marshal for "xsd: date. Time" type Class. Map cm = new Class. Map (Soap. VER 12); Marshal md = new Marshal. Date (); md. register (cm); Soap. Envelope envelope = new Soap. Envelope (cm); envelope. parse (xp); Soap. Object order. Status = (Soap. Object) envelope. get. Result(); String customer. Name = (String) order. Status. get. Property ("Customer. Name"); Vector transactions = (Vector) order. Status. get. Property ("Transactions"); // First element in the array Soap. Object transaction 0 = (Soap. Object) transactions. element. At(0); String symbol 0 = (String) transaction 0. get. Property ("Symbol"); Integer share 0 = (Integer) transaction 0. get. Property ("Share"); Boolean buy 0 = (Boolean) transaction 0. get. Property ("Buy"); Soap. Primitive price 0 = (Soap. Primitive) transaction 0. get. Property ("Price"); // Second element in the array Soap. Object transaction 1 = (Soap. Object) transactions. element. At(1); String symbol 1 = (String) transaction 1. get. Property ("Symbol"); Integer share 1 = (Integer) transaction 1. get. Property ("Share"); Boolean buy 1 = (Boolean) transaction 1. get. Property ("Buy"); Soap. Primitive price 1 = (Soap. Primitive) transaction 1. get. Property ("Price");
Validation des documents à l’aide des templates SOAP z Via la classe Class. Map y Ajouter un objet template Soap. Object à l’analyseur z Template y un Soap. Object vide avec de l’information sur xle type SOAP parent x. Les noms des éléments des enfants (properties) x. Leur type Java y Un fils peut lui-même être un template ce qui permet de construire des templates arbitrairement complexes z Si l’analyseur détecte une erreur, alors il lance une exception et s’arrête
Une transaction doit contenir xsd: string value Symbol, xsd: int value Share, xsd: boolean value Buy, xsd: float value Price Byte. Array. Input. Stream bis = new Byte. Array. Input. Stream (array. Soap. Resp. Mesg. get. Bytes ()); Input. Stream. Reader reader = new Input. Stream. Reader (bis); Xml. Parser xp = new Xml. Parser (reader); Class. Map cm = new Class. Map (Soap. VER 12); // Register Marshal for "xsd: date. Time" type Marshal md = new Marshal. Date (); md. register (cm); Soap. Object so = new Soap. Object ("http: //www. javaworld. com/ksoap/test", "transaction"); so. add. Property ("Symbol", new String ("")); so. add. Property ("Share", new Integer (0)); so. add. Property ("Buy", new Boolean (true)); so. add. Property ("Price", new Soap. Primitive ("xsd", "float", "")); cm. add. Template (so); Soap. Envelope envelope = new Soap. Envelope (cm); envelope. parse (xp); Soap. Object order. Status = (Soap. Object) envelope. get. Result();
Comparaison entre le package J 2 ME Web Services Optional Package et k. XML + k. SOAP z Modèle de traitement XML y J 2 ME Web Services Optional Package x. SAX seulement yk. XML x. SAX, XMLPull et k. DOM z Centré Java ou centré XML y J 2 ME Web Services Optional Package x. Traite SOAP RPC de manière similaire à RMI RPC x. Pas de contrôle sur les messages yk. XML x. Plus de prise sur la structure XML interne
Références z Enterprise J 2 ME y Chapitre 16 z Access Web services from wireless devices, Handle SOAP messages on MIDP devices using k. SOAP y http: //www. javaworld. com/javaworld/jw-08 -2002/jw-0823 -wireless. html? page=1
- Slides: 34