Utiliser les Callbacks HTTP en Java

Utiliser les Callbacks HTTP en Java

Jusqu'à maintenant, il était possible d’utiliser la librairie Java standard pour accéder à un YoctoHub ou à un VirtualHub, mais un mode de fonctionnement manquait à l’API Java : le mode HTTP Callback. Ce mode, déjà disponible en PHP et Node.js, est désormais présent dans la version beta de l’API Java (v1.10). Pour tester cette nouveauté, voyons comment utiliser le mode HTTP Callback pour se connecter à une servlet JAVA.




Le mode HTTP Callback kezako?

Normalement, c’est le PC/Mac/Smartphone qui contacte les modules Yoctopuce avec la fonction YAPI.RegisterHub(). C'est le fonctionnement par défaut pour tous les langages. Le code de l’application se connecte aux YoctoHub (ou VirtualHubs) et peut communiquer immédiatement avec les modules Yoctopuce. Dans ce mode, c’est l’application qui maîtrise quand les connexions sont faites et c’est aussi l'application qui maîtrise le nombre de threads qui sont utilisés. On pourrait résumer ce mode avec la phrase suivante: "Le programme s’exécute et envoie des instructions aux modules Yoctopuce en passant par un YoctoHub / VirtualHub".

Dans une application traditionnelle c'est L'API qui se connecte à plusieurs YoctoHub
Dans une application traditionnelle c'est L'API qui se connecte à plusieurs YoctoHub



En mode HTTP Callback, c’est le sens contraire. C’est le YoctoHub qui se connecte à l’API et qui démarre l’exécution de l’application. On configure chaque YoctoHub que l’on veut utiliser pour qu’il se connecte périodiquement à un script (ou lorsque la valeur d'un senseur a changé). On pourrait l’exprimer de la manière suivante: "Toutes les X secondes, les YoctoHubs vont se connecter à un serveur pour l’informer de leur état et récupérer les instructions à envoyer aux modules Yoctopuce". Et cela a plusieurs implications qu’il faut prendre en compte:

1. Les connexions TCP sont inversées ce qui veut dire que les modules ne sont plus bloqués par le routeur internet (ou autre filtre NAT). On peut donc installer une servlet JAVA sur un serveur dans le "cloud" et brancher un YoctoHub dans son jardin sans devoir reconfigurer son routeur DSL.

En mode callback, la connexion TCP est inversée, ce qui permet de traverser un filtre NAT
En mode callback, la connexion TCP est inversée, ce qui permet de traverser un filtre NAT



2. L’API n’a accès qu’aux modules rattachés au YoctoHub qui se connecte. Par exemple, si on a sur un YoctoHub A un Yocto-Meteo et sur un YoctoHub B un Yocto-Display, il n'est pas possible d'afficher directement la température du Yocto-Meteo sur le Yocto-Display. Quand le YoctoHub A se connecte, l’application doit stocker la température du Yocto-Meteo et attendre que le YoctoHub B se connecte pour afficher cette température sur le Yocto-Display.

En mode callback, l’API ne peut utiliser qu’un YoctoHub à la fois
En mode callback, l’API ne peut utiliser qu’un YoctoHub à la fois



3. C'est le YoctoHub qui détermine (en se connectant au serveur) quand l’application se lance. Il est possible (et même très probable) que deux YoctoHub se connectent au même moment à l’application. Donc si plusieurs YoctoHub sont configurés pour utiliser l’application, il faut impérativement s’assurer que notre application supporte la concurrence.

Un exemple de servlet

Nous avons déjà utilisé l’API HTTP Callback dans plusieurs articles mais à chaque fois nous avons utilisé le langage PHP. Pour illustrer les différences avec le PHP, voici le code Java d’un servlet qui affiche les derniers posts de notre blog sur un Yocto-MaxiDisplay. L’article original est disponible ici.

....
private void doRSSReader() throws YAPI_Exception
{
  ArrayList<RSSItem> rssItems = RSSReader.getInstance().getAllItems();
  YDisplay display = YDisplay.FirstDisplay();
  while (display != null) {
    // flash the beacon during sequence recording (for debug purposes)
    YModule module = display.module();
    module.set_beacon(YModule.BEACON_ON);
    // start recording a Sequence
    display.newSequence();
    // execute command for all rss items
    for (RSSItem item : rssItems) {
      String productname = module.get_productName();
      if ("Yocto-MiniDisplay".equals(productname)) {
        OutputMiniDisplay(display, item);
      } else {
        OutputMaxiDisplay(display, item);
      }
    }
    display.playSequence("rss");
    display.saveSequence("rss");
    display.playSequence("rss");
    // stop the beacon
    module.set_beacon(YModule.BEACON_OFF);
    // look if we get another display connected
    display = display.nextDisplay();
  }
}

/**
 * Handles the HTTP POST method.
 *
 * @param request servlet request
 * @param response servlet response
 * @throws ServletException if a servlet-specific error occurs
 * @throws IOException if an I/O error occurs
 */

@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException
{
  ServletOutputStream out = response.getOutputStream();
  ServletInputStream in = request.getInputStream();
  try {
    // Setup the Yoctopuce API in HTTP Callback mode
    YAPI.RegisterHub("callback",
            request.getInputStream(),
            response.getOutputStream());
    doRSSReader();
  } catch (YAPI_Exception ex) {
    System.out.println("Yoctopuce API error:" + ex.getMessage());
  } finally {
    YAPI.FreeAPI();
  }
}
...



Comme on peut le voir, l’utilisation de l’API Yoctopuce est très similaire. La seule différence est l’appel à la méthode YAPI.RegisterHub. En Java, en plus du du mot clef "callback", il faut fournir deux paramètres de plus (InputStream request et OutputStream response) pour que l’API Yoctopuce puisse récupérer les données envoyées par le YoctoHub et renvoyer les commandes en retour. Une autre différence est qu’en Java il est obligatoire de traiter correctement les exceptions.

Oui mais....

En raison de la manière dont fonctionnent les servlets, si vous en restez là et que vous branchez plusieurs Yocto-Hub qui utilisent votre servlet, vous allez avoir des problèmes. Voyons pourquoi et comment y remédier.

Contrairement à PHP, en Java l’espace mémoire est partagé
Contrairement à PHP, en Java l’espace mémoire est partagé



En PHP, chaque requête est exécutée dans un nouveau processus, ainsi chaque requête est appelée avec un espace mémoire propre à la requête. A contrario, en Java toutes les requêtes sont exécutées dans le même processus mais dans des threads séparés et l’espace mémoire est partagé. Si c’est plus efficace car on n'a pas besoin de créer un nouveau processus, cela implique que deux Yocto-Hub qui se connectent en même temps vont se battre pour accéder aux caches internes de l’API Yoctopuce.

Pour éviter ce problème, il faut au chargement de la servlet configurer l’API pour ne pas partager les caches internes entre les threads. Pour cela, il faut appeler la méthode YAPI.SetThreadSpecificMode() dans la méthode init() de votre servlet.

Et voici le code final qui est "thread safe":

...
@Override
public void init() throws ServletException
{
  super.init();
  System.out.println("Setup Yoctpuce API to use thread specific cache");
  try {
      YAPI.SetThreadSpecificMode();
  } catch (YAPI_Exception ex) {
      System.out.println("Unable to setup API:" + ex.getMessage());
  }
}
...



Cette nouvelle fonctionnalité est disponible dans la version beta de l’API Java (disponible ici ou sous GitHub). Il est possible que certaines méthodes changent en fonction des premiers retours que nous recevrons. Comme d’habitude, tous vos commentaires (même les négatifs) nous intéressent, donc n’hésitez pas à nous écrire un e-mail ou à poster un commentaire.

Commenter aucun commentaire Retour au blog












Yoctopuce, get your stuff connected.