Upload
kapila
View
47
Download
3
Embed Size (px)
DESCRIPTION
XML, SOAP, Services Web et JAVA Me. SOAP Web Services on Smart Clients. Plan. Services Web XML over http SOAP - RPC. Avantages de SOAP. Support pour le typage Plus de 40 types de données avec les schémas XML Permet aux usagers de se définir des types de données complexes - PowerPoint PPT Presentation
Citation preview
XML, SOAP, Services Web et JAVA Me
SOAP Web Services on Smart Clients
Plan
Services Web XML over http SOAP - RPC
Avantages de SOAP
Support pour le typage Plus de 40 types de données avec les schémas XML Permet aux usagers de se définir des types de données complexes
Messagerie flexible et répandue Supporte plusieurs schémas de messagerie dont
RPC synchrone, messages asynchrones, multicast (souscription), routage complexe des messages avec plusieurs intermédiaires
Standardisation Adhérence répandue à SOAP par les services web Profiter des standards XML qui peuvent être intégrés à SOAP ou utiliser SOAP
WSDL (Web Services Description Language), UDDI (Universal Description, Discovery, and Integration), et la plupart des registres XML;
XML Digital Signature, XML Encryption, SAML (Security Assertion Markup Language)
Rem: sérialisation d’objets Java En vecteur d’octets en tant qu’élément Base64 pour les transporter par SOAP Par contre, si on sait que tout se passe en Java, il vaut mieux utiliser RMI ou JMS
Architecture des services web SOAP J2ME Web Services API (WSA)
Pour tout profil J2ME CDC ou CLDC remote invocation API
Sous-ensemble strict de J2SE Java API for XML-Based RPC (JAX-RPC 1.1),
+ quelques classes Remote Method Invocation (RMI) classes ajoutées pour satisfaire les dépendances de JAX-RPC
Un sous-ensemble strict de SAX, version 2
Organisation d’une application fondée sur JSR
JSR172 run-time et stubs
runtime Permet aux stubs de réaliser toutes les tâches associées à
l’invocation d’un RPC à service web Déterminer les propriétés spécifiques à une invocation RPC Décrire les valeurs d’entrée et le résultat d’une invocation RPC Encoder les valeurs d’entrée Invoquer le RPC au point de livraison du service web Décoder et rendre à l’application tout résultat rendu par le
service
kSOAP
Construit au-dessus de l’analyseur kXML
http://ksoap2.sourceforge.net/ Empreinte petite : 41 K pour v2.1.2 Ne supporte pas la spécification entière de
SOAP
L’exemple qui suit est réalisé avec kSOAP v1.2
Analyseur SOAP
Extraire directement les objets Java d’un document SOAP
Type-mapping Mashalling via un encodage sous forme de chaîne de
caractères
Comprends les informations de typage dans un document SOAP
Convertit automatiquement les éléments SOAP en objets Java
Serialisation / désérialisation devient transparente
Exemple simple
Préparer les arguments à transmettre à la méthode distante Instancier un objet SOAP (SoapObject) Ajouter les arguments de l’appel addProperty()
Préparer le transport objet HttpTransport + URL destination
Invoquer la méthode distante Invocation de la méthode call() sur l’objet HttpTransport Le résultat est rendu par cette invocation
private String licenseKey = "fVqHySRrXuf";private String endPointURL ="http://api.google.com/search/beta2";
/** * Simple spell check using convenience class HttpTransport * This function returns the Google suggested spell.* @param query the string to be spell corrected. */ public String spellCheck (String query) throws Exception { // Prepare request SOAP message in a memory object SoapObject method = new SoapObject("urn:GoogleSearch", "doSpellingSuggestion"); method.addProperty("key", licenseKey); method.addProperty("phrase", query);
// Prepare SOAP RPC call object. HttpTransport rpc = new HttpTransport(endPointURL); // Google uses 1999 SOAP standards. ClassMap cm = new ClassMap(Soap.VER10); rpc.setClassMap (cm);
// Conduct RPC call through HTTP and directly get results String spellSugg = (String) rpc.call (method);
System.out.println(rpc.requestDump); System.out.println(rpc.responseDump);
return spellSugg; }
Fonctionnement de la méthode ‘call’
1- Sérialisation de l’objet SoapObject 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.w3.org/1999/XMLSchema-instance" xmlns:xsd="http://www.w3.org/1999/XMLSchema">
<SOAP-ENV:Body> <ns1:doSpellingSuggestion xmlns:ns1="urn:GoogleSearch" SOAP-ENV:encodingStyle= "http://schemas.xmlsoap.org/soap/encoding/">
<key xsi:type="xsd:string">QLgFCbGCQD6710PlS</key><phrase xsi:type="xsd:string">phon</phrase>
</ns1:doSpellingSuggestion>
</SOAP-ENV:Body> </SOAP-ENV:Envelope>
Fonctionnement de la méthode ‘call’
2. soumission de la requête au point de livraison à travers HTTP
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.w3.org/1999/XMLSchema-instance" xmlns:xsd="http://www.w3.org/1999/XMLSchema"> <SOAP-ENV:Body> <ns1:doSpellingSuggestionResponse xmlns:ns1="urn:GoogleSearch" SOAP-ENV:encodingStyle= "http://schemas.xmlsoap.org/soap/encoding/">
<return xsi:type="xsd:string">phone</return>
</ns1:doSpellingSuggestionResponse> </SOAP-ENV:Body> </SOAP-ENV:Envelope>
4. transformer la réponse en objet Java et rendre cet objet La chaîne « phone » de type String
Transport des message en kSOAP
package org.ksoap.transport;
import java.io.*;import javax.microedition.io.*;
import org.kxml.*;import org.kxml.io.*;import org.kxml.parser.*;
import org.ksoap.*;
public class HttpTransport {
String url; String soapAction = "\"\"";
SoapEnvelope requestEnvelope = new SoapEnvelope (); SoapEnvelope responseEnvelope = new SoapEnvelope ();
HttpConnection connection; OutputStream os; InputStream is; InputStreamReader reader;
Transport des message en kSOAP
/** Sends the requestEnvelope and fills the responseEnvelope @exception InterruptedIOException if transport was closed async.
@exception IOException if an error occurs*/public void call () throws IOException {
ByteArrayOutputStream bos = new ByteArrayOutputStream ();XmlWriter xw = new XmlWriter (new OutputStreamWriter (bos));requestEnvelope.write (xw);xw.flush ();bos.write ('\r');bos.write ('\n');byte [] requestData = bos.toByteArray ();bos = null;xw = null;
requestDump = debug ? new String (requestData) : null;responseDump = null;
try { connected = true; connection = (HttpConnection) Connector.open (url, Connector.READ_WRITE, true);
connection.setRequestProperty ("SOAPAction", soapAction); connection.setRequestProperty ("Content-Type", "text/xml"); connection.setRequestProperty ("Content-Length", ""+requestData.length);
connection.setRequestProperty ("User-Agent", "kSOAP/1.0");
connection.setRequestMethod (HttpConnection.POST);
os = connection.openOutputStream (); os.write (requestData, 0, requestData.length); os.close ();
requestData = null;
is = connection.openInputStream ();
reader = new InputStreamReader (is); XmlParser xp = new XmlParser (reader);
responseEnvelope.parse (xp);
} finally { if (!connected) throw new InterruptedIOException (); reset (); } }
Génération des stubs
IBM WebSphere Studio Device Developer
SunOne Studio
CodeWarrior Wireless Studio
Fonctionnement interne de kSOAP v 1.2
Lorsque l’analyseur kSOAP rencontre un élément SOAP, l’analyseur lit l’élément XML dans un objet Java selon les règles suivantes:
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
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 SoapPrimitive
On peut récupérer les informations de typage de l’élément originel SOAP via les méthodes SoapPrimitive.getNameSpace() et SoapPrimitive.getName()
On peut accéder la valeur de la chaîne de caractères via la méthode SoapPrimitive.toString()
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 KvmSerializable
La classe utilitaire SoapObject implémente cet interface On peut récupérer les information s typages via les méthodes
SoapObject.getNameSpace() et SoapObject.getName()
Les fils d’un élément complexe sont convertis en propriétés de leur parent SoapObject selon les règles précédentes.
Chaque propriété possède se voit aussi associé un objet PropertyInfo qui contient les informations comme le nom de l’élément SOAP et son type Java
Structure des SoapObject
Parce qu’un objet SoapObject peut avoir des propriétés SoapObject, on peut l’utiliséer pour représenter des structures hiérarchiques complexes
Sérialiser un objet
Pour sérialiser un objet Construire une représentaiton hiérarchique où
Toutes les feuilles doivent être soit un objet SoapPrimitive, soit un des quatre types prédéfinis
La racine par contre ne possède pas de paires (SoapObject, PropertyInfo), on a donc perdu en principe le nom de la racine lors de l’analyse
Utiliser un objet « writer » kSOAP pour sérialiser l’objet en mémoire dans un flot XML
// SoapObject "method" is the calling construct // // the "" and "StockOrderParameters" here are// element name/namespace rather than SOAP type name/namespace
SoapObject method = new SoapObject("", "StockOrderParameters");method.addProperty("Symbol", "XYZ"); method.addProperty("From", "Michael Yuan"); method.addProperty("Shares", new Integer (1000)); method.addProperty("Buy", new Boolean (true)); method.addProperty("LimitPrice", new SoapPrimitive
("http://www.w3.org/2001/XMLSchema", "float", "123.4"));
// Assemble "method" into an enveloped SOAP message // and then export to a String
ByteArrayOutputStream bos = new ByteArrayOutputStream (); XmlWriter xw = new XmlWriter (new OutputStreamWriter (bos));
// Use default mapping between Java objects and Soap elements
SoapEnvelope envelope = new SoapEnvelope (new ClassMap (Soap.VER12)); envelope.setBody (method); envelope.write (xw); xw.flush (); bos.write ('\r'); bos.write ('\n'); byte [] requestData = bos.toByteArray ();String requestSOAPmesg = new String (requestData);
Requête<SOAP-ENV:Envelope
xmlns:SOAP-ENC="http://www.w3.org/2001/12/soap-encoding" xmlns:SOAP-ENV="http://www.w3.org/2001/12/soap-envelope" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <SOAP-ENV:Body
SOAP-ENV:encodingStyle="http://www.w3.org/2001/12/soap-encoding">
<StockOrderParameters id="o0" 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> <LimitPrice
xsi:type="xsd:float">123.45</LimitPrice> </StockOrderParameters> </SOAP-ENV:Body>
</SOAP-ENV:Envelope>
Réponse
Récupérer les éléments de la réponse
ByteArrayInputStream bis = new ByteArrayInputStream (soapRespMesg.getBytes ()); InputStreamReader reader = new InputStreamReader (bis); XmlParser xp = new XmlParser (reader);
// Use default mapping between Java objects and Soap elements. SoapEnvelope envelope = new SoapEnvelope (new ClassMap (Soap.VER12)); envelope.parse (xp);
// Get the parsed structure. SoapObject orderStatus = (SoapObject) envelope.getResult();
// Retrieve the values as appropriate Java objects. String customerName = (String) orderStatus.getProperty ("CustomerName"); String symbol = (String) orderStatus.getProperty ("Symbol"); Integer share = (Integer) orderStatus.getProperty ("Share"); Boolean buy = (Boolean) orderStatus.getProperty ("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 "SoapPrimitive". SoapPrimitive price = (SoapPrimitive) orderStatus.getProperty ("Price"); SoapPrimitive execTime = (SoapPrimitive) orderStatus.getProperty ("ExecTime");
Automatiser la sérialisation / désérialisation
Indiquer à l’analyseur la relation entre les type SOAP et les types Java Compléter la table de base
Indiquer à l’analyseur comment convertir les chaînes de caractères en objet Java Enregistrer dans la table un objet Marshal qui sait faire la
conversion
public interface Marshal { public Object readInstance ( SoapParser parser,
String namespace, String name, ElementType expected)
throws IOException;
public void writeInstance (SoapWriter writer, Object instance) throws IOException;
public void register (ClassMap cm); }
La classe utilitaire org.ksoap.marshal.MarshalDate Public class MarshalDate implements Marshal
public Object readInstance ( SoapParser parser, String namespace, String name, ElementType expected)
throws IOException { parser.parser.read (); // Start tag Object result = IsoDate.stringToDate (
parser.parser.readText (), IsoDate.DATE_TIME);
parser.parser.read (); // End tag return result;
}
public void register (ClassMap cm) { cm.addMapping (cm.xsd, "dateTime", MarshalDate.DATE_CLASS, this);
}
ClassMap.addMapping
/** Defines a direct mapping from a namespace and name to a Java class (and vice versa), using the given marshal mechanism */
public void addMapping (String namespace, String name, Class clazz, Marshal marshal)
{ qNameToClass.put ( new SoapPrimitive (namespace, name, null),
marshal == null ? (Object) clazz : marshal); classToQName.put ( clazz.getName (),
new Object [] {namespace, name, null, marshal});
if (prefixMap.getPrefix (namespace) == null) prefixMap = new PrefixMap (prefixMap, "n"+(cnt++), namespace);
}
Ajout à la table des mappings avant de désérialiser la réponse
ByteArrayInputStream bis = new ByteArrayInputStream (mesg.getBytes ());
InputStreamReader reader = new InputStreamReader (bis); XmlParser xp = new XmlParser (reader);
// Register Marshal for "xsd:dateTime" type ClassMap cm = new ClassMap (Soap.VER12); Marshal md = new MarshalDate (); md.register (cm);
SoapEnvelope envelope = new SoapEnvelope (cm); envelope.parse (xp);
SoapObject orderStatus =(SoapObject)envelope.getResult(); Date execTime = (Date) orderStatus.getProperty ("ExecTime");
La sérialisation des « array »
La désérialisation sous forme de Vector
// Register Marshal for "xsd:dateTime" type ClassMap cm = new ClassMap (Soap.VER12); Marshal md = new MarshalDate (); md.register (cm);
SoapEnvelope envelope = new SoapEnvelope (cm); envelope.parse (xp);
SoapObject orderStatus = (SoapObject) envelope.getResult(); String customerName = (String) orderStatus.getProperty ("CustomerName"); Vector transactions = (Vector) orderStatus.getProperty ("Transactions");
// First element in the array SoapObject transaction0 = (SoapObject) transactions.elementAt(0); String symbol0 = (String) transaction0.getProperty ("Symbol"); Integer share0 = (Integer) transaction0.getProperty ("Share"); Boolean buy0 = (Boolean) transaction0.getProperty ("Buy"); SoapPrimitive price0 = (SoapPrimitive) transaction0.getProperty ("Price");
// Second element in the array SoapObject transaction1 = (SoapObject) transactions.elementAt(1);
String symbol1 = (String) transaction1.getProperty ("Symbol"); Integer share1 = (Integer) transaction1.getProperty ("Share"); Boolean buy1 = (Boolean) transaction1.getProperty ("Buy"); SoapPrimitive price1 = (SoapPrimitive) transaction1.getProperty ("Price");
Validation des documents à l’aide des templates SOAP
Via la classe ClassMap Ajouter un objet template SoapObject à l’analyseur
Template un SoapObject vide avec de l’information sur
le type SOAP parent Les noms des éléments des enfants (properties) Leur type Java
Un fils peut lui-même être un template ce qui permet de construire des templates arbitrairement complexes
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
ByteArrayInputStream bis = new ByteArrayInputStream (arraySoapRespMesg.getBytes ());
InputStreamReader reader = new InputStreamReader (bis); XmlParser xp = new XmlParser (reader);
ClassMap cm = new ClassMap (Soap.VER12); // Register Marshal for "xsd:dateTime" type Marshal md = new MarshalDate (); md.register (cm);
SoapObject so = new SoapObject ("http://www.javaworld.com/ksoap/test", "transaction");
so.addProperty ("Symbol", new String ("")); so.addProperty ("Share", new Integer (0)); so.addProperty ("Buy", new Boolean (true)); so.addProperty ("Price", new SoapPrimitive ("xsd", "float", "")); cm.addTemplate (so);
SoapEnvelope envelope = new SoapEnvelope (cm); envelope.parse (xp); SoapObject orderStatus = (SoapObject) envelope.getResult();
Comparaison entre le package J2ME Web Services Optional Package et kXML + kSOAP
Modèle de traitement XML J2ME Web Services Optional Package
SAX seulement kXML
SAX, XMLPull et kDOM
Centré Java ou centré XML J2ME Web Services Optional Package
Traite SOAP RPC de manière similaire à RMI RPCPas de contrôle sur les messages
kXMLPlus de prise sur la structure XML interne
Références
Enterprise J2ME
Chapitre 16
Access Web services from wireless devices, Handle SOAP messages on MIDP devices using kSOAP
http://www.javaworld.com/javaworld/jw-08-2002/jw-0823-wireless.html?page=1