Thématiques principales

Affichage des articles dont le libellé est OSGI. Afficher tous les articles
Affichage des articles dont le libellé est OSGI. Afficher tous les articles

dimanche 3 mars 2019

OSGI : Les annotations

Nous avons vu comment déclarer un Activator/Factory/Tracker [ex-karaf], [uttu-felix] pour construire des bundles OSGI, ensuite nous avons vu comment tirer parti de la philosophie Spring pour alléger la définition des beans, des services  et leur utilisations avec SpringDM et Blueprint [bp-karaf], [uttu-bp]; dans ce dernier article (où presque sur OSGI), je vous propose de nous intéresser à une dernière façon de faire des bundles : en utilisant des annotations [scr-annot].

Bon la question ici n’est pas de faire un laïus sur les annotations, j’en ai déjà parlé dans un article [uttu-annot], donc on va aller directement dans le vif du sujet parce que l’on se doute bien que pour remplacer nos Activator and coe et/ou les description xml, il va nous falloir quelques concepts de base.

Les annotations

Alors en fait si vous ne l’aviez pas encore vraiment compris, avec OSGI, finalement il n’y à pas forcément beaucoup de concepts à mettre en oeuvre…. en effet finalement, on à des beans qui implémentent des services et qui vont être injecté dans d’autres beans…

Du coup dans notre contexte, on va rencontrer les annotations suivantes:
  • @Component: permet de déclarer un bean
  • @Activate/@Deactivate: permet de spécifier une méthode gérant une initialisation spécifique (où inversement pour l’annotation @Deactivate)
  • @Référence: permet de spécifier une donnée membre dans laquelle devra être injectée un autre bean (spécifié par @Component)

samedi 2 mars 2019

OSGI : SpringDM et BluePrint

Nous revoilà avec OSGI. Nous parlions à la fin de l’article sur Karaf et Service-mix de SpringDM et BluePrint… mais qu’est ce que c’est?

SpringDM et Blueprint [gemini] sont des frameworks Java et XML permettant la simplification de la description et la gestion des services OSGI de nos Bundles.

SpringDM a été le précurseur et a été suivi par Blueprint grâce à une normalisation (plus une adhésion) au sein de la norme OSGI.

Le principe est d’utiliser les mécanismes de Spring pour réaliser la déclaration de Beans au sein des bundles qui seront chargé par un bundle context dédiés. Cela ne va pas nous empêcher de devoir déclarer nos services sous la forme d’interfaces et d’en réaliser des implémentation mais cela va nous permet de ne plus avoir à implémenter toute la partie Activator, Factory et Tracker que nous avions vu dans les précédents articles sur le sujet…

Quoi ? mais du coup il n’y à plus rien dans le Bundle?

mercredi 27 février 2019

OSGI : Karaf ServiceMix

On est presque à la fin du mois et je n’ai écrit qu’un seul article! Heureusement j’ai un sujet au chaud pour combler le vide.

On avait parlé du framework OSGI Felix [osgi-felix] la dernière fois et nous avions vu dans un précédent article qu’il en existe d’autres packages sous la forme de serveur d’application (comme le serait un Jboss [jboss] ou un Weblogic [weblogic]).

Nous allons justement nous intéresser à deux de ses serveurs:
  • Karaf [karaf]
  • ServiceMix [servicemix]

Bien sur ceux les connaissant diront que c’est grosso merdo la même chose, et effectivement, ServiceMix s’appuie sur Karaf mais en apportant un ensemble de bundle dédié à la communication et aux services, c’est à dire les WebServices et les services de messageries (SMTP, JMS, etc…). Il était donc important de le connaître également.

dimanche 3 février 2019

OSGI : Felix

Nous revoilà avec OSGI mais cette fois ci pour aller dans le concret, plus de blabla, maintenant on fait chauffer la JVM.

Le problème du choix

Bien tout d’abord il nous faut choisir un framework, c’est à dire une implémentation. Nous en avons vu plusieurs dans l’article précédent [osgi-fwk] et il nous faudra faire un choix. À mon sens il y avait plusieurs possibilité:

  • Knoplerfish [knoplerfish] est trop compliqué bien qu’à jour dans l'implémentation des versions OSGI
  • Karaf [karaf] est un peu trop lourd pour ce que nous voulons montrer ici (mais nous ferons un article dessus)
  • Equinox [equinox] est sympas je l’aurais choisi si je ne prévoyais pas de présenter mon framework equinox-loader [eq-loader] qui l’utilise
  • Concierge [concierge] est hors propos, on ne va pas faire de Iot
  • Donc en toute logique, on va essayer l’utilisation de OSGI avec Felix [felix]

Tout d’abord il faut télécharger la version courante: c’est ici [felix-down]

Dockerisation

Pour simplifier son utilisation, nous allons préalablement le dockeriser pour faciliter son exploitation, on construit donc un fichier Dockerfile dans un répertoire (moi je l’ai nommé felix-framework) contenant le processus de construction suivant:

FROM openjdk:8-jre-alpine

RUN wget http://mirror.ibcp.fr/pub/apache//felix/org.apache.felix.main.distribution-6.0.1.tar.gz \
&& tar zxvpf org.apache.felix.main.distribution-6.0.1.tar.gz && rm org.apache.felix.main.distribution-6.0.1.tar.gz

COPY . /felix-framework-6.0.1/
CMD cd /felix-framework-6.0.1; java -jar bin/felix.jar


mercredi 30 janvier 2019

OSGI : les frameworks

Nous avons vu le fonctionnement de OSGI dans ses principes généraux et un peu plus dans le détails sur les mécanismes qu’il met en oeuvre pour l'exécution des bundles, des services et de leur interconnexion. Dans cet article, un peu plus court j'espère, nous allons un peu plus nous intéresser à ses implémentations [osgi-impl], leur fonctionnalité et contenu et leur intégration dans les outils JEE standard.

Implémentation

Les implémentations du framework OSGI ne sont pas légion, alors bien sur il existe une implémentation de référence fourni par l’OSGI Alliance mais il est bien précisé que celle ci n’est à utiliser qu’à titre d’exemple et ne pourrait être exploité en production car non optimisé. [OSGI-impl-ref]

Heureusement, grâce à son “grand âge”, OSGI a su intéresser des projets qui ont porté quelques implémentations associé à des versions plus ou moins divers d’OSGI. On peut ainsi en note 4 principales.

jeudi 24 janvier 2019

OSGI : Architecture

Nous avions vu dans un précédent article ce qu'était OSGI dans ses grandes lignes et ses principaux concepts [uetteu-osgi]. Dans celui ci, je vous propose de rentrer un peu plus dans le côté technique de cette technologie en détaillant globalement les utilisations de celle ci (surtout pour rappel), d’identifier son écosystème et ensuite de passer en revue la construction des bundles, leur constitution, leur cycle de vie et la déclaration et consommation des services.

À la suite de cela, nous nous intéresserons alors aux différents implémentations du framework réalisé au fil de ces dernières années pour enfin étudier (sommairement) leur différentes intégrations au sein des serveurs d’application Java les plus connu (à notre insu)

Architecture: Vue d’ensemble

Nous avions vu dans ce dernier article [uetteu-osgi] que OSGI était un framework Java modulaire orienté service permettant la modélisation et l'exécution de composants nommés bundle.

Ils permettent à mise en oeuvre d’application dans des contextes d'équipement à ressources limitées, s’appuient sur un modèle de collaboration utilisant une registry pour le partage de services et facilitant l'accès à ces derniers pour les consommateurs.

OSGI permet aussi une gestion à chaud de ses bundles offrant ainsi la possibilité de chargement, mise à jour et déchargement de fonctionnalité dynamiquement sans interruption de service.

Enfin OSGI offre un cycle de vie fourni un cycle de vie à ces bundles et services (que nous verrons dans un des chapitres suivant) permettant la mise en oeuvre d’une gestion intelligente des fonctionnalités mis en ligne.

C’est pour ces différentes raisons que OSGI est aujourd’hui intégrée par défaut dans la grande majorité des serveurs d’applications JEE permettant l’ajout de fonctionnalité java standard de manière plus aisé et ce même dans un contexte JEE.

Environnement d'exécution

De par son côté modulaire, OSGI offre donc la possibilité de construire des applications via une logique de puzzle où de briques, constitué selon des niveaux fonctionnelles différentes. Cette approche a donc permis de constituer un catalogue riche et varié de bundles offrant une multitude de services métiers et ou technique [tuto-osgi-oscar].

On trouvera ainsi facilement sous la forme de bundle des

  • services de base permettant l’utilisation de logs
  • bundle de gestion de configuration
  • bundles de gestions de Préférences
  • Services HTTP (e.g :servlets, ou Spark [uetteu-spark]))
  • Gestion des utilisateurs
  • Parseurs XML
  • Gestion de droits,
  • Politique de sécurité
  • Monitoring
  • de l'intégration JEE [integ-jee]



vendredi 28 décembre 2018

OSGI : Concepts généraux


Aujourd’hui nous allons parler d’un framework qui me tient à coeur: OSGI. Cela faisait un moment que je voulais écrire un article sur celui ci mais beaucoup d’autre sujet, se sont trouvé être plus intéressant sur le moment.

À vrai dire, OSGI est clairement très intéressant mais l’utilisant depuis déjà près de 8 ans, malgré l'intérêt qu’il a intrinsèquement, il ne porte plus pour moi ce goût de nouveau que peuvent avoir les sujets comme l’IA... , c’est évident.

Pourtant voilà, je me suis dit, il est temps de faire le point sur le sujet et de le mettre un peu plus sous les projecteurs, car mine de rien, quasiment tout le monde l’a un jour utiliser, mais très peu de gens le savent!

Mais repartons du début!

Historique

OSGI [OSGI], [wikipedia] ou Open Service Gateway Initiative est un framework de gestion de composants et de services. Initialement prévu pour le monde de l’embarqué (si si ^^), il a été utilisé par des constructeur comme Volvo, BMW ou encore Cisco et s’emploie dans les produits logiciels à destination du monde de la domotique et des systèmes de sécurités

Nous le verrons plus en détail mais pourquoi OSGI? parce que ce framework est léger (en dehors de la JVM) et permet le chargement et le déchargement de ses librairies à chaud tout en facilitant la manipulation de ces dernières dans des versions différentes simultanément.

Issu de la JSR 8 [JSR8], OSGI a été créé dans les années 2000 et a évolué régulièrement. Ainsi aujourd’hui la spécification OSGI en est à la version 7 [OSGI-V7] avec une implémentation de référence fourni par l’Alliance OSGI qui ne doit pas être considéré comme une version de production mais “juste de références”. Ainsi différentes versions open sources ont été implémenté pour répondre à des besoins plus techniques et se sont accaparé ces différentes versions des spécifications comme equinox [equinox], knoplerfish [knoplerfish], concierge [concierge] ou encore felix [felix].

Aujourd’hui la spécification 7 de OSGI forme un pavé de plus de 1000 pages de documentation [OSGI-V7-CORE] et il nous est impossible d’en faire un résumé exhaustif ici cependant dans cet article nous tâcherons de passer en revu les concepts pivots de OSGI pour en comprendre les mécanismes clefs puis nous nous intéresserons aux différentes implémentations ainsi que leur intégrations dans les frameworks plus classique (mais qu’on sait pas que OSGI est dedans…. O_o)

OSGI concepts généraux

OSGI est donc un framework Java. Conçu il y a près de 18 ans, celui ci est un peu partout sans que personne ne le sache vraiment. On le trouve dans la plupart de nos serveurs d’applications JEE, jusque dans nos IDE comme eclipse qui à fondé sa architecture dessus… si si…

Bien sûr ce n’est pas parce que quelque chose est utilisé partout que forcément c’est bien…. c’est vrai on le voit tous les jours avec le framework Spring! non blague à part (ou pas), OSGI est partout mais pour de bonnes raisons et c’est justement sa discrétion qui en fait sa force et sa pertinence.

En effet, OSGI est un framework amenant des moyen technique de mise en oeuvre logicielle mais aussi des moyens conceptuelles, apportant avec lui quelques paradigme de modélisation simple mais efficace laissant libre le développeur de faire ce qu’il veut tout en lui garantissant plus de souplesse à son application.

Il fournit pour cela une implémentation à deux paradigmes importants en développement logiciel:

  • la modularité qui permet la gestion et l’articulation logique des éléments de l’application
  • les services qui fournissent les moyens de donner une opérationnalitée à ces éléments en leur donnant du sens.

La modularité dans OSGI

Sans aller trop loin dans le débat de la modularité [serv-side], on rappellera quelques principe de façon à poser ce à quoi nous attendre dans OSGI

La modularité est une approche de conception permettant la séparation des préoccupations, que celles-ci soient fonctionnelle, ou technique.

Bien sur il existe différents degrés de modularité et celle-ci s’appliquant sur la solution logicielle à des niveaux très variés.

Il est ainsi possible de concevoir de façon modulaire tant au niveau de l’architecture système que de l'architecture logicielle. Quel que soit l’objectif métier, le but est de permettre de scinder les problématiques et amener du découplage facilitant ainsi: la réalisation, le test, la compréhension, la maintenance, la mise à jour, etc...



Pour mettre en oeuvre de la modularité dans une architecture, il existe divers solutions et implémentations: certains design pattern comme l’observateur [observ], l’association du pattern proxy et factory [invochand] ou encore l’utilisation de contrat de services avec des interfaces et des API comme illustré ci dessus.

OSGI propose une autre alternative en se situant à la croisé des chemins de ces approches. Nous en avions parlé dans l’article [whriteboard]. En résumé, la modularité consiste en la construction de composants interdépendants via des interfaces (API). Des lors, l’utilisation d’un module par un autre passe par une api et masque donc l’identité du composant réellement utilisé, c’est le principe du masquage de l'implémentation permettant ainsi découplage, réutilisation, capacité à être testé etc…

Cependant, on constate une limite a l’utilisation des contrats de service et des API : il faut etre capable de re-associer les composants interdépendants [serv-side]. Il faut pour cela utiliser des patterns comme la Factory et au final déplacer le couplage vers la factory [whiteboard].


Alors bien sur il existe d’autres approches pour répondre à cette problématique avec les framework d’IoC comme Spring (implémentant le pattern Hollywood [hollywood]) utilisant des xml ou des annotations. Pourtant ces solutions sont assez peu satisfaisantes car elles confient les détails d'implémentations à un acteur tiers qui aura la charge de faire communiquer les composants entre eux sur la base d’une description donné statiquement. Finalement cela re-créera un couplage car si en effet dans Spring (par exemple) on spécifie la dépendance d’un composant via une API et des interfaces, il faudra lui spécifier un à moment l'implémentation qui y répondra et cela de façon statique par configuration.

Le pattern Broker

OSGI fournit une alternative en utilisant le pattern Broker [broker] permettant, au travers d’un registre de bundle (nom des composants ou modules OSGI) et de service, de déporter le couplage en dehors de la préoccupation des composants mis en interaction.

Il s’agit avant tout d’un pattern d’architecture (non d'implémentation) qui classiquement s’utilise dans le cadre de service de messagerie comme JMS mais qui ici se focalise sur la mise en collaboration des bundles entre eux, à la demande, et ce géré par le registre.

Dans sa mise en oeuvre, un ensemble de composants (les bundles) vont s’enregistrer auprès du registre comme fournisseur de services liés à différents contrats d’interfaces. Ensuite, par l'intermédiaire du registre, ils seront appelé par d’autres bundle ayant besoin des services remplissant les contrats d’interfaces souhaités.

Dans ce principe, aucun bundle ne se connait directement, tout passe par le registre qui aura à gérer l’ensemble des services offerts et les clients qu’il faudra rediriger vers les bonnes implémentations.


Les services

OSGI est une implémentation du pattern Broker. Il s’agit donc en réalité d’un framework permettant la conception logicielle de façon modulaire mais et surtout de construire des applications selon une logique orienté service.

Ainsi comme nous venons de le voir la modularité va nous amener à séparer les préoccupations, les services vont en plus nous amener à réfléchir nos bundles selon le rôle qu’ils ont à mener dans notre application de façon à en exposer juste et seulement leur valeur ajouté.

L’idée est la encore et toujours la modularité, mais en ayant une forte décomposition, on maximise alors le re-use car un service implémentant un contrat de service pourra être mis à disposition par le registre à tous les bundles en ayant le besoin.

Vous allez dire mais ça Spring le fait déjà au final le registre, c’est le fichier xml de Spring.

Effectivement mais OSGI va plus loin:

  • D’une part, l’utilisation du registre va autoriser un bundle à consommer un service à la demande et de s’en défaire, le couplage entre les bundles est dynamique et non permanent.
  • La conséquence du point précédent que nous détaillerons plus loin dans l’article est que cela permet la mise en ligne des bundles sans que ces derniers n’aient eu le besoin de résoudre à leur chargement toute leur dépendance et service.
  • Ceci nous amènera alors à la possibilité de gérer des versions concurrente d’un même service pour faciliter leur mise à jour à chaud.

Avec OSGI, la gestion des services par le registre des bundles nous laisse entrevoir quelques fonctionnalités dont nous n’avons pas vraiment l’habitude. Dans un projet classique, généralement nous pensons notre application comme un tout unique dont les éléments, librairies et services, devront évoluer conjointement. Mais avec OSGI, cette vision limitative devient caduc et il faudra penser l’application comme un système en perpétuel mutation dont les éléments nouveau côtoient des éléments anciens et dont les services seront utilisés selon le besoin.

Gestion des dépendances

Pour permettre des mécanismes de gestion à chaud des bundles et de la consommations dynamiques des services, OSGI va donc fournir un certain nombre de concepts focalisé sur une gestion un peu particulière des dépendances.

Cette gestion des dépendances va s’exprimer selon deux types [10min]:

  • les dépendances statiques
  • les dépendances dynamiques

Statiquement

La gestion statique des dépendances dans OSGI est assez similaire à la gestion des dépendances Java réalisé avec le classpath à ceci prêt que celui ci est plus stricte car embarque avec les lui le detail des versions impliqué dans la dépendance.

Cela paraît dans un premier temps très contraignant cependant cela permet en fait de faire vivre au sein du framework deux versions distinctes d’une même dépendance, laissant alors au composant qui en ont besoin d’utiliser celle avec laquelle il sera le plus en phase.

Ce type de dépendance se déclarent au sein du manifest java décoré et adapté au formalisme OSGI (nous verrons cela plus en détails dans le chapitre sur les bundles).

Ainsi les bundles lorsqu’ils seront chargé par le framework OSGI (on verra plus tard mais il s’agit de la phase d’installation) devront trouver dans leur classpath ou dans les classloader du framework les dépendances apportées par les autres bundles dans les versions attendues


Dynamiquement

Une fois installé, un bundle apporte un ensemble de dépendance statique, cependant, pour créer un minimum de couplage, il est préférable de s’appuyer autant que faire se peut sur le pattern broker.

Ainsi pour cela le framework OSGI nous amene à construire des bundles définissant des contrats des services ne contenant que des informations spécifiques aux contrats de services.

Ainsi ces contrats seront ensuite implémentés par un autre bundle qui aura la charge de l'implémentation du contrat de service. Ainsi, ce bundle s'enregistrer auprès du registre et lorsqu’un autre bundle demandera au registre OSGI un service conforme au contrat de service défini dans le bundle contrat alors le registre fournit l'implémentation.

L'intérêt de cette approche est qu’il est possible alors de proposer divers implémentation d’un même contrat de service.


Conclusion

Nous avons dans les grandes lignes les principes généraux de OSGI, son paradigme de modélisation modulaire et orienté service.

L'intérêt de son utilisation est double, d’une part de fournir une solution réelle de couplage des modules mais aussi la capacité de faire évoluer une application dynamiquement tout au long de son cycle de vie et ce, “à chaud”.

Il peut être intéressant maintenant d’en parcourir l’utilisation dans le concret (dans le prochain article sur OSGI) afin de mieux appréhender ses contraintes techniques.

Références

vendredi 23 novembre 2018

IA : Presentation du neurone

Un petit article rapide pour attendre les prochains articles sur OSGI et SPARK .

Ici je parlerai d'une petite (grosse) présentation sur le neurone intitulé:

Que faire avec son neurone ?

Il s'agit en fait d'un recap des 2 ou 3 articles écrits jusque ici sur l'IA et sur le neurone implémenté en mode adhoc.

jeudi 8 novembre 2018

Design Pattern : Whiteboard

Pourquoi le pattern whiteboard?

Le pattern Whiteboard [1, 2] est un pattern un peu spécifique, il à la particularité d'être intimement associé à la technologie OSGI [3, 5] et comme il était question dans ce blog de parler de ce framework, nous voici donc avec une petite introduction de ce dernier via ce pattern de conception.

Au delà du prétexte de l'écriture d’un article introductif à OSGI, ce pattern pattern à bien entendu une raison d'être qui lui est propre: proposer une alternative raisonnable au pattern listener dans la conception de logiciel à base de microservice comme le permet OSGI [4].

On entrevoit donc ici les raisons de l’utilisation du pattern mais pour etre plus precis, nous regarderons avant cela les concepts de base de OSGI afin d’en comprendre les besoins et avant de détailler plus en avant le pattern whiteboard, nous regarderons pourquoi le pattern listener n’est plus satisfaisant dans certaines situations.

Techno OSGI dans les grandes lignes

La technologie OSGI ou Open Service Gateway Initiative est un framework Java pour la construction d’application à base de composants et de services. Il s’agit d’un framework ayant pour vocation initial la réalisation d’application à taille réduite où la gestion mémoire est millimétré.

Il permet techniquement de gérer simultanément des librairies java évoluant dans des versions différentes ainsi que de charger et décharger ces librairies dynamiquement sans nécessiter le redémarrage de la JVM. Par contre, pour permettre ces capacités, OSGI “impose” (mais en fait c’est un bien) un paradigme de modélisation impliquant la construction de nos application selon une architecture un peu spécifique à base de composant (les bundles) et de services.

Avec cette petite introduction, on perçoit rapidement l'intérêt de ce framework! Nous y reviendrons plus tard, nous en avons vu l’essentiel pour l’instant. Il faut surtout en retenir que OSGI nous permet de construire des applications modulaires à base de composants et de services. Dédié initialement à l’embarqué, il est sortie rapidement de son contexte d’utilisation initial et s’est alors confronté aux méthodes et techniques de construction des architectures logiciels classiques.

Pourtant avec une architecture tel que proposée par OSGI, ce pattern comporte de nombreuses limites.

En effet, dans une architecture à composant ou les dépendances entre composant ne peuvent être forte, il est nécessaire de permettre à deux objets de communiquer sans forcément qu’ils aient connaissance de l’un et de l’autre directement.

Pattern Listener et limites

Entre autre, le cas du pattern Listener est caractéristique car dans le cadre de son utilisation dans le cadre OSGI, il comporte quelques limites.

Nous avons traité le pattern listener dans un autre article [6], je n’y reviendrais pas ici. disons simplement que ce pattern est un pattern d’architecture et comportemental permettant le découplage d’un observateur et d’un observer tout en formalisant son moyen de communication via un objet de type événement. Il s’agit en fait du pattern observateur mais simplifié.

Ce pattern est souvent utilisé pour sa nature événementielle dans le cadre de la gestion des IHM. Ainsi, par exemple, lorsque utilisateur sollicite la souris de son ordinateur, le contrôleur associé va générer des événements permettant de suivre ses déplacements. L'utilisation du pattern listener est en première approche une solution intéressante pour traiter ces événements surtout lorsque les sources possibles sont multiples. Pourtant c’est là sa limite également. Car alors si ces sources produisent de multiples événements simultanément alors le système peut être soumis à un “EventStorm” [1] amenant à une utilisation élevée de la mémoire et du CPU, perdre gravement en performance et dans le pire des cas conduire à un crash.

Whiteboard pattern

Le pattern Whiteboard est une solution apportée comme alternative au pattern listener dans le cadre du framework OSGI.

Il est intimement lié à OSGI cependant comme nous verrons ce framework par la suite il me semble plus pertinent d'éviter d’entrer dans trop de détails d'implémentation lié à cette technologie. Ainsi nous nous attacherons à une présentation d’un modèle abstrait du pattern (sous la forme d’un type PIM, Plateform Independant Model dans le MDA [7])

Ce pattern propose de découpler la source des événements du listener en introduisant un objet supplémentaire entre les deux servant de registre et transformant la relation entre les deux éléments par une relation de service et de consommateur de service.

Ce qui servait donc de listener devient un composant fournissant un service qui sera enregistrer dans un registre. La source des événements aura alors la tâche de demander au registre le service adéquat afin de pouvoir lui transmettre les événements produits.




L'intérêt de l'approche en ajoutant ce registre qui finalement réalisé la réification de la relation listener/sources des événements est de permettre de contrôler cette relation et son utilisation par la source des événements.

Il va être alors possible :
  • de réaliser du monitoring sur le flux d’informations voir même de le debugger
  • de rendre indisponible le service du listener si celui ci est trop utilisé et implique une consommation des ressources trop importante
  • d’adjoindre des droits spécifiques d’utilisations en ajoutant sur le registre une couche de sécurité et des permissions afin de ne pas le rendre disponible à n’importe quel consommateur du service venu
  • injecter des propriétés spécifique pour customiser le mapping (comme par exemple pour préciser un quota en événement par seconde à traiter ou pour proposer une taille de tampon d'événements, etc…)

Exemple

Pour illustrer ces mécanismes voici dans un contexte hors OSGI ce qu proposerait une implémentation du pattern listener (observateur) et ensuite son équivalent dans la philosophie du pattern Whiteboard. On précise ici que l’on reste dans une implémentation de type PIM afin de ne pas perturber la compréhension du pattern avec les spécificités technologiques du framework OSGI

Avec Listener


package listener

class Event{
    String message

    Event(String m){
        this.message=m
    }
}

interface IObserver{
    def update(Event e)
}

interface IObserved{
    def notifyAll(Event e)
}

class TrucQuiEcoute implements IObserver{
    def update(Event e){
        println("Reception d'un message")
        println(">>"+e.message)
    }
}

class TrucQuiFait implements IObserved{
    List obs=new ArrayList<Observer>()

    def notifyAll(Event e) {
        for( Observer o in obs){
            o.update(e)
        }
    }

    def makeSomething() {
        def e = new Event("Ceci est le message")
        println("Envoie d'un message")
        this.notifyAll(e)
    }
}


def ob=new TrucQuiEcoute()
def obd=new TrucQuiFait()
obd.obs.add(ob)
obd.makeSomething()

Avec Whiteboard


package whiteboard

interface IService{
    def serve(Event e)
}

class ServiceRegister{
    Map services=new HashMap<String,IService>()
}

class Event{
    String message

    Event(String m){
        this.message=m
    }
}

class TrucQuiEcoute implements IService{
    def serve(Event e){
        println("Reception d'un message")
        println(">>"+e.message)
    }
}

class TrucQuiFait implements IService{
    ServiceRegister register;

    TrucQuiFait(ServiceRegister register)
    {
        this.register=register;
    }

    def serve(Event serviceNameEvent) {
        def e = new Event("Ceci est le message")
        println("Envoie d'un message")
        this.register.services.get(serviceNameEvent.getMessage()).serve(e)
    }
}

def reg=new ServiceRegister()
reg.services.put("TrucQuiEcoute",new TrucQuiEcoute())
reg.services.put("TrucQuiFait",new TrucQuiFait(reg))

reg.services.get("TrucQuiFait").serve(new Event("TrucQuiEcoute"))

Conclusion

Voilà nous avons fait le tour de ce pattern un peu spécial enfin, surtout un peu spécialisé, qu’est le pattern Whiteboard. Celui-ci est très associé à OSGI mais il peut se comprendre sans et surtout mieux comprendre certains mécanisme de ce framework que nous verrons dans un prochain article.

Références

[1] https://www.osgi.org/wp-content/uploads/whiteboard1.pdf
[2] https://en.wikipedia.org/wiki/Whiteboard_Pattern
[3] https://www.osgi.org/
[4] https://enroute.osgi.org/FAQ/400-patterns.html
[5] https://www.theserverside.com/news/1363820/The-Whiteboard-Pattern-for-OSGi
[6] https://un-est-tout-et-tout-est-un.blogspot.com/2017/11/design-pattern-observateur.html
[7] https://laine.developpez.com/tutoriels/alm/mda/generalites-approche-mda/



dimanche 28 janvier 2018

Gradle

Lors de la production de systèmes logiciels, il ne fait aucun doute que la phase la plus importante est la compilation qui nécessite l’utilisation d'outils tels que gcc ou javac. Aujourd’hui pourtant limiter la production d’un logiciel a la compilation n’est plus suffisant. De nombreuses phases périphériques à la compilation sont devenu indispensables, comme l'exécution des tests unitaires ou des tests fonctionnels, la production automatique de documentations ou de code, le packaging multi plateforme, ou même la mise en production. Ceci s'appelle l'intégration continu au sein duquel on va trouver divers outils à différents niveau d’abstraction (Jenkins[1] , artifactory [2]) ou differents roles (Sonar [3], RobotFramework [4]). Nous reviendrons sur ces outils, mais nous en avions déjà vu un nommé Maven dans un précédent article [5] dont le but est justement de couvrir l’ensemble des phases du build.

Aujourd’hui nous allons nous intéresser à ce que l’on pourrait appeler un peu abusivement son concurrent: Gradle [7].

A mon sens Gradle en est plutot le successeur et nous verrons pourquoi. En effet, même si personnellement j’utilise encore beaucoup Maven, les raisons sont surtout historique et que faire la migration de l’un vers l’autre, ne peut être qu’un bien [9] mais cela repose sur une bonne disponibilité en temps.

Voyons ce que propose Gradle par dela Maven. Pour faire simple et rapide sur l'intérêt de Gradle est qu’il permet de dépasser le côté monolithe de Maven. En effet, Maven repose sur un socle stable et très sain d’un process de build. Du moins lorsque ce processus est classique et standard. Gradle, tout en conservant ce socle permet d'être plus souple et dynamique car contrairement a Maven qui repose sur xml pour décrire le contenu du build (donc a une vision configuration du process), Gradle lui repose sur groovy qui est lui un langage de programmation.

En fait si l’on reprend le titre de la publication de Leon Osterweil:  “software processes are software too” [8], nous sommes face à un véritable changement de paradigme dans la façon de gérer la production de logiciel ou celle-ci est également vu comme une partie intégrante du logiciel lui même.

Par exemple, Google a adopté Gradle pour la production de ses applicatifs Android et l’on peut assister que cette adoption a été largement suivi par une très bonne intégration de ce nouvel outils dans les IDE standard de la communauté. Ainsi developper une application android sous Gradle n’est vraiment pas un probleme [11] (nous y reviendrons dans un futur article)

Initialisation

Avant de nous pencher sur android, regardons déjà comment faire le build d’une application java standard avec Gradle.

Il faut commencer par télécharger Gradle [12] et d’ajouter son GRADLE_HOME/bin au PATH du système. Ceci permettra de lancer gradle en ligne de commande :

gradle -v

Votre installation est bonne? Ok nous allons alors pouvoir initialiser notre premier projet Gradle en lancant la commande init:

gradle init

A la console normalement vous devriez obtenir les log suivant

Starting a Gradle Daemon, 1 incompatible Daemon could not be reused, use --status for details
Support for running Gradle using Java 7 has been deprecated and is scheduled to be removed in Gradle 5.0. Please see https://docs.gradle.org/4.3/userguide/java_plugin.html#sec:java_cross_compilation for more details.
BUILD SUCCESSFUL in 7s
2 actionable tasks: 2 executed

Cette commande va tout d’abord lancer un demon pour accélérer les build suivant du projet et va preinitialiser pour votre système un certain nombre de fichiers, un répertoire wrapper et un répertoire .gradle (invisible sous unix)

ls -a
.  ..  build.gradle  gradle  .gradle  gradlew  gradlew.bat  settings.gradle

Alors commençons par la partie wrapper. Celle ci n’est pas indispensable mais Gradle préconise son utilisation afin de garantir l'homogénéité des builds du projet [13]. Les repertoires et fichiers concernés sont gradle, gradlew et gradlew.bat. En fait le wrapper permet contrairement à Maven,  le rechargement lors du build de la version proposée de gradle qui doit être utilisée pour construire le projet. Ainsi, pour tous les développeurs utilisant le wrapper, le build sera forcément identique (ou du moins reposera sur un environnement identique). Les fichiers gradlew permettent de lancer le wrapper et dans le repertoire nous trouverons un jar (réalisant le maintien de la version) et un fichier de propriétés pour le wrapper (contenant des données d’environnement) [14].

Les fichiers et répertoires participant a proprement parler au build sont build.gradle, settings.gradle et .gradle. Le repertoire .gradle est un repertoire interne a gradle propre au projet permettant à gradle de tagger les fichiers nouvellements modifiés et devant être incorporé au build incremental (c’est lui qui va rendre le processus de build plus efficace et plus rapide également). Normalement il ne devrait pas y avoir de besoin d’aller mettre son nez dedans; par contre, nous arrivons enfin sur les deux fichiers qui nous interesse le plus settings.gradle et build.gradle.

Le fichier settings.gradle est optionnel mais, il est recommandé de systématiquement l’utiliser. En effet celui-ci n’est pas utile pour un projet isolé mais sera indispensable dans le cas des multi-projets (equivalent aux modules maven). De plus il permet de définir un nom aux projets qui par défaut s’il n’existe pas est pris sur la base du nom du repertoire contenant le projet (ce qui n’est pas tiptop…)

settings.gradle

De façon simple voici ce qu’il peut contenir:

/*
// To declare projects as part of a multi-project build use the 'include' method
include 'shared'
include 'api'
include 'services:webservice'
*/
rootProject.name = 'monProjetGradle'

On aura compris que rootProject.name est le nom de notre projet…. A noter la primitive include afin de déclarer des sous projets à construire.

build.gradle

Intéressons nous au fichier de build lui-même: build.gradle. Ce fichier a pour vocation de décrire le contenu du build lui-même en s’appuyant sur la syntaxe Groovy. On imagine alors ce que l’on va y decrire sera considéré avant tout comme du comportement plutôt que de la configuration (a l’inverse de Maven) et c’est effectivement le cas à quelques exception près.

Prenons l’exemple d’un projet Java, il va falloir commencer par indiquer à Gradle que le build s’effectuera en Java. Pour cela, on va lui specifier l’utilisation d’un plugin [15]:

apply plugin: 'java'

Ensuite, à l'instar de maven on pourra donner une description et une version à l’artifact que nous allons créer. A la suite de quoi on va lui donner la version java pour la compilation:

description ="Projet de test pour gradle"
version = '0.1.0-SNAPSHOT'
sourceCompatibility = 1.8

Pour identifier les sources, il est possible de spécifier leur emplacement, ainsi que l’emplacement des tests.

sourceSets {
    main {
         java {
              srcDir 'src/main/java'
              }
         }
    test {
         java {
              srcDir 'src/test/java'
              }
         }
}

Encore une fois comme pour maven, il faut définir quelles vont être les dépendances nécessaires à la compilation et aux tests: Plus simplement que pour maven il suffit de déclarer le bloc dependencies comme suit:

dependencies {
    compile 'org.tc.osgi.bundle.utils:tc-osgi-bundle-utils-interfaces:0.1.0-SNAPSHOT'
    testCompile 'junit:junit:4.12'
    testCompile 'org.mockito:mockito-all:1.9.5'
}

A noter que le nommage des artifacts peut suivre les règles d’ecriture prescrit par Maven et permettre d’utiliser des repository Maven.
C’est d’ailleur ce que l’on va ajouter à notre build, la possibilité d’aller rechercher des artifacts dans un artifactory maven. Ainsi, si vous utilisez un repository maven perso, il faudra le déclarer avec la primitive repositories comme suit:

repositories {
    //jcenter()
    maven {
        url "http://localhost:8081/artifactory/cots"
        credentials {
            username = "toto"
            password = "tata"
        }
   }
}

Voila, et enfin pour les plus aguerri, il est possible de modifier manuellement le Manifest du jar produit. Pour exemple, pour construire des Bundles OSGI (nous regarderons cela dans un autre article sur ce qu’est OSGI) il faudra non seulement rajouter le plugin osgi mais aussi triturer un peu le manifest:

apply plugin: 'osgi'
jar {
    manifest {
    attributes 'Bundle-SymbolicName' : project.name
attributes 'Bundle-Name' : project.name + '-' + version
attributes 'Bundle-Version' : version
attributes 'Bundle-Vendor' : 'TC'
        attributes 'Bundle-Activator': 'org.tc.osgi.bundle.utils.module.activator.UtilsActivator'
        attributes 'Bundle-Description': 'Un bundle pour contenir des services utilitaires'
    }
}

ou plus classiquement pour un jar java standard:

jar {
    manifest {
        attributes 'Main-Class': 'monProjet.Main'
    }
}

Voila, ceci termine la partie statique du build. Maintenant découvrons sa partie dynamique, les taches.

Les taches

Les tâches sont du code groovy permettant d’orchestrer le déroulement du build. Alors bien sur, il ne faudra pas écrire tout le code nécessaire à son exécution. En effet si il existe deux types de tâches, les premières et les plus employées sont celles par défauts déclarer dans les plugins [15] [16].

Ensuite bien sur, il est possible d’en créer soit même avec à terme la définition d’un plugin.. A noter que outre la simplicité évidente du langage, dans le monde maven, il ne serait pas possible d’ajouter du comportement au build sans faire obligatoirement un plugin-maven puisque l’on ne peut ajouter directement du comportement dans le pom (a moins d’utiliser un plugin de type script).

Par exemple voici une petite tache propre a notre build:

// définition d'une tache perso nommé hello
task matache {
    doLast {
        println 'Building ' + project.name
    }
}

Voila il suffira d’appeler la commande

gradle matache

Pour afficher dans la console de build, “Building monProjetGradle”

Voila on a fait le tour de Gradle sans forcement etre rentrer dans le détail mais probablement suffisamment pour pouvoir rapidement mettre en oeuvre un début de build. A mon sens gradle, au vue de sa flexibilité, ne peut que finir par remplacer Maven car il en détient tous les avantages et en complète les défauts (attention par contre a ce que flexibilité ne ressemble pas a chaos). Finalement, son seul tort est peut etre encore son manque de popularité et de visibilité auprès des grands groupes du fait de son “jeune” âge même si la communauté est très active et fournit du contenu riche et très varié.  Pour plus d’informations, n'hésitez pas à consulter [17] [18] qui m’ont été d’une grande aide pour découvrir gradle et écrire cet article.

References:

[1] https://jenkins.io/
[2] https://jfrog.com/artifactory/
[3] https://www.sonarqube.org/
[4] http://robotframework.org/
[5] https://maven.apache.org/
[6] http://un-est-tout-et-tout-est-un.blogspot.com/2017/12/maven-introduction.html
[7] https://gradle.org/releases/
[8] Leon Osterweil:  “software processes are software too”, Proceeding ICSE '87 Proceedings of the 9th international conference on Software Engineering, Pages 2-13
[9] https://dzone.com/articles/gradle-vs-maven?edition=306207&utm_source=Daily%20Digest&utm_medium=email&utm_campaign=dd%202017-07-02
[10] https://devops.com/puzzle-gradle-maven/
[11] http://www.tutos-android.com/maitriser-gradle-partie-1
[12] http://www.gradle.org/downloads
[13] https://docs.gradle.org/current/userguide/gradle_wrapper.html
[14] https://docs.gradle.org/2.4/userguide/build_environment.html#sec:gradle_configuration_properties
[15] https://docs.gradle.org/2.4/userguide/standard_plugins.html
[16] https://plugins.gradle.org/
[17] https://www.petrikainulainen.net/getting-started-with-gradle/
[18] http://www.vogella.com/tutorials/Gradle/article.html

jeudi 9 novembre 2017

Design pattern : Adaptateur

Le pattern adaptateur est un pattern très simple dont le seul but est de fournir une interface adaptant le comportement d'un composant afin de se conforme a l'API d'un autre.



Il se situe ainsi entre un pattern structurel car il sert d'interface entre deux systèmes et un pattern comportemental car il facilite la manipulation de l'un par l'autre. En ce sens le pattern adaptateur porte également le nom de Wrapper et et répondre a ce que l'on appelle communément service (Web, OSGI, etc....)

Un client va donc employer les services d'une API dont l’implémentation va réaliser le mapping vers les fonctionnalités concrète du framework.

interface Adaptateur
{
    void roule();
}


class Client{
    void doIt(Adaptateur adaptateur)
    {
        adaptateur.roule();
    }
}

class Pierre{
    void quiroule()
    {
        println "ba oui je roule!"    }
}


class AdaptateurImpl implements Adaptateur{

    Pierre p;

    AdaptateurImpl(Pierre p)
    {
        this.p=p;
    }


    void roule()
    {
        p.quiroule();
    }
}


Client c=new Client();
c.doIt(new AdaptateurImpl(new Pierre()));

Voila en groovy ce que cela donnerai. On peut voir que le pattern adaptateur permet vraiment simplement la translation de comportement.