Archive

Posts Tagged ‘java’

Patates et exceptions

mai 30, 2013 1 commentaire

On a vu précédement pourquoi les exceptions vérifiées sont une mauvaise idée (que je vous conseille de lire en préambule), voyons à présent comment bien gérer les exceptions.

Rassurez vous, c’est tout simple : faut voir ça comme le jeu de la patate chaude. Par défaut, on sait pas quoi en faire et faut juste refiler le bébé le plus vite possible aux autres. Facile non ?

Bon, on est joueur, on va faire ça en trois parties :
1. Passer la patate efficacement
2. Savoir mettre le feu à la patate
3. l’art de bien attraper la patate

1. Passer la patate efficacement

Comme vous le savez, bien jouer à la patate chaude implique, surtout, de ne pas avoir à s’occuper de la patate. Si on ne l’a pas, on risque pas de se rater lors de la relance. En Java, c’est pareil. Si on ne sait pas quoi faire d’une exception, le mieux est de la laisser filer. On ne l’attrape (catch) pas, rien, nada.

Bien sûr, on a ces merveilles d’exceptions vérifiées (Checked exception), celles qui vous forcent à les catcher. On en fait quoi alors ? C’est tout simple, on en fait des RuntimeException, par exemple :

try {
	// code lançant des exceptions vérifiées
} catch (MonExceptionVerifiee e){
	throw ExceptionUtils.wrap(e);
}

avec :

public class ExceptionUtils {
	
	public static RuntimeException wrap(Throwable t){
        if (e instanceof RuntimeException) {
            return (RuntimeException) e;
        } else {
            return new RuntimeException(e);
        }
	}
}

Du coup l’appelant n’à rien à attraper et l’exception sera traitée à plus haut niveau. La vie est belle non ?

Certes, par rapport aux exceptions vérifiées, l’appelant en sait moins sur les façons dont votre méthode est susceptible de mal tourner. Mais, ça n’a rien d’inéluctable : le mot clé throws, indiquant les exceptions lancées par une méthode, marche tout autant pour des exceptions vérifiées que nous vérifiées. Aussi, rien ne vous empêche d’écrire:

public Foo bar() throws BarException{
	// ..
}

avec

public BarException extends RuntimeException {
	// ..
}

Vu que BarException étend RuntimeException, vous ne serez pas obligé de catcher à chaque throw, par contre votre IDE préféré devrait vous indiquer son existence à la moindre occasion.

Par contre, par pitié, n’indiquez pas que vous êtes susceptibles de jeter n’importe quelle exception, genre:

public Bad doBad() throws Throwable

ainsi que la variante

public Bad doBad() throws Exception

En effet, là vous vous contentez d’indiquer que le code est susceptible de mal tourner, d’avoir des bugs et ainsi de suite. Or c’est le cas de tout bout de code. Du coup n’importe quelle application se doit de gérer le cas de l’exception inattendue, celle due à un bug bien idiot. Aussi, en indiquant « throws Throwable », vous ne faites que rappeller l’évidence verbeusement. Maaaal.

Il y a encore pire : avaler l’exception. Vous savez, ce que propose de faire Eclipse par défaut:

} catch (Exception e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
}

Mais encore plus pire est possible (youpee) :

} catch (Throwable t) {
}

Certes, vous n’aurez plus d’exception dans l’application. Mais celles ci ne sont que les symptômes du mal… Sans elles, le mal sera toujours présent mais en plus indétectable. Plantages et comportements aléatoires en perspective, que du bonheur.

A noter que catch(Throwable t) détient la palme. En effet, pour mémoire, la hiérarchie des exceptions Java est la suivante:

Throwable (vérifiée) <- Error (non vérifiée)
^
|

Exception (vérifiée)
^
|
RuntimeException (non vérifiée)

Tous les problèmes du niveau de la JVM remontent via des sous classes d'Error. Quelques exemples fameux: StackOverflowError, OutOfMemoryError et autres KernelError.

Les problèmes dus au code sont signalés via des classes héritant d'Exception ou de RuntimeException. Genre les IOException ou les ClassCastException.

Du coup, le petit malin qui avale tout à partir de Throwable ne saura notifié ni des erreurs de son code ni des problèmes de la JVM. Sympa non ?

2. Bien allumer la patate lors de sa cuisson

Maintenant qu’on sait comment passer la patate, voyons comment la créer.

En premier lieu, toujours hériter de RuntimeException (sauf pour les développeurs derrière la JVM, bien sûr, qui eux étendent Error).

Pourquoi RuntimeException ? Facile : on veut faciliter la passe de la patate chaude, donc autant que l’appelant n’ait rien à faire par défaut, comme ça au moins il ne risque pas de faire mal. Genre avaler l’exception.

Ensuite, quel est le but de la patate ? Signaler un problème, un dysfonctionnement, une erreur. Du coup, autant communiquer un maximum d’informations : vos exceptions doivent toujours avoir un constructeur avec un message de type String. A chaque création d’une instance on pourra alors donner un maximum d’information de contexte. Genre les paramètres de la méthode appelée. Par contre, le nom de la méthode et la pile d’appel sont là par défaut, dans la pile d’appels (stack trace) pas besoin de dupliquer…

Si jamais votre exception encapsule une autre exception, merci de la lui donner. En effet, que se passe-t-il si je code ainsi:

catch (IOException e){
	throw new MyException("File access failed");
}

C’est tout simple : la personne traitant mon exception ne pourra pas en connaître la cause réelle. Et même dans le cas de cette bonne vieille IOException, si commune, ne vous laissez pas abuser : ces sous classes sont aussi diverses que ErrorInQuitException ou BadAudioHeaderException. Bref, si une exception a pour origine une autre exception, toujours la transmettre.

Bien sûr, si on peut donner du contexte, c’est encore mieux :

catch (IOException e){
	throw new MyException("File access failed for file '" + file + "' and user '" + user + "'", e);
}

In fine, le squelette d’une bonne exception à soi est, à mon humble avis, quelque chose du genre :

public class MyException extends RuntimeException{
	
	public MyException(String message){
		super(message);
	}

	public MyException(String message, Throwable throwable){
		super(message, throwable);
	}

	public MyException(Throwable throwable){
		super(throwable);
	}

} 

Pas de constructeur sans paramètre: on veut nécessairement du contexte. (Bon des fois y en a vraiment pas au delà de la pile d’appels, mais bon, comprenez le message ;)).

Si jamais vous décidez d’ajouter des paramètres supplémentaires et spécifiques à votre application, n’oubliez pas alors de surcharger getMessage(), afin que tout le contexte soit toujours affiché.

3. L’art de bien attraper la patate

A l’occasion, si on sait quoi faire sur l’exception, alors on s’en occupe.

Cela arrive généralement en deux circonstances : soit au plus près de l’exception, quand on peut retomber sur ses pieds autrement, soit plusieurs niveaux d’abstraction plus haut, aux frontières de l’application ou du module. Genre pour afficher un message d’erreur à l’utilisateur, ou au système tiers.

Gérer l’exception au plus près est normalement simple : on ne fait cela que si on sait quoi faire.

Par exemple:

public boolean isValidInteger(String text){
	try {
		Integer.parseInt(text);
		return true;
	} catch (NumberFormatException e){
		return false;
	}
}

Pour la gestion à plus haut niveau, il faut s’assurer d’attraper vraiment toutes les exceptions. Pour cela, il y a depuis Java 5 la méthode Thread.setDefaultUncaughtExceptionHandler(UncaughtExceptionHandler handler) qui définit qui sera appelé en dernier recours, si rien n’a attrapé l’exception au préalable. Ainsi toutes les exceptions seront attrapées de façon certaines, qu’elles aient été lancées le thread courant ou un autre. Faites en bon usage.

La gestion de l’erreur implique souvent la communication d’un message à un tiers, que ce soit l’utilisateur ou le système appelant. Il arrive parfois que des actions plus drastiques soient nécessaires, particulièrement dans le cas des Error, où parfois l’arrêt est la seule option (dans le cas d’une OutOfMemoryError, c’est le seul remède que je connaisse par exemple).

Toutefois, qu’on traite l’exception au plus près ou à plus haut niveau, toujours, j’ai bien dit TOUJOURS, faire en sorte de donner tout son contenu au développeur qui devra débugger le code. Ne serait ce qu’un log, fusse-t-il de niveau debug, ou, même, au pire, une sortie console. L’essentiel est que toute l’info soit accessible sans devoir changer le code. Se contenter d’afficher le message de l’exception (sans la pile d’appels) est, par exemple, notoirement insuffisant. De même, si vous utilisez un framework de logging, assurez vous qu’il affiche bien tout le contenu de l’exception, ainsi que des diverses différentes exceptions éventuellement contenues dans l’exception courante. La stack trace complète est de la plus haute importance.

Espérons que ces conseils améliorent votre gameplay à la patate chaude. Bien que souvent négligé et bien moins hype que d’autres jeux plus récents (comme réinventer la roue par exemple), gérer correctement les exceptions est crucial pour toute application, afin d’en assurer l’évolution et la maintenance sereinement.

Au plaisir de vous lire !

NB: pour les utilisateurs d’Eclipse (je sais, ça aussi c’est pas à la mode, désolé), notez qu’il y a une « Java Stack Trace Console » disponible au niveau de la console eclipse, via le bouton « Open Console ». Lorsque vous y collez une stack trace, eclipse vous permet d’aller aux différents points concernés en cliquant sur les lignes de la stack trace. Pratique. Pas révolutionnaire mais pratique.

NB2: Java 7 introduit le multi catch et autres try with resources. Bien que pratiques, ils ne changent pas fondamentalement la donne (sauf pour l’art obscur de la fermeture de ressources, non abordé ici).

Publicités
Étiquettes : , , ,

Pourquoi les exceptions vérifiées sont une mauvaise idée

mai 30, 2013 5 commentaires

Dans la série « je blogue pour éviter de me répéter », je demande les exceptions vérifiées.

Attendez, je vous devine: c’est quoi une exception vérifiée ?

C’est une invention de Java (à ma connaissance) consistant en une exception que le contexte est obligé de considérer

Autrement dit, si j’écris:

throw new MonExceptionVerifiee();

avec

public class MonExceptionVerifiee extends Exception

alors le code entourant cette instanciation est obligé de prendre en compte l’exception.

Deux façons pour cela, la première consistant à relancer l’exception pour ne pas avoir à s’en préocupper :

public void maMethode() throws MonExceptionVerifiee {	
	throw new MonExceptionVerifiee("Pour la cause");
}

Le throws au niveau du nom de la méthode est ce qui permet de relancer l’exception.

La seconde façon consiste à attraper l’exception pour la traiter, comme suit:

public void monAutreMethode() {	
	try {
		throw new MonExceptionVerifiee("Pour la cause");
	} catch(MonExceptionVerifiee e){
		// ?
	}
}

Bon, là ça présente peu d’intérêt, en général on attrape plutôt les exceptions vérifiées lancées par les autres, par exemple :

public void monAutreMethode() {	
	try {
		maMethode();
	} catch(MonExceptionVerifiee e){
		// ?
	}
}

Pour finir avec l’introduction aux exceptions vérifiées, sachez qu’une exception, pour être vérifiée, doit hériter de Throwable ou Exception, mais qu’elle ne l’est pas si elle hérite d’Error ou de RuntimeException, ce qui la hiérarchie des exceptions Java suivante :

Throwable (vérifiée) <- Error (non vérifiée)
^
|

Exception (vérifiée)
^
|
RuntimeException (non vérifiée)

Autrement dit, Throwable est tout en haut et est une exception vérifiée. Error étend Throwable, et n'est pas vérifiée. Exception étend Throwable, et est vérifiée. RuntimeException étend Exception et… n'est pas vérifiée.

Alambiqué hein ? Je suis d'accord, et en général si la conception est compliquée, alors l'idée est foireuse. Mais j'anticipe.

En effet, pourquoi diable les exceptions vérifiées?

L'intention initiale est de forcer le code à considérer les exceptions. En effet, comme cela, en lisant un fichier, je serai bien conscient que la lecture de ce dernier peut planter. Certes, c'est appréciable, mais que puis je faire pour autant ? Et là est tout le mal des exceptions vérifiées. Leur traitement n'est pas simple et, surtout, rien ne garanti qu'il sera bien fait.

Revenons à l'exemple précédent :

public void monAutreMethode() {	
	try {
		maMethode();
	} catch(MonExceptionVerifiee e){
		// ?
	}
}

A noter que si une méthode lance plusieurs exceptions vérifiées, on est obligé de les traiter chacune. Par exemple, l’autre de maMethode pourrait choisir de lancer également des IOException, comme suit :

public void maMethode() throws MonExceptionVerifiee, IOException {	
	throw new MonExceptionVerifiee("Pour la cause");
}

alors la méthode appelante sera du genre :

public void monAutreMethode() {	
	try {
		maMethode();
	} catch(MonExceptionVerifiee e){
		// ?
	} catch(IOException e){
		// ??
	}
}

Verbeux. Et embêtant: la prochaine fois que l’auteur de maMethode choisira d’ajouter un throw, il faudra que je change à nouveau mon code. Que faire quand on est malin ? Facile, l’obligation de traiter les exceptions vérifiées prend en compte la hiérarchie, du coup je peux écrire ça :

public void monAutreMethode() {	
	try {
		maMethode();
	} catch(Throwable t){
		// ?
	}
}

Tadamm ! C’est nettement moins verbeux, et même plus robuste au changement : le petit gars derrière maMethode peut se lâcher. Désormais, j’suis blindé.

Vous noterez le commentaire « // ? » dans le catch, vu que sur le coup je ne savais pas quoi faire. Faire un tel catch qui ne renvoie aucune exception s’appelle avaler une exception, ou dans le cas présent avaler toutes les exceptions. Fort hein ? Ca semble la parade ultime…

Sauf que… sauf que désormais, plus aucune exception ne remonte. Vérifiée ou pas. Lancée par le programme ou la JVM (toutes les exceptions découlant d’Error). Nada. Rien. Et là, bonjour l’enfer : désormais en cas de plantage, plus aucune info n’est dispo. Avec un peu de chance l’appelant se rend compte qu’un effet de bord n’est pas présent (genre je clique et rien ne se passe), mais ce n’est pas garanti. A débugger, cela relève des travaux d’Hercule : aucune info, sauf que ça marche pas. Pas de trace.

Les seules options que je voie est de modifier tous les catch (ah ah ! – surtout sur du code tiers) ou de s’taper toute l’application au débuggeur… Dans les deux cas, vous serez forcé de faire ça après coup sans aucun élément sur l’origine du problème. Dans les deux cas, vous chercherez une aiguille dans une botte de foin. Et si votre code contient beaucoup de catch avalant des exceptions, vous avez un sacré paquet d’aiguilles différentes à chercher une à une, tout au long de la vie de votre application…

Bien sûr, me direz vous, aucun développeur digne de ce nom n’aurait la bonne idée d’avaler toutes les exceptions. Mais le catch vide est juste très facile, tentant même. Dans l’exemple ci dessus, dans monAutreMethode, je ne savais pas quoi mettre lors de la rédaction de l’exemple, j’ai mis un commentaire vide, le // ?, pour remplir. Et devinez quoi, ça compile et ça peut partir en prod sans problème! Combien de développeurs se retrouvent exactement dans la même situation ? Combien laissent un commentaire type « TODO » et autres « Euh, à traiter? » puis continuent comme si de rien n’était ? Beaucoup. Trop. De plus, cela semble résoudre le problème du traitement d’erreur, de ces satanés IOEXception dont on ne sait que faire…

Sans compter que cela ne semble pas être une si mauvaise pratique : eclipse propose par défaut de quasiment avaler les exceptions vérifiées. En effet, le quick fix par défaut d’eclipse pour gérer cette fameuse maMethode() throws MonExceptionVerifiee, IOException est le suivant :

try {
    maMethode();
} catch (MonExceptionVerifiee e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
} catch (IOException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
}

Génial non ? Exception avalée, pile d’appels imprimée mais… sans le message de l’exception (accessible via e.getMessage()). Noter cet appel direct à e.printStackTrace() : votre API de logging préférée n’a aucune chance de s’en mêler.

Bref, le professionnalisme est mis à rude épreuve et avaler les exceptions semble la bonne solution. Du coup, chaque code lançant une exception vérifiée est à la merci du premier développeur commettant une erreur dans son traitement. Quelques lignes et zou plus rien, des erreurs cachées et une application à débugger dès qu’on se rendra compte de l’erreur. Peut être après mille appels à la méthode plantant. Peut être après milles confirmations envoyées à tort. Splendide et… imparable.

Pour la petite histoire, avaler les exceptions n’est pas toujours le fait de développeurs. Eh oui, j’ai vu des architectes, et pas nécessairement Java, faire ainsi dans leur code. Sur toute l’application. A chaque fois qu’ils pouvaient se faire mordre par une saleté d’exception. Pour la défense de ces érudits, notons que nos glorieuses écoles d’ingénieur en informatique n’enseignent rien en la matière. J’ai discuté avec de nombreux étudiants de nombreuses (hautes) écoles différentes, ou d’université, et jamais le thème n’avait été abordé. Après tout, les exceptions, c’est pour ceux qui font du mauvais code en premier lieu non ?

In fine, sommes nous désormais d’accord que les exceptions vérifiées sont une mauvaise chose ? Rassurez vous, y a moyen de les traiter correctement : c’est l’objet de l’article suivant, Patates et exceptions. On se voit là bas 😉

Étiquettes : , , ,

CloudBees talk at the ElsassJug

Yesterday night, Sacha Labourey came to the Elsass Jug to introduce CloudBees.

It was pretty nice to see Sacha IRL: he’s a very friendly and humble person (while being, for those not knowing him, creator and CEO of CloudBees after quite a career). It’s really easy and interesting to speak with him so go and get him whenever you need/can.

CloudBees specializes in using the clouds resources and tools for developing and running Java (web) applications (Platform As A Service way). It’s what they call their Dev@Cloud and Run@Cloud.

Having Koshuke among their staff, the whole stack is centered around Jenkins: if you use it, then you’ll be like at home. Actually, you’ll be most likely better than at home: their jenkins come with slaves running each job (infinite scaling FTW) as well as the usual plugins plus some on top from third parties.

Roughly put, it’s a nicely already set up Jenkins environment, with some goodies like remote console line tools or Eclipse plugins. To me it really felt like all the tools you wanted to use with Jenkins but already there and waiting for you (like having slaves running the jobs to avoid bottlenecks).

The Run@Cloud part is also interesting: basically, once your jenkins jobs are done, you can decide to promote some to production. They are then deployed to your web apps. The web apps location(s) are pretty flexible: they can either host them (if I got it right), put them in some well known hoisters or, in fact, any cloud (as long as openstack compatible). Actually, it’s not only about web apps, they can also handle DBs (mysql only AFAIK).

One option I wasn’t aware of is that the deployment part can also be building images (VSphere ones, so VMWare) and push these images wherever you want. In line with their concept, looks like they handle the OS and stack parts of these images: you just have to put in your WAR file and you’re done. Sweet isn’t it?

For sure, they’ve plenty of goodies not spoken of here: they can have webdav based maven repos (you can also rent on top some artifactory), the monitoring tools for the running apps look great (again, the fancy tools you heard of but never bothered to actually put in use are available here) and so forth.

To sum up, they really aim on doing the « devops » part of development, so developers can concentrate on… developing. Not too bad isn’t it? In terms of target, they have pay as you go pricing and others one for bigger users.

One example Sacha put forward to showcase the whole concept is Loose It. Loose It is a mobile/web app helping you to loose weight. The interesting part there is that they’re only 5 developers and they’re able to deliver 1.5 millions users and up to 20 000 transactions per minutes. All this without scaling issues and dedicated staff. Just 5 devs in the wild. Well, for sure, I guess they owe CloudBees some money, but obviously only a fraction of what it would have costed them to handle it all on their own.

My thought being put to words, I’m off 😉

++
joseph

Side note: in case you wonder why this post is in english, it’s pretty straightforward: I wanted this dear uwe to be able to be able to read it, since his company looks like the perfect fit for CloudBees and… I would be eager to have some first hand feedback. Nasty me? You bet 😉
BTW, thanks uwe for proof reading this post.

Étiquettes : , , ,

Multithreaded performance testing checklist

In the past months we did some performance testing at work, making quite some mistakes on the way, and probably still doing some. In between, I’ve read « Java Concurrency in practice », by Brian Goetz, and learned once again some more goodies. As such, I’ve written this quick checklist, in order to forget less next time I’ll try to do some performance testing.

As usual, let me know of any mistake, lack or questions.

before starting the test

  • check your issue still with the latest JVM to make sure the trouble still exists.
  • use the latest JVM: java.util.concurrent had some great improvements in Java 6. Furthermore the various JVM options are more complete (includes display of Lock and its sub classes locking state).

while coding the test

  • mind locking in utilities libraries. For example UUID.randomUUID() uses SecureRandom, which is thread safe… Prefer less secure random value generators which don’t imply locking, like System.nanoTime().
  • measure time before and after all threads/tests, dividing it as needed, instead of many small measurements (less impacts on the tested code).
  • do unpredictable stuff: the JVM is very good at optimizing out code whose result can be guessed, like by pre computing it once and for all. For example, compare some hashCode() with System.nanoTime(), printing out something in (highly unlikely) case of equality.
  • do production representative work: the JVM always tries to optimize the code. It can take shortcuts which became invalids with further class loading. Restricting yourself to few classes increase the risk of optimization which won’t happen in production.

test launch set up

  • Be as close from production as possible

    • mind the -server option, which has important effects.
    • define your memory using -Xms and -Xmx (see java -X for more information).
  • setup runtime information display

    • add -verbose:gc to see garbage collection.

      By default, 2 types of garbage collection exist:

      • minor ones (iterative), which garbages out the low hanging fruits. Quite frequent, these ones don’t affect performance too much. A typical minor collection is displayed this way in the console:

        [GC 325407K->83000K(776768K), 0.2300771 secs]

        It shows the decrease in memory consumption and the time it took to get rid of this memory.
      • « stop the world » garbage collection. Nothing else happens during these majors garbage collections, hence the stopping world name. As such, it’s a really performance hit: plan your test to run long enough to streamline its effects.
        A stop the world collection is shown this way in the console:

        [Full GC 267628K->83769K(776768K), 1.8479984 secs]

      more options exist to monitor garbage collection, for example -XX:+PrintGCDetails. See Java HotSpot VM Options
      and Tuning Garbage Collection with the 5.0 Java[tm] Virtual Machine.

    • add -XX:-PrintCompilation to see the JVM compiling bytecode to assembler code where it sees it fits.

      • have accordingly a « warm up » period when running your test, to put this compilation out of the tested code.

while running the test

  • look at what’s going on in the JVM

    • use jps to locate the test process.
    • use jstack to see the current stack.

  • monitor your system

    • what about the network traffic. Is the application network bound?
    • what about CPU usage: a properly multi threaded software should make good use of them all.
    • what about RAM, before starting and while running. Swapping shouldn’t be used normally.
  • Be patient: the test should run some minutes to be conclusive…

all this time: test your intuitions/assumptions/known facts

  • Surprises are lurking all over the place.
  • Facts of yesterday are today’s illusions!

That’s all for now folks!

Étiquettes : , , ,

Book: Implementations Patterns

In Implementations Patterns, Kent Beck focuses on « low level » advices. It’s all about how to write nice, readable and maintainable code.

Such a narrow focus is good and provides a nice occasion to think on one own’s habits.The extensive thinking put down in the book quite often put words on feelings/intuitions one can have while coding. It makes them explicit/obvious and helps to think more rationally about them. It also put new light on different aspects, widening the comprehension.

The chapter « Theory of Programming » is also pretty nice, esp. when addressing flexibility. Indeed, flexibility is about being able to change easily the code, not providing the user with hooks all over the place to change everything in the software. Insisting on code readability is also always welcomed and well put in perspective. It somehow managed to feel more convincing than previous readings I had on the topic.

Yet it isn’t all nice in Implementations Patterns. The term pattern feels often overstretched. Kent Beck is mainly just browsing through the available options in Java and discussing their pro and cons. Sometimes it feels obvious and a bit overdone.

The chapter on collection performance feels also a bit like « space filling » rather than helping achieving the book goal. A nasty voice inside of me can’t help noticing that for a 129pages yet 45$ book, it’s comprehensible…

A point has also really surprised me: Kent Beck speaks of final fields and says he usually doesn’t bother writing the final keyword. He would only if his code would be changed by many people. Not only it’s contradict his main motto of communication to the readers, but it’s actually a big hole in the class, both in terms of performance and maintenance… Crazy it managed to go through the editing process IMHO.

To conclude, the book is helpful and hopefully my coworkers will appreciate its effects on my code. I’ve more tools/knowledge/options to write readable code, I just have to make good use of them by now… Is it a must read ? Dunno. Maybe I start to have read quite a bunch of such books to have a feeling of « deja vu ». Surely as well I’m getting older. Anyway, it was a good read, I recommend it. Whether it’s a must read is left to the reader as an exercise 😉

Side note: for a deeper look at the book content, there’s this infoq review Book Review: Implementation Patterns which shows it well.

Étiquettes : , , ,

Wicket et ses fonctionnalités de templating

juin 19, 2010 1 commentaire

[This note is also available in English.]

Wicket fournit des fonctionnalités de templating. Rien de bien folichon, mais c’est tout de même bien pratique, surtout quand il faut intégrer du JavaScript.

Ces fonctionnalités sont cependant très peu discutées voir même, je suspecte, globalement inconnues. Aussi, creusons un peu la chose!

Comme tout système de templating, tout tourne autour de texte contenant des variables, définies par ${variable} et dont les valeurs sont données via Java.

Voyons un exemple simple, un fichier de template nommé javascript.tpl:

alert('${variable}');

Wicket permet d’aisément accéder à ces templates en tant que ressources mises dans des packages Java, via la classe PackagedTextTemplate:

public PackagedTextTemplate(final Class clazz, final String fileName)

Par exemple:

PackagedTextTemplate jsTemplate = new PackagedTextTemplate(this.getClass(), "javascript.tpl");

Ainsi, le template se trouve à côté de la classe Java et de l’html l’utilisant, rendant le tout aisé d’utilisation.

Les variables sont fournies au moyen d’une simple Map:

Map parameters = new HashMap();
parameters.put("variable","test working");

Au final ce template trônera certainement au milieu d’html. Aussi Wicket fournit plusieurs options pour cela:

  • contribution au header html:
    add(TextTemplateHeaderContributor.forJavaScript(jsTemplate, new  Model((Serializable) parameters)));
  • accolé à des éléments du body html:
    Java:

    Label myScript = new Label("myScript", new JavaScriptTemplate(jsTemplate).asString(parameters));
    myScript.setEscapeModelStrings(false);
    add(myScript);

    Html :

    <wicket:container wicket:id="myScript"></wicket:container>

Vous avez sans doute remarqué que, dans chacun des cas, je ne fournis pas le tag qui devrait entourer le tout. Pas d’inquiétude à avoir, Wicket le fait pour vous.
L’html résultant est en effet:

<script type="text/javascript"><!--/*--><![CDATA[/*><!--*/
alert('test working');
/*-->]]>*/</script>

Si le template contenait plutôt du CSS, il faut juste utiliser un CssTemplate au lieu du JavaScriptTemplate.

Quelques info supplémentaires sont disponibles sur le wiki wicket: Including CSS resources.

++
joseph

Étiquettes : , , , ,

Certification, part 2 ;)

février 11, 2010 Laisser un commentaire

hi

Small post to tell that I’ve started to look into SCJD, another certification. As such, I fear I will once again post way less (in case anyone cared, which might be quite optimistic, yes I know, thanks ;)).

Anyway, not to do a totally useless entry, let’s share a few links :

see ya !
++

Étiquettes : ,
%d blogueurs aiment cette page :