Les webservices avec Play Framework 1.2.5

Je suis parti d’une recherche autour de la création d’objets à partir d’un flux JSON. Au fur et a mesure de mon avancement, j’ai construit un document autour de JSON, XML, Webservice SOAP.

Le document est construit autour d’exemples

  • de création de flux X à partir de Play
  • de consommation de flux Y dans Play.
  • de test fonctionnel
  • de copie d’écran Poster
  • de script Curl

Cet article est une base de travail autour des divers types de webservices. Il permet de construire rapidement un prototype fonctionnel, de debugger des flux, de voir ce qui ce passe.

J’utilise JSON depuis JavaScript, Jquery et AJax, mais pas seulement. La communication entre une application et une autre, entre une application mobile et un serveur. JSON est en train de sur-planter les architecture classique, dans beaucoup de domaine (base de donnée NoSQL, mobilité, etc ).

Je pense construire le même article en Play! 2.2.

Nota :

Cet article est un export d’un document LibreOffice, il y a des problèmes de pagination, de taille de police, des sauts de lignes en trop, etc. Je vais corriger petit à petit l’article et le rendu.

J’ai d’autres articles sous LibreOffice et je recherche un outil de publication qui fonctionne.

Les webservices JSON

Obtenir une liste au format JSON

Source :
https://github.com/loicdescotte/vote4music/

J’appelle le serveur en JSON.. avec
Content Type : application/json; charset=utf-8

Le fichier route :

GET
/vote
Vote.index

GET
/api/albums.{<json|xml>format}
Vote.listByApi

GET
/api/{genre}/albums.{<json|xml>format}
Vote.listByApi

GET
/api/{genre}/{year}/albums.{<json|xml>format}
Vote.listByApi

GET
/api/artists.{<json|xml>format}
Vote.listArtistsByApi

POST /api/album
Vote.saveAlbumByApi

POST
/albumm

Le source :

/**

* List albums in xml or json format

*

* @param genre

* @param year

*/

public static void listByApi(String genre, String year) {

List<Album> albums;

if (genre != null) {

Genre genreEnum = Genre.valueOf(genre.toString().toUpperCase());

albums = Album.find(« byGenre », genreEnum).fetch();

} else {

albums = Album.findAll();

}

if (year != null) {

albums = Album.filterByYear(albums, year);

}

if (request.format.equals(« json »))

renderJSON(albums);

render(albums);

}

La réponse :

[

{« name »: »coolAlbum », »artist »:{« name »: »joe », »id »:1}, »releaseDate »: »nov.
12, 2010″, »genre »: »ROCK », »nbVotes »:0, »hasCover »:false, »id »:1},

{« name »: »superAlbum », »artist »:{« name »: »joe », »id »:1}, »releaseDate »: »oct.
9, 2011″, »genre »: »ROCK », »nbVotes »:0, »hasCover »:false, »id »:2},

{« name »: »The Monster », »artist »:{« name »: »Lady
gaga », »id »:2}, »releaseDate »: »juin 1,
2011″, »genre »: »ROCK », »nbVotes »:0, »hasCover »:false, »id »:3},

{« name »: »Live after death », »artist »:{« name »: »Iron
maiden », »id »:3}, »releaseDate »: »janv. 1,
2011″, »genre »: »METAL », »nbVotes »:0, »hasCover »:false, »id »:4},

{« name »: »Death Magnetic », »artist »:{« id »:4}, »releaseDate »: »janv.
1, 2008″, »genre »: »METAL », »nbVotes »:0, »hasCover »:false, »id »:5}

]

Création
d’un album à partir d’un flux JSON ..

Le flux :

{
« name »: »Death Magnetic22″, « artist »:{« name »: »Metallica » }, « releaseDate »: »12 sept. 2010 00:00:00″, « genre »: »METAL » }

Le code source :

/**

* Save album via API

*/

public static void saveAlbumByApi() {

System.out.println(« saveAlbumByApi »);

Logger.error(« Encoding= » + request.encoding);

Logger.error(« ContentType= » + request.contentType);

if(request.contentType.equalsIgnoreCase(« application/xml »))

saveAlbumXml(request.body);

else
if (request.contentType.equalsIgnoreCase(« application/json »))

saveAlbumJson(request.body);

System.out.println(« request.contentType= » + request.contentType);

}

/**

* Save album via JSON API

*/

private static void saveAlbumJson(InputStream requestBody) {

System.out.println(« saveAlbumJson »);

Gson gson = new Gson();

Album album = gson.fromJson(new InputStreamReader(requestBody),Album.class);

album.replaceDuplicateArtist();

album.save();

}

Poster :

Résultat :

Vérification :

Les logs :

saveAlbumByApi

16:10:31,045 ERROR ~ Encoding =UTF-8

16:10:31,045 ERROR ~ ContentType =application/json

saveAlbumJson

16:10:31,048 ERROR ~ Nom =Death Magnetic22

16:10:31,048 ERROR ~ Genre =METAL

16:10:31,048 ERROR ~ HasCover =false

request.contentType=application/json

Appel JSON depuis JUNIT

https://github.com/loicdescotte/vote4music/blob/master/test/ApplicationTest.java

Le code source :

@Test

    public void testJsonApi() {
        //preconditions
             Response artists = GET("/api/artists.json");
        assertFalse(artists.out.toString().contains("john"));
                Response albums = GET("/api/albums.json");
        assertFalse(albums.out.toString().contains("album1"));
                String album1 = "{ \"name\":\"album1\", \"artist\":{ \"name\":\"john\" }, \"releaseDate\":\"12 sept. 2010 00:00:00\", \"genre\":\"ROCK\" }";
        POST("/api/album", "application/json", album1);
        artists = GET("/api/artists.json");
        assertTrue(artists.out.toString().contains("john"));
                albums = GET("/api/albums.json");
        assertTrue(albums.out.toString().contains("album1"));
    }

Appel JSON depuis un autre serveur

Un exemple avec Jakarta commons httpclient :

HttpClient httpClient = new DefaultHttpClient();

try {
HttpPost request = new HttpPost(« http://localhost:9000/api/XXX/ &raquo;);
request.addHeader(« content-type », « application/json; charset=utf-8 »);

String album1 = « { \ »name\ »:\ »album1\ », \ »artist\ »:{ \ »name\ »:\ »john\ » }, \ »releaseDate\ »:\ »12 sept. 2010 00:00:00\ », \ »genre\ »:\ »ROCK\ » } »;
StringEntity se = new StringEntity(album1);
request.setEntity(se);

HttpResponse response = httpClient.execute(request);

// handle response here…
} catch (Exception ex) {
// handle exception here
} finally {
httpClient.getConnectionManager().shutdown();
}
}

Aller plus loin avec JSON

{ « name »: »paramPlus », « artist »:{ « name »: »Iron Maden » }, « releaseDate »: »12
sept. 2010 00:00:00″, « genre »: »METAL », « monparam »: »inconnu » }

J’ai créer un enregistrement avec un param de plus.

L’application fonctionne à l’identique.

Attention:

Il existe des surprises entre JSON (et GSON) et JPA. Ils ne font pas très bon ménage.

Le toJson() de GSON n’aime pas les objets Hibernate, et les références circulaires.

Je vous conseille de prendre la librairie flexjson.

Les webservices XML

Source :
https://github.com/loicdescotte/vote4music/

Réponse au format XML

/**

* List artists in xml or json format

*/

public static void listArtistsByApi() {

List<Artist> artists = Artist.findAll();

if (request.format.equals(« json »))

renderJSON(artists);

render(artists);

}

GET /api/{genre}/albums.{<json|xml>format}
Vote.listByApi

Création d’un album à partir d’un flux XML

<album>

      <artist>Metallica</artist>
      <name>Death Magnetic</name>
      <release-date>2008</release-date>
      <genre>METAL</genre>
</album>


Fonctionne que avec application/xml → Normal

Ne fonctionne pas avec text/xml

Le code source :

/**

* Save album via API

*/

public static void saveAlbumByApi() {

System.out.println(« saveAlbumByApi »);

Logger.error(« Encoding = » + request.encoding);

Logger.error(« ContentType = » + request.contentType);

if (request.contentType.equalsIgnoreCase(« application/xml »))

saveAlbumXml(request.body);

else
if (request.contentType.equalsIgnoreCase(« application/json »))

saveAlbumJson(request.body);

System.out.println(« request.contentType = » + request.contentType);

}

Résultat :

Vérification :

Appel XML depuis JUNIT

        @Test
    public void testXmlApi() {
        Response artists = GET("/api/artists.xml");
        assertFalse(artists.out.toString().contains("john"));
                Response albums = GET("/api/albums.xml");
        assertFalse(albums.out.toString().contains("album1"));
                String album1 = "<album><artist><name>john</name></artist><name>album1</name><release-date>2010</release-date><genre>ROCK</genre><nvVotes>0</nvVotes></album>";
        POST("/api/album", "application/xml", album1);
           artists = GET("/api/artists.xml");
        assertTrue(artists.out.toString().contains("john"));
                albums = GET("/api/albums.xml");
        assertTrue(albums.out.toString().contains("album1"));
    }

Les webservices- SOAP

Source :

http://playframework.wordpress.com/2010/08/15/web-services-using-play/

et

https://github.com/chamerling/play-soap-wsnclient

Appel du webservice

package controllers;

import play.mvc.*;

import play.libs.*;

import org.w3c.dom.Document;

 public class Application extendsController
{

    publicstaticvoidconvert(String from, String to, Float amount) {

         String wsReq = "<?xml version=\"1.0\" encoding=\"utf-8\"?><soap12:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"
xmlns:xsd=\"
http://www.w3.org/2001/XMLSchema\"
xmlns:soap12=\"
http://www.w3.org/2003/05/soap-envelope\">"
+"<soap12:Body><ConversionRate xmlns=\"http://www.webserviceX.NET/\">"
+"<FromCurrency>"+from+"</FromCurrency>"
+"<ToCurrency>"+to+"</ToCurrency>"

+"</ConversionRate></soap12:Body></soap12:Envelope>";

Document doc = WS.url("http://www.webservicex.net/CurrencyConvertor.asmx").setHeader("Content-Type",
"application/soap+xml").body(wsReq).post().getXml();

String rate = doc.getElementsByTagName("ConversionRateResult").item(0).getTextContent();

Float total = amount * Float.parseFloat(rate);

render(from, to, amount, rate, total);

}

 

//---

    }

Réponse webservice

public static void router() {

String body = IO.readContentAsString(request.body);

Document xml = XML.getDocument(body);

if (xml == null) {

error(StatusCode.INTERNAL_ERROR, « XML is malformed… »);

}

Map<String,Header> map = request.headers;

Header header = map.get(« soapaction »);

String soapAction = header.value();

if (soapAction == null) {

wsdl();

}
else {

soapAction = soapAction.replaceAll(« \ » », «  »);

}

if (soapAction.endsWith(« sayHello »)) {

sayHello(xml);

} else if (soapAction.endsWith(« sayBye »)) {

sayBye(xml);

}

error(StatusCode.NOT_FOUND, « SOAPAction not found… »);

}

privatestaticvoid sayHello(Document xml) {

String name = XPath.selectText(« //sayHelloRequest/text() »,xml);

name= String.format(« Hello %s! »,name);

render(« Application//MyService_SayHelloResponse.xml »,name);

}

et

public static void wsdl() {

render(« Application/MyService.wsdl »);

}

Les routes

#SOAP MyService

GET/services/RawService.{wsdl} RawService.wsdl

POST /services/RawService RawService.any

Advertisements

A propos Duarte TERENCIO

Chef de projet et Architecte J2EE - Portail d'entreprise - Cloud computing Vous trouverez plus d'information sur la page "Me contacter"
Cet article, publié dans Programmation, est tagué , , , , , , . Ajoutez ce permalien à vos favoris.

Laisser un commentaire

Entrez vos coordonnées ci-dessous ou cliquez sur une icône pour vous connecter:

Logo WordPress.com

Vous commentez à l'aide de votre compte WordPress.com. Déconnexion / Changer )

Image Twitter

Vous commentez à l'aide de votre compte Twitter. Déconnexion / Changer )

Photo Facebook

Vous commentez à l'aide de votre compte Facebook. Déconnexion / Changer )

Photo Google+

Vous commentez à l'aide de votre compte Google+. Déconnexion / Changer )

Connexion à %s