Posts
-
Deploying to Maven Central using GitHub Actions
I have this library that I work on from time to time, that I published on Maven Central. A few days ago I released a new version, and since I always forget what the exact
mvn
command is, what my GPG passphrase is, etc. I thought it would be a good opportunity to automate the release process using GitHub Actions.I came across several outdated tutorials that create
(read more)settings.xml
and import GPG keys manually, but as of Feb. 2021 most of this is not needed anymore, thanks to recent changes in thesetup-java
action. -
High performance IBM MQ & JMS applications
Using the JMS API to do messaging over IBM MQ is rather easy, but writing programs that perform well can be a bit tricky. In this post, I’m going to share a few tips I’ve gathered here and there that might help you write faster MQ+JMS applications.
My examples are based on MQ 9 and JMS 2.0 but most of the tips will likely work with other versions of these products, and some of them can even apply to other message brokers.
(read more) -
Ceylon + jOOQ = <3
So you want to try Ceylon on a new side project, but don’t feel like writing yet another boring command line application? In this article, I will show you how to set up a new Ceylon application that uses jOOQ seamlessly. We will see how easy it is to use Ceylon’s Java interoperability, and how easy it is to customize jOOQ and adapt it to Ceylon’s conventions. The sample application will use an existing database.
(read more) -
Monitorer ses logs avec Logstash
Lundi matin, aux environs de 9 h 30. Vous arrivez un peu en retard, mais bon c’était pour la bonne cause, il fallait impérativement finir de merger ces pull requests sur votre projet perso et vous en avez eu jusqu’à 3h du mat’. Même pas le temps d’aller prendre une boisson chaude pour se réveiller, le téléphone sonne : une anomalie ultra-bloquante-qui-va-mettre-en-péril-le-projet-c’est-pas-possible vient d’être ouverte, c’est la catastrophe bla bla bla… Classique, me direz-vous, mais comment trouver facilement l’origine du problème ?
(lire la suite) -
Un switch annoté en Java
Un billet sur le blog de l’Agilitateur répondant à un billet sur le blog d’Excilys concernant les switchs en java me donne envie de parler un peu de codage en Java. Cet article est une variante du code C# proposé par Oaz en Java.
Je vais vous épargner toute la discussion sur le switch c'est bien / c'est nul, il y a déjà les commentaires enflammés sur le blog d'Excilys pour ça.
Passons directement au code : de la même manière qu'Oaz l'a fait, je dispose d'une interface Function qui définit le contrat que vont suivre les différents cas du switch. Pour que l'on sache que les différentes sous-classes sont bien des cases, on les annote avec un @Case créé pour l'occasion : On demande au compilateur de garder cette annotation au runtime (pour faire du scanning dynamique), et on précise qu'elle peut s'appliquer à un type (classe ou interface).
On peut alors utiliser l'annotation de cette façon :
Reste maintenant le plus dur à faire : scanner un package à la recherche de classes annotées @Case et qui héritent de notre classe de base (ici Function, mais on va essayer de rester génériques). J'ai fait appel au generic type introduit en Java5, cela permet d'avoir un switch acceptant n'importe quelle classe de base qu'implémentent les différents cas. J'ai été obligé de repasser cette information dans le constructeur car en Java il n'est pas possible de faire un T.class dans la phase de scan des classes (pour savoir si la classe scannée étend ou implémente T). À la place, on a donc un Class
(lire la suite)en second paramètre.</p> La méthode scanCases va parcourir toutes les classes d'un package (grâce à la méthode getClasses() honteusement trouvée sur le forum de
SunOracle). Pour chaque classe, on regarde si elle est annotée @Case et si elle étend ou implémente T. Si c'est le cas, on en ajoute une instance dans une Map avec le nom du cas comme clé.Dernière étape : la méthode on() qui renvoie l'instance associée à un cas ou jette une exception s'il n'existe pas.
La glue entre tout ça, c'est un main assez simple : Notez le dernier appel qui va planter : j'ai bien une classe annotée @Case(name="othercase") mais elle n'implémente pas Function (une ruse de sioux pour égarer le lecteur peu attentif ;-) ).
Conclusion : c'est aussi possible en Java, avec un peu de gymnastique intellectuelle pour arriver à faire ce qu'on souhaite avec les generics :P
-
Le logger de la mort
Parfois, au cours d'une mission chez un client, on tombe sur du code pas testé, et pas toujours prévu pour être testé non plus. Je vais présenter un cas sur lequel je suis tombé récemment, issu d'un assez gros projet Java EE en cours de développement.
Une classe de services X effectue une certain nombre de traitements. En cas d’erreur, au lieu de jeter une exception métier, un code d’erreur est loggué. Impossible d’utiliser un
@Test(expected=...)
, donc. Fort heureusement, le champ logger dans X est une interface, potentiellement mockable :Dans tous les cas où nous sommes intéressés, la méthode logError est appelée avec un paramètre Key représentant le code d’erreur. Malheureusement, le logger n’est pas injecté dans un setter, et il est privé. On aimerait tout de même vérifier que l’erreur est bien logguée sous certaines conditions. Solution, un peu de réflexion pour forcer le champ logger à une instance que l’on contrôle :
La méthode
resetLogCalls
permet d’utiliser la même instance du logger sur plusieurs tests, il faut l’appeler dans une méthode annotée@After
.Il faut maintenant injecter notre propre logger dans le service testé :
Et voila, nous pouvons maintenant faire des
assertTrue
utilisant la méthodewasLogged
et la Key nous intéressant ! Notez l’appel àField#setAccessible(boolean)
pour contourner le caractère private du champlogger
(que l’on restaure par la suite).Note : si le logger n’avait pas utilisé d’interface, nous aurions pu nous en sortir en créant une classe fille redéfinissant toutes les méthodes sans appels à
(lire la suite)super()
. -
Contrôler la bande passante de sa machine linux
Le haut débit c'est bien, mais des fois on a quand même un côté nostalgique du 56k, soit parce qu'on a envie d'embêter les visiteurs de son serveur, soit parce que pour débugger une application (par exemple) on a envie que les données arrivent lentement. Sous linux, il existe la commande
tc
, pour traffic control, qui permet de contrôler ses connexions réseaux, notamment leur débit...J'ai donc trouvé un script tout fait permettant de limiter la bande passante d'une interface réseau, en upload ou en download.
(lire la suite) -
Pourquoi Netbeans c'est bien
C'est un fait avéré, Netbeans c'est mieux qu'Eclipse. (comment ça, un troll tout poilu ?). Pas plus tard qu'il y a une minute, j'en ai refait l'heureuse expérience. Agacé de voir une série de getters/setters dans ma classe, qui sont triviaux à comprendre mais qui prennent de la place, j'ai voulu utiliser l'editor folding, propre à Netbeans (je crois, du moins).
(lire la suite) -
Récupérer de la musique depuis Deezer
Même si je ne suis pas trop fan de Deezer pour diverses raisons (interface Flash trop lourde, beaucoup trop de pub, ...), je suis quand même bien content de pouvoir y rechercher une musique que j'ai en tête et que je peux récupérer pour la réécouter par la suite...
En effet, il est de notoriété publique que ce système met en cache la chason en cours d'écoute et la stocke dans un fichier flv nommé /tmp/Flash* sous linux.
À partir de là, il est facile de créer un script shell qui va se charger de récupérer ce ficher, puis d'en extraire la musique en MP3 et de la sauvegarder dans notre dossier de musique favori. Top du top, le script que je vous propose par la suite permet également d'éditer les tags ID3 et de renommer le fichier en conséquence, puis ajoute le morceau à la playlist Amarok en cours :D
Voici la bête :
(lire la suite) -
Security holes in symfony apps
symfony 1.2 was just released, and came along with a brand new advent calendar. The first day mentions two ways to set up your web server to host a symfony project. The ugly way seems to be very... ugly and crazy, putting your app directly in your webserver's root folder allows anyone to access all the files. But this security hole can be easily found in 'real' apps, as well as a few others...
This article will try to enumerate some of the mistakes that are often done when a symfony application is put in production environment.
Development environment is still present
These files, ending with _dev.php, are very useful when you are coding: they provide a lot of information on the configuration, the SQL queries that were executed, your PHP version etc. But on the other hand, they should never be accessible to your visitors (I mean, bad ones, you know, those who type in the darkness). They can show your kernel version, the symfony plugins which are installed, the escaping method you are using (or not using...), etc., which can lead to other vulnerabilities.
The project root is the webserver's root folder
This can also give a lot of information to an attacker, especially your database connection settings. Just search for 'web/frontend.php' in your favorite search engine, and you will have a bunch of apps which are potentially in this case. Then you just have to browse config/databases.yml and you get what you want. Just consider that if the application is unsecure, the webserver which is running it is also unsecure, and you can have a remote access to MySQL on port 3306, which will show you a lot of interesting things...
The backend is not protected
Harder to find, but not impossible. Even if this page is not indexed by search engines, it's quite easy to see if a web app is powered by symfony, and the majority of these web apps have a backend which is called 'backend' (if not, just try 'admin' :)). So it's very important to restrict access to this backend, as it can contain sensitive information (user accounts, etc.). Imagine that you didn't make a recent backup of your database, and that someone deletes all its content...
How to fix it?
It's not difficult to avoid these problems. In fact, the solutions are very well explained in the official symfony book, but nonetheless they are often not applied.
- Check that *_dev.php files are not uploaded (see the rsync_excludes.txt file for example)
- If you can, put the whole project (except the web/ folder) outside the web document root
- Protect your backend with sfGuard, or at least a htaccess/htpasswd file :) (and do not user admin/admin or something like this)
subscribe via RSS