dimanche 18 novembre 2012

Menu Login du Mac - Cacher un utilisateur

Cacher par exemple l'utilisateur postgres

J'ai récemment installé postgreSQL et depuis apparaît dans la liste des utilisateurs de la fenêtre de login l'utilisateur technique postgres.
La commande ne semble pas accesible via les outils graphiques et necessite de passer par un shell :
> sudo defaults write /Library/Preferences/com.apple.loginwindow HiddenUsersList -array-add postgres

Pour supprimer cette liste des utilisateurs cachés :

> sudo defaults delete /Library/Preferences/com.apple.loginwindow HiddenUsersList
Je n'ai pas trouvé comment supprimer un seul utilisateur.

Consulter la liste des utilisateurs cachés

> sudo defaults read /Library/Preferences/com.apple.loginwindow HiddenUsersList

samedi 20 octobre 2012

MAC - Administration


Dans ce billet, je vais essayer de compiler les astuces d'administration de mon mac;

Service daemon lancés au démarrage

Exemple pour postgresql


  • stopper un service : launchctl unload /Library/LaunchDaemons/com.edb.launchd.postgresql-9.0.plist
  • relancer un service : launchctl unload /Library/LaunchDaemons/com.edb.launchd.postgresql-9.0.plist

MAC - Options au redémarrage


Vérifier votre disque ou réinstaller votre système

Pour cela, la commande magique est de redémarrer en laissant appuyé su CMD+R.

Démarrer sur un autre périphérique

Redémarrer en laissant appuyé sur option (voir ici).

lundi 24 septembre 2012

Des infos Mac.

Heureux détenteur d'un mac, je me trouve confronté à des problèmes de débutant sur cette plate-forme. Je vais essayer de regrouper les différentes infos que je regrouperai au fur et à mesure sur ce blog.

mercredi 18 juillet 2012

J'ai testé Google play books

Le test

Un premier billet pour faire part de mon premier test du service d'achat de livres de Google ( Play Books ). Mon objectif était d'acheter un livre et de pouvoir le lire sur ma liseuse bookeen ( cybook odyssey ). L'achat est très simple du moment que vous disposez d'un compte Google wallet. Une fois l'achat effectué vous pouvez lire votre livre en ligne, le télécharger au format pdf, ou au format ePub. C'est ce dernier format qui m'intéresse car c'est le format standard des liseuses dotées d'encre électronique ( ou ereaders ). Quand vous téléchargez votre livre dans ce format, le fichier résultat n'est pas un fichier ePub mais une sorte de descripteur que adobe digital edition ( outil à utiliser pour copier vos livres électroniques protégés par un DRM sur votre liseuse ) sait ouvrir. Quand ce descripteur est ouvert, l'application va générer dans votre disque le fichier ePub tant attendu et vous pourrez ensuite le copier sur votre liseuse sans problème.

Bilan

L'interface est très bien, l'achat est facile ( mais payer est rarement difficile ), le téléchargement des livres est aussi très simple. Ma liseuse a lu le livre que je viens d'acheter de manière tout à fait normale. Je regrette juste ce choix de ne pas délivrer directement de fichier ePub, fichier qui pourrait d'ailleurs être dépourvu de DRM : un simple watermarking suffirait ( cette technique laisse une liberté totale à l'utilisateur : elle permet juste de remonter à la source d'un fichier qui se retrouverait diffusé un peu partout, et ainsi de trouver le contrevenant ). Il me restera aussi à voir si la bibliothèque fournie est vraiment conséquente et si elle est mise à jour régulièrement.

mardi 17 juillet 2012

java 7 nio

In this short post, I will focus on the points I found interesting in java 7 new classes introduced into the package java.nio.file.
I will not describe all this framework, the best documentation for that is the official javadoc.

Manipulating the Path

These two classes Paths and Path are introducing some very nice methods to manipulate files path.

java.nio.files.Paths

This is the factory class, to be used for Path creation

java.nio.files.Path

This class is used to locate an object in the file system. Such instances are immutable and Thread safe.
Note that you can construct a Path which is not associated with an existing file. This new class is very easy to manipulate, you can iterate on each segment of the path easily, you do not see any more the file system separator ( except if you really want )

Useful methods :
  • normalize : very classic, to remove things like '..', './' , ... from the actual Path - returns the new Path without these redundant informations
  • relativize : return the absolute path from a relative path
  • toFile : return the file associated with this path
  • iterator() to iterate on each segment
  • ...

Manipulating Files

Most of the operation on files will be done using the final class java.nio.files.Files.
Useful methods :

  • public static byte[] readAllBytes(Path path) : we all did it ourself, or by using well-known libs.
  • public static long copy(Path source,OutputStream out) : avoid a lot of code to copy a file in an already opened stream
  • static Path move(Path source, Path target, CopyOption... options): without this weird boolean result returned in the former file API. You should simply rely on the exception thrown in case of problem. See enum StandardCopyOption.
  • ...

Watching a Directory for Changes

This is the killer feature I was waiting for. I was previously using some JNI extensions I did  ( one for linux based on the inotify kernel feature, one based on the mac FileSystem Events Api ).
My first test illustrate the fact that the linux implementation is efficient, but the mac implementation seems to be a simple polling : not very efficient ... ( with oracle jdk 1.7.0_05 ).


Useful classes

  • java.nio.file.WatchService : the service responsible to deliver the notification to your application
  • java.nio.file.WatchKey : returned for each directory you are watching

Links

le puits des mémoires de Gabriel Katz

Trois hommes se réveillent , chacun dans une espèce de cercueil ; cercueils eux-même entassés dans un chariot accidenté. Le problème pour eux est qu'ils sont vierges de toute mémoire personnelle : leur connaissance du monde extérieur est intacte mais ils n'ont aucune idée de qui ils sont. Une fois sortis de la zone de montagne dans laquelle l'accident a eut lieu, ils vont rapidement se rendre compte que des hommes sont à leur recherche. Ce premier tome raconte la fuite de ces trois personnages, durant laquelle chacun va apprendre à se connaître : l'un est un excellent escrimeur, l'autre aime les chevaux et le troisième se révèle doté de pouvoirs magiques. Toute l'intrigue de ce premier tome se déroule dans un petit royaume voisin du puissant duquel semblent venir ceux qui cherchent nos trois comparses.
Le scénario de ce livre est original, ce n'est pas une nouvelle circonvolution autour des schémas efficaces mais parfois éculés de la Fantasy : le monde qui y est décrit est réaliste, original et semble prêt à accoucher d'autres histoires toutes aussi intrigantesQue dire d'autre, en plus de ce résumé du premier tome, si ce n'est que j'ai été content de lire ce bouquin ( notons qu'il est écrit en français )  , qu'il ce lit d'une traite ( seulement 300 pages environ) et que j'attend sa suite avec impatience !

Ma note : 15 / 20

dimanche 8 juillet 2012

Les autres - James Herbert

Un détective, le personnage central, est embauché par une veuve pour retrouver son enfant, enfant qu'elle pense qu'on lui a dérobé juste après sa naissance. Lors de l'accouchement on lui a dit que le bébé n'a pas survécu mais elle est désormais rongée par le doute ... Seulement cette naissance a eu lieu il y a 18 ans  et aucune trace n'en subsiste ! Notre détective prend l'affaire en main sans savoir vers où celle-ci va l'entraîner ; malgré son handicap, notre héros est bossu et affligé d'un visage peu avenant, il va poursuivre son enquête. Dismas - nom que lui donnèrent les soeurs qui l'élevèrent en espérant ainsi l'aider pour son futur -  avance aiguillonné par son instinct et d'étranges visions qui lui font prendre cette investigation de manière de plus en plus personnelle. Au cours du récit viendront l'aider une voyante, appelée par la veuve, et une jeune fille au visage d'ange mais souffrant d'un corps tordu par la maladie.

Suspens, fantastique, amour, émotions poignantes, peurs, karma, ... tout cela mélangé avec soin par un "James Herbert" qui avec ce livre m'a fait vivre une expérience inoubliable. Cinq cents pages dans la peau d'un personnage torturé par la vie, auquel on ne tarde pourtant pas à s'identifier. Lecteurs, ne vous laissez pas rebuter par l'idée de lire un bouquin duquel le héros n'est pas dans les standards habituels ; vous passeriez à côté de quelque chose de rare. Si comme d'habitude ( voir cet autre article ) cet auteur nous fait rentrer dans la peau de son personnage par "petite touches"  il nous tient aussi en haleine, particulièrement à la fin, avec un suspens incroyable : j'aurai voulu faire défiler les pages encore plus vite pour découvrir ce qui allait m'arriver arriver à Dismas et me libérer de cette délicieuse angoisse qui me tenaillait.

Ma note : 18/20

mercredi 4 juillet 2012

Magic Cottage de James Herbert

Un jeune couple décide de quitter la grande ville et de s'installer dans un cottage à la campagne pour trouver un nouveau rythme de vie. Lui, est un musicien doué, travaillant pour les plus grands ; elle, est une illustratrice de talent. Ils rêvent de pouvoir échapper à leur vie citadine même si leur travail les y ramènera régulièrement ; mais jusqu'à présent ils n'ont pas trouvé la perle rare dans laquelle ils souhaitent habiter. Jusqu'au jour où madame est mystérieusement attirée par une annonce dans le journal. A partir de là, tout s'enchaîne rapidement : visite, coup de coeur, achat, ... installation. Dans ce nouveau nid d'amour, leur talent respectif semble prendre une résonance toute particulière : il joue de la guitare comme jamais ; elle produit des dessins plus que splendides. Même leur vie amoureuse semble plus intense, magique ... Une magie qui semble petit à petit prendre possession d'eux, dans tout un tas de petits faits merveilleux qui, dans l'atmosphère du cottage, semblent presque anodins pour notre couple : les animaux guérissent à leur contact, leur maison et son entourage s'épanouissent, ... Mais, petit à petit, cette magie semble se noircir sous l'influence d'une force maléfique non authentifiée ...


J'ai particulièrement bien aimé cette oeuvre pour son excellente narration ; l'auteur nous plonge, par petites touches, dans l'intimité de ce couple. Il nous fait partager leurs joies, leurs rêves ; puis leurs peurs ... Ce n'est pas tout à fait un livre d'horreur ; disons qu'il est à la croisée de l'horreur et du fantastique ; avec un peu de suspens pour corser le tout.


Ma note : 17/20


PS : je profite au passage de ce billet pour dire que j'ai acheté ce livre au format électronique sur le bookeenstore ; magasin en ligne dans lequel on peut trouver certains livres sans DRM.

jeudi 21 juin 2012

Minutes de Dominique Raymond Poirier

Voulant tester le service d'achat de livre électroniques d'Amazon, j'y ai acheté ce bouquin un peu par hasard. J'ai été agréablement suppris par ce livre qui ce lit d'une traite. Son histoire est originale, son style très agréable. En voici un bref résumé qui je l'espère vous incitera à le lire.

Un savant, le docteur Théodore Arenson, découvre un moyen d'envoyer des objets dans une dimension temporelle parallèle. Dans cette dimension, le temps s'écoule 500 fois plus rapidement que dans la notre. Notre bon docteur décide d'y envoyer un explorateur ; celui-ci sera son ami Robert Haas pour qui cette aventure sera un moyen d'échapper à son triste quotidien : Robert est un amateur de science mais qui la journée est un simple gardien dans un immeuble. Les deux comparses réaliseront cette expérience en secret ; secret qui renforcera leur amitié et les mènera à terme à partager un destin assez surprenant.

Le seul bémol que j'aurai à formuler est que ce livre est presque trop court. L'intrique aurait pu être légèrement plus étoffée.

Ma note : 15/20

vendredi 8 juin 2012

Les seigneurs des runes

Voilà un cycle qui m'a beaucoup plu et sur lequel je voulais écrire quelques lignes depuis longtemps.
Le récit se déroule au sein d'un monde féodal dans lequel les seigneurs sont pourvus d'attributs sur-humains ; attributs qui leur ont été 'donnés' par des dédiés. Ces dédiés sont des hommes ou des femmes, tellement dévoués à leur maître qu'ils leur font don d'une partie d'eux même. Certains donnent leur odorat, d'autres leur force, certains leur intelligence, ... Ces supers seigneurs utilisent leurs pouvoirs pour protéger leur domaine et les personnes qui le composent. Un jour pourtant cette paix est mise en péril par Raj Ahten, un seigneur loup : un homme qui en plus d'avoir accepté les dons de milliers de ses sujets a aussi accepté des dons d'animaux. Cette guerre qui commence à ravager les royaumes se déclenche au moment où les ennemis ancestraux de l'humanité font leur ré-apparition dans quelques coins du royaume. C'est dans ce contexte qu'un jeune seigneur, Gaborn, prend la succession de son père. Rapidement, notre héros apparaît comme le seul espoir de l'humanité ; même la terre semble l'avoir compris en le faisant son champion : le "Roi de la Terre".
J'ai lu ce cycle jusqu'au quatrième tome et je n'ai pas été déçu. Je compte attaquer le cinquième rapidement ; celui-ci aura d'ailleurs pour personnage principal le fils de Gaborn.


Ma note ( pour ces quatre premiers tomes ) : 16/20

dimanche 6 mai 2012

Les bannis et les proscrits - Suite et fin

Cela devait arriver, je me suis laissé déborder : j'ai terminé les trois tomes de ce cycle avant même de mettre à jour mon blog.
Vous allez me dire que c'est plutôt bon signe ; et en effet, les trois derniers tomes ont tenu toutes les promesses que les deux premiers nous avaient fait , je n'ai pas pu m'arrêter avant d'avoir terminé le dernier élément du cycle.

Sans dévoiler aucune piste sur le déroulement de cette histoire, je peux vous dire que dans ces trois volumes nous allons voir une Elena grandir et prendre de l'ampleur. Ses compagnons et elle vont être soumis à des épreuves de plus en plus rudes. Le lecteur, quant à lui, sera tenu en haleine jusqu'au bout. Car, contrairement à d'autres cycles, ce qui est aussi très agréable dans cette oeuvre est que justement il y a un bout, une fin qui ne nous laisse pas sur notre faim.

JAVA 7 - Fork/Join framework

En parcourant le net, je me suis rendu compte que peu de pages, françaises, étaient présentes pour décrire de façon simple et concise le framework Fork/Join apporté par Java 7. Le but de ce billet sera d'en donner les éléments clés ainsi que les pointeurs sur les pages qui m'ont aidé à me faire une rapide compréhension de ce nouveau standard.

Le principe général

C'est une mise en application du vieil adage "diviser pour mieux régner" ; sauf que dans notre cas c'est pour la bonne cause.
Désormais, quand on commence à coder une boucle qui risque d'être longue car consommatrice de CPU ou lorsque l'on commence à implémenter un algorithme dont l'exécution sera longue en terme de temps CPU ; JAVA met à notre disposition un lot de classes permettant de coder facilement l'exécution en parallèle de certains traitements mais aussi, et surtout, aidant différentes unités d'exécution (ou Tache) à se synchroniser les unes par rapport aux autres. 

Mise en application

C'est au développeur de découper son calcul/traitement en unités d'exécution (ou tache) plus petites, jusqu'à obtenir une taille qu'il considérera comme suffisamment petite pour pouvoir être exécutée sans être divisée. Ce découpage peut être fait de manière récursive. Chaque tâche devra dériver de la classe "ForkJoinTask". En fait, le framework fournit deux classes spécialisant la class ForkJoinClass :
  • RecursiveTask<T> : pour coder une tâche retournant une valeur de Type T 
  • RecursiveAction : pour coder une tâche dont on n'attend pas de valeur résultat, mais devant réaliser une action.
Une fois ce travail de découpage effectué, la tâche principale ( ou point d'entrée ) est passé à un executor spécialisé ( class ForkJoinPool ).

Les liens

JMX à travers un firewall

Comme je l'ai déjà dit ici ( en anglais ) je suis un adepte de la technologie JMX. Mais je viens d'être confronté à un problème : la connection (en JMX) à une JVM cachée derrière un firewall. Après avoir un peu cherché, j'ai fini par trouver comment le solutionner  ; par contre, je n'ai pas trouvé de documentation en français. C'est pourquoi j'écris cet article : si vous aussi, vous avez des problèmes pour établir une connexion JMX à un serveur JAVA et cela au travers d'un firewall alors il pourra vous intéresser.

Description de la problématique

J'essaie de me connecter à un serveur écoutant sur le port JMX 1100 ; serveur séparé de mon poste client ( sur lequel je lance par exemple une jconsole ) par un firewall.
Pour forcer le port JMX j'ai rajouté les paramètres suivant à la ligne de commande de démarrage de mon serveur :
-Dcom.sun.management.jmxremote.port=1100
-Dcom.sun.management.jmxremote.authenticate=false
-Dcom.sun.management.jmxremote.ssl=false
Du côté de mon firewall nous avons fait le nécessaire pour ouvrir le port TCP 1100. Et pourtant ma jconsole n'arrive pas à se connecter au serveur distant. Après analyse j'ai fini par comprendre qu'en fait d'autres ports sont mis en jeux.

Les explications

En fait le port 'jmx' n'est que celui recevant les connexions ; ensuite un autre est utilisé sur lequel sont exportés les objets (RMI) accédé via JMX. Cet autre port est en général alloué dynamiquement ; mais il est possible de le contrôler.

La solution

Elle consiste à créer une instance de la classe JMXConnectorServerFactory, et de l'associer au MBean server de l'application. Si vous ne voulez pas, ou si vous ne pouvez pas, créer un tel serveur dans le code de votre application ( par exemple si vous n'avez pas la main sur toutes les sections du code ; voir pas la main du tout ) vous pouvez le créer dans un agent enregistré au démarrage de la VM : ainsi vous allez modifier le fonctionnement de votre application sans toucher à son code.

Exemple d'agent

public class JmxDefaultAgent {
    
    
    public static MBeanServer getMBeanServer() {
        ArrayList list =MBeanServerFactory.findMBeanServer(null) ;
        return((list.size()==0)?ManagementFactory.getPlatformMBeanServer():list.get(0));
    }
    
    public static void premain(String agentArgs) throws IOException {
        int port = Integer.parseInt(System.getProperty("com.me.jmxport", "1100"));
        
        String hostname = System.getProperty("com.me.jmxhost", null);
        if (hostname==null) hostname = InetAddress.getLocalHost().getHostName();

        System.out.println("Create RMI registry for JMX on port " + port);
        LocateRegistry.createRegistry(port);

        
        MBeanServer mbs = getMBeanServer();

        // Environment map
        HashMap env = new HashMap();
        JMXServiceURL url = new JMXServiceURL("service:jmx:rmi://"+hostname+":" + port + "/jndi/rmi://" + hostname
                + ":" + port + "/jmxrmi");

        // Now create the server from the JMXServiceURL
        //
        JMXConnectorServer cs = JMXConnectorServerFactory.newJMXConnectorServer(url, env, mbs);

        // Start the RMI connector server.
        //
        System.out.println("Start the RMI connector server on port " + port);
        cs.start();
    }
}

Si vous avez la main sur le code

Il n'est pas nécessaire d'utiliser un agent ; il vous suffit simplement de démarrer le serveur JMXConnectorServer lors du chargement de votre application.

Dernier problème

Le code précédent fonctionne parfaitement ; son seul problème est que le server JMXConnectorServer démarré dans l'agent va empêcher l'arrêt correct de la JVM : un tel serveur doit être stoppé via sa méthode stop. Autrement dit, ce serveur n'est pas démarré sous la forme d'un thread daemon qui à l'arrêt de la JVM nettoierait ses ressources et s'arrêterait automatiquement.

Si vous n'avez pas la main sur le code du serveur pour y rajouter l'appel à la méthode stop ; une méthode consiste à créer un thread dans l'agent vu précédemment, thread dont le rôle sera de détecter la mort imminente de l'application. Cette détection consiste à repérer qu'il n'existe plus de thread actif au sein de la JVM, en dehors des thread daemon et de ceux liés au serveur JMXConnectorServer ; et dans ce cas, on peut appeler la méthode stop du JMXConnectorServer de manière sure.

Exemple de thread détectant l'arrêt de l'application

public class Cleaner extends Thread {
    public Cleaner(JMXConnectorServer connectorServer) {
        super("ThreadCleaner");
        this.connectorServer = connectorServer;
    }

    @Override
    public void run() {
        boolean alive = true ;
        try {
            while( alive == true ) {
                Thread[] activeThreads = new Thread[Thread.activeCount()+10];
                int total = Thread.enumerate(activeThreads);
                try {
                    alive = false ;
                    for (int i=0;i<total;i++) {
                        Thread currentThread = activeThreads[i];
                        if (currentThread.getName().contains("RMI")) continue;
                        if (currentThread.equals(this)) continue;
                        if (currentThread.isDaemon()) continue;
                        else {
                            alive = true ;
                            currentThread.join();
                            break;
                        }
                    }
                    if (alive == false) {
                        System.out.println("no more thread remaining - stopping jmxconnectorserver");
                    }
                } catch(InterruptedException e) {
                    System.out.println("received interruption - stopping jmxconnectorserver");
                    alive = false ;
                }
            }
        } finally {
            try {
                connectorServer.stop();
            } catch (IOException e) {

            }
        }
    }

    private JMXConnectorServer connectorServer ;
}

Lien utiles

lundi 16 avril 2012

JAVA - Récupérer la version courante d'un JAR / WAR programmatiquement

Récupérer la version courante d'un JAR

C'est facile, et cela se fait en deux temps : 
  1. Tout d'abord, il s'agit de configurer MAVEN pour que le manifest associé à votre JAR contienne la version de votre librairie. C'est le composant MAVEN ARCHIVER qui doit être paramétré de façon à rajouter l'information attendue dans le fichier manifest de votre JAR. Il suffit de rajouter ce fragment de XML dans votre fichier pom :
   <plugin>
    <groupid>org.apache.maven.plugins</groupid>
    <artifactid>maven-jar-plugin</artifactid>
    <version>2.3.2</version>
    <configuration>
     <archive>
      <manifest>
       <adddefaultimplementationentries>true</adddefaultimplementationentries>
       <adddefaultspecificationentries>true</adddefaultspecificationentries>
      </manifest>
     </archive>
    </configuration>

   </plugin>
  1. Puis, dans le code, il vous suffit de récupérer l'objet Package associé à l'une des classes du JAR (par exemple LaClasseDuJar ) dont vous voulez récupérer la version ; l'instance de cet objet vous donnera les informations de version que vous cherchez, selon :
Package objPackage = LaClasseDuJar.class.getPackage();
String version = objPackage.getImplementationVersion();

Version d'une application web (ou WAR)

C'est un peu plus compliqué : le coup du Manifest ne marche pas tout le temps. En tous les cas, avec tomcat, je ne suis pas arrivé à faire fonctionner la technique précédente même si celle-ci fonctionne parfaitement pour les JAR utilisés par la webapp. Du coup, j'utilise l'astuce tout bête suivante : dans mon WAR j'inclue un fichier texte contenant la version de l'application.

Génération du fichier texte avec maven

Pour générer le fichier texte avec l'information de version attendue , j'utilise le plugin maven replacer. L'idée consiste à faire remplacer un pattern spécifique par l'information attendue lors de la phase de préparation du war (ici lors de la phase précédant sa génération ). Voici par exemple un extrait d'un fichier pom permettant de faire ce que nous attendons :
<build>
...
<plugin>
       <groupId>com.google.code.maven-replacer-plugin</groupId>
       <artifactId>maven-replacer-plugin</artifactId>
       <version>1.3.9</version>
       <executions>  
       <execution>  
         <!-- le remplacement doit se faire avant que le war soit packagé -->  
         <phase>prepare-package</phase>  
         <goals>  
           <goal>replace</goal>  
         </goals>  
       </execution>  
     </executions>
     <configuration>  
       <includes>
         <include>target/mywebapp/WEB-INF/classes/com/me/config/version.prop</include>
       </includes>  
       <regex>false</regex>  
       <!-- chaîne à remplacer -->  
       <token>PROJECT_VERSION</token>  
       <!-- remplacer par la version du projet -->  
       <value>${project.version}</value>  
     </configuration>
      </plugin>
...
</build>
Pour que cela fonctionne, il faut tout d'abord que vous disposiez d'un fichier version.prop dont le contenu peut être -
version=PROJECT_VERSION
- et devant se trouver par exemple dans le package com.me.config ; puis que vous configuriez ainsi la génération de votre fichier war :
<plugin>
       <groupId>org.apache.maven.plugins</groupId>
       <artifactId>maven-war-plugin</artifactId>
       <version>2.1.1</version>
       <executions>
       <execution>
          <id>prepare-war</id>
          <phase>prepare-package</phase>
          <goals>
            <goal>war</goal>
          </goals>
       </execution>
   </executions>
       <configuration>
        <useCache>true</useCache>
     </configuration>
      </plugin>
Cette configuration ( en particulier le useCache=true ) signifie à maven de réutiliser les fichiers générés dans target pour constituer le war. Ainsi, le fichier patché par le plugin replacer sera celui inclus dans le package. Si jamais cette technique ne fonctionne pas pour vous (le useCache étant marqué comme expérimental) vous pouvez toujours demander au plugin replacer de patcher le fichier source version.prop : c'est à dire celui se trouvant dans vos sources ( il vous faudra sans doute utiliser une expression régulière plutôt qu'un simple mot à remplacer ).

Lecture du fichier texte

C'est très simple, par exemple à partir d'une classe MainConfig, contenue dans le même package ( com.me.config ) que le fichier version.prop :
InputStream is = MainConfig.class.getResourceAsStream("./version.prop");
if (is!=null) {
  Properties prop = new Properties();
  String version =  null;
  try {
     prop.load(is);
     version = prop.getProperty("version");
  } catch (IOException e1) {
               
  }
}

dimanche 25 mars 2012

tcpdump - reminder

Ce billet pour me servir de pense bête - pour mes captures réseaux

Capture

sudo tcpdump -s 0 -i < nom de l'interface réseau > -w out.dump

Analyse

Ouvrir le fichier out.dump avec wireshark.

Cake aux courgettes et à la féta



Les ingrédients


  • 75 g de farine
  • 3 oeufs
  • un sachet de levure chimique
  • 2 cuillères à soupe de crème fraîche
  • 4 cuillères à soupe d'huile d'olive
  • 2 courgettes
  • 200g de féta
  • de la ciboulette

Les étapes de la recette

  1. Mélanger la farine, les oeufs et 2 cuillères d'huile d'olive à l'aide d'un fouet.
  2. Incorporer la crème fraîche.
  3. Préchauffer votre four à 180°C
  4. Couper la courgette en petits morceaux dans une poële) ; puis faire chauffer 5 à 10 minutes avec 2 cuillère à soupe d'huile d'olive
  5. Laisser refroidir 5 minutes puis mélanger la ciboulette à la courgette
  6. Mélanger la courgette à la pâte
  7. Couper en dés la féta et la rajouter au mélange
  8. Verser dans un moule et cuire 25 minutes à 180°C

Les suggestions du chef




Laisser le cake refroidir une heure à température ambiante ; puis le metter au frigo pendant deux heures ou plus (je le trouve meilleur froid).
Bon appétit.

vendredi 23 mars 2012

mousse au chocolat



Pour 4 à 5 personnes

Ingrédients

  • 3 oeufs
  • 150 gr de chocolat
  • 1 sachet de sucre vanillé
  • 3 cuillères à soupe de sucre
  • 15 gr de beurre
  • 2 cuillères à soupe de lait

Préparation

  1. Mélanger les jaunes avec le sucre vanillé et le sucre dans un récipient
  2. Faire fondre le chocolat dans une casserole avec le beurre et le lait
  3. Battre les blancs en neige
  4. Rajouter le chocolat au récipient
  5. Rajouter les blancs en neige
  6. Réserver au frigo pendant 24h minimum avant consommation

Crème caramel à la vanille





Ingrédients

  • 1 litre de lait
  • une gousse de vanille
  • 6 œufs
  • 14 cuillères à soupe de sucre
  • 14 sucres en morceau

Préparation

  1. Mélanger le lait et la vanille ; puis porter à ébullition
  2. Mélanger les œufs et le sucre en poudre (les battre au fouet)
  3. Faire chauffer à feu vif les sucres en morceau (avec un peu d'eau) pour constituer le caramel
  4. Mélanger le lait avec les œufs
  5. Verser le caramel au fond de votre plat
  6. Verser le mélange dans le plat

Cuisson

Faire cuire à 180°C pendant 45 minutes ; puis laisser reposer une bonne heure.
Bon appétit.

Tarte au citron meringuée

Ingrédients


  • 4 gros citrons
  • 80 grammes de maïzena
  • 4 gros œufs
  • 175 g de sucre
  • 1 pâte brisée

Préparation

  • Etaler la pâte dans le moule et piquer le fond avec une fourchette, avant de la cuire pendant 15 minutes au four thermostat 7/220°C.
  • Presser les citrons et râper un peu de zeste.
  • Mélanger la maïzena avec la moitié du jus.
  • Dans la deuxième moitié du jus ajouter 3 verres d'eau froide, mettre dans une casserole et faire bouillir.
  • Verser le mélange jus + maïzena dans la casserole, bien remuer puis faire cuire doucement jusqu'à épaississement, laisser refroidir.
  • Séparer les blancs des jaunes d'œufs.
  • Battre les blancs en neige très ferme et y ajouter, délicatement, à la cuillère 50g de sucre.
  • Ajouter les jaunes d'œufs et 100g de sucre au mélange refroidi maïzena/citron et le verser dans le moule.
  • Remettre au four pendant 15 minutes.
  • Verser l'appareil à meringue (les blancs d'œufs battus et sucrés) sur toute la surface de la tarte ; pour la présentation y tracer des sillons avec la tranche d'une cuillère à soupe puis y saupoudrer le sucre restant.
  • Remettre au four 10 minutes.

Recette du gâteau à la crème (cake)


Ingrédients :

  • 3 oeufs
  • 3 verres de sucre( un peu plus que la moitié pour chaque verre)
  • 1/2 paquet de levure
  • 1 paquet de sucre vanillé
  • 3 verres de farine bien pleins (ou pour le faire plus léger remplacer
  • l'un des verres de farine par un verre de maïzena)
  • 1 pot de 25 cl de crème fraîche

Recette :

  1. Battre longuement le sucre, sucre vanillé et oeufs ( le mélange doit bien augmenter de volume et "blanchir")
  2. Ajouter la farine, puis la levure et enfin la crème.
Cuire à four moyen (200°)pendant environ 3/4 d'heure( vérifier la cuisson en piquant le centre avec un couteau, la lame doit ressortir sèche )

Variantes :

  1. On peut ajouter des raisins secs ou des fruits secs ( il faut les mélanger à une cuillère de farine avant de les mettre dans la pâte)
  2. On peut ajouter des pépites de chocolat et des morceaux d'amandes
  3. On peut faire un marbré au chocolat en partageant la pâte en deux . ajouter dans une partie du sucre vanillé et dans l'autre du chocolat fondu ou même du chocolat en poudre.Alterner les deux pâtes dans le moule.

Le flan aux oeufs


Ingrédients



  • 4 oeufs
  • 2 sachets de sucre vanillé
  • 4 cuillères à soupe de sucre en poudre
  • 75 cl de lait (possible avec du lait écrémé)


La recette


Casser les oeufs, ajouter le sucre (poudre + vanillé)
Battre assez longtemps
Ajouter le lait peu à peu
Verser dans un moule déjà nappé de caramel
Cuire au bain-marie dans le four à 160 degré (maxi) pendant environ 1 heure
Piquer pour vérifier la cuisson

La quiche au saucisson à l'aïe



  • 4 tranches de saucisson à l'aïe
  • 2 tranche de jambon cuit
  • lardons
  • battre 6 oeufs avec un pot de crème fraîche
  • recouvrir dans la quiche
  • 200°C pendant 3/4 heure

Supervision in JAVA applications / Using JMX



I will present a few tricks I'm using systematically to create Java applications easily supervisable ( the  best practices I'm following ). My first POST, on that subject, will introduce how I'm using JMX to deliver peaces of software that will be correctly managed and monitored by the team of technicians in charge of it.


1 - JMX (Java Management Extensions) and MBeans objects


This is a standard technology defining architecture and design patterns for application management and monitoring. Using this technology, the attributs exposed and the operations offered are provided by objects called "Managed Mbean" ( MBean ). See this page for an overview of this technology.


2 - Using MBeans to make the application configurable 'in live'


Changing the configuration of an application without restarting it is sometimes very valuable. MBeans are made for that. Using these objects, you will be able to change the behavior of your soft without effort. So, since the beginning of a new project, I tried to put as much of the configuration properties as possible in these objects. Doing that, your application will be dynamically managed without stopping the production.


3 - Why using this standard


If you choose this technology, you will not have to construct any GUI ( graphical user interface ) to make these objects accessible to your users. Many tools are already capable to connect to a running JVM and to interact with its registered MBeans. For example, the jconsole, provided with every JDK, display all the registered MBean and allow the user to modify the properties and to call the operations of these MBeans.


4 - Persisting the MBean in an XML file


All the MBean I create are saving there configuration in an XML file, so that, after restarting the application, the changes applied will be restored. To make the code of the MBean very simple, I'm using JAXB to marshall all the properties in the target XML File. Let's take an example :
@XmlRootElement(name="test")
public class Test implements TestMBean {

    @XmlElement(name="count")
    @Override
    public Integer getCount() {
        return(this.count);
    }
    @Override
    public void setCount(Integer count) {
        this.count=count;
    }

    /**
     * persist in the XML File
     */
    protected synchronized void save() {
        try {
            Marshaller ma = context.createMarshaller();
            ma.marshal(this, new File(configFileName));
        } catch(Exception e) {
            System.err.println("unable to save file"+e.getMessage());
        }
    }
    
    /**
     * construct the MBean from the XML file
     * @param xmlFileName
     * @return
     */
    protected static Test makeFromXMLFile(String xmlFileName) {
        File configFile = new File(xmlFileName);
        Test result = null ;
        if (configFile.exists()) {
            try {
                Unmarshaller un = context.createUnmarshaller();
                result=(Test) un.unmarshal(configFile);
            } catch (Exception e) {
                throw new RuntimeException("unable to read config file",e);
            }
        }
        if (result==null) {
            result = new Test();
        }
        result.configFileName = xmlFileName ;
        result.save();
        return(result);
    }

    private Integer count ;
    private String configFileName;
    
    private final static JAXBContext context  ;

    static {
        try {
            context = JAXBContext.newInstance(Test.class);
        } catch (JAXBException e) {
            throw new RuntimeException("Programmatic error :",e);
        }
    }
}


As you can see in this exemple, you just need to add some very simple annotations on the bean's properties you want to be saved in the XML file : that's what we did on the Count MBean attribut.

5 - Conclusion


Don't hesitate to provide many MBeans in your software : with a very little cost, you will be able to deliver an application configurable in live, easily monitored and managed.

dimanche 11 mars 2012

Les foudres de la sor'cière

Et hop, je viens de terminer le deuxième tome ( Les foudres de la sor'cière ) du cycle "Les bannis et les proscrits" de James Clemens. Celui-ci est aussi bon que le premier, je l'ai terminé en quelques soirées. On y retrouve les même ingrédients que dans le premier : de la magie (que Elena commence à maîtriser un petit peu plus), des monstres, et des paysages que l'on découvre au fil des errances des divers personnages. Là encore, nous passons d'un groupe de protagonistes à un autre ; et l'histoire est tellement bonne que à chaque séquence où l'auteur zappe j'ai ressenti une certaine frustration. Un petit résumé :


L'hiver terminé, Elena et ses camarades descendent des montagnes de Kral pour repartir à la recherche du Journal Sanglant. Ils vont être confrontés à des malegardes ( élémentaux corrompus par la magie noire ) tous plus horribles les uns que les autres. De nouveaux personnages, certains très surprenants, vont aussi rejoindre le camp d'Elena durant cet épisode.


Pour conclure, j'ai trouvé ce deuxième tome excellent ; tout aussi bon que le premier, mais pas tout à fait dans la même gamme : certaines scènes avec les malegardes dépeignent leur côté corrompu avec un grand réalisme : je pense par exemple à une scène d'accouchement d'un monstre, tout à fait réaliste. On ne peut parler de gore car c'est bien écrit, mais âmes sensibles abstenez vous ! Le premier tome était peut être un peu plus soft, enfin légèrement :)


Ma note : 16/20

samedi 10 mars 2012

JAVA 7 Pour Mac

Je viens d'installer la JDK 7 sur mon mac : pour être plus précis j'ai installé "Oracle JDK7u4 Mac OS X Port Developer Preview Release", trouvée à cet URL. L'installation s'est effectuée sans aucune surprise, et la JVM semble fonctionner très bien, du moins pour les quelques tests que j'ai réalisé : j'ai compilé, via maven, gsync ( projet JAVA 6 ) et testé le résultat de la compilation, à priori tout fonctionne.
Il me reste maintenant à tester les nouvelles fonctionnalité de la JDK 7 ainsi que son intégration à Eclipse et NetBeans sous Mac. Plus d'info dans un autre billet.
Si tout fonctionne, je migre tous mes projets sous cette nouvelle version.

vendredi 9 mars 2012

SAMI mon ami

Un petit hommage au SAMI ( Services d'Accueil Médical Initial ). Cette mission de service publique, que l'on pourrait qualifier de  service d'intérêt général, vous permet de consulter un médecin généraliste les week end et jours fériés. Ainsi, plus besoin d'aller encombrer les urgences pour une maladie pouvant être soignée par un généraliste.
C'est très pratique quand votre enfant tombe malade le week end. Je ne sais pas pour vous, mais les miens choisissent quasi exclusivement le samedi soir pour déclencher une fièvre à en faire exploser le thermomètre, ou pour remplir un nombre inimaginable de seaux de vomit.
Désormais, quand la chose arrive, si je sens que l'on ne peut pas attendre le lundi je n'appelle plus le 15  (et oui dans le 94 il n'y a pas de SOS médecin , juste le 15) ; j'amène le petit malade directement chez le docteur du SAMI.

Le feu de la sorcière

Il s'agit du premier tome du cycle "Les bannis et les proscrits" de James Clemens. Ce livre m'a enthousiasmé : enfin un cycle dont j'ai acheté le deuxième tome sans hésitation.
Commençons par un petit résumé, histoire de vous mettre l'eau à la bouche, mais sans trop vous en dire ...

Le monde dans lequel se déroule l'histoire est un monde en crise. 500 ans plus tôt les magiciens ( tous des hommes ) luttent contre les "forces du mal" mais se retrouvent peu à peu dépourvu de toute magie. Résultat, les méchants progressent. Trois mages parmi les derniers forgèrent un livre rempli d'un mystérieux pouvoir avant de disparaître eux-même.
A l'heure à laquelle le récit se déroule, une jeune adolescente hérite d'un pouvoir, semblable à celui autrefois réservé aux mages (tous des mâles), que l'on croyait désormais disparu. Malheureusement cet héritage n'est pas passé inaperçu et toutes les forces du mal se déchaînent pour tenter de s'emparer de notre héroïne. Heureusement celle-ci va rencontrer différents personnages qui vont l'aider à s'élever pour atteindre sa destinée : devenir une "sor'cière".

Ce bouquin, bien construit, reproduit - mais sans copier - certains des schémas du seigneurs des anneaux : des personnages dont les destinées se croisent, se séparent ; de la magie, un seigneur du mal fort peu sympathique ... Le monde des sor'ciers et sor'cières est vraiment original, l'écriture de ce premier tome est fort agréable et évite le côté légèrement répétitif que l'on pourrait reprocher à certains cycles de fantasy.


Ma note : 16/20

vendredi 24 février 2012

Marsupial technologique

C'est arrivé le 31 janvier, je suis désormais papa pour la deuxième fois ( il s'agit cette fois-ci d'un garçon : un petit Loïc ).
Je ne vais pas m'épancher sur les joies que la paternité me procure car elles sont du domaine privé.
Le but de ce billet est juste de partager une impression ressentie ce matin : essayant désespérément de travailler, malgré un gros chagrin, inconsolable, que le petit partageait avec nous depuis quelques heures ; j'ai essayé le porte bébé pour pouvoir continuer à coder tout en essayant de réconforter Junior. Au même moment, passait en bruit de fond à la télévision un reportage animalier sur les kangourous.
Ma femme, rentrant dans la pièce à ce moment, a cru discerner un certain mimétisme entre le reportage télévisuel : à gauche des animaux sauvages, bébé sur le ventre se repaissant tranquillement ; à droite un marsupial technologique se nourrissant d'octets. Comme quoi, l'homme, malgré son génie, n'a de cesse d'imiter la nature :)

Documentation HTML

Je profite de mon congé paternité pour peaufiner une documentation que je fais pour le boulot ; cette documentation est réalisée en HTML, ou pour être plus précis en XHTML. Voici quelques bêtes tuyaux qui me sont utiles pour générer ma documentation.

Pour la numéroter les chapitres j'utilise les titres (h1,h2,...) et je profite des possibilités offertes par le CSS :

h1:before {
    content: counter(chapter) ". ";
    counter-increment: chapter; 
}
h1 {
    counter-reset: section;
    font-size: 150%;
    color:rgb(17,127,185);
}

h2:before {
    content: counter(chapter) "." counter(section) ". ";
    counter-increment: section;
}
h2{
counter-reset: subsection;
font-size: 140%;
color:rgb(17,127,185);
}

h3:before {
    content: counter(chapter) "." counter(section) "." counter(subsection) ". ";
    counter-increment: subsection;
}
h3{
counter-reset: h4section;
font-size: 130%;
color:rgb(17,127,185);
}
...


Pour générer la table des matières j'ai une petite fonction javascript toute prête ; faite en quelques minutes, donc sans doute très largement améliorable, mais qui a le mérite de marcher :)


tdm = new Array();

function generateTDM(startTag) {
 var nbChilds = startTag.childNodes.length;
 for (var i = 0; i < nbChilds; i++) {
  var tag = startTag.childNodes[i];
  var tagName = tag.nodeName.toLowerCase();
  if (tagName == 'h1' || tagName == 'h2' || tagName == 'h3' 
                              || tagName == 'h4' || tagName == 'h5' 
                              || tagName == 'h6') {
         tdm[tdm.length] = tag ;
        }
        else {
         generateTDM(tag);
        }
 }
}


function start() {
 var text ="<ul class=\"tdm\">\n";
 generateTDM(document.getElementsByTagName("body")[0]);
 var number = new Array();
 for (i=0;i<tdm.length;i++) {
  if (tdm[i].nodeName.toLowerCase()=="h1") {
   if (!number[0]) number[0]=0;
   number[0] = 1+number[0];
   while (number.length>1) number.pop();
  }
  else if (tdm[i].nodeName.toLowerCase()=="h2") {
   if (!number[1]) number[1]=0;
   number[1] = 1+number[1];
   while (number.length>2) number.pop();
  }
  else if (tdm[i].nodeName.toLowerCase()=="h3") {
   if (!number[2]) number[2]=0;
   number[2] = 1+number[2];
   while (number.length>3) number.pop();
  }
  else if (tdm[i].nodeName.toLowerCase()=="h4") {
   if (!number[3]) number[3]=0;
   number[3] = 1+number[3];
   while (number.length>4) number.pop();
  }
  else if (tdm[i].nodeName.toLowerCase()=="h5") {
   if (!number[4]) number[4]=0;
   number[4] = 1+number[4];
   while (number.length>5) number.pop();
  }
  else if (tdm[i].nodeName.toLowerCase()=="h6") {
   if (!number[5]) number[5]=0;
   number[5] = 1+number[5];
  }
  
  if (tdm[i].id=="") {
   tdm[i].id="td"+i;
  }
  text+="<li class=\""+tdm[i].nodeName.toLowerCase()+"\">";
  for (j=0;j<number.length;j++){
   text+=number[j];
   if (j<number.length-1) text+=".";
  }
  text+="<a href=\"#"+tdm[i].id+"\">"+tdm[i].innerHTML+"</a></li>\n";
 }
 text+="</ul>\n";
 document.getElementById("thetdm").innerHTML=text;
}


Cette fonction génère le code HTML de la table des matières puis l'ajoute dans l'élément HTML trouvé d'id=thetdm du document ; par exemple :


<div id="thetdm">...</div>

Et voilà, rien de plus simple :)

mardi 21 février 2012

Dragon

Je viens d'achever la lecture de Dragon, de E.E. Knight, tome 1 de l'âge de feu.

Le personnage central du livre est un dragon : Auron, dont nous suivons les aventures de la naissance jusqu'au début de sa période adulte. Son monde est peuplé de nains, d'elfes, d'humains et bien sur de dragons ; ces différentes espèces ne vivent pas toujours, c'est peu dire, dans la plus parfaite harmonie : les dragons tendent à disparaître, certains humains ont des tendances hégémoniques, ... Auron commence dans la vie de façon très sauvage ( il chasse, mange même des enfants, ... ) mais il développera une attitude réfléchie, n'utilisant plus la violence que contraint et forcé, ou alors pour des causes qui lui tiennent à coeur. Et si l'avenir de la paie entre les espèces dépendait d'un dragon ?

Outre l'originalité du personnage, l'histoire est vraiment très prenante : ce tome 1 se lit avec grand plaisir. J'ajoute d'ailleurs qu'il se suffit à lui même ; il se termine par une vrai fin. Je lirai quand même les suites : le tome 2 a, si j'ai bien compris, comme personnage central une des soeurs d'Auron.


Ma note : 15/20

mardi 14 février 2012

La Légende de Marche Mort



Je viens de terminer un nouveau David Gemmell : "La légende de marche mort". Dans la lignée de "Druss la légende" et de "Légende", mais avec un Druss peut-être un peu plus tiraillé par le doute, plus humain. J'ai lu cette oeuvre d'une seule traite, sans avoir le temps de m'ennuyer.
Tout comme dans "Légende", vous vivrez un siège passionnant, et si certains schémas de ces deux livres sont identiques, je n'ai pas eu l'impression de relire deux fois la même chose.
Un autre aspect intéressant de cette histoire est qu'elle est racontée par Druss lui même, pendant sa dernière bataille ( voir "Légende" ) ; ce qui apporte un éclairage nouveau à certains personnages de "Légende". On apprend aussi de nouvelles choses sur Druss : en autre d'où lui vient le surnom de "Marche Mort".
Bref, pour conclure, si vous aimez le genre Fantastique, les batailles épiques, n'hésitez pas, lisez ! 


Au passage, je signale, comme la photo l'illustre que j'ai lu ce bouquin sur mon IPad et que le format numérique de ce livre est tout à fait correcte.


P.S. : je viens de trouver un bon site sur Gemmell ici.


Ma note : 14/20