Twister's blog

Aller au contenu | Aller au menu | Aller à la recherche

vendredi, août 2 2013

Lecteur RSS [suite]

Après la mort de Google Reader je pensais avoir trouvé plusieurs remplaçants dont un qui me convenait vraiment : The old reader. Malheureusement suite à un crash majeur de leurs serveurs ils ont décidé de jeter l'éponge et de passer à un mode de site privé pour quelques élus... Résultat je me re-retrouve au point de départ, plus rien pour lire mes flux. Sur les lecteurs existant qu'il me reste il y a donc :

  • Feedly buggant toujours pas mal et étant un poil lourd de temps en temps
  • Newsblur, payant à partir de 64 flux.

N'ayant que 50 flux, je partait donc sur Newsblur. Tout se passa bien pendant une semaine. Mais qu'elle ne fut pas ma surprise de découvrir ce matin une nouvelle limitation à Newsblur : on ne peut plus afficher que 8 articles non lus par flux en version gratuite ! Exit donc Newsblur.

J'ai donc décidé de redonner leur chance au petits lecteurs RSS installable sur un serveur. J'ai commencé par essayer d'installer Newsblur (oui c'est possible puisque le code est sur GitHub). Mais ce truc est une vrai usine à gaz ! Impossible de l'installer facilement... Poubelle!

Finalement après avoir réessayé tout ce qui trainait j'ai fini par installer Tiny-Tiny-RSS qui a en plus sa propre interface Android! Je vais donc voir ce que ça donne à terme, en espérant ne plus avoir à bouger de si tôt :p.

Pour ceux qui le voudrait mon install est ici : http://rss.perriot.fr/. Si vous voulez un compte n'hésitez pas à me faire signe.

mercredi, juillet 24 2013

Lire le contenu de fichiers dans un fichier zip en JAVA

Je viens de tomber sur un problème bête en Java, j'ai une application client/serveur avec un client qui envoie régulièrement des fichiers de logs au serveur sous forme de fichier ZIP. Le serveur doit décompresser les fichiers afin de la analyser pour en tirer des statistiques. Ce qui m'embêtait dans ce développement c'est qu'il faut dézipper les fichiers avant de pouvoir les analyser et que ce "dézippage" pourrait éventuellement laisser trainer des fichiers temporaires quelque part sur le serveur. Il me fallait donc une autre solution. J'en voyais 2 :

  • soit concatener les fichiers de logs en un seul fichier qu'il aurait suffit de gzipper pour pouvoir le lire avec un GZIPInputStream côté serveur.
  • soit permettre au serveur de lire de manière transparente les données de tous les fichiers contenus dans le zip.
La première solution aurait impliqué de faire des modifications sur le client qui utilise un système déjà existant (et standard pour notre application) pour envoyer ses fichiers ZIP, donc pas top. La seconde pose problème parce que le JDK ne fournit qu'un ZipInputStream qui permet de lire le Zip fichier par fichier, il faut en effet faire un appel à ZipInputStream.getNextEntry() entre chaque fichier pour passer à la suite. Comme l'ordre de lecture des fichiers n'a pas d'importance je décidais de faire un petit wrapper au stream afin qu'il soit capable de passer tout seul d'un fichier à l'autre. Et voilà le travail :

public static Reader acquireReader(File file) throws IOException {
       if (file.getName().endsWith(".zip")) {
           final ZipInputStream zis = new ZipInputStream(new FileInputStream(file));
           return new InputStreamReader(zis) {
               @Override
               public int read(char cbuf, int offset, int length) throws IOException {
                   int read = super.read(cbuf, offset, length);
                   if (read < length) {
                       if (read == -1) {
                           read = 0;
                       }
                       zis.getNextEntry();
                       read += super.read(cbuf, offset + read, length - read);
                   }
                   return read;
               }

               @Override
               public int read() throws IOException {
                   int c = super.read();
                   if (c == -1) {
                       zis.getNextEntry();
                       c = super.read();
                   }
                   return c;
               }
           };
       }
       return new FileReader(file);
   }

Comme vous pouvez le voire c'est relativement bateau :).

vendredi, juin 28 2013

Google Reader [RIP]

Vous le savez forcément, Google Reader tirera le rideau le 1er juillet 2013. C'est une page de l'histoire d'Internet qui se tourne. En effet depuis son lancement en 2005 aucun autre Reader n'aura jamais attiré autant de monde. Aucun autre n'est aussi simple, efficace et ne met à jour les flux aussi rapidement que Google Reader.

Depuis l'annonce faite par Google je me suis intéressé de près à tout ce que je pouvais trouver comme remplaçant. Que ce soit une application à installer sur un serveur ou un service clé en main en ligne je n'ai pas encore trouvé chaussure à mon pied. QUOI! me direz vous, et bien oui, je suis chiant et exigeant. Je veux tout comme Google Reader, tout de suite, et malheureusement ça n'existe pas.

Cependant, depuis quelques mois beaucoup de sociétés se sont mise en tête de devenir le nouveau Google Reader. Pas étonnant vus la masse d'utilisateur qui vont se retrouver sans foyer au 1er juillet il y a là un marché à conquérir. Ainsi durant les mois de mai et de juin nous avons vu de tout nouveaux reader apparaître, d'ancien évoluer rapidement, d'autre crouler sous la charge induite par tous ces nouveaux utilisateurs...

Au cours de ces derniers moi j'ai donc moi aussi fait le tour de ce qu'il existait. Je ne vous ferais pas ici un résumé complet de mes pérégrinations. Vous, comme moi, n'en avons pas le temps. Je vais donc aller droit au but :

Après 2 mois de tests divers et variés il en ressort 3 concurrents sérieux :

Et voici maintenant juste un résumé des pour/contre :

Feedly :

Pour Contre
  • Joli
  • Application Android (un peu difficile à appréhender au début, mais une fois habitué elle n'est pas si mal)
  • Mise à jour des flux relativement rapide
  • Beaucoup de vue différentes possible
  • Ne sait pas compter correctement le nombre de posts
  • Ne marque pas correctement les posts lus lors du scroll si le layout est 'serré'
  • Ne sauvegarde pas le layout par flux
  • Digg reader (beta fermée) :

    Pour Contre
  • Simple
  • (et oui c'est tout :))
  • Ne se met pas toujours à jour (sûrement des pbs sur les serveurs d'aggregation)
  • Ne sauvegarde pas le layout par flux
  • Pas d'application Android
  • Ne permet pas de caché les articles non lus
  • The Old Reader

    Pour Contre
  • Simple
  • Sauvegarde le layout par flux
  • Les flux sont mis à jour relativement rapidement
  • Pas d'application Android
  • Voilà pour un résumé rapide. Pour le moment mon choix se porte sur The Old Reader qui est le plus proche de Google Reader.

    Digg Reader est pour le moment très (trop) basique mais je pense qu'il vaut le coup de le surveiller.

    mardi, avril 23 2013

    PWGen

    J'ai découvert aujourd'hui l'extension .pw et je n'ai pas pu m'en empêcher : http://pwgen.pw. Et voilà un petit générateur de password. :-)

    vendredi, décembre 7 2012

    Arretez de recoder ce qui existe !!!

    Dans un moment d'égarement, je viens de regarder en détail une des classes de mon projet qui est très utilisée. StringHelper...

    Les 9/10è des fonctions présentes dans cette classes font les même choses que leurs homonymes dans StringUtils de Apache.commons-lang. La même chose, non, pas tout à fait, elles le font en moins bien codées...

    Je vais vous fournir ici quelques unes des gemmes de cette classe, à vous de me trouver ce qui en fait des fonctions stupides par rapport à celles de StringUtils.

    Facile :
    	public static final boolean isBlank(final String str) {
    		return str == null || str.trim().isEmpty();
    	}
    
    Dans la famille "je ne fais pas tout à fait ce que je dis que je fais" :
    	public static final int compare(final String one, final String two) {
    		if(one == two) {
    			return 0;
    		}
    		if(one != null) {
    			if(two != null) {
    				return one.toUpperCase().trim().compareTo(two.toUpperCase().trim());
    			}
    			return -1;
    		}
    		return 1;
    	}
    
    Suivie dans la classe par "je fais ce que je dis que je fais" :
    	public static final int compareIgnoreCase(
    			final String one,
    			final String two) {
    		if(one == two) {
    			return 0;
    		}
    		if(one != null) {
    			if(two != null) {
    				return one.compareToIgnoreCase(two);
    			}
    			return -1;
    		}
    		return 1;
    	}
    
    Et par "je le fais, mais je ne le fais pas vite" :
    	public static final String concat(final String...strs) {
    		if(strs != null) {
    			final int nbStr = strs.length;
    			if(nbStr > 0) {
    				final StringBuilder sb = new StringBuilder();
    				for(int index = 0; index < nbStr; ++index) {
    					sb.append(strs[index]);
    				}
    				return sb.toString();
    			}
    		}
    		return null;
    	}
    
    Et par "alors moi je suis méga pas pressé, le CPU et la RAM je m'en cogne, alors je m'éclate" :
    	public static final boolean isNumber(final String str) {
    		if(str != null) {
    			return str.matches("[0-9]*");
    		}
    		return false;
    	}
    
    Un petit peu plus compliqué :
    	public static String rightPad(String stringToPad, String padder, int size) {
    		if (padder.length() == 0) {
    			return stringToPad;
    		}
    		StringBuffer strb = new StringBuffer(stringToPad);
    		StringCharacterIterator sci = new StringCharacterIterator(padder);
    
    		while (strb.length() < size) {
    			for (char ch = sci.first(); ch != CharacterIterator.DONE; ch = sci
    					.next()) {
    				if (strb.length() < size) {
    					strb.append(String.valueOf(ch));
    				}
    			}
    		}
    		return strb.toString();
    	}
    
    Une de mes préférées :
    	public static <T> String loopAppender(
    			final Iterable<T> iterable,
    			final CollectionHelper.Stringuifier<T> stringuifier,
    			final String appender
    	) {
    		final StringBuilder sb = new StringBuilder();
    		if(iterable != null) {
    			final Iterator<T> it = iterable.iterator();
    			while(it.hasNext()) {
    				sb.append(stringuifier.stringuify(it.next())).append(appender);
    			}
    			cleanStringBuilder(sb, appender);
    		}
    		return sb.toString();
    	}
    
    	public static void cleanStringBuilder(
    			final StringBuilder sb,
    			final String appender
    	) {
    		final int finalSize= sb.length() - appender.length();
    		if (finalSize > 0) {
    			sb.setLength(finalSize);
    		}
    	}
    
    Suivi par une téléportation rapide dans NumberUtils (ou alors les int sont des String travesties ???) :
    	private static final int minimum(final int a, final int b, final int c) {
    		return Math.min(a, Math.min(b, c));
    	}
    

    Bref, arrêtez de recoder des trucs qui existent dans des jar classiques, surtout quand ces jar fournissent des méthodes bien plus efficaces que les vôtres ! Sachez reconnaître que des fonctions existantes depuis des dizaines d'années et utilisée par des dizaines de milliers de développeurs sont sûrement plus efficace que les votre! Surtout quand votre projet inclus déjà ces JARs !!! Et oui StringHelper existe alors que apache.commons-lang est dans les dépendances du projet. sic...

    Cela dit c'est peut être un autre problème qui est à la source de cette aberration : les développeurs ont peut être juste oublié de chercher sur internet s'il n'existait pas déjà quelque chose qui faisait ce qu'ils voulaient faire et du coup ont codé ces fonctions la tête dans le guidon! C'est mal!

    - page 2 de 14 -