OAuth and Desktop Apps

I started to develop QuickHub some weeks ago by focusing on features and without taking into account security issues such as this critical information which are login and password credentials… As mentioned in the GitHub developer pages, I started to use Basic Auth for all the requests QuickHub does to get retrieve data from GitHub. I started to think about moving to OAuth when a user said me that he bought QuickHub but that he did not use it because of Basic Auth. He was afraid that I can rob its credentials and so have a look to its repositories and more. I totally understand this argument and so I started to think that it limits QuickHub adoption by developers and that I should do something.

So, I discussed with GitHub guys through their support channel (Here I want to say that I am really impressed on how fast and professional is the GitHub support team!). Of course, they also told me that they will never use QuickHub if OAuth is not provided. After discussions with the guys, I started to implement a workaround to provide OAuth support in QuickHub by using the OAuth Web flow and adding some stuff to QuickHub.

Let’s see how we can do that in a generic way so that you can use it in your app if needed since every serious Internet service also provide OAuth support… Note that I will not give many details about OAuth itself but I will use some terms, so have a look to OAuth documentation for more details.

Register a Web application

The first step is to register your application to the developer portal. Here you need to provide some information such as the app name and its callback URL. Even if we are developing a desktop app and not a Web one, we need to be able to provide this HTTP based callback URL. We will see in the next section what is inside this application. By registering our application, the service will generate and give us some keys to be used in the next steps, mostly to recognize us when calling the service.

Create a Web application

We need a Web application to handle callback calls from the service we want to use OAuth. This application will only be used at authorization time and just have to be able to receive the service call, get the code sent by the service, then call the service again with the code and our application keys (there is a secret one to be used here). As a result, the service will send you back your OAuth token to be used in all the future service calls. This token is used to authenticate your service calls, no more password stuff inside! Here is a quick sequence diagram showing all the exchanges between actors…

On the QuickHub side, I chose to create this Web application by using the Play Framework I already mentioned several times in this blog. I used the Heroku paas to provide the Web application publicly.

As showed in this Gist (https://gist.github.com/1466592), the callback method is really simple (as usual with Play!): just get the code and call GitHub with it and your application keys. When all lis done, just display a result page with a specific URL. Here it starts with ‘quickhubapp://oauth?’. Let’s see what it means in the next section…

Add custom URL handlers to your desktop app

Once the desktop application is authorized, our Web application redirects the user to a Web page which embeds a button targeting an URL starting by ‘quickhubapp://oauth?’. Here you already understand that by clicking on such a link must drive you to something special. The cocoa framework allows developers to register specific URL handlers for their applications. So we need to register QuickHub handlers so that OS X knows that every link  with the quickhubapp scheme must me routed to QuickHub. This is as easy as showed in this Gist https://gist.github.com/1466628.

This code snippet just tells QuickHub to invoke the getUrl method when it receives a quickhubapp event. Up to the getUrl method to handle things. In QuickHub, I just extract the OAuth token in order to persist it locally for future use.

Done!

So now we are able to use OAuth Web flows for desktop applications. In the best of the worlds, every service provider may provide a real desktop flow to be used without the need to create this additional web application. In the real world, it is not the case but as you see it can be bypassed quite easily.

I will provide more technical details on the second section ‘Create a Web application’ with real sample and code in the next weeks.

BPEL support in Petals DSB

As promised in the last article about my talk at OW2Con 2011 last week, here is a video on something I was not able to show due to some low resolution problems. The video is a bit long but shows several things (in the right order):

  1. The DSB Manager Web application is used to manage the Distributed Service Bus. It uses the DSB Web service API to interact with node instances running somewhere…
  2. The DSB Manager is used to bind business services to the DSB (let’s forget JBI, the user does not care about it…). DSB services are also exposed. Every DSB node provides the same business API with the help of the distributed endpoint registry it uses.
  3. The DSB Manager uses the DSB BPEL API to deploy BPEL processes to the DSB. Up to the DSB to use the right internal endpoint when the process is executed. Services can be hosted on any node, it is the role of the DSB to route messages to the right endpoint on the right node. The BPEL process is exposed as Web service and can be invoked by any Web service client. Here I just use SOAPUI client.
  4. We can monitor what happens when invoking a service! For now the DSB Manager uses Web service notification to subscribe to some monitoring topic hosted on the DSB node. When a message is exchanged between the client and the services involved in the process execution, notification are automatically published to the DSB Manager which has just subscribed. The monitoring uses Web sockets for live display in the browser…
  5. Last thing is just a test to show more monitoring data when many calls are exchanged between consumers and providers.
Let’s go one step further… The BPEL engine we use in the DSB is our own (PetalsLink) BPEL engine we developed from scratch. This allows us to have a complete control on it and to be able to extend it and embed it as we want without any constraint. In the current case, the BPEL Engine is hosted on a dedicated DSB component. It means that we do not have an external thing which talk with services through some exposed services. This is really important to notice that by doing such thing we can really base process execution on a Service Oriented Architecture. When developing the BPEL process with the Petals Studio, or when creating a BPM process (more details in a future post), you do not have to care about service endpoints. You just have to say to the process that you want to call operation X of service Y or interface Z. It is up to the DSB hosting the BPEL engine to resolve endpoints at runtime. By using this approach we can really do interesting things, just because the DSB is Distributed: services can be hosted on any nodes, can be replicated, can move, can be updated without any impact on the process itself: Oh wait this is SOA!

Related articles

Create a management application in 3 hours with Play

Story, code, compare

Yet another ‘nightly project’ (thanks to current house build project and the lack of sleep it brings). This time I needed to be able to manage the so-famous Service Bus from some Web enabled tooling. I already developed such tool in a research project but the fact is that the licence of some libraries are not compatible with the petalslink open source approach. The second thing is that it is GWT based (which bores me, has almost 100 libraries dependencies and takes 10 minutes to compile). So this application is a good candidate to compare development productivity between GWT and the Play Framework. Here is a summary of the application creation:

  • I bootstraped the application yesterday during lunch between 1PM and 2PM. I was already able to invoke most of the interesting service bus actions with the help of service bus SOAP API.
  • I added some pages and actions last night, let say that since it was between 11PM and 1AM I was not very productive…
  • I fixed some bugs this morning

As a result, I think I worked around 3 hours on this application. I think I spent one hour to resolve a dependency conflict between Play and a CXF dependency but as a result I have a good result which is almost equivalent in functionality to the GWT based application. I still miss some operations but I do not need them for now… I feel ashamed to say how long it tooks me to create the GWT version…

Deploy

Let’s talk about deployment… I did not have time to play with heroku to push this application in the cloud. Tis will be a future step but since I use Play and git, I am able to push the code to github and then pull it on an OVH server I rent. I am able to provide this instance for some project partners if they want to manage the service bus. The time it took? 5 minutes (wget play, git clone and play start…).

Code

The Play enabled application is available on github at chamerling/dsbmanager-webapp.

Jouons avec WebServiceProvider…

Il y a des jours où exposer ses classes annotés avec @WebService n’est pas satisfaisant…
Pour moi ce jour c’est aujourd’hui: Il m’est impossible de marshaller mes beans en document DOM à cause d’un contexte JAXB tordu et d’une API qui ne prend que du DOM en entrée (OK bon ça c’est nul mais c’est pas de moi…). Qu’a cela ne tienne, il est temps d’utiliser les WebServiceProvider puisque ils vont me permettre de directement récupérer mon message SOAP sous forme de document… Un peu moins straight forward comme approche mais qui peut convenir dans certains cas. Comme les exemples ne courent pas le Web, regardons ce que l’on peut faire pour s’en sortir…

(Tout le code source de cet article est disponible sur Github : http://github.com/chamerling/chamerling.org-samples/tree/master/cxf-serviceprovider-072011)

Une première solution simple est d’implémenter javax.xml.ws.Provider, de rajouter deux/trois annotations et le tour est quasiment joué:

package org.chamerling.blog.cxf.serviceprovider;

import javax.xml.soap.SOAPMessage;
import javax.xml.ws.Provider;
import javax.xml.ws.ServiceMode;
import javax.xml.ws.WebServiceProvider;

/**
* @author chamerling
*
*/
@WebServiceProvider
@ServiceMode(value = javax.xml.ws.Service.Mode.MESSAGE)
public class SimpleServiceProvider implements Provider {

/*
* (non-Javadoc)
*
* @see javax.xml.ws.Provider#invoke(java.lang.Object)
*/
@Override
public SOAPMessage invoke(SOAPMessage in) {
return null;
}
}

Reste à l’exposer avec CXF en utilisant org.apache.cxf.jaxws.JaxWsServerFactoryBean. Cette approche simpliste a le mérite de marcher, il ne reste plus qu’a manipuler les SOAPMessage dans l’implémentation de la méthode invoke.

Besoin de l’opération qui est appelée? Ajoutons javax.xml.ws.WebServiceContext en tant que javax.annotation.Resource. Ce contexte sera automatiquement rempli pour nous par CXF et accessible dans le corps de la méthode invoke. Par exemple, on peut travailler de la sorte:

/**
 *
 */
package org.chamerling.blog.cxf.serviceprovider;

import javax.annotation.Resource;
import javax.xml.namespace.QName;
import javax.xml.soap.SOAPMessage;
import javax.xml.ws.Provider;
import javax.xml.ws.ServiceMode;
import javax.xml.ws.WebServiceContext;
import javax.xml.ws.WebServiceProvider;
import javax.xml.ws.handler.MessageContext;

/**
 * @author chamerling
 *
 */
@WebServiceProvider
@ServiceMode(value = javax.xml.ws.Service.Mode.MESSAGE)
public class SimpleServiceProvider implements Provider {

	@Resource
	WebServiceContext wsContext;

	/*
	 * (non-Javadoc)
	 *
	 * @see javax.xml.ws.Provider#invoke(java.lang.Object)
	 */
	@Override
	public SOAPMessage invoke(SOAPMessage in) {
		System.out.println("Operation : " + getOperation());
		System.out.println("Message In :");
		try {
			in.writeTo(System.out);
		} catch (Exception e) {
			// bad
		}
		System.out.println();
		return null;
	}

	private QName getOperation() {
		QName result = null;
		if (wsContext != null && wsContext.getMessageContext() != null) {
			Object o = wsContext.getMessageContext().get(
					MessageContext.WSDL_OPERATION);
			if (o != null && o instanceof QName) {
				result = (QName) o;
			}
		}
		return result;
	}
}

Et invoquer le service:

package org.chamerling.blog.cxf.serviceprovider;

import org.apache.cxf.jaxws.JaxWsProxyFactoryBean;
import org.apache.cxf.jaxws.JaxWsServerFactoryBean;

import junit.framework.TestCase;

/**
 * @author chamerling
 *
 */
public class SimpleServiceTest extends TestCase {

	public void testExpose() throws Exception {
		String url = "http://localhost:9999/foo/bar/SimpleService";
		final JaxWsServerFactoryBean ssf = new JaxWsServerFactoryBean();
		ssf.setAddress(url);
		ssf.setServiceBean(new SimpleServiceProvider());
		ssf.create();

		HelloService client = getClient(url);
		client.sayHello("Rock N Roll!");
	}

	/**
	 * @param url
	 * @return
	 */
	private HelloService getClient(String url) {
		JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();
		factory.setAddress(url);
		factory.setServiceClass(HelloService.class);
		Object client = factory.create();
		return HelloService.class.cast(client);
	}
}

Dans ce cas, on a une opération affichée qui est {http://serviceprovider.cxf.blog.chamerling.org/}invoke et le message SOAP

Rock N Roll!

Pas très convaincant pour l’opération avec cette approche… Le mieux est de pousser un peu plus loin et partir du contrat de service (WSDL) de notre Provider. CXF permet de le spécifier via ses factories lors de la construction du service. Cette utilisation plus avancée est détaillée en partant de org.chamerling.blog.cxf.serviceprovider.CXFExposer. L’approche utilisée dans CXFExposer permet aussi de cacher toute la tambouille JAXWS à l’utilisateur, au final il a besoin d’implementer seulement org.chamerling.blog.cxf.serviceprovider.Service

package org.chamerling.blog.cxf.serviceprovider;

import javax.xml.namespace.QName;

import org.w3c.dom.Document;

/**
 * @author chamerling
 *
 */
public interface Service {

    /**
     * Get the WSDL description
     *
     * @return
     */
    String getWSDLURL();

    /**
     * Get the service URL ie where to publish it...
     *
     * @return
     */
    String getURL();

    QName getEndpoint();

    QName getInterface();

    QName getService();

    /**
     * Invoke the service
     *
     * @param request
     * @param action
     */
    Document invoke(Document in, QName operation) throws ServiceException;

}

WTF Spoonlet?

Ca fait longtemps que je n’ai pas parlé de code. Qu’a cela ne tienne, dans la série “Le bon gros bug de m****”, je vous présente Spoon… Dans un élan de refactoring, je me suis mis à extraire une vrai API du kernel de Petals DSB. L’idée est simple, le faire aurait du l’être: Extraire toutes les interfaces d’un projet A pour créer un projet A-api et en dépendre dans le projet A. Trois clics de souris et deux drag&drop plus loin, testons la compilation:

[INFO] ------------------------------------------------------------------------
[INFO] Building dsb-kernel
[INFO] task-segment: [install]
[INFO] ------------------------------------------------------------------------
[INFO] [resources:resources {execution: default-resources}]
[INFO] Using default encoding to copy filtered resources.
[INFO] [compiler:compile {execution: default-compile}]
[INFO] Nothing to compile - all classes are up to date
[INFO] [spoon:recompile {execution: default}]
[INFO] org.objectweb.fractal.fraclet.annotation.processor.FractalComponentProcessor
[WARNING] FractalComponentProcessor >> No value found for property 'generatorClass' in processor org.objectweb.fractal.fraclet.annotation.processor.FractalComponentProcessor
[INFO] ------------------------------------------------------------------------
[ERROR] BUILD ERROR
[INFO] ------------------------------------------------------------------------
[INFO] fail to execute</code>

[INFO] ------------------------------------------------------------------------
[INFO] For more information, run Maven with the -e switch
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 23 seconds
[INFO] Finished at: Mon Jun 20 23:27:21 CEST 2011
[INFO] Final Memory: 50M/123M
[INFO] ------------------------------------------------------------------------

Ahah, qu’a cela ne tienne, le même en mode debug donc…

[DEBUG] Trace
org.apache.maven.lifecycle.LifecycleExecutionException: fail to execute
at org.apache.maven.lifecycle.DefaultLifecycleExecutor.executeGoals(DefaultLifecycleExecutor.java:719)
at org.apache.maven.lifecycle.DefaultLifecycleExecutor.executeGoalWithLifecycle(DefaultLifecycleExecutor.java:556)
at org.apache.maven.lifecycle.DefaultLifecycleExecutor.executeGoal(DefaultLifecycleExecutor.java:535)
at org.apache.maven.lifecycle.DefaultLifecycleExecutor.executeGoalAndHandleFailures(DefaultLifecycleExecutor.java:387)
at org.apache.maven.lifecycle.DefaultLifecycleExecutor.executeTaskSegments(DefaultLifecycleExecutor.java:348)
at org.apache.maven.lifecycle.DefaultLifecycleExecutor.execute(DefaultLifecycleExecutor.java:180)
at org.apache.maven.DefaultMaven.doExecute(DefaultMaven.java:328)
at org.apache.maven.DefaultMaven.execute(DefaultMaven.java:138)
at org.apache.maven.cli.MavenCli.main(MavenCli.java:362)
at org.apache.maven.cli.compat.CompatibleMain.main(CompatibleMain.java:60)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.codehaus.classworlds.Launcher.launchEnhanced(Launcher.java:315)
at org.codehaus.classworlds.Launcher.launch(Launcher.java:255)
at org.codehaus.classworlds.Launcher.mainWithExitCode(Launcher.java:430)
at org.codehaus.classworlds.Launcher.main(Launcher.java:375)
Caused by: org.apache.maven.plugin.MojoExecutionException: fail to execute
at net.sf.alchim.spoon.contrib.maven.AbstractSpoonMojo.execute(AbstractSpoonMojo.java:96)
at org.apache.maven.plugin.DefaultPluginManager.executeMojo(DefaultPluginManager.java:490)
at org.apache.maven.lifecycle.DefaultLifecycleExecutor.executeGoals(DefaultLifecycleExecutor.java:694)
... 17 more
Caused by: java.lang.NullPointerException
at spoon.support.reflect.declaration.CtAnnotationImpl.convertValue(CtAnnotationImpl.java:160)
at spoon.support.reflect.declaration.CtAnnotationImpl.getElementValue(CtAnnotationImpl.java:253)
at spoon.support.reflect.declaration.CtAnnotationImpl$AnnotationInvocationHandler.invoke(CtAnnotationImpl.java:69)
at $Proxy31.name(Unknown Source)

Yeah cool, une NPE. Ah dommage, sur $Proxy31.name… Genre le proxy généré par Spoon. Et donc bon, on fait quoi la? On revert tout et on tente de bouger les interfaces une par une pour voir qui fout son bordel? Mouais… Trève de blahblah, après avoir passé quelques dizaine de minutes à bouger, compiler, reverter, voici la conclusion: Définir des constantes dans des interfaces qui sont dans des dépendances et les utiliser dans les annotations des implémentations n’est pas possible, par exemple, dans une implémentation du style :

@FractalComponent
@Provides(interfaces = { @Interface(name = "service", signature = ServiceBinderRegistry.class) })
public class ServiceBinderRegistryImpl implements ServiceBinderRegistry {

@Requires(name = BINDER_PREFIX, signature = ServiceBinder.class, cardinality = Cardinality.COLLECTION, contingency = Contingency.OPTIONAL)
private final Map<String, Object> binders = new Hashtable<String, Object>();

On ne peut pas avoir BINDER_PREFIX dans l’interface ServiceBinderRegistry qui est dans une dépendance, par contre ca marche bien quand l’interface est dans le même projet… Quand on tombe la dessus à minuit, c’est rude…

Jouons avec le Petals Kernel et Apache CXF

Oui, à chacun sa façon de s’amuser… Je viens d’ajouter une feature dans le Petals Distributed Service Bus qui me trottait dans la tête depuis un petit moment: Pouvoir invoquer des services techniques (distants ou pas) du coeur du DSB en utilisant la couche de transport naturellement utilisée pour invoquer des services métiers (les services hostés par le bus ou liés à celui ci). Autrement dit, imaginons que j’ai un service technique qui tourne sur un noeud et que depuis un autre noeud, je dispose d’un client pour l’invoquer de façon simple mais aussi totalement transparente.

Ce que l’on pouvait faire jusqu’à présent, c’est utiliser l’API Web service exposée par le DSB pour invoquer le service pour peux que le service soit annoté comme il faut (pour rappel, cette API Web service utilise Apache CXF pour exposer automatiquement les composants Fractal qui sont annotés avec JAXWS). Bien, mais par défaut on utilise deux ports pour les communications inter noeuds: Le port utilisé par Apache CXF, et l’autre par la couche de transport du DSB (en fait c’est le cas dans Petals ESB, mais dans le DSB, la couche de transport étant par défaut une implémentation en Web service, on utilise le même port pour les deux). En allant un peu plus dans les détails, même si on utilise le même port pour les deux modules dans le DSB, ceci n’est plus vrai si une nouvelle implémentation de la couche de transport utilise autre chose que CXF (pour info, dans le DSB, une implémentation de la couche de transport en XMPP existe aussi). C’est donc la qu’on arrive a la solution d’utiliser le canal de communication du DSB pour toute invocation entre noeuds, comme on sait déjà échanger des messages avec le DSB, pourquoi s’en priver?

C’est bien beau de vouloir exposer des services, des composants Fractal, ou quoi que ce soit, si on veut rester en Java et ne pas avoir besoin de se triturer le peu de cerveau qu’il nous reste, autant penser à utiliser tout ou partie d’une solution qui existe deja. En allant dans ce sens, comme on doit au final avoir une sorte de serialization des messages, autant utiliser quelque chose qui sait deja le faire, j’ai nommé le couple inséparable JAXB+JAXWS. Ceci impliquera seulement d’annoter ses interfaces et de créer des types propres et JAXB-aware mais au final, je ne pense pas que cela soit une contrainte forte… C’est bien beau tout cela mais JAXB + JAXWS tout seul ca ne fait pas grand chose. C’est la qu’entre en jeu Apache CXF. Puisque l’utilisation de JAXWS est simple avec CXF, autant s’intéresser un peu à la bete. Pour le coup cà tombe bien, dans CXF il y a deja une notion de transport multiple: HTTP, XMPP, JMS et si on regarde bien on a même JBI (les potes de chez JonAS ont d’ailleurs implémenté un transport CXF utilisant les EJB ou un truc J2EE dans le style si ma mémoire est bonne). Tiens donc, il y a un transport JBI? Ca tombe (presque) bien, le DSB est basé sur Petals ESB qui est JBI compliant. Oui mais en fait non. J’aurais presque pu l’utiliser mais le but est d’implémenter quelque chose d’assez ‘JBI independant’. Le tout est maintenant d’implémenter un nouveau transport pour le DSB et grace au code source de CXF et à cette page http://cxf.apache.org/custom-cxf-transport.html on comprend assez bien comment faire. Dans la terminologie CXF, le client est le ‘conduit’ et le serveur est la ‘destination’. Il suffit donc d’implémenter nos propres conduit et destination pour pouvoir échanger des messages avec CXF.

Une fois CXF configuré avec nos conduit et destination, ou plutôt une fois la bonne transport factory implémentée, on devrait pouvoir faire quelque chose du style:

// 1. Initialize CXF Bus with factory
Bus bus = BusFactory.getDefaultBus();
DestinationFactoryManager dfm = bus.getExtension(DestinationFactoryManager.class);
DSBTransportFactory petalsTransportFactory = new DSBTransportFactory();
petalsTransportFactory.setBus(bus);
petalsTransportFactory.registerWithBindingManager();

// 2. Start service
System.out.println("Starting CXF server...");
JaxWsServerFactoryBean sf = new JaxWsServerFactoryBean();
sf.setAddress("dsb://host/serviceA");
sf.setServiceClass(HelloService.class);
sf.setServiceBean(new HelloService() {
    public String sayHello(String input) throws PEtALSWebServiceException {
        System.out.println("SAY HELLO INVOKED!");
        return pre+input;
    }
});
sf.create();

// 3. Create the client and invoke
JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();
factory.setAddress("dsb://host/serviceA");
factory.setServiceClass(HelloService.class);
HelloService hello = (HelloService) factory.create();
String out = null;
try {
    out = hello.sayHello(in);
} catch (PEtALSWebServiceException e) {
}

Je passe les détails d’implémentation (que j’ai eu le plaisir de faire dans un bon vieux TGV en panne entre Montpellier et Bruxelles) pour le moment, mais ce qui se passe se résume à:

  1. On configure CXF en lui ajoutant notre Transport Factory. Au niveau de l’implémentation, il y a ce qu’il faut pour que lorsque une client ou une server factory est configurée avec une adresse qui commence par ‘dsb://’, ce soit notre DSBFactory qui soit automatiquement appelée par CXF.
  2. La création du service se fait comme si on créait un Web service sur http sauf que là c’est un ‘Web service sur DSB’.
  3. Idem que pour 2 mais on génère un client qui nous permettra d’appeler le service créé auparavant.

En résultat, pour peu que le client (en 3) et le serveur (en 2) soient exécutés sur des noeuds séparés, le DSB se chargera d’acheminer la requête et la réponse comme il faut entre les acteurs et ceci de façon complètement transparente. Au niveau de l’implémentation coté kernel du DSB (ceci vaut aussi pour Petals ESB), il suffit de connaître quand même un peu le coeur pour créer des fakes de composants JBI en farfouillant dans les APIs disponibles, de savoir jouer avec le DeliveryChannel, le ComponentContext, le NormalizedMessageRouter, ajouter quelques modules de routage, savoir recevoir des messages et y répondre, et surtout implémenter le Conduit et la Destination CXF en s’inspirant de ce qui existe déjà et en mettant les doigts dans le cambouis. Pour les curieux, je vous conseille de jeter un oeil au code de CXF assez compréhensible et pas mal fait du tout.

Enfin pour étendre cela aux services techniques du coeur du DSB, il suffit, au runtime, de scanner les services disponibles offerts par les composants du kernel et automatiquement créer les services comme décrit dans l’étape 2. Chose que l’on sait déjà faire dans le DSB via le scan pour exposer les services en Web service sur HTTP avec CXF (oui toujours lui, avant je m’en prenais a Axis2…).

Et voila donc une belle et simple façon de simplifier la vie du développeur du DSB (c’est à dire moi). Il va être maintenant possible d’invoquer n’importe quoi de n’importe où avec une API Java. Pour peu que l’on plugge quelques modules au bon endroit, on peut imaginer faire des choses assez sympa: Le Cloud en fait partie.

Note: Le code sera disponible d’ici la fin de la semaine sur le SVN du DSB. Surement sous https://svn.petalslink.com/svnroot/trunk/research/commons/dsb/modules/dsb-kernel, je mettrais a jour l’article en fonction…

Bye Bye SOAP, salut REST?!

En tout cas cela est vrai pour les API exposées sur le Web, je ne suis pas vraiment sûr que ce soit le cas en entreprise… Bref, je pense que j’avais déjà parlé de ce déclin il y a quelque temps mais je vais en reparler tout de même un petit peu.

Toujours est il que les faits sont là. Les moteurs ont beau crawler le Web à la recherche de services Web (les vrais avec un WSDL!), ils depuis un certain temps dans une phase stagnante. Pour preuve, le nombre de services trouvés par le moteur Seekda est aussi plat que la pleine Toulousaine, on devine un peu plus de 25000 Web services publics trouvés et ce chiffre est le même depuis presque 3 ans:

Source : Seekda.com

Source : Seekda.com

Il y a bien de nouveaux services découverts de temps en temps, mais bon, il me semble que c’est plus de l’ordre du prototype ou du test que d’autre chose, la preuve en image:

Oh la belle calculette...

Oh la belle calculette...

Bref, le déclin est annoncé. Pour preuve, on peut aussi regarder l’intérêt que portent les utilisateurs aux APIs SOAP et REST par le biais des tendances de recherche Google (via http://www.google.com/insights/search/#q=soap%20api%2Crest%20api&cmpt=q). Bien sûr l’internaute ne dicte pas la mort de SOAP et la percée de REST, mais il est clair que ce qui est ‘trendy’ de nos jours est bien REST :

SOAP vs REST

SOAP vs REST

Et vous dans la vrai vie, vous êtes plutôt SOAP ou REST?

Mises à jour Twitter