Gatling – Test de charge et cloudification

Dans le cadre du développement de l’application FastContest et de son déploiement dans le cloud d’Amazon avec Cloudify, nous avons souhaité effectuer des tests de charge automatisés afin :

  • d’évaluer la charge maximale que notre application pouvait soutenir
  • de dimensionner les machines du Cloud sur lesquelles nous déployons
  • de mettre en exergue les faiblesses de notre application
  • de jouer des scénarios définis automatiquement avec plusieurs centaines de joueurs concourants et ainsi de vérifier la bonne intégrité des données à l’issue

Nous avons choisi d’utiliser Gatling, un outil de test de charge open-source, qui permet d’écrire les scénarios de test sous forme de codes élégants et concis.

Arborescence de Gatling

Le dossier d’installation de Gatling est organisé selon l’arborescence suivante :

  • /results : Contient les résultats des benchs sous format web
  • /bin : Contient les scripts permettant de lancer Gatling
  • /target : Contient les fichiers issus de la compilation de nos scénarios + cache
  • /conf : Contient les fichiers de configuration (niveau de log…)
  • /user-files : Contient les fichiers .scala de définition des scénarios
  • /lib : jar de gatling

Des scénarios implémentés en Scala

À la différence de JMeter qui dispose d’une interface graphique pour la définition des scénarios de simulation et de ses paramètres, Gatling propose une API écrite en Scala. Contre-intuitivement, il est assez élégant et aisé de définir des scénarios en Scala plutôt que via une interface graphique, surtout qu’il n’est pas nécessaire d’être un ninja en Scala pour réaliser ses premiers scénarios. Gatling propose une multitude de fonctionnalités dont les basiques seront présentées plus loin.
La documentation complète est disponible à ce lien.
Les scénarios sont placés dans le dossier /user-files/simulations. Voici, typiquement, un scénario implémenté en Scala :

val scn = scenario("User play")
  .feed(myCustomFeeder)
  .exec(
     http("register")
      .post("/user/register")
      .param("email", "${email}")
      .param("password", "${password}")
      .param("pseudo", "${pseudo}")
      .headers(headers_1)
      .check(status.is(200)))
  .pause(0 milliseconds, 100 milliseconds)
  .repeat(10) {
    feed(csv("question_answer.csv").circular)
      .exec(
        http("answer")
         .post("/response")
         .param("questionId", "${questionId}")
         .param("answerId", "${answerId}")
         .headers(headers_1))
      .pause(0,5)
  }

Dans ce cas, Gatling va effectuer une requête post /user/register avec les paramètres email et password (défini dans un fichier séparé), et vérifiera que la réponse a bien un status 200. Enfin, après une pause de 0 à 100 ms, Gatling effectue 10 requêtes /response avec une pause de 0 à 5 sec entre chaque. Les paramètres sont fournis par un « feeder » qui permet de factoriser des variables au sein d’un fichier CSV par exemple (pour plus d’infos, suivez le lien)
Pour apprendre à écrire un scénario avec Gatling, il y a le tutorial officiel.

Exécution de bench

Pour lancer un scénario il suffit d’exécuter le script gatling.sh ou .bat selon l’environnement qui se trouve dans le dossier /bin. Gatling va compiler automatiquement les classes Scala puis vous demande de choisir le scénario à exécuter. À l’issue de la simulation, un rapport web est généré automatiquement à partir du fichier de log. Il contient toutes les métriques mises en forme de façon graphique grâce à la librairie Javascript HighChart.

Un exemple de rapport :

Cloudification

Afin d’effectuer des tests de charges proches des conditions réelles nous avons cloudifié Gatling en automatisant son installation et son exécution sur les VM d’Amazon.
Grâce à Cloudify, nous pouvons désormais lancer les tests de charge à partir d’Internet et sur autant de machine que nous voulons. Les recipes sont relativement simples puisqu’il s’agit essentiellement de télécharger et de dézipper le dossier d’installation de Gatling. Les scénarios sont uploadés avec la recipe, ils doivent donc être déplacés dans le répertoire /simulation de Gatling.
L’exécution du bench s’effectue grâce à une custom command « executeBench » dont le premier paramètre est le nom du scenario à exécuter et le second, le nom que l’on donne à cette simulation. La custom command lance alors le test de charge pour toutes les instances de Gatling sur chaque VM. Les rapports sont donc générés individuellement sur chaque VM.

Pour obtenir un rapport unique, on pourrait scripter la récupération de tous les résultats générés, leur fusion et la regénération d’un nouveau rapport global.
Le rapport est ensuite poussé sur S3 soit automatiquement, soit via une custom command (pushResult).

À travers ce use-case de Cloudify, nous montrons, une fois encore, sa simplicité et sa commodité d’utilisation en automatisant complètement la chaîne : déploiement, installation et exécution de tests de charge à partir du Cloud Amazon EC2.

Conclusion

L’un des avantages le plus important de Gatling est sans conteste sa capacité à générer des rapports graphiques de qualité à l’issue de chaque simulation. De cette façon, le testeur a immédiatement accès aux résultats de manière visuelle, sans post-traitement supplémentaire.
De plus, l’écriture des scénarios de test de façon fonctionnelle en Scala peut faciliter la lisibilité du test. Surtout grâce aux feeders qui permettent de factoriser les paramètres dans des fichiers à part.

Enfin, le lancement des tests via des simples commandes de script rend sa cloudification aisée.

Créer rapidement un prototype d’application HTML5 pour téléphones portable avec Sencha Touch.

Sencha Touch est un framework Javascript. Il dispose d’une bibliothèque riche pour mettre en place rapidement une application HTML5 orienté Single Page Application.

Nous avons utilisé Sencha Touch pour développer rapidement notre jeux de quizz pour le Devoxx France 2013. Il s’agissait d’expérimenter ce framework dans le cadre d’un développement court et au budget limité. Sencha répond à cette problématique en produisant des applications HTML5 utilisables sur une grande majorité des téléphones du marché sans développement spécifique pour chaque plateforme (mis à part un design spécifique pour les tablettes).

FastContestSenchaTouch

Points positifs :

Points négatifs :

  • fort couplage (l’application créée ne pourra se défaire de Sencha)
  • documentation pas très à jour
  • forte dépendance à webkit ( => ne supporte pas Firefox, Opera, IE ainsi que de nombreux autres navigateurs)

Installer Sencha

Pour développer une application HTML5 en utilisant Sencha, il est nécessaire de télécharger l’API Sencha Touch ainsi que l’application Sencha Cmd. Le premier permet à l’application de fonctionner tandis que le second permet de créer l’archétype de l’application et de fabriquer le paquet que l’on mettra en production (ne copier que les bibliothèques Sencha effectivement utilisées, minification du Javascript, …)

API Sencha

  1. Télécharger Sencha Touch (http://www.sencha.com/products/touch/download/)
  2. Dézipper et placer dans un serveur Apache (pour éviter les problèmes de Cross Domain, sinon lancer un navigateur en désactivant la sécurité pour tester votre application en développement).

Sencha Cmd

  1. Télécharger Sencha Cmd (http://www.sencha.com/products/sencha-cmd/download)
  2. Installer (répertoire par défaut : ~/bin/Sencha)

Créer une application de type HelloWorld

Plutôt que de présenter l’application utilisée lors du Devoxx, on commencera par mettre au point une simple application.

Pour générer l’archétype de l’application, il faut créer un dossier portant le nom de l’application (ex : myapp) et lancer la commande idoine :

~\Desktop\blog\touch-2.1.1>mkdir myapp
~\Desktop\blog\touch-2.1.1>cd myapp
~\Desktop\blog\touch-2.1.1\myapp>sencha generate app myapp ../myapp

Maintenant le dossier « myapp » contient un projet Sencha. Quelques explications sur les ressources créés :

  • le fichier app.js est le point d’entrée de l’application
  • le dossier app contient les différentes classes javascript du projet,
  • le dossier ressources contient les éléments externes (icones, libs…)
  • le dossier touch contient un sous-ensemble de l’API

Développer

Nous vous proposons maintenant de créer une application Sencha. Plutôt que de vous donner le code de notre jeux de quizz, nous allons créer une application plus simple qui permet de lister des pizzas et de voir leurs ingrédients.

Sencha repose sur un framework MVC et il propose des classes que l’on peut étendre : Ext.data.Model, Ext.dataview.List, Ext.Panel, …

Nous allons débuter par décrire le modèle de donnée : ici nos pizzas et leurs ingrédients. Une relation « One to Many » relient les pizzas à leurs ingrédients, sachant qu’un ingrédient ne peut se trouver plus d ‘une fois dans une pizza.

myapp/app/model/ingredient.js

Ext.define('myapp.model.Ingredient', {
  extend: 'Ext.data.Model',
  config: {
    fields: [
     {name: 'name'}
    ]
  }
});

myapp/app/model/pizza.js

Ext.define('myapp.model.Pizza', {
  extend: 'Ext.data.Model',
  uses: ['myapp.model.Ingredient'],
  config: {
    fields: [
      {name: 'name'}
    ],
    hasMany: {
      model: 'myapp.model.Ingredient',
      name: 'ingredients'
    }
  }
});

Nous allons maintenant implémenter un store de pizzas. Un store permet de gérer les données, de lire ou de sauvegarder depuis une source locale (json, xml) ou distante (ajax, jsonp, …). Dans notre cas, on lira des données directement écrites dans le code.

myapp/app/store/menu.js

Ext.define('myapp.store.Menu', {
  extend: 'Ext.data.Store',
  requires: ['myapp.model.Pizza'],
  config: {
    model: 'myapp.model.Pizza',
    storeId: 'Menu',
    autoLoad: true,
    data: [
      {
        name: 'marguerita',
        ingredients:[
          {name: 'Tomato'},
          {name: 'Cheese'},
          {name: 'Olives'}
        ]
      }
    ]
  }
});

Les vues de l’application sont la liste des pizzas et une fenêtre qui s’ouvre lors de la sélection d’une pizza pour afficher les ingrédients

myapp/app/view/MenuList.js

Ext.define('myapp.view.MenuList', {
  extend: 'Ext.dataview.List',
  requires: ['myapp.store.Menu'],
  origin: 'menu', //custom identifier for the controller pizzaiolo
  config: {
    store: 'Menu',
    itemTpl: [
      '<div>{name}</div>'
    ]
  }
});

myapp/app/view/ingredientsListOverlay.js

Ext.define('myapp.view.IngredientsListOverlay', {
  extend: 'Ext.Panel',
  alias: 'widget.ingredientsListOverlay',
  config: {
    centered: true,
    height: 200,
    width: 200,
    modal: true,
    items: [
      {html: '<h3>Ingredients</h3>',styleHtmlContent: true}
    ]
  }
});

Nous allons maintenant implémenter un contrôleur qui gèrera l’affichage de la liste d’ingrédients quand une pizza est sélectionnée.

myapp/app/controller/pizzaiolo.js

Ext.define('myapp.controller.Pizzaiolo', {
  extend: 'Ext.app.Controller',
  requires: ['myapp.view.IngredientsListOverlay'],
  config: {
    control: {
      'list[origin=menu]': {
        itemtap: 'displayIngredients'
      }
    }
  },
  displayIngredients: function(list, index, target, record, e, eOpts){
    var menu = new myapp.store.Menu();
    overlay = Ext.widget('ingredientsListOverlay');
    Ext.Viewport.add(overlay);
    menu.getAt(index).ingredients().each(
      function(ingredient){
        overlay.insert(overlay.getItems().length,{html: ingredient.get("name")});
      }
    );
  }
});

Enfin, on modifie app.js pour qu’il charge le store et affiche la première vue (la liste de pizzas) au démarrage.

var menu = new myapp.store.Menu();
Ext.Viewport.add(Ext.create('myapp.view.MenuList'));

Embedding Tomcat 7 for unit tests

Recently (in fact, few months ago), I have had to develop a small REST service exposing some methods that could be invoked remotely by a REST client (using GET and POST methods). The service contract was so simple that I took less time to write the service class by using Jersey that declaring all the Spring dependencies in the project pom.xml or creating a new application with the Play! framework.

As a not fully agile developer, I didn’t write the tests before starting the service (oh !! you don’t respect the TDD ? no ! I don’t — unless for this time — :)). So after finishing the few lines of code of my service (<500 lines), came the time to test my service.

Then I was wondering myself how could make quickly an integration test in my JUnit test case inside my IDE, before creating a new Jenkins Job (yes ! this time I’ve heard about the CI :)). Below some of them :

  • Servlet Unit test
  • using Arquilian
  • starting manually an external servlet container
  • starting a container with Cargo
  • using an embedded server started during the test setup phase (@Before for instance)
  • etc…

As a lazzy developer as usual, I opted for the simpliest choice (for me) : using an embedded Tomcat server.

First, I added the following line (dependencies management) in my project pom.xml. Yes! here the project is a Maven based project.


<properties>
	<tomcat-version>7.0.26</tomcat-version>
</properties>
...
<!-- TEST -->
		<dependency>
			<groupId>org.apache.tomcat.embed</groupId>
			<artifactId>tomcat-embed-core</artifactId>
			<version>${tomcat-version}</version>
			<scope>test</scope>
		</dependency>
		<dependency>
			<groupId>org.apache.tomcat.embed</groupId>
			<artifactId>tomcat-embed-logging-juli</artifactId>
			<version>${tomcat-version}</version>
			<scope>test</scope>
		</dependency>
		<dependency>
			<groupId>org.apache.tomcat.embed</groupId>
			<artifactId>tomcat-embed-jasper</artifactId>
			<version>${tomcat-version}</version>
			<scope>test</scope>
		</dependency>
		<dependency>
			<groupId>org.apache.tomcat</groupId>
			<artifactId>tomcat-jasper</artifactId>
			<version>${tomcat-version}</version>
			<scope>test</scope>
		</dependency>
		<dependency>
			<groupId>org.apache.tomcat</groupId>
			<artifactId>tomcat-jasper-el</artifactId>
			<version>${tomcat-version}</version>
			<scope>test</scope>
		</dependency>
		<dependency>
			<groupId>org.apache.tomcat</groupId>
			<artifactId>tomcat-jsp-api</artifactId>
			<version>${tomcat-version}</version>
			<scope>test</scope>
		</dependency>

And then, here comes the code… :)

Please note that there are so many different ways to achieve the same goal, therefore my following code is provided  for the example purpose only. Of course, you can write your classes by using your own style :)

First, I wrapped the Tomcat inside a Runnable that will be started during the test init phase

//import are removed
public class EmbeddedServer implements Runnable {

	private Tomcat	tomcat;
	private Thread	serverThread;

	public EmbeddedServer(int port, String contextPath) throws ServletException {
		tomcat = new Tomcat();
		tomcat.setPort(port);
		tomcat.setBaseDir("target/tomcat");
		tomcat.addWebapp(contextPath, new File("src/main/webapp").getAbsolutePath());
		serverThread = new Thread(this);

	}

	public void start() {
		serverThread.start();
	}

	public void run() {
		try {
			tomcat.start();
		} catch (LifecycleException e) {
			throw new RuntimeException(e);
		}
		tomcat.getServer().await();
	}

	public void stop() {
		try {
			tomcat.stop();
			tomcat.destroy();
			deleteDirectory(new File("target/tomcat/"));
		} catch (LifecycleException e) {
			throw new RuntimeException(e);
		}
	}

	void deleteDirectory(File path) {
		if (path == null) return;
		if (path.exists()) {
			for (File f : path.listFiles()) {
				if (f.isDirectory()) {
					deleteDirectory(f);
					f.delete();
				} else {
					f.delete();
				}
			}
			path.delete();
		}
	}

Finally run my JUnit tests where my client could request my REST service that has been previously deployed on the embedded Tomcat instance

public class MyAppDeployedOnLocalTest {

	@Before
	// or @BeforeClass
	public void startServer() throws ServletException {
		embeddedServer = new EmbeddedServer(9090, "/myservice");
		embeddedServer.start();

	}

	@After
	// or @AfterClass
	public void stopServer() {
		embeddedServer.stop();
	}

	public void test_send_request_without_parameters (){
            Client client = ...
            Reply reply = client.sendRequest();
            assertTrue (reply.isOk());
    }
}

And ..voilà ! :)

FastConnect Inside : le vendredi du connaisseur

Pour notre session de juillet du « Vendredi du connaisseur » (session technique où chacun parle d’un sujet/problématique qu’il a rencontré pendant le mois), nous avons choisi de faire simple : pizza pour tous & prez en freestyle.

Finalement au menu, nous avons eu droit à :

  • une introduction résumée de la formation MongoDB que Mael & Florian ont suivie le mois dernier dans les locaux de FastConnect à Issy (en partenariat avec 10gen)
  • une petite présentation sur la gestion de la mémoire par la JVM et le pourquoi du classique « java.lang.OutOfMemoryError: PermGen space » par Arnaud
  • un survol sur le fonctionnement du SSO & intégration CAS accompagné d’une démo qui marche :) par Marc

Sans oublier les 6 pizzas (de 2 personnes) : Ananas, Cap Horn, Bolognaise, Catalane, Los Angeles et Orientale ;)

Rendez vous à la prochaine session …

Équipe FastConnect Rennes

DevoxxFR 2012, c’est fini

DevoxxFR 2012 est terminé.

Nous avons animé notre stand de manière festive et nous avons présenté, avec un succès certain, notre société et nos métiers.

Notre quiz en ligne a été un succès. Plus qu’un concours il s’agissait d’une des démonstrations que nous avions préparée pour illustrer notre savoir-faire. L’application s’exécutait dans un data center en Irlande et nous avions automatisé son déploiement à l’aide de Cloudify, un outil de PaaS fabric réalisé par GigaSpaces.

Nous publierons bientôt les vidéos de ces démonstrations. En attendant, voici un extrait des questions que nous avons posées.

le premier gagnant de notre quiz

A constructor is used to

  • Free memory
  • Initialize a newly created object
  • Import packages
  • Create a JVM for applets

What is the number of bytes used by Java primitive long?

  • The number of bytes is compiler dependent
  • 2
  • 4
  • 8

Which of the following statement is False?

  • The throw keyword denotes a statement that causes an exception to be initiated
  • A class that is declared without any access modifiers is said to have package or friendly access
  • A class inherit the constructors of its superclass
  • The primitive types are byte, char, short, int, long, float, double, and boolean

A mechanism of moving the session from one server to another in case of server failure is called as

  • Session Hijacking
  • Session Migration
  • Session Tracking
  • None of the Above

Which one of the following method is not Agile?

  • The Scrum method
  • The XP method
  • The Rache method
  • The RAD method

Who did create the mechanical calculator in 1642?

  • Blaise Pascal
  • Sir Isaac Newton
  • Gottfried Wilhelm Leibniz
  • Alan Mathison Turing

What is Corba?

  • A free Java tool that calculates the percentage of code accessed by tests
  • A broker for building distributed object-oriented applications
  • A member of the family Elapidae
  • A man with a Psycho-Gun in his left arm

le second gagnant de notre quiz

Consider the following piece of code byte x = 0; x += 1;

  • Results in x having the value 1
  • Will require a cast (byte) before 1
  • Will give syntax error
  • Will cause an error during execution

What are Java varargs?

  • A keyword to denote non-constant values
  • A syntax to write methods that took an arbitrary number of arguments
  • An object reference that may be updated atomically
  • A keyword to indicate that a variable’s value will be modified by different threads

In java, which mechanism allows to use a same function with different argument types?

  • Inheritance
  • Overriding
  • Overloading
  • Encapsulation

Choose the statement that best describes the relationship between JSP and servlets.

  • Servlets are built on JSP semantics and all servlets are compiled to JSP pages for runtime usage.
  • JSPs are built on servlet semantics and all JSPs are compiled to servlets for runtime usage.
  • Servlets and JSP are competing technologies for handling web requests.
  • JSP and servlets are unrelated technologies.

In java, which one of these statements is true?

  • An anonymous class can be declared as both extending a class and implementing an interface
  • An anonymous class can extend a class or implement an interface
  • An anonymous class can only extend a class
  • All statements above are false
  • An anonymous class can extend a class or implement an interface

Which of the following is not a programming language?

  • Luminaire
  • Eiffel
  • OCaml
  • Smalltalk

What means JIT in Java?

  • Java interface transaction
  • Just in time transaction
  • Just in time compiler
  • Juvenile in training

Colore ta console

As for my previous article, I would like to talk about a not well known subject: How to color your console?

As administrator, and in particular when my eyes are tired, I am happy to read « OK » in green and « Not OK » in red. If you google with this subject, you will find many pages with simple tricks, but few with good explanations.

The purpose of this article is not to give hints about colorization, but to explain how it works and the main differences between a Linux terminal and a Windows console.

Linux terminal

History

A long time ago, a time that the youngest can not know, a computer terminal referred to an hardware device that was used for entering data into (a keyboard), and displaying data (a screen) from a computer. Somehow the end of a network.

VT100 was a video terminal. Its detailed attributes became the de facto standard for terminal emulators.
It communicated with its host system over serial lines using the ASCII character set and control sequences (a.k.a. escape sequences) standardized by ANSI. The VT100 was also the first Digital mass-market terminal to incorporate « graphic renditions » (blinking, bolding, reverse video, and underlining) as well as a selectable 80 or 132 column display.

Today we use mostly virtual terminals (in Linux, the first six virtual terminals provide a text terminal with a login prompt to a Unix shell) or emulators as xTerm that provides VT102 compatible terminals.

Here few escape sequences commonly used by VT100 compatible terminals.

How to colorize my VT100 terminal

The following lines should show « OK » in green and « Not OK » in red.

echo -e '&#092;&#048;33[32m OK &#092;033[0m'
echo -e '&#092;&#048;33[31m Not OK &#092;033[0m'

The previous script mingles Bash and VT102 escape sequences. Bash interprets and replaces « \033″ by the escape ASCII code. Then the VT102 emulators interpret « <ESC>[32m » as set the foreground color to green.

Portability

A good script should work not only on your computer but everywhere. So we should test the capabilities of our environment before relying on it. I found a lot of examples on Internet that perform tests based on $SHELL or $TERM environment variables. From my experience, these are not a good practices as I will explain.

Shell capabilities

$SHELL contains the login Shell, not the current Shell. Therefore scripts that use it are often buggy and people that use several Shells (like me) are very unhappy.

Simple is beautiful! I advice to do a non-portable script or to insert directly the escape character into your script in order to be independent of the Shell (its implementation of the escape characters and on its possible echo builtin command).

Good text editors show special characters, but it is painful to write « <ESC> » on a keyboard (on Windows you can press « ALT » and type « 0027 » on the keypad…)

echo '<ESC>[32m OK <ESC>[0m'
echo '<ESC>[31m Not OK <ESC>[0m'

Terminal capabilities

A script should check the terminal capabilities before to use VT102 color sequences. We can use the $TERM environment variable and the « test -t fd » conditionnal expression. But it is not easy.

$TERM can take a lot of different values (aterm, xterm, cygwin, etc.) Therefore it is difficult to create an exhaustive list of all terminals that understand the color sequences. Elsewhere, if you are bound to a pseudo-terminal it is not always possible to know the real capabilities of the real end-terminal. And I already experienced few bugs so…

Finally, I think the best practice is to implement a color parameter as the ls command:

  • never means the script will not generate VT102 color sequences
  • always means the script will generate VT102 color sequences
  • auto is where you try to implement a smart default behavior

function print_help() {
	cat <<EOF
# ...
       --color[=WHEN]
              control  whether color is used to distinguish file types.  WHEN
              may be 'never', 'always', or 'auto'
# ...
EOF
}

#...

if [ $color = always -o $color = auto -a -t 1 ]
then
	function print_KO() { echo '&#092;&#048;33[31mKO&#092;&#048;33[0m'; }
	function print_OK() { echo '&#092;&#048;33[32mOK&#092;&#048;33[0m'; }
else
	function print_KO() { echo 'KO'; }
	function print_OK() { echo 'OK'; }
fi

Windows console

History (source Wikipedia)

MS-DOS 1.0 did not support the ANSI or any other escape sequences. Only a few control characters (CR, LF, BS) were interpreted.

MS-DOS 2.0 introduced the ability to add a device driver for the ANSI escape sequences – the de facto standard being ANSI.SYS. This continued to work through Windows 98. Extreme slowness and the fact that it was not installed by default made usage by software almost non-existent.

Console windows in Windows versions based on NT (Windows NT 4.0, Windows 2000, Windows XP, Windows Server 2003, Windows Vista and Windows Server 2008) do not support ANSI escape sequences at all. Softwares can manipulate the console with the ioctl-like system Console API.

Few examples

Many script languages (Perl, Tk, and so on) provide library based on the Console API to change the color of a Windows console. If you use them, the commands to change colors is interlaced with the text output.

Another solution is to use a library that provides an ANSI support. So POSIX guys can keep their habbits.

So how you would color your Windows console depends on the programming langage you chose and its helper libraries.

MS-DOS

MS-DOS is a very poor language (not only for color). We can change the color of the entire Windows console, but we cannot change the color of a particular line.

REM MS-DOS example
REM Creates a Black background with light bright green text
COLOR 0A

My advice, do not use MS-DOS to colorize your output or do not use MS-DOS at all if you can.

PowerShell

I’m not completely a fan of PowerShell because of some strange syntaxes, supposed to make life simpler. But it is a very powerful language and, obviously, we can change color output easily.

Here is a powershell function that I use in my daily work. It is able to print a string with ANSI escape sequences to control colors. I use it basically when I run a remote command on a Linux machine.

### Author: Cyril Martin (mcoolive)

function Write-ColoredHost
{
	Param(
		[switch]$noNewLine,
		[String]$separator=" ",
		[System.ConsoleColor]$foregroundColor = $HOST.UI.RawUI.ForegroundColor,
		[System.ConsoleColor]$backgroundColor = $HOST.UI.RawUI.BackgroundColor
	)
	BEGIN {
		$fgc, $bgc = $foregroundColor, $backgroundColor
	}
	PROCESS {
		$token, $coloredTokens = ([Regex]"&#092;&#048;33[").split($_)
		Write-Host $token `
				   -noNewLine -separator $separator `
				   -foregroundColor $fgc `
				   -backgroundColor $bgc
		foreach ($coloredToken in $coloredTokens) {
			$colorCodes, $token = ([Regex]"m").split($coloredToken, 2)
				([Regex]";").split($colorCodes) | foreach-object {
					switch -regex ($_) {
						"^0{1,2}$" { $fgc, $bgc = $foregroundColor, $backgroundColor }
						"^30$"     { $fgc       = "Black"                            }
						"^31$"     { $fgc       = "Red"                              }
						"^32$"     { $fgc       = "Green"                            }
						"^33$"     { $fgc       = "Yellow"                           }
						"^34$"     { $fgc       = "Blue"                             }
						"^35$"     { $fgc       = "Magenta"                          }
						"^36$"     { $fgc       = "Cyan"                             }
						"^37$"     { $fgc       = "White"                            }
						"^39$"     { $fgc       = $foregroundColor                   }
						"^40$"     {       $bgc =                   "Black"          }
						"^41$"     {       $bgc =                   "Red"            }
						"^42$"     {       $bgc =                   "Green"          }
						"^43$"     {       $bgc =                   "Yellow"         }
						"^44$"     {       $bgc =                   "Blue"           }
						"^45$"     {       $bgc =                   "Magenta"        }
						"^46$"     {       $bgc =                   "Cyan"           }
						"^47$"     {       $bgc =                   "White"          }
						"^49$"     {       $bgc =                   $backgroundColor }
					}
				}
			Write-Host $token `
					   -noNewLine -separator $separator `
					   -foregroundColor $fgc `
					   -backgroundColor $bgc
		}
		if (!$noNewLine) { Write-Host }
	}
}

### A little test
$plink= # path of plink (see PuTTY)
$linuxServer= # hostname
$login= # username
&"$plink" -ssh $login@$linuxServer ls --color=always / | Write-ColoredHost

Java : quizz #4

Il y a quelques temps, une de mes connaissances (qui a délaissé le Java au profit du C embarqué) m’a montré quelques lignes de son code en Java et m’a demandé que va-t-il se passer à l’exécution ?

(Ci-dessous le code, que j’ai fortement allégé et gardé le nécessaire pour notre quizz :))

public class Quizz4 {

	public void handle(Object obj) {
		System.out.println("Handle object : "+obj);
	}
	
	public void handle(String string) {
		System.out.println("Handle string : "+ string);
	}

	public static void main(String[] args) {

		Quizz4 quizz4 = new Quizz4();
		Object obj = null;
		quizz4.handle(null);
		quizz4.handle(obj);
		obj = new String ("my string");
		quizz4.handle(obj);
		quizz4.handle(obj.toString());
	}

}

Bien entendu, ici je simule certains traitements par un simple d’affichage à la console. Et donc, questions pour vous : à votre avis, si on exécute le code (la méthode main) :

A. le code ne se compile pas.
B. le code s’exécute correctement. Dans ce cas, que verrait on affiché à la console ? Et pourquoi ?
C. le code s’exécute correctement, mais on ne peut pas prédire son comportement. Et pourquoi ?

Java : quizz #3

Bonjour,

Il y a quelques jours, Jo (le nom a été changé pour préserver son anonymat :)), un développeur qui a été contraint par son manager d’écrire du code (qui doit utiliser les generics) permettant d’abstraire le code de la nouvelle application et celui du l’ancienne (basée sur une vieille techno maison). On lui a imposé le pattern suivant :

1. soit l’interface commune :

public interface Service<T>
{
  T process (Command command);
}

2. la nouvelle implémentation (de l’application new generation) :

public class NewGenerationService<Result> implements Service<Result>
{
   public Result process (Command...command){....}
}

3. cependant le code basé sur le legacy system ne retourne pas de résultat. De ce fait Jo ne sait pas comment écrire son service

public class LegacySystemService implements Service<??>
{
  public ?? process (Command...command){...}
}

Et bien, que pouvez-vous dire à Jo ici ?

A. Pauvre Jo, fais grève car c’est impossible à faire ce que  ton manager voulait faire !

B. Eh Jo, cherche dans la javadoc et tu trouveras la réponse ! (Dans ce cas, que peut-on mettre à la place des <??> ?)

C. Je te comprends Jo, car c’est trop compliqué pour moi aussi :(

Réponse : Jo pourra d’abord utiliser la classe « java.lang.Void » pour son implémentation legacy, puis étudier le commentaire de Cyril :)

public class LegacySystemService implements Service<Void>
{
   public Void process (Command...command){.... return null;}
}

Java : quizz #2

Question : que se passera-t-il avec le code ci-dessous ?

List suits = ...;
List ranks = ...;
List sortedDeck = new ArrayList();

for (Iterator i = suits.iterator(); i.hasNext(); )
    for (Iterator j = ranks.iterator(); j.hasNext(); )
        sortedDeck.add(new Card(i.next(), j.next()));

A : rien, le code s'exécute correctement
B : le code ne se compile pas
C : le code ne s'exécute pas
D : une exception sera levée pendant l'execution

=== Réponse : on peut compiler et executer le code sans problème. 
Cependant à l'execution si la liste "suits" ne contient pas assez d'éléments 
pour les 2 boucles imbriquées, on aura alors une NoSuchElementException car
la méthode "i.next()" de la liste "suits" sera appelée "trop" de fois (on sera arrivé
à la fin de la liste "suits" avant celle de la liste "ranks")

Java varargs – Pas de magie: soyez prudents!

J’ai rencontré une erreur bizarre, liée aux varargs, sur un projet que je visitais récemment…

Tout d’abord un petit rappel de ce que sont les varargs en java:
Comme vous le savez surement les varargs permettent de définir des méthodes qui peuvent accepter des arguments optionnels et au nombre variable. Définir une telle méthode est aussi simple que ci-dessous:

public void doSomething(String... values) {
// do something here
}

La méthode est alors accessible avec aucun paramètre ou n’importe quel nombre de paramètres:

public void callDoSomething() {
doSomething();
doSomething("a","b","c");
}

Bref les varargs apportent une vrai souplesse dans la définition et l’utilisation des méthodes aux paramètres optionnels et/ou variables en java.
Maintenant que ce passe-t-il réellement ? Comment JAVA gère cette magie ? En fait la réalité est relativement simple et peut-être pas aussi idéale que ce qu’on aurait pu le souhaiter… En effet les varargs ne sont pas une nouvelle super feature de java mais plutôt une feature de son compilateur. Le compilateur va tout simplement remplacer les appels en générant des signatures de méthodes basées sur le passage de tableaux d’objets. Si l’on reprends notre exemple précédent nous avons donc l’équivalent suivant:

public void doSomething(String[] values) {
// do something here
}

Et le client:

public void callDoSomething() {
doSomething(new String[0]);
doSomething(new String[]{"a", "b", "c"});
}

Bref les varargs c’est bien, ça simplifie l’écriture de mon code mais… Mais si je ne comprends pas comment ça marche je peux faire des erreurs bête… Et je dirais que même si je comprends comment ça marche je peux louper certains changements relativement facilement.

Prenons un exemple simple. Disons qu’une équipe A est chargée de développer un jar d’utilitaires pour une équipe B.

La première version de l’utilitaire contient dans une des classes la méthode suivante:

public void doSomething() {
// do something here
}

L’équipe B utilise ma méthode avec un appel simple:

public void callDoSomething() {
doSomething();
}

Dans la release suivante l’équipe A ajoute un nouveau paramètre optionnel à l’aide des VarArgs. L’intérêt est évident: les utilisateurs existants n’auront pas à modifier leur code pour continuer d’utiliser l’utilitaire, et les nouveaux utilisateurs peuvent bénéficier des nouvelles options offertes par le nouvel argument optionnel.

public void doSomething(String... params) {
// do something here
}

Mon utilitaire comprends d’autres méthodes et la nouvelle amélioration en plus d’ajouter cette modification améliore le comportement de plusieurs autres de ces outils (sans changement dans l’API). L’équipe B particulièrement intéressée par ces améliorations décide donc de migrer vers la nouvelle version.
Les développeurs des l’équipe B sont des gens consciencieux, ils ont développé leurs tests unitaires, d’intégration etc.. et leur intégration continue fonctionne bien. Sans aucune modification à leur code l’inclusion de ma nouvelle version n’a causé aucun soucis.

L’équipe B décide donc d’inclure mon nouveau jar dans leur environnement de production. Comme leur application est très lourde et n’a pas été modifiée (aucun changement de code) l’équipe décide pour faciliter la manoeuvre de ne mettre à jour que le jar utilitaire.

A l’execution comme vous vous en doutez puisque vous avez bien suivi la réalité des VarArgs l’erreur suivante se produit:

java.lang.NoSuchMethodError: fr.fastconnect.java.blog.varargs.MyProviderClass.doSomething()V
at fr.fastconnect.java.blog.varargs.UsingClass.main(UsingClass.java:10)

Note: dans le contexte de mon projet réel l’inclusion a heureusement été faite sur un environnement de test (je voulais donner un effet « scénaristique » un peu plus dramatique).

Gardez donc en tête, les Varargs ne sont pas une fonctionnalité de runtime mais de compilation, il n’y a pas de magie donc soyez prudents!!