Dans la société de surveillance, ne pas se tromper d'ennemi

David Legrand a publié sur Next INpact un bel édito, argumenté, appelant à un démantélement de Google.

Il y a quelques jours, Usbek et Rica tenait peu ou prou le même discours.

Le président de l'ARCEP, Sébastien Soriano, appelle même à ne plus se poser la question de la pertinence du démantèlement de la firme de Mountain View. Pour lui, l'heure est - déjà - à débattre des modalités.

Qwant, dont l'ADN est le refus du traçage des utilisateurs, a produit un clip publicitaire qui se veut alarmiste.

Un tel unanimisme, certes tardif et limité à un certain microcosme, réveille toujours en moi un réflexe de suspicion...

Qui souhaite que sa vie soit entièrement transparente ? Que le moindre de ses actes soit publicisé, exploité ? Qui veut de cette abolition de sa vie privée ?

La réponse semble être : beaucoup de monde, si l'on en juge par le succès des enceintes connectées telles que "Google Home" ou "Amazon Echo". Que sont-elles d'autre que des microphones fonctionnant 24/24, qui écoutent le moindre de vos soupirs, ne serait-ce que pour détecter la prononciation de leur mot d'activation, envoyant ce qu'ils veulent aux serveurs de ces sociétés ?

Je me souviens de mon effroi quand LinkedIn est apparu. Quel outil d'espionnage de nos vies professionnelles, me suis-je dit. On ne m'y prendra pas. Aujourd'hui, comme beaucoup d'autres, je gère mon profil, comme une vitrine où je mets ce qui m'arrange. Déjà en 2009, Jean-Marc Manach se demandait si « Big Brother » n'était pas « un truc de vieux »...

A contrario, quand je vais sur Amazon ou un autre site de commerce, j'aime qu'on me reconnaisse et que l'on me fasse des suggestions pertinentes. Ce qui est loin d'être acquis, les ratages risibles étant encore nombreux.

J'aime également les innombrables outils et contenus que me met à disposition Google. Merci pour TensorFlow, Angular, etc. Merci à Amazon d'avoir popularisé la location de services de stockage, de calcul, etc.

Je déteste, par contre, les "boîtes noires" et autres dispositifs d'écoute massive, intrusive, hors de tout contrôle réel, déployés par les détenteurs du monopole de la force : les États.

Quel est l'adversaire prioritaire des défenseurs des libertés numériques aujourd'hui ? Celui qui nous propose de poser volontairement des micros (et demain des caméras ?) chez nous ? Ou celui qui cède à toutes les demandes des services spéciaux, paniqué par la crainte de ne pas avoir l'air d'en faire assez ?

Il est paradoxal de voir Google attaqué en premier lieu, alors qu'il est un des principaux contributeurs - en tous cas bien plus que les autres GAFAM - d'outils ouverts. Tout comme il est saisissant de voir une telle passion pour la fiscalité s'appliquant à Google sans évoquer la plupart des autres multinationales, également friandes de dispositifs sophistiqués d'évasion, pardon d'optimisation.

Je suis utilisateur de Qwant depuis quelques mois. Par réflexe anti-monopolistique. Par goût de l'exploration régulière d'alternatives. Pas pour qu'on ne me recommande pas des contenus ou des articles pertinents. Et je trouve bien excessif ce rejet de tout traçage, quel qu'en soit la finalité.

Plutôt qu'au démantèlement d'un acteur qui a contribué bien plus que notre vieil État et ses élites paresseuses à notre capacitation numérique, il me semblerait bien plus utile de consacrer et de faire respecter quelques principes fondamentaux.

Neutralité des réseaux. L'ARCEP serait probablement mieux inspirée de s'attaquer à l'énorme avantage que confère à Orange la maîtrise des infrastructures historiques de génie civil.

La puissance publique, nationale ou supranationale, serait bien plus utile en faisant en sorte que le consentement des internautes soit réellement requis et respecté, et que la proportionnalité des collectes aux usages soit réelle.

L'État devrait réguler bien plus finement les pratiques d'un acteur comme Apple qui, sous couvert de protection de nos vies privées, modifie ses produits pour pousser encore plus vers la publicité "in app" et "connectée".

La puissance publique, enfin, devrait réellement soutenir le développement d'alternatives respectueuses, par leur conception, de nos libertés. Et, peut-être, interdire tout simplement la vente de micro espions installables, même volontairement, à domicile. Il y a quelques jours, l'Allemagne interdisait la vente de montres connectées pour enfants...

Alors que la France se montre, à travers les alternances, incapable d'affirmer une simple priorité au logiciel libre, dilapide notre argent dans des éléphants blancs comme le "cloud souverain", ne pratique qu'un open data "canada dry" (et ne parlons même pas de la transparence des algorithmes) ou, bien pire encore, approuve la vente de systèmes d'écoute à l'échelle d'un pays à des régimes autoritaires, comme le rappelaient encore récemment reflets.info et Libération, l'urgence semble plutôt de reconfigurer cet appareil d'État manifestement défaillant, voire prédateur.

Utiliser un casque bluetooth avec un ordinateur sous Debian

J'ai récemment acheté un casque bluetooth d'une bonne qualité de son et avec des fonctionnalités de réduction active de bruit, le Philips SHB9850NC. J'en suis content, cela adoucit bien mon aller-retour quotidien travail/domicile en bus/métro/RER. Mais là n'est pas l'objet de ce billet.

Aucun soucis pour utiliser ce casque avec mon téléphone portable. Il intègre (évidemment !) le bluetooth, l'utilisation est immédiate. Sur des PC fixes, par contre, c'est une autre histoire. Ni mon PC pro, ni mon PC perso, n'ont de puce bluetooth. J'ai donc acheté un dongle USB 4.0 réputé fonctionner sous GNU/Linux. Les deux PC sont sous Debian.

L'installation n'est pas d'une grande difficulté, mais avoir un récapitulatif vous fera peut-être gagner du temps.

J'ai dû (source) :

  • installer bluetooth et blueman et deux petits bouts de pulseaudio :

sudo apt install bluetooth blueman pulseaudio-module-bluetooth pavucontrol

bluetooth était déjà installé. J'ai pris blueman car il semblait le moins "lourd". Au quotidien, j'utilise fluxbox, un environnement de bureau très léger (et encore, je n'utilise pas de transparence, etc.). Je ne voulais pas ajouter un gros machin. blueman-applet ajoute une petite applet plutôt discrète. Exactement ce que je veux.

pulseaudio-module-bluetooth sert à connecter l'audio bluetooth à pulseaudio, le système de son actuellement utilisé sous Debian GNU/Linux.

pavucontrol permet, lui de gérer les sorties sons, leur association avec les flux audio, etc.

  • redémarrer pulseaudio

pulseaudio -k

  • avec l'applet blueman, associer le casque :

blueman-applet puis suivre le clicodrome.

Notez que j'ai du m'y reprendre à plusieurs fois pour réussir la première association. Une fois effectuée, on ne la refait normalement plus.

Une fois cette étape franchi, dans le menu contextuel (clic droit sur le casque dans blueman-applet), vérifiez bien que le profil audio ("Audio profile") est "High Fidelity Playback (A2DP sink)". Sans quoi, la qualité du son sera... décevante.

C'est presque terminé. Ne reste plus qu'à expliquer à pulseaudio quand vous souhaitez utiliser votre casque. Une fois le casque associé, lancez pavucontrol puis la lecture d'une vidéo (par exemple : Chicken Attack).

  • rediriger certains flux audio vers le casque bluetooth

Dans pavucontrol, vous devez voir votre casque dans les périphériques de sortie. Dans l'onglet lecture, une fois la vidéo lancée, vous avez la possibilité de choisir vers quelle destination envoyer le playback. Pour moi, c'était "Philips SHB9850NC" plutôt que "Audio interne stéréo analogique".

Ce réglage peut être fait flux par flux. Donc, vous pouvez parfaitement diffuser Chicken Attack ou un extrait d'une oeuvre proposée par Bide et Musique à l'attention de votre entourage pendant que vous écoutez de la musique avec votre caque bluetooth. :-)

  • En cas de pb de passage en "A2DP sink" après un redémarrage

Dans mon cas, il a fallu, enfin, recourir à ces contournements documentés par Debian après un reboot. Le symptôme est le suivant : il est impossible de passer en profil audio "High Fidelity Playback (A2DP sink)".

Présidentielle 2017 : une boussole plutôt qu'une girouette

29 mars 2017. Je regarde le calendrier et me dis que je n'aurais jamais cru il y a un an, il y a six mois que nous en serions là. Que François Fillon serait le candidat de la droite, et qu'il serait en miettes. Que Benoît Hamon serait le candidat de la gauche de gouvernement et serait dans un tel pot au noir. Qu'Emmanuel Macron ne se soit pas encore effondré. Il est vraiment dommage que l'on ne parle pas plus du fond dans cette campagne, tant toute discussion un temps soit peu approfondi a sur lui un véritable effet Dracula.

Le moins que l'on puisse dire est que cette campagne est... surprenante. À gauche, je m'attendais après la belle victoire de Benoît Hamon à des peaux de banane de la "droite du PS", qui a perdu sa gauche depuis longtemps. Je ne m'attendais cependant pas à une trahison aussi claire et nette que celle de Manuel Valls.

C'est peut-être, quelque part, un mal pour un bien. Le PS aura connu sous l'ère Hollande (Martine Aubry me pardonnera d'oublier un instant son passage au primo-secrétariat) une longue déliquescence, de synthèses molles en débats non tranchés. Combien de fois ai-je entendu des amis brillants, pour certains ex-mitterrandiens regretter navrés que "ces gens ne savent vraiment pas faire". Fini, les fausses synthèses qui disent tout et son contraire. Fini, peut-être, le parti d'élus trop souvent au service de leur seule réélection. Il y a une possibilité d'ouvrir en grand les portes et les fenêtres, de débattre à nouveau, de se retrouver sur des bases plus solides.

Je relisais il y a quelques jours le discours de François Mitterrand à Épinay. Ce n'est pas son plus grand. On n'en a retenu que certains passages. Il vaut d'être relu. Le Grand François y parle de l'importance du fond, du travail intellectuel. De l'importance du travail de terrain. Et de bien d'autres choses que le PS ne fait plus depuis longtemps. Certes, l'époque a changé et idéaliser Mitterrand et les années 70 ne nous emmènerait pas bien loin. Mais je suis convaincu que le PS et nombre de ses grands élus ont perdu en grande partie la bataille en ne menant plus dans la durée ce combat des idées, du terrain et en se prêtant trop au jeu de la communication. Qu'il est étonnant aujourd'hui de voir le système médiatique contrôlé à de très rares exceptions près par les puissances de l'argent se jouer des candidats de gauche ! La Gauche s'est laissée emmener sur le terrain de la Droite. Sans surprise, cette dernière joue mieux à son propre jeu de coups médiatiques, d'affaires, d'affaires dans l'affaire, de populisme et d'électoralisme à la petite semaine. Tout cela peut changer, doit changer. Vivement demain !

Ce constat étant fait, cette lueur d'espoir étant entrevue, que faire pour la présidentielle ? En 2012, j'avais défini 7 critères. Et j'avais fait mon choix. En 2017, je n'ai pas besoin d'autant finasser. Je suis de gauche, parce que je pense que l'égalité ne vient pas naturellement, mais qu'il faut sans cesse remettre le métier sur l'ouvrage pour plus d'égalité, de principe ou réelle. Parce que je pense que je vivrai mieux et que mes enfants vivront mieux si tout le monde vit dignement. Parce que je ne pense pas que la quête effrénée de la richesse (et de la niche fiscale) donne du sens à la vie. Parce que je crois que le bon vieux discours sur la lutte des classes garde aujourd'hui l'essentiel de sa justesse, même si les contours de ces classes ont changé. Les damnés de la terre ne sont plus aujourd'hui mineurs, mais agents d'entretien auto-entrepreneurs au temps de travail (partiel) éclaté, exploités dans certains centres d'appel, etc. L'argent va toujours à l'argent. Mieux vaut, plus que jamais, être héritier plutôt que travailleur.

Laissons de côté Fillon et Le Pen. Il est évident que je ne voterai jamais pour ces gens. Oublions également les candidats fantaisistes ou les simili-lepénistes comme Nicolas Dupont-Aignan. Au centre droit, Emmanuel Macron place le curseur économique bien trop à droite avec des politiques qui ont déjà échoué sous Hollande. Ses propositions "sociales" me hérissent. J'ai beau être plutôt dans le camp des favorisés, avec un métier sûr (aujourd'hui !) et rémunérateur, j'ai déjà pu ressentir à quel point on ne négocie pas sur un pied d'égalité avec son patron, quel qu'il soit. Exit Macron, donc, avec l'illusion individualiste.

Je suis, soit dit en passant, sidéré par la fascination que certain-e-s ont pour Emmanuel Macron et par la nouveauté que certains lui prêtent. Ainsi, un inspecteur des finances, ancien banquier, ancien secrétaire général de l'Élysée, ancien ministre serait un anti-système... Je me demande avec quelle définition de "système". Je ne recherche pas, pour ma part, un candidat "anti-système", ne serait-ce que parce que je crois plus aux évolutions qu'aux révolutions. Mais, tout de même... Ces gens ont perdu le nord... Entendons-nous bien : tous les soutiens de Macron ne sont pas comme ces lapins affolés par les phares d'une candidate blonde qui a la côte dans les sondages. Certains sont sincèrement sociaux-libéraux. Je ne pense pas qu'ils soient plus que quelques pourcents.

Bien à gauche sont Jean-Luc Mélenchon et ses "insoumis". J'ai beaucoup de respect et d'estime pour Mélenchon. De manière intéressante, Michel Rocard, avec qui il s'est souvent confronté, avait également beaucoup de respect pour son travail intellectuel. J'ai cependant un premier problème avec la tonalité de sa campagne. Le «dégagisme», c'est bien gentil, mais ça ne fait pas une société sereine. Vous la pressentez, vous aussi, cette chasse aux sorcières qui vient ? Son programme est, sinon, intéressant et le fruit d'un passionnant travail de fond. Il pêche souvent malheureusement par manque de réalisme. Tantôt on renationalise les autoroutes. Je ne suis pas contre, mais avec quel argent ? Tantôt on "socialise" (que cela est joliment dit !) les banques de dépôt. Même remarque ! En plus de ces points, je pense cependant que c'est son attitude vis-à-vis de l'Europe qui me pose le plus problème. J'ai encore en tête les paroles de Michel Rocard à qui l'on demandait ce qu'a réussi l'Europe et qui expliquait, non sans les longues disgressions dont il était coutumier, que l'Union Européenne a apporté la paix en Europe. Que les générations plus jeunes comme les nôtres l'avaient oublié, mais que les tensions, les guerres ne s'étaient éloignées de notre continent que fort récemment. Je ne suis pas satisfait de l'Europe telle qu'elle est aujourd'hui. J'enrage devant son déficit démocratique et avait voté "non" en 2005. Je ne veux pas pour autant jeter le bébé avec l'eau du bain.

Chez Hamon, je n'aime pas tout. Je n'aime pas, par exemple, son discours sur la Russie, même si je suis d'accord avec lui sur la nécessité d'engager le rapport de force avec Vladimir Poutine. Lui et ses amis ne comprennent que cela. Je pense, comme Mélenchon, qu'il faut une grande conférence sur les frontières issues de l'ex-URSS, qui sont une véritable poudrière. Mikhaïl Gorbatchev nous avait prévenu dès la chute de l'URSS : nous ne pouvons pas laisser les frontières en l'état. Si nous ne menons pas cette discussion, n'exigeons pas des référendums d'auto-détermination dans les zones litigieuses, j'ai bien peur que nous ne connaissons un nouveau conflit. Je ne vois pas beaucoup de Français prêts à envoyer leurs enfants mourir pour Talinn. J'y suis encore moins prêt, la mère des miens ayant grandi de l'autre côté de la frontière et mes gosses regardant "Masha et Medved" en version originale. Les français connaissent trop mal la Russie. J'avais été frappé dès 2006 par de jeunes ukrainiens de l'est du pays m'expliquant tranquillement que pour eux, l'Ukraine, la Russie, c'était la même chose, qu'ils étaient nés dans un même pays et que la séparation était bien artificielle. Je revois le grand père de ma femme, artiste peintre, me montrer fin 2008 une toile représentant l'Ukraine volée à la Russie par Khrouchtchev. Je me souviens du «cousin ukrainien» dont on riait un peu de l'accent au repas de famille, mais qui n'était clairement pas un étranger d'une autre culture. Je croise des ressortissants russophones des pays baltes me parlant de leur nationalité de papier et de celle de cœur. Les frontières n'ont rien d'intangibles.

Mais, en plus du discours sur l'Europe, je retrouve chez Hamon mes fondamentaux. Et j'apprécie certaines de ses ruptures. Le revenu universel, moqué, caricaturé, est pour moi une des clés à de l'adaptation dans la douceur aux nouvelles formes d'emploi. La taxation des robots est une manière de taxer la valeur ajoutée plutôt que le travail. La lutte contre les perturbateurs endocriniens ne peut que remporter l'adhésion d'un père inquiet qui achète tout plus bio que bio pour ses enfants. J'aime bien également sa posture assumée d'anti-hyper président. Le monde est trop complexe. Personne ne sait tout sur tout. Nous ne pourrons gouverner demain efficacement que collectivement.

Bref, quand je ressors ma bonne vieille boussole, je ne trouve pas le choix bien difficile, ce même si les girouettes médiatiques tournent et grincent. Le Nord n'a pas changé de place. :-)

À propos du projet de loi "numérique"

Après trois ans d'attente, le projet de loi numérique maintes fois promis mais toujours remis sur le numérique a été mis en discussion en ligne.

L'intitulé du projet de loi est ambitieux, très ambitieux : "La République numérique". Vaste programme ! Voyons ce que cela recouvre...

Lire la suite...

Surveillance de masse : principes, problèmes et préconisations

Une courte note présentant rapidement les fondements de la surveillance de masse des communications électroniques, ses principaux problèmes et se hasardant à quelques préconisations

Lire la suite...

Mais où est Charlie ?

L'assassinat d'une partie de la rédaction de Charlie Hebdo a été un choc. Cabu, Wolinski, notamment. Pas des gens que j'avais le plaisir de fréquenter, mais au moins celui de les lire depuis tant d'années. Cabu, notamment, toutes les semaines dans le "Canard Enchaîné". Sans parler de ses dessins dans "Récré A2" quand j'étais petit.

Choc, d'abord, devant l'acte en tant que tel. J'essaye d'avoir en tout temps du recul, voire du décalage. C'est une bonne protection contre certaines absurdités, contre certains abus. Là, pendant les 30mn qui ont suivi l'annonce des meurtres, je n'en ai juste pas été capable.

Choc, ensuite, devant les réactions. A la fois positif du nombre de réaction. Mais, surtout, négatif, devant leur nature. La cérémonie aux Invalides... Les cloches de Notre Dame et une messe... Pour une partie de la rédaction de Charlie Hebdo ? Vraiment ? Mais à quel point sommes-nous perdus, à quel point les mots ont-ils perdu tout sens ?

Charlie Hebdo, faut-il le rappeler, ou plutôt l'apprendre à des millions de personnes qui déclarent soudain "Je suis Charlie", n'est pas un cousin de Valeurs Actuelles ou un opuscule de jésuites. Charlie Hebdo s'en prend depuis toujours aux religions, à toutes les religions (même s'il se préoccupait bien sûr moins d'Islam dans les années 70 que dans les années 2000...). Charlie Hebdo est également pacifiste, anti-militariste. Charlie Hebdo est laïc, républicain et engagé de longue date contre le FN, lançant même à une époque une pétition pour demander l'interdiction de ce parti et comptant plusieurs litiges avec lui ou ses dirigeants.

D'où un autre choc, devant le culot décidément sans borne de Marine Le Pen qui feint de s'offusquer que l'on puisse la trouver indésirable dans une manifestation d'hommage... Vraiment ??? Et choc devant la masse de grands bêtas pour lesquels les compteurs sont tout le temps remis à zéro et qui semblent vivre dans un monde de Bisounours où la "gentille dame blonde exclue du système" aurait bien sûr sa place à un hommage à Cabu...

Choc, encore, devant les images de la manifestation. Choc positif du nombre de personnes - j'aurais aimé en être si la fièvre ne m'avait cloué chez moi. Mais choc également devant la nature de l'hommage. J'ai tiqué dès le jour de la tuerie sur le slogan "Je suis Charlie". Autant de centaines de milliers de personnes qui pensent rendre un hommage à un déconstructeur de symbole comme Charlie en en faisant un symbole... C'est flippant. Le pire est encore quand ils chantaient la "Marseillaise". Non que je dédaigne l'exercice... Mais en hommage à ces gens la... Vraiment ???

J'ose à peine le dire mais... Je ne suis pas Charlie. Je les ai beaucoup lus dans les années 90. Je me souviens particulièrement d'un numéro "spécial JMJ" titré "L'obscurantisme envahit la ville lumière" qui remettait quelques pendules à l'heure en pleine cathomania (subventionnée par la gauche au pouvoir...). Je me souviens également d'un reportage de Cavanna au Puy du Fou qui m'avait littéralement fait pleurer de rire. Depuis l'époque Val, je les aimais moins. Beaucoup moins. Je n'ai pas acheté un "Charlie" depuis au moins 10 ans. Je ne suis pas Charlie non plus parce que je n'ai certainement pas leur courage. Je ne me vois pas dire comme Charb que je préfère mourir debout. Contrairement à lui, j'ai une femme, des enfants. Je suis prêt à me battre, mais pas à me faire trouer la peau pour un bon mot. Je ne me sens pas au niveau de Charlie, et son humour était de moins en moins le mien.

En définitive, ce qui me choque le plus, à part les morts proprement dites, c'est l'absence de repères dont tout ce que j'énumère ci-dessus me semble être la traduction. Si notre réaction collective à l'assassinat d'une bandes d'anars et de gauchistes est de défiler en chantant la Marseillaise (côté "peuple") et de faire un hommage aux Invalides (côté "élites"), on est vraiment, vraiment mal. Cela montre, je pense, que nous n'avons plus grand chose qui ressemble à un "vivre ensemble", pas de culture commune nous permettant de réagir positivement.

Après cela, quelle réponse trouver ? Elle n'est certainement pas dans un "Patriot Act" à la française. Elle n'est pas dans le rétablissement des frontières : les terroristes étaient français. Elle est peut-être dans un accroissement des moyens des "services secrets", notamment pour analyser les informations déjà collectées. J'ai trouvé Alain Bauer percutant sur ce thème, estimant que la France disposait de beaucoup d'informations sur les terroristes et d'équipes de haut niveau pour réagir après les attentats, mais qu'il manquait des moyens pour analyser cette masse d'information et y réagir. Dans tous les cas, cela ne reste qu'une réaction au problème. Notre vrai problème a plutôt sa traduction dans les réactions observées dans les établissements scolaires lors de la minute de silence en hommage aux victimes. Les enfants, plus ou moins grands, ne sont le plus souvent que le décalque de leurs parents. Pour que certains en soient à perturber un hommage ou à estimer que "ils l'ont bien cherché", il faut tout de même un sacré fossé entre "eux" et "nous".

Non, la vraie bataille est culturelle, au sens le plus large. Retrouver quelques éléments de culture commune passera par l'éducation, mais pas uniquement. Cela ne peut pas suffire pour tous ceux qui sont déjà grands. Les artistes, les intellectuels, les commentateurs autorisés (ou non) ont un rôle important à jouer. Ainsi que les anonymes, comme toi, lecteur, et moi, scribaillon de ce blog. Nous ne devons plus rien laisser passer, plus rien céder sur le terrain de la laïcité. De la laïcité tout court. Pas la positive de Sarko ni sa version dévoyée version soupe au cochon. Nous ne devons plus non plus laisser le moindre espace aux islamophobes. Ne plus tolérer les discours sur ces populations non intégrables qui n'auraient pas vocation à rester en France (dédicace à Eric Zemmour et... Manuel Valls). C'est, quelque part, faire vraiment de la politique. Pas en glissant un bulletin dans une urne à quelques années d'intervalle. Mais en défendant des valeurs, une manière de vivre, des choix au quotidien. Il faudrait idéalement que se concrétise le projet de "Parlement des invisibles" de Pierre Rosanvallon.

De cela, de cette réappropriation du commun pourra découler "le reste". Sur son blog, Dominique Boullier a fait une liste en 11 points que j'aurais aimer écrire et à laquelle je souscris. Pour en faire ne serait-ce qu'un seul, il faudra un sacré sursaut politique. Recréer une vraie offre politique et les conditions d'un vrai choix, autre que la fausse opposition entre un Hollande et un Sarkozy d'accord sur l'essentiel. Avoir enfin un jour un dirigeant capable, comme le maire d'Oslo après la tuerie de 2011, de déclarer que Nous allons punir le coupable. La punition, ce sera plus de générosité, plus de tolérance, plus de démocratie.

Et, dans l'immédiat, ne pas accepter que l'on donne le droit aux forces de l'ordre d'écouter ou de censurer n'importe qui sans qu'un vrai contre-pouvoir indépendant existe. 3,7 millions de personnes ont, paraît-il, manifesté pour la liberté d'expression. Je doute qu'elles appelaient à un remake français de "La Vie des Autres"...

Les survivants de Charlie Hebdo nous donnent déjà du boulot avec leur dernière couverture, qui déchaînent les passions dans certains pays... Comme le tirait avec cette ironie que j'adore le Canard Message de Cabu : "Allez les gars, ne vous laissez pas abattre !"

JSF in the cloud : Finding the PaaS - Part 5 : Heroku

Basic usages

Heroku is often mentionned as an example of PaaS provider. Although I found a few opinions stating that «Java is a second or third class passenger on Heroku», I wanted to test it myself.

Creating a free account is straightforward. Language specific tutorials are provided. I followed the one dedicated to Java.

Requirements, apart from an heroku account, are just «Java» (no version mentionned, but the example in the tutorial i Java 7) and Maven 3.

CLI tools should be downloaded and are available for Debian, Windows, OS X and «standalone» (?). As a debian user, I followed the instructions :

wget -qO- https://toolbelt.heroku.com/install-ubuntu.sh | sh

This :

  • adds a package repository : deb http://toolbelt.heroku.com/ubuntu ./
  • installs two packages : foreman and heroku.

After that, you have to login on heroku using the

heroku login

commands.

It checks your account/password then let you choose the SSH public key you want to upload.

The getting started tutorial then let you clone an example project. Its pom.xml is a bit surprising :

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.example</groupId>
  <version>1.0-SNAPSHOT</version>
  <artifactId>helloworld</artifactId>
  <dependencies>
    <dependency>
      <groupId>org.eclipse.jetty</groupId>
      <artifactId>jetty-servlet</artifactId>
      <version>7.6.0.v20120127</version>
    </dependency>
    <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>servlet-api</artifactId>
      <version>2.5</version>
    </dependency>
    <dependency>
      <groupId>postgresql</groupId>
      <artifactId>postgresql</artifactId>
      <version>9.0-801.jdbc4</version>
    </dependency>
  </dependencies>
  <build>
    <plugins>
      <plugin>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>2.3.2</version>
      </plugin>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-dependency-plugin</artifactId>
        <version>2.4</version>
        <executions>
          <execution>
            <id>copy-dependencies</id>
            <phase>package</phase>
            <goals><goal>copy-dependencies</goal></goals>
          </execution>
        </executions>
      </plugin>
    </plugins>
  </build>
</project>

The target artefact is not a war but a jar. The only class seems to be some kind of autosufficient servlet. It uses jetty 7.6.0. It uses the dependency-plugin to copy jar dependencies in the target/dependency subdir.

The recommended way to proceed if to use a beta feature : creating a git repo where the project will be pushed.

$ heroku create --http-git
Creating glacial-sands-3101... done, stack is cedar-14
https://glacial-sands-3101.herokuapp.com/ | https://git.heroku.com/glacial-sands-3101.git
Git remote heroku added

Then push the code to remote master branch :

$ git push heroku master
Décompte des objets: 33, fait.
Delta compression using up to 2 threads.
Compression des objets: 100% (27/27), fait.
Écriture des objets: 100% (33/33), 4.89 KiB | 0 bytes/s, fait.
Total 33 (delta 12), reused 0 (delta 0)
remote: Compressing source files... done.
remote: Building source:
remote: 
remote: -----> Java app detected
remote: -----> Installing OpenJDK 1.7... done
remote: -----> Installing Maven 3.2.3... done
remote: -----> executing /app/tmp/cache/.maven/bin/mvn -B -Duser.home=/tmp/build_5d419e548f5f5358e7f369fc9f0f73e0 -Dmaven.repo.local=/app/tmp/cache/.m2/repository  -DskipTests=true clean install
remote:        [INFO] Scanning for projects...
remote:        [INFO]                                                                         
remote:        [INFO] ------------------------------------------------------------------------
remote:        [INFO] Building helloworld 1.0-SNAPSHOT
remote:        [INFO] ------------------------------------------------------------------------
remote:        [INFO] Downloading: https://repo.maven.apache.org/maven2/org/apache/maven/plugins/maven-clean-plugin/2.5/maven-clean-plugin-2.5.pom
...
remote:        [INFO] Downloaded: https://repo.maven.apache.org/maven2/org/codehaus/plexus/plexus-utils/3.0.5/plexus-utils-3.0.5.jar (226 KB at 6619.0 KB/sec)
remote:        [INFO] Installing /tmp/build_5d419e548f5f5358e7f369fc9f0f73e0/target/helloworld-1.0-SNAPSHOT.jar to /app/tmp/cache/.m2/repository/com/example/helloworld/1.0-SNAPSHOT/helloworld-1.0-SNAPSHOT.jar
remote:        [INFO] Installing /tmp/build_5d419e548f5f5358e7f369fc9f0f73e0/pom.xml to /app/tmp/cache/.m2/repository/com/example/helloworld/1.0-SNAPSHOT/helloworld-1.0-SNAPSHOT.pom
remote:        [INFO] ------------------------------------------------------------------------
remote:        [INFO] BUILD SUCCESS
remote:        [INFO] ------------------------------------------------------------------------
remote:        [INFO] Total time: 9.911 s
remote:        [INFO] Finished at: 2014-12-03T09:56:38+00:00
remote:        [INFO] Final Memory: 19M/644M
remote:        [INFO] ------------------------------------------------------------------------
remote: -----> Discovering process types
remote:        Procfile declares types -> web
remote: 
remote: -----> Compressing... done, 62.8MB
remote: -----> Launching... done, v6
remote:        https://glacial-sands-3101.herokuapp.com/ deployed to Heroku
remote: 
remote: Verifying deploy... done.
To https://git.heroku.com/glacial-sands-3101.git
 * [new branch]      master -> master

this automatically builds the artefact, then launch it using the Procfile :

web:    java -cp target/classes:target/dependency/* Main

The app is then up and running.

The tutorial indicates then how to view logs :

heroku logs --tail

The tutorial then gives a hint on how to scale an app, manually allocating nodes using heroku ps.

Then, like Google App Engine, the tutorial indicates how to run the app locally using foreman :

$ foreman start web
11:09:05 web.1  | started with pid 8160
11:09:05 web.1  | 2014-12-03 11:09:05.695:INFO:oejs.Server:jetty-7.6.0.v20120127
11:09:05 web.1  | 2014-12-03 11:09:05.760:INFO:oejsh.ContextHandler:started o.e.j.s.ServletContextHandler{/,null}
11:09:05 web.1  | 2014-12-03 11:09:05.822:INFO:oejs.AbstractConnector:Started SelectChannelConnector@0.0.0.0:5000

This is something that I really appreciate. Local (and thus fast) debugging is mandatory in most complex projects.

I just skipped the part on pushing changes with maven (it is just @@git push heroku master@...).

Next, the tutorial introduces add-ons.

As I guessed, an add-on was already configured : the free "postgresql instance" I provisionned when creating my account.

$ heroku addons
=== glacial-sands-3101 Configured Add-ons
heroku-postgresql:hobby-dev  HEROKU_POSTGRESQL_MAROON

Heroku allows the execution of remote commands, using what it calls a "one-off dyno". Dyno are, in a nutshell, nodes instantiated for your apps. Command execution is performed by nodes instantiated on demand, in opposition to the always running web nodes. That why they are called "off nodes".

Lauching bash is straightforward :

$ heroku run bash
Running `bash` attached to terminal... up, run.4406
~ $ 

The filesystem seems to be the same as the webapp.

The tutorial finally deals with environment variables and database (PostgreSQL).

Running a very simple JSF app

I then wanted to run this very simple test, which uses a PrimeFaces 5.1 / MyFaces 2.2.6 / OpenWebBeans 1.2.6 / DeltaSpike 1.1 stack.

Heroku features detailed information on how to get a Tomcat webapp up and running.

I followed the recommendation and added the maven-dependency-plugin declaration, as a heroku profile :

        <profile>
            <id>heroku</id>
            <properties>
                <cloud.extension>-heroku</cloud.extension>
            </properties>
            <build>
                <plugins>
                    <plugin>
                       <groupId>org.apache.maven.plugins</groupId>
                       <artifactId>maven-dependency-plugin</artifactId>
                       <version>2.3</version>
                       <executions>
                           <execution>
                               <phase>package</phase>
                               <goals><goal>copy</goal></goals>
                               <configuration>
                                   <artifactItems>
                                       <artifactItem>
                                           <groupId>com.github.jsimone</groupId>
                                           <artifactId>webapp-runner</artifactId>
                                           <version>7.0.40.0</version>
                                           <destFileName>webapp-runner.jar</destFileName>
                                       </artifactItem>
                                   </artifactItems>
                               </configuration>
                           </execution>
                       </executions>
                   </plugin>
                </plugins>
            </build>
        </profile>

Then, I build the project using :

$ mvn -Pheroku clean install

and tried to run it using :

$ java -jar target/dependency/webapp-runner.jar target/test-heroku##1.0-SNAPSHOT.war

It did not work at first. I got exactly the same problem I had with OpenShift : it seems that my beans were not instantiated.

Suspecting some file-scanning problem, I tried again with the --expand-war parameter... And it worked !

Following the tutorial, I added the following Procfile :

web:    java $JAVA_OPTS -jar target/dependency/webapp-runner.jar --port $PORT --expand-war target/*.war

Then I created the app, requesting that it runs in the European Union and sepcifying a name (because test is, well, widely used. :-) ).

$ heroku create --region eu testlp-heroku

and uploaded the app

$ git push heroku master

...and it did not work. The reason was simple : the heroku profile was not activated, the webapp-runner was not downloaded and not found, as you can se in the logs :

lpenet@dsi-lpenet-personnel:~/heroku/test-jelastic$ heroku logs --tail
2014-12-03T12:54:14.883097+00:00 heroku[api]: Enable Logplex by ludovic@penet.org
2014-12-03T12:54:14.883131+00:00 heroku[api]: Release v2 created by ludovic@penet.org
2014-12-03T12:55:37+00:00 heroku[slug-compiler]: Slug compilation started
2014-12-03T12:57:11.381707+00:00 heroku[api]: Scale to web=1 by ludovic@penet.org
2014-12-03T12:57:11.913533+00:00 heroku[api]: Set DATABASE_URL config vars by ludovic@penet.org
2014-12-03T12:57:11.913616+00:00 heroku[api]: Release v3 created by ludovic@penet.org
2014-12-03T12:57:11.996784+00:00 heroku[api]: Attach HEROKU_POSTGRESQL_CYAN resource by ludovic@penet.org
2014-12-03T12:57:11.996784+00:00 heroku[api]: Release v4 created by ludovic@penet.org
2014-12-03T12:57:12+00:00 heroku[slug-compiler]: Slug compilation finished
2014-12-03T12:57:12.109260+00:00 heroku[api]: Set PATH, JAVA_OPTS config vars by ludovic@penet.org
2014-12-03T12:57:12.109289+00:00 heroku[api]: Release v5 created by ludovic@penet.org
2014-12-03T12:57:12.178189+00:00 heroku[api]: Deploy 8b59698 by ludovic@penet.org
2014-12-03T12:57:12.178189+00:00 heroku[api]: Release v6 created by ludovic@penet.org
2014-12-03T12:57:21.961334+00:00 app[web.1]: Error: Unable to access jarfile target/dependency/webapp-runner.jar
2014-12-03T12:57:22.898521+00:00 heroku[web.1]: State changed from starting to crashed
2014-12-03T12:57:22.899254+00:00 heroku[web.1]: State changed from crashed to starting
2014-12-03T12:57:21.452363+00:00 heroku[web.1]: Starting process with command `java -Xss512k -XX:+UseCompressedOops -jar target/dependency/webapp-runner.jar --port 35347 --expand-war target/*.war`
2014-12-03T12:57:22.895807+00:00 heroku[web.1]: Process exited with status 1
2014-12-03T12:57:36.194058+00:00 app[web.1]: Error: Unable to access jarfile target/dependency/webapp-runner.jar
2014-12-03T12:57:35.466658+00:00 heroku[web.1]: Starting process with command `java -Xss512k -XX:+UseCompressedOops -jar target/dependency/webapp-runner.jar --port 11978 --expand-war target/*.war`
2014-12-03T12:57:37.051245+00:00 heroku[web.1]: Process exited with status 1
2014-12-03T12:57:39.153329+00:00 heroku[router]: at=error code=H10 desc="App crashed" method=GET path="/" host=testlp-heroku.herokuapp.com request_id=dd20e9a1-0038-48af-bbea-34998ffacb0a fwd="83.202.122.226" dyno= connect= service= status=503 bytes=
2014-12-03T12:57:39.804428+00:00 heroku[router]: at=error code=H10 desc="App crashed" method=GET path="/favicon.ico" host=testlp-heroku.herokuapp.com request_id=dcd0ea94-4895-46f2-95dd-75f372778ad2 fwd="83.202.122.226" dyno= connect= service= status=503 bytes=
2014-12-03T12:57:37.060623+00:00 heroku[web.1]: State changed from starting to crashed

So I added an automatic activation when an heroku specific variable is defined, DYNO :

            <activation>
                <property>
                    <name>env.DYNO</name>
                </property>
            </activation>

... and it worked like a charm.

More complex example, with PostgreSQL database

I then decided to run my (a little) more complex test, which features JPA 2 / Hibernate 4.2 / PostgreSQL.

So, I added a Procfile and copied in pom.xml the heroku profile from the simple test.

I wanted to avoid copying the DB parameters in my application context.xml.

So, I first tried to use an observer of the PostConstructApplicationEvent. This bean was in an additional build tree, src/heroku/java, that is added using the build-helper-maven-plugin. However, it failed because the InitialContext was not accessible.

So, I switched back to using environment variables that will then be used as username, password and URL in the resource declared in context.xml. It leverages heroku's environment variable management features.

Despite a lot of efforts, I could not get the JNDI part up and running. It it rather disappointing. Heroku java documentation explains how to instantiate a connection programmatically but, well, we are in 2014 and this should be possible using xml configuration files and annotations.

Conclusion

Heroku is a pleasant alternative for a developper, mostly because of the ability to execute locally the webapp in a controlled environment. However, the lack of netbeans support is disappointing, along with the lack of JNDI support. AFAIK, there is no private PaaS version.

JSF in the cloud : Finding the PaaS - Part 4 : CloudFoundry

Pivotal CloudFoundy is one of the leading PaaS provider. So, it was just mandatory to test it.

They propose a 60 days free trial. After registration, you have to install their CLI tool, available for Windows, Mac OS X and GNU/Linux (at least Debian and RPM-based distros).

I am a Debian 64 bits user, so I downloaded and installed the proper .deb, then as suggested logged in

lpenet@dsi-lpenet-personnel:~/Downloads$ cf login -a https://api.run.pivotal.io
Endpoint de l'API: https://api.run.pivotal.io

Email> ludovic@penet.org

Password> 
Authentification en cours ...
OK

Org ciblée lpenet

Espace ciblé development


                   
Endpoint API:   https://api.run.pivotal.io (Version API: 2.18.0)   
Utilisateur:    ludovic@penet.org   
Org:            lpenet   
Espace:         development   

(everything is in French, the offer seems to be properly localized).

CloudFoundry is more complex to learn than the other offers I tested. It is more of an open source project used as the basis of other offers. It seems very powerful, versatile and so on, but getting the pieces of the puzzle together requires some time.

I finally got a grasp on it by reading the following docs :

After reading the three first ones, I felt confident building and deploying my very simple test webapp :

$ git clone https://github.com/lpenet/test-jelastic.git
...
$ cd test-jelastic
$ mvn clean install
...
$ LANG=C cf push testlp -p target/test##1.0-SNAPSHOT.war 
Creating app testlp in org lpenet / space development as ludovic@penet.org...
OK

Creating route testlp.cfapps.io...
OK

Binding testlp.cfapps.io to testlp...
OK

Uploading testlp...
Uploading app files from: target/test##1.0-SNAPSHOT.war
Uploading 69.2M, 44 files
Done uploading               
OK

Starting app testlp in org lpenet / space development as ludovic@penet.org...
-----> Downloaded app package (16M)
-----> Java Buildpack Version: v2.5 | https://github.com/cloudfoundry/java-buildpack.git#840500e
-----> Downloading Open Jdk JRE 1.8.0_25 from https://download.run.pivotal.io/openjdk/lucid/x86_64/openjdk-1.8.0_25.tar.gz (2.2s)
       Expanding Open Jdk JRE to .java-buildpack/open_jdk_jre (1.1s)
-----> Downloading Tomcat Instance 8.0.15 from https://download.run.pivotal.io/tomcat/tomcat-8.0.15.tar.gz (0.9s)
       Expanding Tomcat to .java-buildpack/tomcat (0.1s)
-----> Downloading Tomcat Lifecycle Support 2.4.0_RELEASE from https://download.run.pivotal.io/tomcat-lifecycle-support/tomcat-lifecycle-support-2.4.0_RELEASE.jar (0.0s)
-----> Downloading Tomcat Logging Support 2.4.0_RELEASE from https://download.run.pivotal.io/tomcat-logging-support/tomcat-logging-support-2.4.0_RELEASE.jar (0.0s)
-----> Downloading Tomcat Access Logging Support 2.4.0_RELEASE from https://download.run.pivotal.io/tomcat-access-logging-support/tomcat-access-logging-support-2.4.0_RELEASE.jar (0.0s)

-----> Uploading droplet (61M)

0 of 1 instances running, 1 starting
1 of 1 instances running

App started


OK
Showing health and status for app testlp in org lpenet / space development as ludovic@penet.org...
OK

requested state: started
instances: 1/1
usage: 1G x 1 instances
urls: testlp.cfapps.io
last uploaded: Mon Dec 1 21:02:10 +0000 2014

     state     since                    cpu     memory         disk   
#0   running   2014-12-01 10:03:00 PM   26.2%   446.9M of 1G   181M of 1G   

And the magic is: it worked at first attempt. So,my webapp was running with a JDK8 in a Tomcat 8 container in a snap.

Wow.

As far as I understand, I can customize almost everything by tweaking (which often implies forking) the java buildpack.

Accessing logs and performing basic operations is simple. To get logs, juste use cf logs <APP>. Exemple :

$ LANG=C cf logs testlp
Connected, tailing logs for app testlp in org lpenet / space development as ludovic@penet.org...

2014-12-01T22:19:02.78+0100 [API]     OUT Tried to stop app that never received a start event
2014-12-01T22:19:02.80+0100 [API]     OUT Updated app with guid be8a1ecc-a006-4554-8549-2606843734e7 ({"state"=>"STOPPED"})
2014-12-01T22:19:02.86+0100 [App/0]   OUT [CONTAINER] org.apache.coyote.http11.Http11NioProtocol         INFO    Pausing ProtocolHandler ["http-nio-64570"]
2014-12-01T22:19:02.93+0100 [App/0]   OUT [CONTAINER] org.apache.catalina.core.StandardService           INFO    Stopping service Catalina
2014-12-01T22:19:02.98+0100 [App/0]   OUT [CONTAINER] pache.webbeans.web.lifecycle.WebContainerLifecycle INFO    OpenWebBeans Container was stopped for context path, []
2014-12-01T22:19:03.04+0100 [App/0]   OUT [CONTAINER] org.apache.coyote.http11.Http11NioProtocol         INFO    Stopping ProtocolHandler ["http-nio-64570"]
2014-12-01T22:19:03.04+0100 [App/0]   OUT [CONTAINER] org.apache.coyote.http11.Http11NioProtocol         INFO    Destroying ProtocolHandler ["http-nio-64570"]
2014-12-01T22:19:03.13+0100 [App/0]   ERR 
2014-12-01T22:19:03.98+0100 [DEA]     OUT Stopping app instance (index 0) with guid be8a1ecc-a006-4554-8549-2606843734e7
2014-12-01T22:19:03.98+0100 [DEA]     OUT Stopped app instance (index 0) with guid be8a1ecc-a006-4554-8549-2606843734e7
2014-12-01T22:19:05.48+0100 [API]     OUT Updated app with guid be8a1ecc-a006-4554-8549-2606843734e7 ({"state"=>"STARTED"})
2014-12-01T22:19:05.49+0100 [DEA]     OUT Starting app instance (index 0) with guid be8a1ecc-a006-4554-8549-2606843734e7
2014-12-01T22:19:09.78+0100 [App/0]   OUT [CONTAINER] org.apache.coyote.http11.Http11NioProtocol         INFO    Initializing ProtocolHandler ["http-nio-63959"]
2014-12-01T22:19:09.79+0100 [App/0]   OUT [CONTAINER] org.apache.catalina.startup.Catalina               INFO    Initialization processed in 545 ms
2014-12-01T22:19:09.80+0100 [App/0]   OUT [CONTAINER] org.apache.catalina.core.StandardService           INFO    Starting service Catalina
2014-12-01T22:19:09.80+0100 [App/0]   OUT [CONTAINER] org.apache.catalina.core.StandardEngine            INFO    Starting Servlet Engine: Apache Tomcat/8.0.15
2014-12-01T22:19:09.82+0100 [App/0]   OUT [CONTAINER] org.apache.catalina.startup.HostConfig             INFO    Deploying web application directory /home/vcap/app/.java-buildpack/tomcat/webapps/ROOT
2014-12-01T22:19:09.88+0100 [App/0]   OUT [CONTAINER] org.apache.tomcat.util.digester.Digester           WARNING [SetContextPropertiesRule]{Context} Setting property 'antiJARLocking' to 'true' did not find a matching property.
2014-12-01T22:19:12.08+0100 [App/0]   OUT [CONTAINER] pache.webbeans.web.lifecycle.WebContainerLifecycle INFO    OpenWebBeans Container is starting...
2014-12-01T22:19:12.08+0100 [App/0]   OUT [CONTAINER] org.apache.webbeans.plugins.PluginLoader           INFO    Adding OpenWebBeansPlugin : [OpenWebBeansJsfPlugin]
2014-12-01T22:19:12.08+0100 [App/0]   OUT [CONTAINER] webbeans.corespi.scanner.AbstractMetaDataDiscovery INFO    added beans.xml marker: jar:file:/home/vcap/app/.java-buildpack/tomcat/webapps/ROOT/WEB-INF/lib/deltaspike-core-api-1.1.0.jar!/META-INF/beans.xml
2014-12-01T22:19:12.08+0100 [App/0]   OUT [CONTAINER] webbeans.corespi.scanner.AbstractMetaDataDiscovery INFO    added beans.xml marker: jar:file:/home/vcap/app/.java-buildpack/tomcat/webapps/ROOT/WEB-INF/lib/deltaspike-core-impl-1.1.0.jar!/META-INF/beans.xml
2014-12-01T22:19:12.08+0100 [App/0]   OUT [CONTAINER] webbeans.corespi.scanner.AbstractMetaDataDiscovery INFO    added beans.xml marker: jar:file:/home/vcap/app/.java-buildpack/tomcat/webapps/ROOT/WEB-INF/lib/deltaspike-jsf-module-impl-1.1.0.jar!/META-INF/beans.xml
2014-12-01T22:19:12.08+0100 [App/0]   OUT [CONTAINER] webbeans.corespi.scanner.AbstractMetaDataDiscovery INFO    added beans.xml marker: jar:file:/home/vcap/app/.java-buildpack/tomcat/webapps/ROOT/WEB-INF/lib/deltaspike-security-module-api-1.1.0.jar!/META-INF/beans.xml
2014-12-01T22:19:12.08+0100 [App/0]   OUT [CONTAINER] webbeans.corespi.scanner.AbstractMetaDataDiscovery INFO    added beans.xml marker: jar:file:/home/vcap/app/.java-buildpack/tomcat/webapps/ROOT/WEB-INF/lib/deltaspike-security-module-impl-1.1.0.jar!/META-INF/beans.xml
2014-12-01T22:19:12.08+0100 [App/0]   OUT [CONTAINER] webbeans.corespi.scanner.AbstractMetaDataDiscovery INFO    added beans.xml marker: jar:file:/home/vcap/app/.java-buildpack/tomcat/webapps/ROOT/WEB-INF/lib/deltaspike-jsf-module-api-1.1.0.jar!/META-INF/beans.xml
2014-12-01T22:19:12.09+0100 [App/0]   OUT [CONTAINER] webbeans.corespi.scanner.AbstractMetaDataDiscovery INFO    added beans.xml marker: file:/home/vcap/app/.java-buildpack/tomcat/webapps/ROOT/WEB-INF/beans.xml
2014-12-01T22:19:12.29+0100 [App/0]   OUT [CONTAINER] apache.deltaspike.core.util.ClassDeactivationUtils INFO    class: org.apache.deltaspike.jsf.impl.scope.mapped.MappedJsf2ScopeExtension activated=true
2014-12-01T22:19:12.30+0100 [App/0]   OUT [CONTAINER] apache.deltaspike.core.util.ClassDeactivationUtils INFO    class: org.apache.deltaspike.core.impl.jmx.MBeanExtension activated=true
2014-12-01T22:19:12.30+0100 [App/0]   OUT [CONTAINER] apache.deltaspike.core.util.ClassDeactivationUtils INFO    class: org.apache.deltaspike.core.impl.message.MessageBundleExtension activated=true
2014-12-01T22:19:12.31+0100 [App/0]   OUT [CONTAINER] apache.deltaspike.core.util.ClassDeactivationUtils INFO    class: org.apache.deltaspike.core.impl.message.NamedMessageBundleInvocationHandler activated=true
2014-12-01T22:19:12.31+0100 [App/0]   OUT [CONTAINER] apache.deltaspike.core.util.ClassDeactivationUtils INFO    class: org.apache.deltaspike.security.impl.extension.SecurityExtension activated=true
2014-12-01T22:19:12.31+0100 [App/0]   OUT [CONTAINER] apache.deltaspike.core.util.ClassDeactivationUtils INFO    class: org.apache.deltaspike.core.impl.scope.DeltaSpikeContextExtension activated=true
2014-12-01T22:19:12.31+0100 [App/0]   OUT [CONTAINER] apache.deltaspike.core.util.ClassDeactivationUtils INFO    class: org.apache.deltaspike.core.impl.config.ConfigurationExtension activated=true
2014-12-01T22:19:12.31+0100 [App/0]   OUT [CONTAINER] apache.deltaspike.core.util.ClassDeactivationUtils INFO    class: org.apache.deltaspike.jsf.impl.injection.proxy.ConverterAndValidatorProxyExtension activated=true
2014-12-01T22:19:12.31+0100 [App/0]   OUT [CONTAINER] apache.deltaspike.core.util.ClassDeactivationUtils INFO    class: org.apache.deltaspike.core.impl.exclude.extension.ExcludeExtension activated=true
2014-12-01T22:19:12.31+0100 [App/0]   OUT [CONTAINER] apache.deltaspike.core.util.ClassDeactivationUtils INFO    class: org.apache.deltaspike.core.impl.exclude.CustomProjectStageBeanFilter activated=true
2014-12-01T22:19:12.31+0100 [App/0]   OUT [CONTAINER] apache.deltaspike.core.util.ClassDeactivationUtils INFO    class: org.apache.deltaspike.core.impl.exclude.GlobalAlternative activated=true
2014-12-01T22:19:12.31+0100 [App/0]   OUT [CONTAINER] apache.deltaspike.core.util.ClassDeactivationUtils INFO    class: org.apache.deltaspike.core.impl.exception.control.extension.ExceptionControlExtension activated=true
2014-12-01T22:19:12.31+0100 [App/0]   OUT [CONTAINER] apache.deltaspike.core.util.ClassDeactivationUtils INFO    class: org.apache.deltaspike.jsf.impl.scope.view.ViewScopedExtension activated=true
2014-12-01T22:19:12.31+0100 [App/0]   OUT [CONTAINER] apache.deltaspike.core.util.ClassDeactivationUtils INFO    class: org.apache.deltaspike.jsf.impl.config.view.ViewConfigExtension activated=true
2014-12-01T22:19:12.33+0100 [App/0]   OUT [CONTAINER] g.apache.deltaspike.core.util.ProjectStageProducer INFO    Computed the following DeltaSpike ProjectStage: Production
2014-12-01T22:19:13.13+0100 [App/0]   OUT [CONTAINER] org.apache.webbeans.config.BeansDeployer           INFO    All injection points were validated successfully.
2014-12-01T22:19:13.16+0100 [App/0]   OUT [CONTAINER] pache.webbeans.web.lifecycle.WebContainerLifecycle INFO    OpenWebBeans Container has started, it took [1080] ms.
2014-12-01T22:19:13.16+0100 [App/0]   OUT [CONTAINER] apache.deltaspike.core.util.ClassDeactivationUtils INFO    class: org.apache.deltaspike.jsf.impl.config.view.ViewConfigPathValidator activated=true
2014-12-01T22:19:13.25+0100 [App/0]   OUT [CONTAINER] e.myfaces.config.DefaultFacesConfigurationProvider INFO    Reading standard config META-INF/standard-faces-config.xml
2014-12-01T22:19:13.54+0100 [App/0]   OUT [CONTAINER] e.myfaces.config.DefaultFacesConfigurationProvider INFO    Reading config /WEB-INF/faces-config.xml
2014-12-01T22:19:13.93+0100 [App/0]   OUT [CONTAINER] e.myfaces.config.DefaultFacesConfigurationProvider INFO    Reading config : jar:file:/home/vcap/app/.java-buildpack/tomcat/webapps/ROOT/WEB-INF/lib/deltaspike-jsf-module-impl-1.1.0.jar!/META-INF/faces-config.xml
2014-12-01T22:19:13.93+0100 [App/0]   OUT [CONTAINER] e.myfaces.config.DefaultFacesConfigurationProvider INFO    Reading config : jar:file:/home/vcap/app/.java-buildpack/tomcat/webapps/ROOT/WEB-INF/lib/openwebbeans-jsf-1.2.6.jar!/META-INF/faces-config.xml
2014-12-01T22:19:13.93+0100 [App/0]   OUT [CONTAINER] e.myfaces.config.DefaultFacesConfigurationProvider INFO    Reading config : jar:file:/home/vcap/app/.java-buildpack/tomcat/webapps/ROOT/WEB-INF/lib/primefaces-5.1.jar!/META-INF/faces-config.xml
2014-12-01T22:19:13.96+0100 [App/0]   OUT [CONTAINER] e.myfaces.config.DefaultFacesConfigurationProvider INFO    Reading config : jar:file:/home/vcap/app/.java-buildpack/tomcat/webapps/ROOT/WEB-INF/lib/openwebbeans-el22-1.2.6.jar!/META-INF/faces-config.xml
2014-12-01T22:19:14.09+0100 [App/0]   OUT [CONTAINER] org.apache.myfaces.config.LogMetaInfUtils          INFO    Artifact 'myfaces-api' was found in version '2.2.6' from path 'file:/home/vcap/app/.java-buildpack/tomcat/webapps/ROOT/WEB-INF/lib/myfaces-api-2.2.6.jar'
2014-12-01T22:19:14.09+0100 [App/0]   OUT [CONTAINER] org.apache.myfaces.config.LogMetaInfUtils          INFO    Artifact 'myfaces-impl' was found in version '2.2.6' from path 'file:/home/vcap/app/.java-buildpack/tomcat/webapps/ROOT/WEB-INF/lib/myfaces-impl-2.2.6.jar'
2014-12-01T22:19:14.10+0100 [App/0]   OUT [CONTAINER] org.apache.myfaces.util.ExternalSpecifications     INFO    MyFaces CDI support enabled
2014-12-01T22:19:14.10+0100 [App/0]   OUT [CONTAINER] e.myfaces.spi.impl.DefaultInjectionProviderFactory INFO    Using InjectionProvider org.apache.myfaces.spi.impl.CDIAnnotationDelegateInjectionProvider
2014-12-01T22:19:14.13+0100 [App/0]   OUT [CONTAINER] apache.deltaspike.core.util.ClassDeactivationUtils INFO    class: org.apache.deltaspike.jsf.impl.listener.action.DeltaSpikeActionListener activated=true
2014-12-01T22:19:14.13+0100 [App/0]   OUT [CONTAINER] apache.deltaspike.core.util.ClassDeactivationUtils INFO    class: org.apache.deltaspike.jsf.impl.resource.DeltaSpikeResourceHandler activated=true
2014-12-01T22:19:14.15+0100 [App/0]   OUT [CONTAINER] apache.deltaspike.core.util.ClassDeactivationUtils INFO    class: org.apache.deltaspike.jsf.impl.listener.system.JsfSystemEventBroadcaster activated=true
2014-12-01T22:19:14.16+0100 [App/0]   OUT [CONTAINER] org.apache.myfaces.util.ExternalSpecifications     INFO    MyFaces Bean Validation support disabled
2014-12-01T22:19:14.26+0100 [App/0]   OUT [CONTAINER] apache.deltaspike.core.util.ClassDeactivationUtils INFO    class: org.apache.deltaspike.jsf.impl.listener.request.DeltaSpikeLifecycleFactoryWrapper activated=true
2014-12-01T22:19:14.26+0100 [App/0]   OUT [CONTAINER] apache.deltaspike.core.util.ClassDeactivationUtils INFO    class: org.apache.deltaspike.jsf.impl.listener.phase.JsfRequestLifecyclePhaseListener activated=true
2014-12-01T22:19:14.26+0100 [App/0]   OUT [CONTAINER] apache.deltaspike.core.util.ClassDeactivationUtils INFO    class: org.apache.deltaspike.jsf.impl.listener.phase.DeltaSpikePhaseListener activated=true
2014-12-01T22:19:14.27+0100 [App/0]   OUT [CONTAINER] org.apache.myfaces.application.ApplicationImpl     INFO    Couldn't discover the current project stage, using Production
2014-12-01T22:19:14.27+0100 [App/0]   OUT [CONTAINER] org.apache.myfaces.config.FacesConfigurator        INFO    Serialization provider : class org.apache.myfaces.shared_impl.util.serial.DefaultSerialFactory
2014-12-01T22:19:14.27+0100 [App/0]   OUT [CONTAINER] .config.annotation.DefaultLifecycleProviderFactory INFO    Using LifecycleProvider org.apache.myfaces.config.annotation.Tomcat7AnnotationLifecycleProvider
2014-12-01T22:19:14.33+0100 [App/0]   OUT [CONTAINER] faces.webapp.PostConstructApplicationEventListener INFO    Running on PrimeFaces 5.1
2014-12-01T22:19:14.33+0100 [App/0]   OUT [CONTAINER] org.apache.myfaces.webapp.AbstractFacesInitializer INFO    ServletContext initialized.
2014-12-01T22:19:14.33+0100 [App/0]   OUT [CONTAINER] org.apache.myfaces.util.ExternalSpecifications     INFO    MyFaces Unified EL support enabled
2014-12-01T22:19:14.34+0100 [App/0]   OUT [CONTAINER] org.apache.myfaces.view.facelets.ViewPoolProcessor INFO    org.apache.myfaces.CACHE_EL_EXPRESSIONS web config parameter is set to "noCache". To enable view pooling this param must be set to "alwaysRecompile". View Pooling disabled.
2014-12-01T22:19:14.37+0100 [App/0]   OUT [CONTAINER] apache.deltaspike.core.util.ClassDeactivationUtils INFO    class: org.apache.deltaspike.jsf.impl.listener.request.DeltaSpikeFacesContextFactory activated=true
2014-12-01T22:19:14.38+0100 [App/0]   OUT [CONTAINER] org.apache.catalina.startup.HostConfig             INFO    Deployment of web application directory /home/vcap/app/.java-buildpack/tomcat/webapps/ROOT has finished in 4,557 ms
2014-12-01T22:19:14.38+0100 [App/0]   OUT [CONTAINER] org.apache.coyote.http11.Http11NioProtocol         INFO    Starting ProtocolHandler ["http-nio-63959"]
2014-12-01T22:19:14.39+0100 [App/0]   OUT [CONTAINER] org.apache.tomcat.util.net.NioSelectorPool         INFO    Using a shared selector for servlet write/read
2014-12-01T22:19:14.40+0100 [App/0]   OUT [CONTAINER] org.apache.catalina.startup.Catalina               INFO    Server startup in 4614 ms

(log on a @@cf restart testlp).

Emboldened by this somewhat easy start, I wanted to go further and to get up and running this other simple test app, dosleg-test, which also uses JPA 2.0, Hibernate 4.2 and PostgreSQL.

So, I followed the Deploying Community Services tutorial, starting with installing BOSH :

$ sudo apt-get install build-essential ruby ruby-dev libxml2-dev libsqlite3-dev libxslt1-dev libpq-dev libmysqlclient-dev
$ sudo gem install bosh_cli bosh_cli_plugin_micro

When I tried to install bosh, rubygems.org was unreachable, because of DNS problems. So, I set up my /etc/resolv.conf to use Google public DNS. At last, the domain was correctly resolved, but the gems where however not available on AWS...

So, I ended installing ElephantSQL, which claims to be PostgreSQL in the cloud, using Pivotal console.

Once this is done, you can "manage" this service. On the "management" page, the first provided info is the DB URL, which is like :

URL	postgres://<login>:<postgresql>@<host:port>/<instance>
/

We shall use

  • <host:port>/<instance> as JNDI URL
  • login as... login
  • password as... password (really).

Then, we deploy the app

$ LANG=C cf push dosleg-test -p target/dosleg-test##1.1-SNAPSHOT.war 
Updating app dosleg-test in org lpenet / space development as ludovic@penet.org...
OK

Uploading dosleg-test...
Uploading app files from: target/dosleg-test##1.1-SNAPSHOT.war
Uploading 676.1K, 48 files
Done uploading               
OK

Stopping app dosleg-test in org lpenet / space development as ludovic@penet.org...
OK

Starting app dosleg-test in org lpenet / space development as ludovic@penet.org...
-----> Downloaded app package (16M)
-----> Downloaded app buildpack cache (46M)
-----> Java Buildpack Version: v2.5 | https://github.com/cloudfoundry/java-buildpack.git#840500e
-----> Downloading Open Jdk JRE 1.8.0_25 from https://download.run.pivotal.io/openjdk/lucid/x86_64/openjdk-1.8.0_25.tar.gz (found in cache)
       Expanding Open Jdk JRE to .java-buildpack/open_jdk_jre (1.9s)
-----> Downloading Tomcat Instance 8.0.15 from https://download.run.pivotal.io/tomcat/tomcat-8.0.15.tar.gz (found in cache)
       Expanding Tomcat to .java-buildpack/tomcat (0.2s)
-----> Downloading Tomcat Lifecycle Support 2.4.0_RELEASE from https://download.run.pivotal.io/tomcat-lifecycle-support/tomcat-lifecycle-support-2.4.0_RELEASE.jar (found in cache)
-----> Downloading Tomcat Logging Support 2.4.0_RELEASE from https://download.run.pivotal.io/tomcat-logging-support/tomcat-logging-support-2.4.0_RELEASE.jar (found in cache)
-----> Downloading Tomcat Access Logging Support 2.4.0_RELEASE from https://download.run.pivotal.io/tomcat-access-logging-support/tomcat-access-logging-support-2.4.0_RELEASE.jar (found in cache)

-----> Uploading droplet (60M)

0 of 1 instances running, 1 starting
1 of 1 instances running

App started


OK
Showing health and status for app dosleg-test in org lpenet / space development as ludovic@penet.org...
OK

requested state: started
instances: 1/1
usage: 1G x 1 instances
urls: dosleg-test.cfapps.io
last uploaded: Mon Dec 1 22:48:39 +0000 2014

     state     since                    cpu    memory         disk   
#0   running   2014-12-01 11:49:41 PM   0.0%   421.3M of 1G   126.6M of 1G   

...and it just runs.

It has an high latency as Pivotal Web Services are accross the ocean, but it is still quite acceptable.

Conclusion

My favorite application stack just works out of the box on CloudFoundry. Given the enormous amount of documentation available on this software, the fact that it can manage AWS, vSphere, etc. nodes, I have no doubts it can fulfill all my needs. A private PaaS offer is available. I only wonder whether I can CloudFoundry usable enough for a fluid development experience.

It seems that I am not the only one to find some edges of CloudFoundry a bit rough... Several offers of PaaS based on CloudFoundry emerged those last month, including Atos Canopy, Stackato, AppFog, and IBM BlueMix. SAP also has a strong interest in CloudFoundry.

JSF in the cloud : Finding the PaaS - Part 3 : Jelastic

Introduction

I found Jelastic while googling for TomEE PaaS offerings. I found an article on jaxenter featuring a quote from David Blevins, a founder of Apache TomEE :

“They have put a significant amount of time into offering TomEE users the best experience possible. It’s very tightly integrated with the functionality of all the other layers of their stack including load-balancing, replication, persistence to SQL or NoSQL databases and more.”

So, I signed up for a two-week free trial offering me to try:

  • 1 environments per account
  • 2 app servers per environment
  • 2 cloudlets per app server
  • 1 GB storage per app server

Jelastic partnered with 30 hosting services across the world. They proposed me to test their offer on a French hosting service, lunacloud.

It just works

Creating an environment takes a few minutes. Deploying the first sample app too. Then you are proposed a link to do what you really want to do : deploy your own application as a WAR or with git and maven.

My simple test app immediatly worked. I set it up in a git repo on github. It just deployed and worked. Slowly because the default free test config has no muscle, but that is not an issue.

Maven plugin

Jelastic provides a maven plugin. Using it, I could setup an automatic deployment on the server.

This is performed when you

mvn -Pjelastic clean deploy

on this github project.

This pom.xml also automatically publishes release artefaces on github (or when the deploy-github profile is activated).

Netbeans plugin

Jelastic officially provides a netbeans plugin.

The plugin allows full control of the environments and claims to support remote debugging. I wanted to test this feature and tried to upgrade to a regular account. With LunaCloud, it involved paperwork such as sending a copy of my ID, electricity bill and credit card, which I really did not want to do for a simpletest. So, I switched to Magic.fr Jelastic offer. The version of Jelastic it provides seems a bit older, but I could pay for an account without providing a DNA sample... However, even when paying and activating the public IPv4 address feature, I still could not perform remote debugging.

Conclusion

Jelastic fulfilled all my requirements, with no hassle. It is definitely an offer I would consider if I have to use a PaaS for serious things. It seems to provide everything I can expect in a cloud environment in terms of load balancing, database replication, and so on. I tried to use a nginx and performed smoothly vertical and horizontal scaling, transparently.

I even went a bit further than my initial, very restricted test, and coded a (little) more advanced one, dosleg-test. I performed the quick scaling tests with this last project. This test uses data provided by the French Senate on its opendata platform (full disclosure : as of the writing of this note, I am working there). I just sampled it to make an auto-deployable test case. It is a bit slow on startup because it must create the database schema then insert thousands of records, but it performs quite well then. Moreover, no platform specific API is used, just plain JEE6 MyFaces 2.2 / DeltaSpike 1.1 / OpenWebBeans 1.2.6 / JPA 2.0 / Hibernate 4.2 / PrimeFaces 5.1.

To use it, you will have to provide a profile such as :

    <profile>
      <id>jelastic</id>
      <properties>
          <jelastic.login>yourmain@yourdomain</jelastic.login>
          <jelastic.password>password</jelastic.password>
          <jelastic.testcontext>context</jelastic.testcontext>
          <jelastic.testenvironment>environment</jelastic.testenvironment>
          <jelastic.api_hoster>api of your hosting service</jelastic.api_hoster>
          <dosleg.url>URL of your hosted pgsql instance</dosleg.url>
          <dosleg.user>db user</dosleg.user>
          <dosleg.password>db password</dosleg.password>
      </properties>
    </profile>

and define your github server profile :

    <server>
      <id>github</id>
      <username>your_account</username>
      <password>your_password</password>
    </server>

...then deploy it using

mvn -PJelastic clean deploy

or build then upload the war file using the admin panel.

Jelastic is also available as a private cloud offering, claims to offer an ssh access and other key features.

JSF in the cloud : Finding the PaaS - Part 2 : OpenShift

Introduction

OpenShift is Red Hat cloud offering.

Like Google App Engine (GAE), it supports many languages. It is newer than GAE and can not claim that it is used to run a performance monster like the Google Search Engine.

Its specification sheet looked very interesting to me for many reasons :

  • It is fully free software ;
  • It is standard based ;
  • It proposes Tomcat 6 or 7 as webapp container ;
  • Private cloud offering is not a third party project. It is in the main offering.

Moreover :

  • Its free offer includes 3 apps, 3 "small gears" (~3 VMS), access to a database instance. With a free account, you can have a jenkins instance, for continuous integration, a "gear" for your webapp and use a PostgreSQL database.
  • It gives you extensive control on the configuration of the webapp container. You can even use a custom realm by putting the realm's jar and dependencies (ex: a DB driver) in a custom dir and then adding it to the path in a catalina.properties file (see this blog entry for a detailed explanation).

In fact, I could not find a thing that I usually do that I could not do with OpenShift. I still have to check if I can do parallel deployment with it, but it might not be relevant in a cloud based app, where one might instanciate VMs running the new version rather than upgrading running instances.

After some (simple but blocking) configuration trouble, OpenShift delivers. It is both fast and convenient. It clearly is a very interesting alternative for running a PrimeFaces / MyFaces / Deltaspike / OpenWebBeans stack.

Tomcat 7 cartridge

Once you have created an account and installed rhc client tools, instantiating a VM (a "gear") having Tomcat 7 and PostgreSQL 9.2 is as simple as :

lpenet@boulier:~/openshift$ rhc app create testlp jbossews-2.0 postgresql-9.2
Application Options
-------------------
Domain:     penet
Cartridges: jbossews-2.0, postgresql-9.2
Gear Size:  default
Scaling:    no

Creating application 'testlp' ... done

  PostgreSQL 9.2 database added.  Please make note of these credentials:

   Root User: not-your-business
   Root Password: not-your-business-too
   Database Name: testlp

Connection URL: postgresql://$OPENSHIFT_POSTGRESQL_DB_HOST:$OPENSHIFT_POSTGRESQL_DB_PORT

Waiting for your DNS name to be available ... done

Clonage dans 'testlp'...
The authenticity of host 'testlp-penet.rhcloud.com (54.166.197.252)' can't be established.
RSA key fingerprint is cf:ee:77:cb:0e:fc:02:d7:72:7e:ae:80:c0:90:88:a7.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added 'testlp-penet.rhcloud.com,54.166.197.252' (RSA) to the list of known hosts.

Your application 'testlp' is now available.

  URL:        http://testlp-penet.rhcloud.com/
  SSH to:     547208c94382eccd73000002@testlp-penet.rhcloud.com
  Git remote: ssh://547208c94382eccd73000002@testlp-penet.rhcloud.com/~/git/testlp.git/
  Cloned to:  /home/lpenet/openshift/testlp

Run 'rhc show-app testlp' for more details about your app.

You can use your usual tools, such as pgadmin3 to admin the database. To do so, just create port forwardings, in crypted tunnels using

lpenet@boulier:~/openshift$ rhc port-forward testlp
Checking available ports ... done
Forwarding ports ...
Address already in use - bind(2) while forwarding port 5432. Trying local port 5433

To connect to a service running on OpenShift, use the Local address

Service    Local               OpenShift
---------- -------------- ---- ----------------
java       127.0.0.1:8080  =>  127.4.111.1:8080
postgresql 127.0.0.1:5433  =>  127.4.111.2:5432

Press CTRL-C to terminate port forwarding

then connect pgadmin3 to the server listening on host 127.0.0.1 port 5433 (in this case).

As you could see, the rhc app create testlp jbossews-2.0 postgresql-9.2 automatically pulled the app source code.

The default source tree is quite small, as for GAE :

lpenet@boulier:~/openshift/testlp$ tree
.
├── pom.xml
├── README.md
├── src
│   └── main
│       ├── java
│       ├── resources
│       └── webapp
│           ├── images
│           │   └── jbosscorp_logo.png
│           ├── index.html
│           ├── snoop.jsp
│           └── WEB-INF
│               └── web.xml
└── webapps

There are no IDE specific files there, as for GAE. Application deployment is mostly handled by git.

The default pom.xml is quite simple :

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>testlp</groupId>
	<artifactId>testlp</artifactId>
	<packaging>war</packaging>
	<version>1.0</version>
	<name>testlp</name>
	<repositories>
		<repository>
			<id>eap</id>
			<url>http://maven.repository.redhat.com/techpreview/all</url>
			<releases>
				<enabled>true</enabled>
			</releases>
			<snapshots>
				<enabled>true</enabled>
			</snapshots>
		</repository>
	</repositories>
	<pluginRepositories>
		<pluginRepository>
			<id>eap</id>
			<url>http://maven.repository.redhat.com/techpreview/all</url>
			<releases>
				<enabled>true</enabled>
			</releases>
			<snapshots>
				<enabled>true</enabled>
			</snapshots>
		</pluginRepository>
	</pluginRepositories>
	<properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<maven.compiler.source>1.6</maven.compiler.source>
		<maven.compiler.target>1.6</maven.compiler.target>
	</properties>
	<dependencies>
		<dependency>
			<groupId>org.postgresql</groupId>
			<artifactId>postgresql</artifactId>
			<version>9.2-1003-jdbc4</version>
		</dependency>
		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
			<version>5.1.25</version>
		</dependency>     
		<dependency>
			<groupId>javax.servlet</groupId>
			<artifactId>javax.servlet-api</artifactId>
			<version>3.0.1</version>
			<scope>provided</scope>
		</dependency>
	</dependencies>
	<profiles>
		<profile>
			<!-- When built in OpenShift the 'openshift' profile will be used when 
				invoking mvn. -->
			<!-- Use this profile for any OpenShift specific customization your app 
				will need. -->
			<!-- By default that is to put the resulting archive into the 'webapps' 
				folder. -->
			<!-- http://maven.apache.org/guides/mini/guide-building-for-different-environments.html -->
			<id>openshift</id>
			<build>
				<finalName>testlp</finalName>
				<plugins>
					<plugin>
						<artifactId>maven-war-plugin</artifactId>
						<version>2.1.1</version>
						<configuration>
							<outputDirectory>webapps</outputDirectory>
							<warName>ROOT</warName>
						</configuration>
					</plugin>
				</plugins>
			</build>
		</profile>
	</profiles>
</project>

It only adds Red Hat repositories, usual JDBC drivers and servlet 3.0 API spec.

Compared to GAE, we can see that it is Java 6 (7 for GAE) and Servlet API 3.0 (2.5 for GAE).

So, Java 6 seems to be the default choice. We can also request java 7 by adding a marker in the .openshift/markers directory. In fact, as this marker is present by default in the Tomcat7 cartridge, java7 is used by default with Tomcat 7 and we can safely upgrade to java version 1.7 in the pom.xml.

Having Servlet API 3.0 is more important, as it is the official target of MyFaces 2.2. Having Servlet API 2.5 instead of 3.0 introduces very few JSF related restrictions (I can think of nothing excepted file upload), but this might change and can avoid annoying "bugs", as with MyFaces 2.2.5 which used an API available only in servlet API 3.0 (see MYFACES-3923).

I tried to configure the test project in a way similar to what I did for GAE, just removing the JNDI hacks.

I had a hard time getting it up and running, for a simple (once you found it) reason : the jbossews-2.0 cartridge default config does not unpack application WAR archives. And this blocks OpenWebBeans and other libraries like Weld that I tested from running. They did not find my beans, did not instantiate them, so it did not work.

The fix is simple : edit the .openshift/config/server.xml file so that unpackWARs is set to true :

    <Host name="localhost"  appBase="webapps"
        unpackWARs="true" autoDeploy="true">

I wonder why this is the default config of this cartridge. This is not a usual way to proceed with tomcat. Anyway, it works fine. You can find the project under git.

Getting my a bit-more-complexe example, which also uses JPA, Hibernate and JNDI was very simple too, once you unpack the war. I just added the following openshift profile :

		<profile>
			<!-- When built in OpenShift the 'openshift' profile will be used when 
				invoking mvn. -->
			<!-- Use this profile for any OpenShift specific customization your app 
				will need. -->
			<!-- By default that is to put the resulting archive into the 'webapps' 
				folder. -->
			<!-- http://maven.apache.org/guides/mini/guide-building-for-different-environments.html -->
			<id>openshift</id>
			<properties>
			  <dosleg.url>jdbc:postgresql://${env.OPENSHIFT_POSTGRESQL_DB_HOST}/doslegtest</dosleg.url>
			  <dosleg.user>dosleg</dosleg.user>
			  <dosleg.password>dosleg</dosleg.password>
			</properties>
			<build>
				<finalName>doslegtest</finalName>
				<plugins>
					<plugin>
						<artifactId>maven-war-plugin</artifactId>
						<version>2.1.1</version>
						<configuration>
							<outputDirectory>webapps</outputDirectory>
							<warName>ROOT</warName>
						</configuration>
					</plugin>
				</plugins>
			</build>
		</profile>

It is a copy/paste of the default openshift profile, plus adjusting dosleg.* properties, leveraging openshift vars. DB user and password are hard coded there. Using environment variables would be straightforward.

Debugging

The documentation suggests to forward ports, using the rhc port-forward, then to attach your debugger on the forwarded 8787 port. This is both a bit frustrating when you have to debug start-up related problems and just hell slow for all other purposes.

Red Hat suggests to install the free software openshift origin on premises for development. Doing so solves the slowness problem, but still does not a development environment as polished as GAE or Heroku. With those two lasts, you can easily easily and automatically download and run the exact same software versions used on the server.

I, however, have been using untared versions of Tomcat to develop webapps deployed on production systems using Red Hat packages versions for years without many real problems. So, it might not be such a big deal.

There is no openshift netbeans plugin. However, some people at Oracle seems to think that it would be very easy to develop one.

Other cartridges : Tomcat 7 community cartridge, WildFly and TomEE

Another option with OpenShift is to use another Java Web cartridge. OpenShift provides a JBoss 7.1 cartridge. JBoss can be an interesting alternative to me. It is Tomcat based, so I can recycle my knowledge of its security mechanisms, such as realms. However, JBoss 7.1 is not JSF 2.2. So, it is not an up to date alternative.

We can, of course, use a community cartridge. There is a community tomcat 7 cartridge (and of course a community tomcat 8 cartridge). Romain Manni Bucau documented how to build a TomEE cartridge (which is basically the same stack I use) . But all those cartridges do not get automatic security updates from Open Shift, which is a major drawback.

I played a bit with OpenShift WildFly cartridge. It is a tempting alternative, as WildFly 8 is a JEE7. It is not the same stack (Mojarra instead of MyFaces and Weld instead of OpenWebBeans), but this can be acceptable in some circumstances, as it also neatly integrates DeltaSpike and uses Tomcat 7 as container, so that I can recycle what I know on security. The experience proved interesting. The pom.xml is quite simple :

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>wildfly8</groupId>
    <artifactId>wildfly8</artifactId>
    <packaging>war</packaging>
    <version>1.0</version>
    <name>wildfly8</name>
  
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.7</maven.compiler.source>
        <maven.compiler.target>1.7</maven.compiler.target>
        <maven.compiler.fork>true</maven.compiler.fork>
        <version.jboss.spec.javaee.7.0>1.0.0.Final</version.jboss.spec.javaee.7.0>
        <version.wildfly.maven.plugin>1.0.2.Final</version.wildfly.maven.plugin>
    </properties>
    
    <dependencyManagement>
        <dependencies>
            <!-- Define the version of JBoss' Java EE 7 APIs we want to import.
               Any dependencies from org.jboss.spec will have their version defined by this
               BOM -->
            <!-- JBoss distributes a complete set of Java EE 7 APIs including
               a Bill of Materials (BOM). A BOM specifies the versions of a "stack" (or
               a collection) of artifacts. We use this here so that we always get the correct
               versions of artifacts. Here we use the jboss-javaee-7.0 stack (you can
               read this as the JBoss stack of the Java EE 7 APIs). You can actually
               use this stack with any version of WildFly that implements Java EE 7, not
               just WildFly 8! -->
            <dependency>
                <groupId>org.jboss.spec</groupId>
                <artifactId>jboss-javaee-7.0</artifactId>
                <version>${version.jboss.spec.javaee.7.0}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <dependencies>
        <dependency>
            <groupId>javax.enterprise</groupId>
            <artifactId>cdi-api</artifactId>
            <scope>provided</scope>
        </dependency>

        <dependency>
            <groupId>org.jboss.spec.javax.annotation</groupId>
            <artifactId>jboss-annotations-api_1.2_spec</artifactId>
            <scope>provided</scope>
        </dependency>

        <dependency>
            <groupId>org.jboss.spec.javax.faces</groupId>
            <artifactId>jboss-jsf-api_2.2_spec</artifactId>
            <scope>provided</scope>
        </dependency>

        <dependency>
            <groupId>org.jboss.spec.javax.ejb</groupId>
            <artifactId>jboss-ejb-api_3.2_spec</artifactId>
            <scope>provided</scope>
        </dependency>

	<dependency>
	  <groupId>org.projectlombok</groupId>
	  <artifactId>lombok</artifactId>
	  <version>1.14.4</version>
	  <scope>provided</scope>
	</dependency>

    <!-- primefaces -->
    <dependency>
      <groupId>org.primefaces</groupId>
      <artifactId>primefaces</artifactId>
      <version>5.1</version>
      <type>jar</type>
    </dependency>
    </dependencies>

<profiles>
    <profile>
     <!-- When built in OpenShift the 'openshift' profile will be used when invoking mvn. -->
     <!-- Use this profile for any OpenShift specific customization your app will need. -->
     <!-- By default that is to put the resulting archive into the 'deployments' folder. -->
     <!-- http://maven.apache.org/guides/mini/guide-building-for-different-environments.html -->
     <id>openshift</id>
     <build>
        <finalName>${project.artifactId}</finalName>
        <plugins>
          <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-war-plugin</artifactId>
                <version>2.3</version>
                <configuration>
                    <failOnMissingWebXml>false</failOnMissingWebXml>
                    <outputDirectory>deployments</outputDirectory>
              		  <warName>ROOT</warName>
                </configuration>
            </plugin>
        </plugins>
      </build>
    </profile>
    <profile>
        <activation>
            <activeByDefault>true</activeByDefault>
        </activation>
    <build>
        <plugins>
            <!-- WildFly plugin to deploy war -->
            <plugin>
                <groupId>org.wildfly.plugins</groupId>
                <artifactId>wildfly-maven-plugin</artifactId>
                <version>${version.wildfly.maven.plugin}</version>
                <configuration>
                    <skip>false</skip>
                </configuration>
            </plugin>

        </plugins>
    </build>

    </profile>
  </profiles>
</project>

The web.xml too :

<?xml version="1.0" encoding="UTF-8"?>

<web-app version="3.1"
         xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
         metadata-complete="false">
    <display-name>Hello JSF</display-name>
    <welcome-file-list>
        <welcome-file>accueil.xhtml</welcome-file>
    </welcome-file-list>
   <servlet>
        <servlet-name>Faces Servlet</servlet-name>
        <servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>Faces Servlet</servlet-name>
        <url-pattern>*.xhtml</url-pattern>
    </servlet-mapping>
</web-app>

Locally debugging seems as simple as downloading and unpacking Wildfly 8 archive then fire your favorite debugger. There is a Netbeans plugin that makes this very easy. However, it seemed as easy to do the same for Tomcat 7 and proved wrong... :-/



WildFly configuration seems very similar to Tomcat configuration, the main difference being that there is no more context.xml file. An example of JNDI configuration port is available here and here. There even seems to be a book on the topic of Tomcat to WildFly migration.

Conclusion

OpenShift is a good option for my java stack. I could get my PrimeFaces / MyFaces / Deltaspike / OpenWebBeans stack to run on their JBoss EWS 2.0 Tomcat 7 cartridge. Other cartridges seem interesting, but they lack automatic security upgrades, which I expect from a PaaS offering.



The only problem seems to be the debugging experience. After a few years of developement with Tomcat, I tend to think that it can be quite acceptable. Real developement could be performed with a local Tomcat 7 server. Final tests could be performed on a developement OpenShift system, using OpenShift Origin.

JSF in the cloud : Finding the PaaS - Part 1 : Google App Engine

Short intro

Google App Engine is google PaaS offer. It is a fully managed PaaS. It promises automatic load balancing and handling. Given the identity of the provider, I tend to think it works.

To use Google App Engine, you must have a Google Account. Then, you can access some free offers. Currently, this incudes USD 300 in credit to spend on all Cloud Platform products over 60 days.

The simpliest way to go IMO is to follow the official "Getting started".

The only official technical requirements are Maven 3.1 and Java 7 (which are both pretty much standard).

Creating a project

Your new project will be created in two steps :

For maven users, this is just straightforward.

I created and lptestgcloud2 app in my free account then generated the app skeleton with :

mvn archetype:generate -Dappengine-version=1.9.15 -Dapplication-id=lptestgcloud2 -Dfilter=com.google.appengine.archetypes:

and chosing the first proposal :

com.google.appengine.archetypes:appengine-skeleton-archetype

Full log :

Choose archetype:
1: remote -> com.google.appengine.archetypes:appengine-skeleton-archetype (A skeleton application with Google App Engine)
2: remote -> com.google.appengine.archetypes:endpoints-skeleton-archetype (A skeleton project using Cloud Endpoints with Google App Engine Java)
3: remote -> com.google.appengine.archetypes:guestbook-archetype (A guestbook application with Google App Engine)
4: remote -> com.google.appengine.archetypes:hello-endpoints-archetype (A simple starter application using Cloud Endpoints with Google App Engine Java)
5: remote -> com.google.appengine.archetypes:skeleton-archetype (-)
Choose a number or apply filter (format: [groupId:]artifactId, case sensitive contains): : 1
Choose com.google.appengine.archetypes:appengine-skeleton-archetype version: 
1: 1.8.7
2: 2.0.0-1.9.10
Choose a number: 2: 
Define value for property 'groupId': : fr.penet
Define value for property 'artifactId': : testgcloud2
Define value for property 'version':  1.0-SNAPSHOT: : 
Define value for property 'package':  fr.penet: : 
[INFO] Using property: appengine-version = 1.9.15
[INFO] Using property: application-id = lptestgcloud2
Confirm properties configuration:
groupId: fr.penet
artifactId: testgcloud2
version: 1.0-SNAPSHOT
package: fr.penet
appengine-version: 1.9.15
application-id: lptestgcloud2

The following source tree is generated :

── eclipse-launch-profiles
│   ├── DevAppServer.launch
│   └── UpdateApplication.launch
├── nbactions.xml
├── pom.xml
├── README.md
└── src
    ├── main
    │   ├── java
    │   └── webapp
    │      └── WEB-INF
    │           ├── appengine-web.xml
    │           ├── logging.properties
    │           └── web.xml
    └── test

eclipse-launch-profiles files are used by eclipse to provide shortcuts to debug and publication of the app. As I prefer netbeans to eclipse, the nbactions.xml file is more interesting to me. It contains custom actions that will be proposed for the project under this IDE.

netbeans is not officially supported, but, in addition to the nbactions.xml file, one can use the gaelyk plugin. Its latest version, for Netbeans 7.4, is compatible with Netbeans 8. With this plugin, you can test, debug, profile and upload your webapp.

The original pom.xml is quite short :

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

    <modelVersion>4.0.0</modelVersion>
    <packaging>war</packaging>
    <version>1.0-SNAPSHOT</version>

    <groupId>fr.penet</groupId>
    <artifactId>testgcloud2</artifactId>

    <properties>
        <appengine.app.version>1</appengine.app.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <prerequisites>
        <maven>3.1.0</maven>
    </prerequisites>

    <dependencies>
        <!-- Compile/runtime dependencies -->
        <dependency>
            <groupId>com.google.appengine</groupId>
            <artifactId>appengine-api-1.0-sdk</artifactId>
            <version>1.9.15</version>
        </dependency>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>servlet-api</artifactId>
            <version>2.5</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>jstl</groupId>
            <artifactId>jstl</artifactId>
            <version>1.2</version>
        </dependency>

        <!-- Test Dependencies -->
        <dependency>
            <groupId>com.google.appengine</groupId>
            <artifactId>appengine-testing</artifactId>
            <version>1.9.15</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>com.google.appengine</groupId>
            <artifactId>appengine-api-stubs</artifactId>
            <version>1.9.15</version>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <!-- for hot reload of the web application-->
        <outputDirectory>${project.build.directory}/${project.build.finalName}/WEB-INF/classes</outputDirectory>
        <plugins>
            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>versions-maven-plugin</artifactId>
                <version>2.1</version>
                <executions>
                    <execution>
                        <phase>compile</phase>
                        <goals>
                            <goal>display-dependency-updates</goal>
                            <goal>display-plugin-updates</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <version>3.1</version>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>1.7</source>
                    <target>1.7</target>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-war-plugin</artifactId>
                <version>2.4</version>
                <configuration>
                    <archiveClasses>true</archiveClasses>
                    <webResources>
                        <!-- in order to interpolate version from pom into appengine-web.xml -->
                        <resource>
                            <directory>${basedir}/src/main/webapp/WEB-INF</directory>
                            <filtering>true</filtering>
                            <targetPath>WEB-INF</targetPath>
                        </resource>
                    </webResources>
                </configuration>
            </plugin>

            <plugin>
                <groupId>com.google.appengine</groupId>
                <artifactId>appengine-maven-plugin</artifactId>
                <version>1.9.15</version>
                <configuration>
                    <enableJarClasses>false</enableJarClasses>
                    <!-- Comment in the below snippet to bind to all IPs instead of just localhost -->
                    <!-- address>0.0.0.0</address>
                    <port>8080</port -->
                    <!-- Comment in the below snippet to enable local debugging with a remove debugger
                         like those included with Eclipse or IntelliJ -->
                    <!-- jvmFlags>
                      <jvmFlag>-agentlib:jdwp=transport=dt_socket,address=8000,server=y,suspend=n</jvmFlag>
                    </jvmFlags -->
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

Dependencies on com.google.appengine:appengine-api-1.0-sdk:1.9.15, javax.servlet:servlet-api:2.5 and jstl:jstl:1.2 , a few plugins configuration and that's all.

Adding the stack components

First thing is to add dependencies to MyFaces 2.2.6, Primefaces 5.1, Deltaspike 1.1 and OpenWebBeans 1.2.7-SNAPSHOT.

    <!-- JSF -->
    <dependency>
      <groupId>org.apache.myfaces.core</groupId>
      <artifactId>myfaces-api</artifactId>
      <version>2.2.6</version>
      <scope>compile</scope>
    </dependency>
    <dependency>
      <groupId>org.apache.myfaces.core</groupId>
      <artifactId>myfaces-impl</artifactId>
      <version>2.2.6</version>
      <scope>runtime</scope>
    </dependency>


    <!-- primefaces -->
    <dependency>
      <groupId>org.primefaces</groupId>
      <artifactId>primefaces</artifactId>
      <version>5.1</version>
      <type>jar</type>
    </dependency>

    <!-- Specifications -->
    <!-- JSR-330 -->
    <dependency>
      <groupId>org.apache.geronimo.specs</groupId>
      <artifactId>geronimo-atinject_1.0_spec</artifactId>
      <version>1.0</version>
      <scope>compile</scope>
    </dependency>
    
    <!-- JSR-299 -->
    <dependency>
      <groupId>org.apache.geronimo.specs</groupId>
      <artifactId>geronimo-jcdi_1.0_spec</artifactId>
      <version>1.0</version>
      <scope>compile</scope>
    </dependency>
    
    <dependency>
      <groupId>org.apache.geronimo.specs</groupId>
      <artifactId>geronimo-interceptor_1.1_spec</artifactId>
      <version>1.0</version>
      <scope>compile</scope>
    </dependency>
    <dependency>
      <groupId>org.apache.geronimo.specs</groupId>
      <artifactId>geronimo-validation_1.0_spec</artifactId>
      <version>1.1</version>
      <scope>compile</scope>
    </dependency>

    <dependency>
      <groupId>org.apache.geronimo.specs</groupId>
      <artifactId>geronimo-servlet_3.0_spec</artifactId>
      <version>1.0</version>
      <scope>provided</scope>
    </dependency>

    <dependency>
      <groupId>org.apache.geronimo.specs</groupId>
      <artifactId>geronimo-el_2.2_spec</artifactId>
      <version>1.0.4</version>
      <scope>provided</scope>
    </dependency>

    <dependency>
      <groupId>org.apache.geronimo.specs</groupId>
      <artifactId>geronimo-jsp_2.1_spec</artifactId>
      <version>1.0.1</version>
    </dependency>

     <!-- OpenWebBeans -->
    <dependency>
      <groupId>org.apache.openwebbeans</groupId>
      <artifactId>openwebbeans-impl</artifactId>
      <version>1.2.7-SNAPSHOT</version>
      <scope>runtime</scope>
    </dependency>

    <dependency>
      <groupId>org.apache.openwebbeans</groupId>
      <artifactId>openwebbeans-jsf</artifactId>
      <version>1.2.7-SNAPSHOT</version>
      <scope>runtime</scope>
    </dependency>

    <dependency>
      <groupId>org.apache.openwebbeans</groupId>
      <artifactId>openwebbeans-web</artifactId>
      <version>1.2.7-SNAPSHOT</version>
      <scope>runtime</scope>
    </dependency>

    <dependency>
      <groupId>org.apache.openwebbeans</groupId>
      <artifactId>openwebbeans-spi</artifactId>
      <version>1.2.7-SNAPSHOT</version>
      <scope>runtime</scope>
    </dependency>

    <dependency>
      <groupId>org.apache.openwebbeans</groupId>
      <artifactId>openwebbeans-el22</artifactId>
      <version>1.2.7-SNAPSHOT</version>
    </dependency>

    <dependency>
      <groupId>org.apache.xbean</groupId>
      <artifactId>xbean-asm4-shaded</artifactId>
      <version>3.15</version>
    </dependency>

    <dependency>
        <groupId>org.apache.deltaspike.core</groupId>
        <artifactId>deltaspike-core-api</artifactId>
        <version>1.1.0</version>
    </dependency>
    <dependency>
        <groupId>org.apache.deltaspike.core</groupId>
        <artifactId>deltaspike-core-impl</artifactId>
        <version>1.1.0</version>
        <scope>runtime</scope>
    </dependency>
    <dependency>
        <groupId>org.apache.deltaspike.modules</groupId>
        <artifactId>deltaspike-jsf-module-api</artifactId>
        <version>1.1.0</version>
    </dependency>
    <dependency>
        <groupId>org.apache.deltaspike.modules</groupId>
        <artifactId>deltaspike-jsf-module-impl</artifactId>
        <version>1.1.0</version>
        <scope>runtime</scope>
    </dependency>
    <dependency>
        <groupId>org.apache.deltaspike.modules</groupId>
        <artifactId>deltaspike-security-module-api</artifactId>
        <version>1.1.0</version>
    </dependency>
    <dependency>
        <groupId>org.apache.deltaspike.modules</groupId>
        <artifactId>deltaspike-security-module-impl</artifactId>
        <version>1.1.0</version>
        <scope>runtime</scope>
    </dependency>
    <dependency>
        <groupId>org.apache.deltaspike.modules</groupId>
        <artifactId>deltaspike-bean-validation-module-api</artifactId>
        <version>1.1.0</version>
    </dependency>
    <dependency>
        <groupId>org.apache.deltaspike.modules</groupId>
        <artifactId>deltaspike-bean-validation-module-impl</artifactId>
        <version>1.1.0</version>
        <scope>runtime</scope>
    </dependency>

I use Primefaces 5.1 there only because it is the latest community version available. It is however crucial to use the version I indicate or later for the other packages :

  • MyFaces 2.2.6 corrects MYFACES-3923 . As Google App Engine is "only" servlet spec 2.5, it is required. GAE being servlet 2.5 rather than 3.0 is not big deal.I can see no other feature than jsf file upload that will not work, and other solutions are available.
  • OpenWebBeans 1.2.6 does not work because it uses sun.misc.Unsafe. Google App Engine uses a somewhat strict whitelist mechanism, which prevents access to this class. In 1.2.7-SNAPSHOT, Mark Struberg commited a patch that falls back to java.lang.Class#newInstance in this case. I am not sure that this solution is the best one. I proposed a patch to 1.5.0-SNAPSHOT that leverages google reflection API.

We also have to modify the appengine-web.xml file as explained in this useful blog on JSF Corner. So, our appengine-web.xml file is now :

<?xml version="1.0" encoding="utf-8"?>
<appengine-web-app xmlns="http://appengine.google.com/ns/1.0">
    <application>lptestgcloud2</application>
    <version>${appengine.app.version}</version>
    <threadsafe>true</threadsafe>
    
    <system-properties>
        <property name="java.util.logging.config.file" value="WEB-INF/logging.properties"/>
    </system-properties>

    <sessions-enabled>true</sessions-enabled> 
    <threadsafe>true</threadsafe> 
    <static-files> 
      <exclude path="/**.xhtml" /> 
    </static-files>
</appengine-web-app>

As explained in JSF Corner, we have to provide our own EL 2.2 implementation. After toying a bit, I found not better solution than JSF Corner' one, so let's also add a dependency on org.jboss.el:jboss-el:1.0_02.CR6

    <dependency>
        <groupId>org.jboss.el</groupId>
        <artifactId>jboss-el</artifactId>
        <version>1.0_02.CR6</version>
    </dependency>

and the JBoss repository :

<repositories>
    <repository>
      <id>JBoss</id>
      <url>https://repository.jboss.org/nexus/content/repositories/releases/</url>
    </repository>
 </repositories>

I also use lombok and commons-lang3 in almost all my projects :

    <dependency>
      <groupId>org.apache.commons</groupId>
      <artifactId>commons-lang3</artifactId>
      <version>3.1</version>
    </dependency>

    <dependency>
      <groupId>org.projectlombok</groupId>
      <artifactId>lombok</artifactId>
      <version>1.14.4</version>
      <scope>provided</scope>
    </dependency>

In web.xml, we have to add a context-param to use this EL implementation :

    <context-param>
        <param-name>org.apache.myfaces.EXPRESSION_FACTORY</param-name>
        <param-value>org.jboss.el.ExpressionFactoryImpl</param-value>
    </context-param>
 

A minimal web.xml file looks like :

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">

    <display-name>Test application</display-name>
    <welcome-file-list>
        <welcome-file>accueil.xhtml</welcome-file>
    </welcome-file-list>
    <context-param>
        <param-name>org.apache.myfaces.EXPRESSION_FACTORY</param-name>
        <param-value>org.jboss.el.ExpressionFactoryImpl</param-value>
    </context-param>
    <context-param>
        <param-name>org.apache.myfaces.EL_RESOLVER_COMPARATOR</param-name>
        <param-value>org.apache.myfaces.el.unified.OpenWebBeansELResolverComparator</param-value>
    </context-param>
    <listener>
        <listener-class>
            org.apache.webbeans.servlet.WebBeansConfigurationListener
        </listener-class>
    </listener>
     <servlet>
        <servlet-name>Faces Servlet</servlet-name>
        <servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>Faces Servlet</servlet-name>
        <url-pattern>*.xhtml</url-pattern>
    </servlet-mapping>
 </web-app>

Finally, let's add empty beans.xml and and faces-config.xml files in WEB-INF :

beans.xml

<?xml version="1.0" encoding="UTF-8"?>

<beans  xmlns="http://java.sun.com/xml/ns/javaee" 
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/beans_1_0.xsd" />

faces-config.xml

<?xml version="1.0" encoding="UTF-8"?>
<faces-config xmlns="http://xmlns.jcp.org/xml/ns/javaee"
              xmlns:xsi="http://www.w3.org/2001/XMLSchemainstance"
              xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-facesconfig_2_2.xsd"
              version="2.2" />

If we start it right now with :

mvn clean install appengine:devserver

it almost works. Almost because there are still a few JNDI related errors during DeltaSpike initialization. GAE does not support JNDI. So, until we can cleanly disable it, we have to shadow the BeanManagerProvider and JNDIUtils classes.

In our BeanManagerProvider version, we shall comment the line

result = resolveBeanManagerViaJndi();

and in JNDIUtils we shall comment the static initialization block, where an attempt to access InitialContext is performer, throwing an exception :

    static
    {
        try
        {
            initialContext = new InitialContext();
        }
        catch (Exception e)
        {
            throw new ExceptionInInitializerError(e);
        }
    }

...and then, it finally works as expected. :-)

Source

The source of this (very) simple example is downloadable there.

Conclusion

A few hacks are required to run this PrimeFaces/MyFaces/DeltaSpike/OpenWebbeans stack on Google App Engine. Some workarounds, like using java.lang.Class#newInstance instead of sun.misc.Unsafe can have a performance hit or even raise issues (what happens when you use a proxy for a singleton ???). However, it is still quite acceptable and usable for who wants to leverage all the features of GAE without giving up the power of JSF 2.2 and CDI extensions such as DeltaSpike.

As a tomcat user, I have to learn again how to perform access control and such things, but Google seems to offer rich, yet specific API.

It seems that you can even have Google App Engine on your own private cloud, thanks to a collaboration between Google and Red Hat that led to the project CapeDwarf

JSF in the cloud : Finding the PaaS - Part 0 : Introduction

I have been developping a lot in java those last years. For so called «enterprise» web based applications, there are so many nice libraries and packages available... Even if you are like me a C/C++ geek and think that getting too far from the hardware and forget memory allocation is an highway to performance bottlenecks, it is a good way to go, just because lots of others also travel on this road.

In the world of java webapps, I opted for a PrimeFaces / MyFaces / Deltaspike / OpenWebBeans stack, running in a Tomcat 7 container.

The first reason is my preference for open standards. I do not like to depend on a single provider.

The second reason is that all those packages are Free Software. So, one can study and modify the code, which is just always needed when you do real work.

The third reason is that all those projects, excepted PrimeFaces, are supported by the Apache Foundation. I find that it does a very good long term job of developping libraries and other valuable tools. Moreover, I prefer non-copyleft licences. The developpers of those projects know each other and collaborate. When you ask a question on Deltaspike and it happens to be an OWB question, you are friendly redirected to the right place.

The fourth reason is that all those projects have vibrant communities. I had answers to most of my questions and requests in less than a day.

The fifth reason, at least for PrimeFaces, is that they are de facto standards.

Since 2010, «cloud» has emerged as a buzz word, a magic marketing solution to all problems. Despite the regretable ton of ******, the development of Iaas (Infrastructure as a Service) and PaaS (Platform as a Service) opens new perspectives in the way we, developpers, work.

IaaS is, in very few words, a way to have hardware as a commodity. an IaaS provider such as Amazon will provide you servers and databases instances for a very low fee per hour. You then have to setup your system. PaaS goes a step further. A provider of PaaS also provides a set of libraries and tools. It upgrades and patches them as needed. It sometimes provides features such as automatic load balancing, and so on.

IaaS and PaaS can be public or private (on premise). Big organisations might have security needs that requires the second option.

There are still less PaaS offers than IaaS offers. I think that it will change given the big advantages that a good PaaS offer provides. For one developping software from scratch, it would just be very bad idea not to opt for such an offer, excepted if you have very special requirements.

I asked myself a simple question : how does my usual stack fit in the leading PaaS offers ? As this question seemed interesting to friends and colleagues, I decided to write a few blog notes on this topic. I will try to explain you how you can do JSF in the cloud in a snap (or kind of, as you will see).I will first look at Google App Engine, then OpenShift, then Jelastic, then CloudFoundry, then Heroku. In this first look, I will just try to see how easy it is to get my stack up and running and have a look at the main features. Benchmarks like this one are already performed by experts and I have no value nor time to try to do better than them.

À propos du filtrage DNS

Tel Sisyphe avec son rocher, je reprends ici en une version raccourcie et légèrement actualisée au format «note» un document sur la régulation d'internet que j'avais préparé en 2010 pour... la commission Culture du PS, alors présidée par Patrick Bloche. Le document original comportait également un état des lieux des pratiques de régulation, une flopée de schémas, des principes de régulation rénovée de l'Internet, etc. Il faisait donc un peu moins de 20 pages et est donc beaucoup trop long pour être lu en ligne.

Quel recul depuis 2010... Quelle tristesse de voir l'absence de cohérence et de volonté politiques du hollandisme déboucher sur un désastre tel que la loi terrorisme... Je ne me sens bien sûr par comptable de ce que fait aujourd'hui un parti que j'ai quitté dès le lendemain de la primaire de 2011, ne devinant que trop ce que serait un "quinquennat hollande". Mais il me reste de bons amis dans ses rangs, avec lesquels j'ai pas mal de convictions en commun. Si je tente de m'impliquer (un peu) dans Nouvelle Donne aujourd'hui, je suis cependant convaincu que ces personnes et d'autres qui souhaitent le retour d'une gauche de transformation de la société ont beaucoup à faire en commun, au-delà des clivages partisans.

Si ces quelques paragraphes peuvent les aider, eux ou d'autres promoteur d'un net ouvert, ce sera déjà cela de pris...

Lire la suite...

Quelques réflexions sur «L'affaire de l'article 13 de la loi de programmation militaire»

Tentative d'analyse à chaud de la «controverse sur l'article 13 de la loi de programmation militaire».

Lire la suite...

Note sur l'article 13 de la loi de programmation militaire

Une note préparée pour quelques amis qui me demandaient mon avis sur le désormais fameux article 13 de la Loi de Programmation Militaire. Je la diffuse ici volontairement après la bataille. Le format est volontairement court (et encore, on essaye plutôt de faire une page A4 d'habitude...).

Lire la suite...

OVH + Vidéo Futur + Kartina TV ou merci la neutralité du net

Depuis quelques années maintenant, nous sommes quelques uns à batailler pour «la neutralité du net». Selon ce principe, la règle générale doit être de ne pas différencier les communications en fonction de leur nature ou de leurs interlocuteurs.

J'ai déjà écrit plusieurs billets sur ce thème sur ce blog... Je saisis l'occasion de mon récent déménagement pour illustrer l'intérêt de cette neutralité.

J'ai donc déménagé en juillet et en ai profité pour changer de fournisseur d'accès internet. Abonné depuis quelques années à Free, j'ai décidé de tester l'offre ADSL Pro d'OVH. Pourquoi ?

Je m'étais abonné à Free en 2007-2008, après avoir été de longues années un heureux abonné de Nerim, un fournisseur ADSL devenu très orienté pro et qui s'adressait encore il y a quelques années aux particuliers. Ma motivation pour quitter les eaux tranquilles de Nerim était très simple : je vivais avec celle qui allait devenir ma femme, qui avait un sérieux mal du pays et qui avait très envie de pouvoir regarder la télé de son pays d'origine, la Russie. L'offre de Free n'avait rien de bien génial, mais elle avait le mérite d'exister, et on pouvait avoir accès à quelques chaînes pour 1 euro par mois, dont notamment la première chaîne russe, en plus de l'abonnement de base. Va donc pour Free.

En juin 2013, Free avait bien changé. Ma compagne se plaignait depuis plusieurs mois de ne pas pouvoir regarder confortablement ses vidéos sur YouTube. Perso, je ne suis pas accro, mais le petit jeu auquel Free se livre en refusant "d'augmenter la taille du tuyau" le reliant à YouTube m'irrite et je me refuse à recourir à un proxy pour retrouver un débit normal. J'ai donc commencé à chercher un autre fournisseur d'accès et mon choix s'est arrêté sur OVH, entre autres parce que je trouve le discours de son DG, Octave Klaba, intelligent. Il estime, entre autres, que la mission de sa société est de fournir "un bon réseau" (je raccourcis) dont on fait ce que l'on veut ensuite. OVH fournit, en gros, "un tuyau de données", avec une facilité pour la téléphonie, ce qui évite de devoir acheter un téléphone IP. OVH ne fournit pas de télé sur ADSL ou sur IP et ne propose pas de VOD, et tant mieux. En effet, j'ai ainsi pu acheter les services de mon choix.

Côté VOD, j'ai opté pour la "box" de Vidéo Futur. Pour 10 euros par mois, les contenus accessibles "en illimité", sans surcoût, sont nombreux et d'une qualité satisfaisante. On n'a pas que des vieux nanars et l'offre enfants, et plus particulièrement "tous petits" est bien fournie, pour le plus grand bonheur de mon fils de 2 ans et demi. La VOD classique, non-illimitée, est à 2,99 euros par film, soit moins cher que sur Canal Play, par exemple. On peut pour ce prix également aller louer un DVD ou un Blu-Ray en magasin. Ce qui n'a aucun intérêt pour moi, mais peut-être que pour toi, lecteur... :-)

Côté télé, j'ai recours à la bonne vieille antenne pour les chaînes françaises. La "box" de Vidéo Futur permet, si l'on y branche l'antenne télé, de mettre en pause un visionnage, ce que j'apprécie. Sur mon téléphone portable, j'utilise parfois également Play TV, à l'interface agréable mais à l'offre limitée - j'y reviendrai.

Globalement, je trouve la box de Vidéo Futur très supérieure aux offres de VOD disponibles via la Freebox. CanalPlay, la mieux fournie en contenu, a en effet une ergonomie qui n'est pas sans rappeler le minitel couleur. Au secours.... En prime, la "box" de Vidéo Futur est capable de pré-charger le film. J'ai donc jusqu'à présent toujours pu regarder les programmes de mon choix, sans interruption, sans ces innombrables erreurs que j'avais aux heures de pointe avec le couple Free + CanalPlay.

Côté télés russes, j'ai recours à l'offre de Kartina.tv. Comparer cette offre au bouquet de chaînes russes de Free n'a pas grand sens. Kartina les propose à peu près toutes, ainsi qu'un peu de VOD, là où Free a une offre famélique. Ma compagne peut à nouveau regarder ses émissions préférées. C'est un peu comme si vous n'aviez eu que TV5 (la qualité de la sélection en moins) pendant quelques années puis à nouveau toutes les chaînes françaises accessibles par le câble...

L'offre de Kartina.tv est vraiment attrayante, tant en terme de contenus que d'interface. J'ai déjà parlé des contenus... La box a la meilleure interface que j'ai pu voir jusqu'à présent, mêlant intelligemment les chaînes de télé, les programmes, les applis additionnelles du type facebook ou twitter, voire la navigation web. Sa télécommande a, au verso, un clavier. Chercher un film ou une émission peut se faire selon son nom... Des fonctionnalités de base que l'on aimerait trouver sur une "box" française. On peut également regarder n'importe quel programme du jour (ou de la veille, me semble-t-il) en décalé. En ajoutant une souris, on peut vraiment naviguer et faire ses actions de base en ligne. Bref, c'est le pied.

Où est la neutralité, là-dedans, me direz-vous ? Dans le fait que mon FAI se contente d'être un FAI. Qu'il s'applique à construire un bon réseau, ce pour quoi ses clients, dont mon humble foyer, le payent. Qu'il ne tente pas de tordre le bras d'un éditeur de services (lire ici Google et son service YouTube) pour financer le développement de son réseau, ou plutôt augmenter sa marge. Qu'il n'a pas intérêt à me vendre un service prioritaire, premium, géré ou je ne sais quel autre mot synonyme de priorité ou d'exclusivité pour avoir de la VOD ou de la télé de qualité. Qu'il ne favorise pas ses propres services. Qu'il ne m'impose pas sa boîboîte au look improbable "parce qu'elle fait partie de son réseau".

On notera au passage qu'OVH ne dispose pas de son propre réseau de collecte (les "derniers kilomètres de réseau" qui relient votre domicile au monde) sur tout le territoire français. Sauf erreur de ma part, la collecte de ma ligne ADSL est assurée par le réseau de SFR. La différence se fait bien ici sur le "coeur de réseau".

Vous aurez peut-être également noté que je critique paradoxalement la box de Vidéo Futur dont l'ergonomie, quoi que bien meilleure que celles des autres offres, est encore quelques années derrière celle de la box de Kartina fabriquée par Comigo. Je suis en même temps indulgent, car les pauvres se battent dans un contexte réglementaire extrêmement défavorable aux innovateurs, pour le plus grand bénéfice des rentiers des médias et de la culture. Les russes tombent peut-être dans l'excès inverse, mais le résultat est là : un service de qualité, innovant, alors qu'en France on pleure à l'assemblée nationale sur l'indisponibilité du service public de l'audiovisuel à l'étranger...

Pas de télé sur IP, non plus, dans la box de Vidéo Futur. Cela m'a un peu déçu au début, mais quand on se souvient des batailles livrées par Free au début du Triple play, ou quand on voit dans quelle situation est actuellement Play.tv, je les comprends... Play.tv ne peut par exemple pas rediffuser en ligne TF1 et M6, ni les chaînes du service public qui font pourtant l'objet pour d'autres acteurs d'une obligation de diffusion... On nage en plein délire.

Bref, merci la neutralité, grâce à laquelle j'échappe à l'ORTF 2.0 des offres "triple play"...

Rapport Lescure : de bonnes propositions pour le marché, des enjeux citoyens encore à traiter

Après des mois de travail, Pierre Lescure a rendu son rapport. Il succède dans cet exercice à Denis Olivennes (à l'époque PDG de la Fnac) et Patrick Zelnik, fondateur de Naïve.

À un vendeur de supports physiques et des appareils permettant de les lire et à un producteur succède donc l'ancien patron de Canal +. Cet énoncé est certes très réducteur - chacune de ces trois personnes est bien plus. Mais cette analyse grossière apporte cependant un éclairage intéressant à l'un des principaux apports de ce rapport : l'importance reconnue des distributeurs, essentiellement les éditeurs de service en ligne, et la proposition d'un train de mesures visant à permettre enfin l'émergence de plus de champions français.

Le rapport Lescure propose en effet notamment une mesure aussi emblématique que provocatrice pour les majors de la musique : la gestion collective obligatoire, si un code des usages de ce secteur n'était pas adopté et respecté par les producteurs :

«En outre, dans l’hypothèse où les producteurs phonographiques refuseraient la régulation négociée proposée plus haut (établissement d’un code des usages sur les rapports avec les plateformes et conclusion d’un accord collectif sur la rémunération des artistes), la mise en place d’une gestion collective obligatoire des droits voisins pourrait être envisagée. Il s’agirait de tirer les conséquences de la défaillance de la gestion individuelle qui ne permet pas une exploitation des œuvres dans des conditions satisfaisantes et qui crée des entraves au développement de l’offre, des distorsions concurrentielles et des déséquilibres dans le partage de la valeur.»

Toute personne s'intéressant de longue date à ce secteur ne peut que sourire, les producteurs n'ayant jamais ou presque respecté leurs engagements. L'hypothèse de non-respect est ici toute rhétorique. Il est très heureux de voir ceux qui bloquent le développement d'offres attractives depuis plus de 10 ans ramenés à une plus juste place. Cela me semble être un important symbole, insuffisamment remarqué.

Le rapport Lescure a d'autres vertus. Je tâche un peu plus bas d'énumérer celles qui me semblent les plus remarquables. Je ne lui reconnais cependant pas celle de chercher une paix entre les acteurs de l'Internet et ceux de la Culture. S'il prétend ne pas les opposer, c'est pour mieux regretter l'absence d'éditeurs français, à quelques exceptions près, et mieux désigner comme adversaires des sociétés américaines qui, comme toutes les multinationales du monde, pratiquent l'optimisation fiscale. Je n'apprécie certainement pas cet exercice, mais j'aimerais vraiment comprendre pourquoi on ne le condamne que pour le numérique, si ce n'est du fait du faible nombre d'acteurs français... Non, le rapport Lescure n'est pas un rapport de paix dans la société de l'information, ce malgré quelques avancées notables. Dès sa première page, il évoque ainsi

«La révolution numérique, multiple, universelle, réjouissante, débordante et aussi déstabilisante a, d’ores et déjà, changé le fonctionnement du monde et de nos vies. La révolution est là. Elle ne va faire que croître et embellir et c’est tant mieux.»

Il dénonce également

«Les contraintes liées aux mesures techniques de protection (« DRM » dans le langage courant), qui entravent certains usages, les restrictions territoriales, ou encore les limitations relatives aux supports ou aux moyens de paiement, sont également d’importantes sources de frustration.»

et appelle, page 17, à une régulation plus forte et plus large.

Dans la même section, il estime, mieux encore, que

«il est vain de vouloir éradiquer l’offre illégale et néfaste de stigmatiser ses usagers»

Dans le même esprit, le rapport Lescure appelle à un effort d'imagination et à ne pas recycler de vieilles recettes :

«Les instruments traditionnels mobilisés pour la régulation de la diffusion analogique (quotas de diffusion) ou de la distribution physique (soutien aux librairies, prix unique du livre) ne sauraient être transposés à l’identique dans le monde numérique»

Pour en finir avec les principaux points positifs, notons :

  • un appel insistant à mieux répartir la valeur, en garantissant la part de revenu des auteurs et des artistes-interprètes ;
  • une reconnaissance de l'auto-édition et de l'auto-production, notamment par des collectifs et des coopératives (page 20) :

«L’autoédition et l’autoproduction, rendues plus accessibles par les technologies numériques, permettent à un nombre croissant de créateurs de s’affranchir de la tutelle d’un intermédiaire et, ainsi, de conserver une part plus élevée des revenus de leurs ventes. Toutefois, sous réserve de quelques exceptions très médiatisées, les auteurs autoédités et les artistes autoproduits peinent souvent à se faire connaître et à émerger au milieu de l’hyper-offre numérique. Plus prometteuse est l’émergence de nouvelles formes d’organisation (coopératives d’édition numérique, collectifs d’artistes), qui garantissent aux créateurs un meilleur partage de la valeur que celui applicable dans les modèles traditionnels, tout en leur prodiguant un soutien artistique, technique ou commercial dont ils ne bénéficieraient pas en autoédition ou en autoproduction.»

  • l'appel à améliorer les exceptions éducation et handicap, page 37 ;
  • l'appel à mieux protéger le domaine public, page 38 :
    • en encadrant les partenariats public/privé,
    • en luttant contre les phénomènes de réappropriation,
    • en lui donnant une définition positive.
  • la volonté de conforter les licences libres (à la Creative Commons), notamment face à la gestion collective, page 39, en permettant de placer certaines oeuvres sous de telles licences tout en en confiant d'autres à des sociétés de gestion (comme la SACEM) ;
  • la prise en compte de l'importance des meta-données, essentielle à une bonne traçabilité des oeuvres et à une bonne répartition des droits (page 41).

Si ces avancées sont indéniables, elles n'éclipsent cependant pas les aspects négatifs de ce rapport. S'il met l'accent sur la répression de la contrefaçon commerciale et appelle presque à une légalisation en creux des pratiques à but non-lucratif, ses propositions en la matière sont particulièrement dangereuses. Pages 34-35, le rapport Lescure esquisse ni plus ni moins qu'une «SOPA à la française», un dispositif qui permettrait d'obtenir des intermédiaires techniques et financiers des mesures drastiques contre les acteurs soupçonnés de contrefaçon, sans les garanties que peut apporter l'intervention de l'autorité judiciaire.

Audacieuse sur la gestion collective obligatoire des droits voisins, la position de Pierre Lescure se fait bien plus dogmatique sur une éventuelle légalisation des échanges hors marché (lire la page 31). C'est ici quasiment un copier-coller des arguments des producteurs... Mais est-ce vraiment surprenant ? Pierre Lescure sait qu'il ne pourra pas faire passer toutes les mesures contenues dans son rapport. Il semble chercher à chaque instant jusqu'où il peut «secouer le cocotier», de manière suffisamment argumentée. Ne sous-estimons pas non plus l'importance de sa culture de distributeur. Les producteurs hurlent tout autant à l'inconstitutionnalité d'une légalisation des échanges hors marché qu'à la mise en place d'une gestion collective obligatoire, pour des motifs juridiques analogues. Il y a bien ici un choix, très politique, de ne pas prendre de front tous les acteurs en même temps, de ne pas ouvrir «le front du cinéma» en plus du «front de la musique».

Il reviendra à mon avis au politique - au gouvernement et, s'il ne fait pas son travail, au parlement - de se remettre au travail, d'élargir la perspective et de souligner que l'on ne peut pas raisonner qu'en termes économiques. Le choix de continuer à interdire les échanges non-commerciaux implique de lutter contre leur existence, et donc à une surveillance généralisée des échanges ayant des implications majeures pour notre société. Il revient à des élus mandatés par les Français de poser la question dans toute sa globalité et d'opérer les choix citoyens, et non des seuls acteurs d'une filière économique. Ils ont déjà commencé. Je n'interprète pas autrement les réactions de Patrick Bloche et de Christian Paul.

Le politique pourra également argumenter du respect des droits du public, mis en avant par le rapport page 15 dans la section «Proposer aux publics une offre abordable, ergonomique et respectueuse de leurs droits». J'affirme pour ma part qu'un internaute a le droit d'échanger des oeuvres sans but lucratif et que le distributeur qui ne lui apporte aucune valeur ajoutée par rapport au P2P ne mérite pas d'être rémunéré. En l'absence d'effet négatif clairement démontré sur les ventes, aucune compensation ne devrait être prélevée sur les internautes.

Le rapport Lescure tente également d'adapter le volet «recettes» de l'exception culturelle à l'ère numérique. Si la taxation des opérateurs de telecoms semble légitime, puisque ces derniers sont dorénavant les principaux distributeurs de «contenus», j'ai par contre un avis très négatif sur la nouvelle taxe (ou redevance : peu importe pour le consommateur-payeur) sur les «appareils connectés». Non pas par opposition de principe à une nouvelle taxe, mais parce qu'elle va à son tour frapper une fourniture de biens délocalisables. Hier, on achetait les CD en Belgique ou en Grande-Bretagne pour ne pas s'acquitter de la rémunération sur copie privée. Demain, on commandera dans ces mêmes pays ou directement en Chine son équipement, en réalisant une économie substantielle au passage. Quitte à demander une nouvelle contribution au consommateur, il faut le faire sur un bien ou un service non délocalisable. Je ne vois pas de meilleur candidat que l'abonnement à l'Internet.

Glissons sur les tentations «d'adaptation au cloud» en extrapolant les copies à distance à partir de la taille des supports physiques achetés, augmentant d'autant la rémunération sur copie privée existante. Elle part du postulat que le système de la RCP fonctionne, que son barême est indiscutable et qu'il ne faut qu'aménager sa gouvernance, tant pour ce qui est de la fixation des taux que de la répartition des 25% «de soutien à la création»... (pages 22 et 23)

La persistance de la croyance en ce genre de système dépassé, malgré l'ambition initialement affichée, est encore plus gênante dans certaines mesures envisagées de soutien aux éditeurs, qui relèvent plus de la logique d'un portail tel qu'AOL en 1998 que de l'Internet. Ainsi, le rapport Lescure veut favoriser les éditeurs vertueux, en imposant leur reprise par les distributeurs - j'attends avec impatience de voir les premières exigences de cette nature formulées à un Apple, un Google ou un Yahoo - ou pire encore une priorité de trafic. Malgré l'affirmation (page 3) de « l’absolue nécessité de la neutralité du Net », c'est bien de la mise à mort de cette dernière dont il est ici question... Bref, même si l'effort est indéniable, les réflexes de «contrôles des tuyaux» comme a pu le faire en d'autres temps le CSA avec la radio et la télévision restent présents, dans une moindre mesure, mais tout aussi anachroniques.

La proposition la plus curieuse, du moins sur le seul plan de la logique, concerne l'adaptation de la chronologie des médias. Le rapport Lescure propose en effet essentiellement d'avancer la fenêtre de disponibilité en vidéo à la demande par abonnement à 18 mois et d'expérimenter des avancées de la fenêtre de vidéo à la demande hors abonnement (page 17). Dans la même section, le rapport traite de la disponibilité des séries étrangères, souhaitant accélérer leurs sous-titrage et les rendre disponibles plus tôt. Alors qu'une série comme «Games of Thrones» est massivement téléchargée dès sa première diffusion, on ne peut que s'étonner de la faiblesse de ces mesures. Les internautes attendront sans aucun doute, parce que Pierre Lescure l'a proposé, 18 mois plutôt que 36 pour accéder par abonnement à des oeuvres qu'il peuvent pour la plupart trouver immédiatement en P2P (et parfois avec une qualité supérieure, comme le rapport le pointe lui-même)... ou pas. Si ces propositions défient la réalité, elles n'en sont pas moins le reflet de ce que les professionnels de la profession sont prêts à accepter... Bref, on est ici en plein hollandisme, en pleine recherche d'un consensus introuvable là où il faut assumer une rupture et oser la mise en place d'une chronologie des médias autorisant tous les types d'exploitation d'une oeuvre dès sa première communication au public, comme le propose Philippe Aigrain depuis plusieurs années...

Symbole de la politique culturelle numérique de Nicolas Sarkozy, les lois hadopi et la haute autorité qu'elles ont mise en place sont bien évidemment abordées par ce rapport. Les passages qui en traitent sont parmi les plus étonnants, reprenant sans sourciller le bilan de son action par l'autorité elle-même et les affirmations péremptoires non étayées de ses partisans. Ainsi, la Hadopi aurait un effet avéré, ne coûterait pas si cher (!) et ne devrait être aménagée qu'à la marge, en remplaçant la suspension de l'accès internet par une amende de 60 euros (ou plus en cas de récidive), en transférant la gestion de la riposte graduée au CSA... Pourtant, les pratiques illicites n'ont pas été enrayées en France, même moins que dans bien d'autres pays... Là encore, il semble que Pierre Lescure ait choisi de ne pas prendre de front les partisans de l'hadopi, qui font de cette dernière une quasi-religion, et de mettre le gouvernement et le Parlement face à leurs responsabilités.

En conclusion, on espérera que le gouvernement, puis le Parlement, sauront retenir du rapport Lescure ses aspects touchant à la régulation du marché. Tout comme le rapport Zelnik, il comporte plusieurs propositions intéressants en la matière. Et l'on tentera, sans trop d'espoir au regard de la première année de mandat de François Hollande, de convaincre qu'il est temps, plus que temps, d'avoir une vraie «politique de civilisation» qui reconnaisse tous les apports du numérique au-délà du seul secteur marchand et légalise les échanges à but non lucratif.

Neutralité du net : de multiples enjeux, une réponse multiple

La «neutralité du net» est en débat depuis de nombreuses années maintenant. Même ce modeste blog, dont c'est certes l'un des principaux thèmes, compte 14 billets sur ce thème, dont le plus ancien remonte à 2010.

On peut estimer qu'il a déjà été de nombreuses fois fait le tour de la question. C'est un des "Grands Dossiers" de l'ARCEP. Deux propositions de loi ont été déposées, dont l'une, celle de Christian Paul, à laquelle j'ai contribué, a été inscrite à l'ordre du jour par le groupe socialiste et discutée en séance publique en mars 2012. L'autre est l'oeuvre d'une autre parlementaire fortement impliquée sur ces question, Mme Laure de Laraudière.

On peut donc légitimement se demander à quoi sert de demander un n-ième rapport, qui plus est au Conseil National du Numérique, aux moyens restreints et dont le rôle et l'indépendance posent question, si ce n'est de gagner du temps et d'enterrer le sujet.

La réduction opérée par certains, dont notamment Benjamin Bayart, de la neutralité du net à la seule question de la liberté d'expression me fait cependant réagir. Je tente donc dans les quelques lignes qui suivent de redéfinir ce qu'est la neutralité du net, d'énumérer les principaux types d'atteintes, de lister les principaux enjeux et de proposer les réponses qui me semblent adaptées.

La neutralité du net, qu'est-ce que c'est ?

La neutralité du net est pour moi un principe de respect de chacun des acteurs du réseau par tous. Je parle bien d'acteur au sens large et ne limite donc pas ce principe aux seuls «Fournisseurs d'Accès Internet».

Juridiquement, nous avions proposé avec Christian Paul la définition suivante de ce principe à l'article 1 de sa PPL :

« Le principe de neutralité doit être respecté par toute action ou décision ayant un impact sur l’organisation, la mise à disposition, l’usage d’un réseau ouvert au public. Ce principe s’entend comme l’interdiction de discriminations liées aux contenus, aux émetteurs ou aux destinataires des échanges numériques de données. »

Les articles suivants de cette PPL précisaient notamment des modalités de protection de la neutralité du net concernant plus spécifiquement les FAI.

La neutralité du net, c'est donc la garantie de la liberté, de l'égalité et de l'ouverture sur le réseau, composant essentiel de la société de l'information.

D'autres «couches» importantes doivent être traitées pour garantir ces libertés sur cette dernière : matériel, logiciels, services... S'il est essentiel de les traiter également - un Internet ouvert ne nous sert à rien si tous les utilisateurs voient les logiciels qui permettent de l'utiliser contrôlés par un AppStore» - il me semble important de ne pas mélanger tous les sujets.

En français moins technique, j'aime bien définir la neutralité du net, notamment quand j'ai affaire à des gens s'intéressant de près ou de loin à la politique, comme un volet d'une «laïcité informationnelle», qui permet à chacun d'avoir les pratiques qu'il souhaite dans la sphère privée tant que cela n'impose rien aux autres dans la sphère publique. Comme la laïcité au sens traditionnel, la «laïcité informationnelle» est un principe souple, sujet à interprétation.

Quelles sont les atteintes ?

Ces définitions positives sont peut-être plus intelligibles une fois complétées, en creux, par une liste des types d'atteintes à la «neutralité du net». J'en vois trois grandes.

La plus brutale et la plus facile à constater : le blocage, pur et simple.

À peine plus subtil, le filtrage empêche d'atteindre certains services ou certains contenus.

Plus difficile à constater et donc à empêcher, la discrimination, par exemple en rendant volontairement l'accès à un service plus lent, me semble la menace la plus importante aujourd'hui, du moins comme atteinte à la neutralité du net par un acteur privé. Les deux premiers types d'atteintes sont aujourd'hui l'apanage de la puissance publique.

Tout blocage et tout filtrage ne me semblent pas illégitimes. La neutralité du net n'est, pas plus que les grands principes que l'on défend avec elle, un absolu. L'inefficacité technique de ce type de mesure devraient cependant conduire à ne pas y recourir.

Quels sont les enjeux ?

Ils sont pour moi de trois grands ordres. Démocratique, tout d'abord. L'atteinte à la liberté d'expression ou d'information est évidente lorsqu'un contenu est bloqué. Elle peut être légitime pour les contenus les plus odieux. L'atteinte est également plus réel dans le cas, plus insidieux, de la discrimination. Lorsqu'un texte, un son ou une vidéo est accessible 100 fois plus lentement qu'un autre, pour des raisons ne devant rien à la technique, nous sommes également confrontés à une démarché de réorganisation de l'espace de débat, de réflexion, de pensée.

Économique, ensuite. Le coût d'accès au net est un paramètre important, voire essentiel pour ses acteurs.

De développement, enfin. Que ce soit en terme de développement économique, d'innovation économique, dont notamment celles des «start-ups» et autres jeunes pousses, qui n'existent pour certaines que du fait du faible «ticket d'entrée» ; de développement des territoires, que les grands réseaux s'efforcent traditionnellement, au moins dans leurs objectifs, de ne pas discriminer ; de développement de nouveaux biens communs, enfin, dont l'exemple très souvent avancé est wikipedia.

Qu'est-ce que l'Internet ?

La question peut paraître saugrenue tant «Internet» fait aujourd'hui partie de notre quotidien. Il n'en reste pas moins que «Internet» n'est pas défini en droit. Certaines notions comme celle de «service de communication au public en ligne» existent. Le singulier couramment utilisé pour Internet pose lui-même problème. En pratique, il y a des réseaux et des réseaux de réseaux, dont ce que nous appellons communément «Internet» n'est qu'un exemple. Certains geeks préfèrent d'ailleurs parler «des Internets», ce qui a l'avantage de mieux refléter la pluralité et l'acentrage de ces systèmes.

Ce que nous appelons communément Internet me semble pouvoir être résumé à une capacité générale d'interconnexion. Au fait d'être "relié" à un gros nuage de réseaux.

Ces réseaux appartiennent, pour la plupart, à des acteurs privés. Ils forment ensemble un «bien commun informationnel», qui n'est pas public au sens traditionnel du terme, mais qui n'est pas non plus un bien privé clos, exclusif, au sens traditionnel.

Les observateurs les plus anciens noteront que j'évite délibérément de faire une distinction entre «Internet» et services prétendument «gérés». Tout comme Stéphane Bortzmeyer, j'estime qu'il y a là que des «service privilégiés», dont on ne peut accepter par défaut tous les écarts de neutralité à moins de vider toute protection de la neutralité du réseau de son sens.

Quelle est la légitimé de la puissance publique à réguler des biens privés ?

Elle est pour moi la même que pour quantités d'autres infrastructures. Un centre commercial, même s'il appartient presque toujours à une société privée, n'est pas une zone de non-droit. Il n'est pas la voie publique, mais les lois de la République s'y appliquent. De même pour une gare, un aéroport, etc. Le caractère d'infrastructure essentiel de «l'Internet» légitime à lui seul cette intervention.

Comment agir ?

Tout ceci étant dit, comment agir ? Je continue de penser que la PPL Paul est la meilleure base. Elle fait de la neutralité du net le principe et permet d'autoriser certaines exceptions dûment justifiées.

Je la compléterais par les éléments suivants.

Tout d'abord, une loi protégeant de manière générale la liberté d'expression, puisque certains, comme Benjamin Bayart, estiment que cela est nécessaire. Cette loi ne devrait, comme toute bonne loi, pas être techno-centrée ni restreinte au monde numérique.

Ensuite, en protégeant les conditions d'interconnexion. La PPL Paul avait déjà envoyé un signal, qu'avait bien perçu l'ARCEP, en demandant aux acteurs du réseau des informations sur les conditions d'interconnexion. Une loi devrait faire de la fourniture de ces informations au régulateur une obligation légale et de la fourniture d'une interconnexion «de bonne qualité» la règle.

Afin d'éviter d'imposer une obligation trop forte à tous les acteurs et surtout d'imposer des obligations inadéquates à tous les types de réseaux de communications électroniques ouverts au public (et qui ne sont pas tous Internet), je pense qu'il ne faudrait imposer des obligations en matières d'interconnexions qu'aux seuls opérateurs dominants.

Le régulateur sait identifier ces derniers. La «bonne qualité» est une notion évidemment relative. Une interco peut être de mauvaise qualité pour de bonnes raisons. Ne devrait être répréhensible que la dégradation volontaire de la qualité de l'interconnexion, pour un motif manifestement non technique.

On permet ici de protéger «l'Internet de M. tout le monde» et d'adresser des problèmes tels que le ralentissement de YouTube que subissent les abonnés de Free. On permet cependant en même temps aux nouveaux acteurs de se développer sans subir les mêmes obligations, ainsi que le déploiement d'autres réseaux interconnectés en «réseau de réseaux» distincts.

Enfin, il faut organiser le déploiement rapide de la fibre sur tout le territoire. Le THD fixe est la réponse au risque d'encombrement souvent avancé, jamais constaté, par les fournisseurs d'accès. Le gouvernement est en train de préciser son plan... Attendons qu'il soit précisé pour le critiquer...

À propos de l'avis du Conseil National du Numérique sur la "neutralité du net"

Ça y'est, le «Conseil National du Numérique» 2.0 a rendu son premier avis. Ce très court document (2 pages !) est accompagné d'un rapport lui aussi remarquablement court (15 pages en comptant la couverture...) si on laisse de côté les annexes.

J'ai regretté lors de la mise en place du «Conseil National du Numérique» 2.0 qu'on ait préféré mettre en place une version légèrement remaniée de l'instance mise en place par Nicolas Sarkozy plutôt qu'un «Forum des Droits sur l'Internet» 2.0. Le CNNum continue en effet aujourd'hui de souffrir d'être peuplé de membres nommés par le pouvoir. Si l'essentiel d'entre eux est de grande qualité, la proportion proche de l'actuelle majorité est effarante, sans parler de la dépendance de la Netscouade, la société de son président, envers la commande publique. Dans son discours d'intronisation, Benoît Thieulin indiquait avoir confiance dans la capacité du Conseil à «bousculer» la ministre et le gouvernement... La teneur de l'avis laisse penser que la première partie du discours, riche de remerciements pour tous les politiques ayant contribué à cette nomination, est bien plus fidèle à la réalité.

L'avis du CNNum sur la neutralité du net a en effet un premier défaut. Il est restreint à sa saisine, qui ne portait que sur la liberté d'expression. Peut-être est-ce une qualité. Cela l'aurait sans doute été si l'avis n'avait prétendu porter que sur ce seul sujet. Le sujet de la neutralité du net est cependant également, certains diront surtout, économique. Comme souvent, les deux aspects ne sont pas décorrélés et l'existence d'un écosystème sain est la condition de l'effectivité de liberté toutes théoriques.

Très court, l'avis du CNNum ne s’embarrasse pas de détails. Alors que le débat porte sur des sujets tels que la symétrie des échanges ou le traitement des services que certains appellent «gérés» pendant que d'autres ne les voient que comme des distinctions artificielles du reste de l'Internet, souvent indûment privilégiés, l'avis du CNNum reste à quelques kilomètres au-dessus de la surface du sujet.

Enfin, l'avis du CNNum ne prévoit qu'un principe mou, non-contraignant, une sorte d'objectif assorti d'un «observatoire de la qualité du net». Or, les réseaux continuent à évoluer bien plus vite que la loi, voire même que la vitesse de réaction du régulateur. Et l'ARCEP est pourtant un régulateur actif... Le danger de ne laisser subsister qu'un «Internet résiduel» est réel et sérieux. Le rapport explique ainsi clairement que la neutralité du net ne concerne que l'accès à des contenus légaux, laissant la porte ouverte aux revendications des lobbies de la culture et de la communication et à leur neutralité «dans le respect du droit d'auteur». Pire encore, le rapport est même en retrait sur la position de Neelie Kroes sur la neutralité du net. Si cette dernière souhaite que chacun puisse payer une option pour disposer d'un accès à Internet réellement neutre, le rapport estime uniquement «essentiel que le principe de neutralité garantisse un accès transparent à l’information afin que les usagers puissent choisir en connaissance de cause le réseau et les services qu’ils souhaitent utiliser». Comme le pointe très justement Numerama, le dernier exemple d'atteinte à la neutralité, à la dernière page du rapport, est très parlant : est bien visé ici un défaut d'information sur une atteinte à la neutralité.

Bref, un document qui répond bien à la commande passée par Fleur Pellerin lors du colloque de janvier... On se reportera plutôt à ses annexes pour des pistes de protection de la neutralité du net.

Pour une vraie corégulation du net

Ami lecteur, pose ton café avant de lire la suite de ce billet... Et réjouis-toi, car je vais tenter d'être plus court qu'habituellement (tout arrive).

Je voudrais dire tout le bien que je pense de la dernière proposition de corégulation du CSA. L'approche retenue est celle que je préconise dans divers cercles depuis de nombreuses années : un régulateur puissamment armée posant des principes en fonction desquels les acteurs s'auto-régulent et n'intervenant éventuellement avant l'autorité judiciaire que pour les problèmes les plus graves.

Les plus attentifs auront noté que c'est également ce que je préconise pour la neutralité du net, entre autres dossiers numériques. Que cela soit pour la régulation des contenus en ligne - disposer d'un étiquetage du type "plus de 18 ans" et avoir la possibilité de mettre en place un filtrage parental en fonction est une bonne chose - ou pour protéger un droit positif à la neutralité, nous avons besoin d'un régulateur compétent et bien armé. Ce même si le caractère presque uniformément mauvais des interventions législatives de ces dix dernières années rend légitimement méfiant.

Je regrette par contre que l'on ait à nouveau perdu du temps en repoussant la fusion CSA/ARCEP entre autres autorités que l'on pourrait agréger pour réguler de manière plus cohérente. Je regrette encore plus l'occasion manquée de transformer le CNNum en une vraie instance de corégulation, avec des adhérents, un conseil élu, agrémenté éventuellement de quelques personnalités qualifiées, etc. Il y a là un vrai beau chantier. Mais encore faut-il vouloir faire un peu mieux que du Sarkozy 2.0 saupoudré de social-libéralisme - et perdre une occasion de placer de distribuer quelques hochets aux copains/copines (parité oblige).

- page 1 de 4