Publié le 30 Mai 2012

the-little-redis-book.png

Je viens de lire "The Little Redis Book" de Karl Seguin et ne connaissant pas Redis jusqu'ici j'ai été très agréablement surpris (à la fois par le livre et par Redis).

Comme son nom l'indique c'est un petit livre (à peine 30 pages) mais c'est surtout une excellente introduction à Redis. Bien sûr toute la richesse de Redis n'est pas couverte (et ne prétend pas l'être) dans ce livre, mais si vous cherchez quelque chose pour vous mettre le pied à l'étrier et comprendre Redis c'est vraiment un très bon départ.

Les sujets couverts sont les souvents:

- Installation (rapide - plutôt un getting started)
- Principes de base et les principaux types de données de Redis
- Principes de requêtage
- un zeste d'administration

Ce livre se lit très rapidement, il est très sympa avec une ligne de commande ouverte à côté pour expérimenter les différents exemples du livre et surtout il donne envie d'en savoir plus sur Redis:

- affiche des performances bluffantes: beaucoup de commandes en 0(1) et en temps d'exécution de quelques millisecondes même avec des millions de données
- assure l'atomicité des opération grâce à une implémentation mono-thread.

- etc ... 

Dernier point c'est un livre électronique et il peut être téléchargé ici : http://openmymind.net/2012/1/23/The-Little-Redis-Book/

Voir les commentaires

Rédigé par Bliz

Publié dans #livres

Repost 0

Publié le 25 Mai 2012

Pour étendre une cellule sur plusieurs ligne on peut utiliser rowspan:

rowspan sur 3 lignes ligne 1
ligne 2
ligne 3

xsl-fo est souvent utilisé pour générer de la documentation imprimables (pdf) et bien sûr il est possible d'effectuer le même effet de rowspan qu'en html:

<fo:block>
 <fo:table>
  <fo:table-column/>
  <fo:table-column/>
  <fo:table-body>
   <fo:table-row>
    <fo:table-cell number-rows-spanned="3">
     <fo:block>rowspan sur 3 lignes</fo:block>
    </fo:table-cell>
    <fo:table-cell>
     <fo:block>ligne 1</fo:block>
    </fo:table-cell>
   </fo:table-row>
   <fo:table-row>
    <fo:table-cell>
     <fo:block>ligne 2</fo:block>
    </fo:table-cell>
   </fo:table-row> 
   <fo:table-row>
    <fo:table-cell>
     <fo:block>ligne 3</fo:block>
    </fo:table-cell>
   </fo:table-row>  
  </fo:table-body>
 </fo:table>
</fo:block>

Bien sûr c'est beaucoup plus "wordy" qu'en HTML mais le principe reste le même on déclare le rowspan sur la première ligne.
Puis les lignes suivantes ont une cellule de moins. 

Voir les commentaires

Rédigé par Bliz

Publié dans #XSLT

Repost 0

Publié le 21 Mai 2012

Dans un précédent article sur la génération d'un jar exécutable avec Maven, je proposais d'inclure toutes les dépendances du projet à l'intérieur du jar généré. ça marche mais le jar généré risque d'être un peu gros.

Voici donc une autre solution qui consiste à préciser le classpath dans le manifest du jar, mais toutes les libs devront être présentes lors de l'exécution.

 <build>
    <plugins>
      <plugin>
         <artifactId>maven-jar-plugin</artifactId>
         <configuration>
           <archive>
             <manifest>
               <addClasspath>true</addClasspath>
               <classpathPrefix>lib/</classpathPrefix>
               <mainClass>com.over-blog.patatos.App</mainClass>
             </manifest>
           </archive>
         </configuration>
      </plugin>
    </plugins>
  </build>

Pour plus d'info, voir la documentation Maven: http://maven.apache.org/shared/maven-archiver/examples/classpath.html

Voir les commentaires

Rédigé par Bliz

Publié dans #Maven

Repost 0

Publié le 15 Mai 2012

Voilà j'ai un projet svn qui se trouve dans un repertoire 'ancien' sur le serveur SVN. Nettoyage de printemps oblige je veux le déplacer dans un répertoire 'nouveau' et bien sûr je ne veux pas perdre tout l'historique du projet.

Et bien SVN a tout prévu avec la commande :

svn copy <URL source> <URL destintation>

ce qui donne

svn copy http://serveur_svn/repo/ancien/monProjet http://serveur_svn/repo/nouveau/monProjet

ensuite il ne reste plus qu'à supprimer le projet dans l'ancien répertoire:

svn delete http://serveur_svn/repo/ancien/monProjet

Voir les commentaires

Rédigé par Bliz

Publié dans #Version control

Repost 0

Publié le 14 Mai 2012

CSS permet d'insérer une image directement dans un élément HTML sans avoir à utiliser la balise <img>.

C'est très pratique que le code peut se contenter de générer uniquement une div HTML avec le texte nécessaire. La mise en page (et l'inclusion de l'image se fait uniquement en CSS).

Et côté CSS c'est également très simple, il faut utiliser la propriété background-image:

background-image: url('image.png');

Attention comme indiqué l'image sera placée dans l'arrière-plan de l'élément HTML. Pour éviter qu'elle soit recouverte de texte, il faudra utiliser un padding correspondant à la taille de l'image.

Voir les commentaires

Rédigé par Bliz

Publié dans #CSS

Repost 0

Publié le 11 Mai 2012

J'ai récemment changer d'utilisateur sous Windows (car j'ai oublié le mot de passe de l'ancien) mais comme Windows est configuré pour ouvrir automatiquement une session, je retombe toujours sur la session de mon ancien utilisateur.

Et bien sûr pas moyen de trouver où tout ça est configuré ... comme d'habitude tout est bien caché dans Windows.

Donc pour gérer les utilisateurs (changement de mots de passes, etc) il existe un utilitaire qui se lance de la manière suivante:

Menu démarrer / Exécuter

puis taper

control userpasswords2

Et voilà avec quoi j'ai réussi à supprimer mon ancien utilisateur (accessoirement j'aurai pu juste changer le mot de passe et ne pas recréé un utilisateur, mais bon ...)

Voir les commentaires

Rédigé par Bliz

Repost 0

Publié le 10 Mai 2012

Charger un nouveau jar dynamiquement lors de l'exécution du programme n'est pas aussi simple qu'il y paraît.

En effet le classpath de l'application est déterminé au lancement du programme. Il est accessible au travers du ClassLoader système qu'on peut récupérer de la manière suivante:

ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();

Le ClassLoader système est en fait un URLClassLoader on peut donc effectuer un cast:

URLClassLoader systemClassLoader = (URLClassLoader) ClassLoader.getSystemClassLoader();

Ensuite la difficulté va être d'appeler la méthode addURL() qui est protected, ce qui veut dire qu'elle n'est accessible que depuis une sous-classe.

Hors on ne peut pas remplacer (enfin je crois) le ClassLoader système, donc je ne souhaite pas partir dans cette direction qui m'obligerai à changer les appels à Class.forName() en précisant le ClassLoader à utiliser.

En fait on peut utiliser la réfection pour invoquer addURL() sur le ClassLoader système directement:

URLClassLoader systemClassLoader = (URLClassLoader) ClassLoader.getSystemClassLoader();
try{
   URL url = new File("./maBibliotheque.jar").toURI().toURL();
   Method addURL = URLClassLoader.class.getDeclaredMethod("addURL"new Class<?>[]{URL.class}); 
   addURL.setAccessible(true);
   addURL.invoke(systemClassLoader, new Object[]{url});
}
catch(Exception e){
   e.printStackTrace();
}

Voir les commentaires

Rédigé par Bliz

Publié dans #Java

Repost 0

Publié le 9 Mai 2012

En java les strings sont des objets immuables. Ce qui signifie qu'ils ne sont pas modifiables, c'est à dire que lorsqu'on construit une string en ajoutant des caractères à chaque fois on recrée une nouvelle instance de string:

Par exemple:

String text = "du texte";
text += " et un peu plus"; // là on n'a pas juste rajouter quelques caractères à la chaine initiale mais on a créé une nouvelle chaine contenant le text initial et les caractères supplémentaires

 Comme à chaque opération on crée une nouvelle instance de String (avec allocation mémoire, etc) on impacte rapidement les perfs.

Pour y remedier le JDK fournie 2 classes qui représentent une séquence de caractères modifiables:

  • StringBuffer
  • StringBuilder

La différence est que StringBuffer est synchronisé pour garandir que les caractères seront insérés dans l'ordre chronologique des appels aux méthodes telles que append() ou insert().

Le second StringBuilder n'est pas du tout synchronisé (on y gagne en performance) mais il n'y a plus de garantie quand à la cohérence de la chaine obtenue à la fin.

Mais ça ne pose pas de problème tant qu'on travaille à l'intérieur d'un seul thread (ce qui est le cas la plupart du temps). C'est donc cette classe qu'il faut privilégier pour construire une séquence de caractère.

Voici les résultats d'un petit test que j'ai effectué pour comparer les performances lorsqu'on concatène des chaînes assez longues.

Dans mon test je construit une chaine contenant 100 fois la séquence "zeroonetwothreefourfivesixseveneightnine"

A chaque iteration je rajoute un chiffre dans ma chaîne il me faut donc 1000 iterations pour construire la chaine finale.

Ensuite je répère l'opération 1 000 000 de fois pour avoir des temps significatifs, et voici les résultats:

Concaténation de String 2050811 ms
Utilisation d'un StringBuffer 22560 ms
Utilisation d'un StringBuilder 20565 ms

On note que les StringBuffer et les StringBuilder sont presque 100 foix plus rapide qu'une concaténation de chaine. Le StringBuilder offre un gain de presque 10% par rapport au StringBuffer.

Voilà le code que j'ai utilisé:

import java.util.Arrays;
import java.util.List;

public class TestStringBuilding {

   private static final int NB_CONCAT = 1000;
   private static final int NB_RUN = 1000000;

   private static List<String> TOKENS = Arrays.asList("zero", "one", "thow", "three", "four", "five", "six", "seven", "eight", "nine");

   public static void main(String[] args){
      long start = System.currentTimeMillis();

      for(int loop = 0 ; loop < NB_RUN; loop++){
         String text = "";
         for(int i = 0; i < NB_CONCAT; i++){
            text += TOKENS.get(i % 10);
         }
      }
      long end = System.currentTimeMillis();
      System.out.println("String concatenation: "+(end-start)+" ms");

      start = System.currentTimeMillis();
      for(int loop = 0 ; loop < NB_RUN; loop++){
         StringBuffer text = new StringBuffer();
         for(int i = 0; i < NB_CONCAT; i++){
            text.append(TOKENS.get(i % 10));
         }
      }
      end = System.currentTimeMillis();
      System.out.println("StringBuffer append: "+(end-start)+" ms");

      start = System.currentTimeMillis();
      for(int loop = 0 ; loop < NB_RUN; loop++){
         StringBuilder text = new StringBuilder();
         for(int i = 0; i < NB_CONCAT; i++){
            text.append(TOKENS.get(i % 10));
         }
      }
      end = System.currentTimeMillis();
      System.out.println("StringBuilder append: "+(end-start)+" ms");
   }

Voir les commentaires

Rédigé par Bliz

Publié dans #Java

Repost 0

Publié le 4 Mai 2012

Les caractères utilisés pour le retour à la ligne sont différents d'une plateforme à l'autre.

Par exemple, on utilisera:

  • \n, sous Linux (et Mac OS)
  • \r\n, sous Windows

Bref quand on écrit un programme java on ne sait pas forcément quels caractères utilisés pour le saut de ligne.

Mais heureusement, la JVM fournit la propriété "line.separator" qui permet de récupérer le saut de ligne à utiliser sur la machine où est exécuté le programme.

Dans le code ça donne:

String newLine = System.getProperty("line.separator");
System.out.println("ligne 1"+newLine+"ligne2);
// ce qui affiche, quelque soit l'OS:
// ligne1
// ligne2 

Voir les commentaires

Rédigé par Bliz

Publié dans #Java

Repost 0