HOAB

History of a bug

EJB not found when deploying from Intellij IDEA to JBoss

Rédigé par gorki Aucun commentaire

Le problème :

I follow the integration guide from JetBrains :

But I deploy my application (that use EJB), EJB (referenced by @EJB and defined in ejb-jar.xml) were not found

Solution :

After a few tests, I found that JBoss require that a deployment directory must finished with a known extension

JBAS015010: Le scanner de déploiement a trouvé un répertoire nommé META-INF qui n'était pas à l'intérieur d'un répertoire dont le nom se termine par .ear, .jar, .rar, .sar ou .war.

So when I modify the output dir of the artifact deployed to jboss from "mywebapp" to "mywebapp.war", it works...

 

RestAssured Junit et tests Session

Rédigé par gorki Aucun commentaire

Le problème :

RestAssured est un framework de tests pour les services Rest avec un langage assez simple.

Le seul problème est qu'il demande à ce qu'un serveur soit démarré, ce qui est toujours un peu lent pour les tests unitaires.

Heureusement, est inclu RestAssuredMockMvc qui permet de mocker le serveur, faire "comme si" on avait un serveur, très bien !

Problème :

  • Dans un de mes tests j'utilisent des informations stockées en session

Autant RestAssured a prévu le coup et a des méthodes pour ça (cf SessionFilter) côté client, autant la partie RestassuredMockMvc n'a rien de tout ça dans la partie serveur simulé.

Solution :

J'ai pas mal tatonné/recherché, mais finalement une solution assez simple et non intrusive :

// Création de la requête de test avec serveur simulé (le given() de RestassuredMockMvc)
MockMvcRequestSpecification request = given().standaloneSetup(controller);

// Création d'un session vide
final MockHttpSession session = new MockHttpSession();

// On ajoute un interceptor pour indiquer lors de la construction de la requête d'utiliser notre session
request.interceptor(new MockHttpServletRequestBuilderInterceptor() {
            @Override
            public void intercept(MockHttpServletRequestBuilder requestBuilder) {
                requestBuilder.session(session);
            }
});

// on peut ensuite enchainer les appels, la session sera la même

request.queryParam(...).when(...)...

request.queryParam(...).when(...)...

Donc côté serveur simulé, on intercepte le constructeur pour lui donner une session vide (mais non null). On pourrait imaginer un système plus complexe pour gérer le fait qu'au premier appel la session devrait être null, mais on va s'arrêter là pour l'instant.

 

 

Yourkit et Tomcat5 sous Windows

Rédigé par gorki Aucun commentaire

Le problème :

Connecter Yourkit à un Tomcat installé localement sur une machine Windows

Tomcat exécuté en tant que service avec le profil Administrateur

Solution :

Bon rappel de ce qui est décrit ici

  • Tomcat5 :  installation / désintallation du service
  • Tomcat5w : fenetre de contrôle du service et de ses paramètres

Il faut donc exécuter ces programmes dans une console en ligne de commande "admin" :

# Démarrer
# Exécuter... 
cmd
# Valider avec : "Ctrl + Shift + Enter"

Sinon, on peut toujours faire bouton droit sur Tomcat5w et "exécuter en tant qu'Administrateur".

Ensuite, ajouter le lien vers l'agent Yourkit :

  • Il faut mettre les chemins courts de Windows !
  • De cette manière :
# Nom court sous windows : 
dir /x c:\
# Pour obtenir au final le chemin complet : 
dir C:\PROGRA~2\YOURKI~1.6\bin\win32\yjpagent.dll

Ajouter le chemin aux paramètres de la JVM du service Tomcat :ourkit

-agentpath:C:\PROGRA~2\YOURKI~1.6\bin\win32\yjpagent.dll

Et ne pas oublier de démarrer Yourkit en mode Administrateur.

Commencer un projet avec Hibernate

Rédigé par gorki Aucun commentaire

Le problème :

Utiliser Hibernate, c'est bien, on gagne du temps, mais encore faut-il se poser les bonnes questions.

Solution :

Voici une liste de questions à se poser :

  • le modèle physique de données existe-t-il ? DDL ?

Si le modèle physique existe, le mapping JPA devra s'adapter, en DDL le modèle physique est généré par hibernate, il peut même être mis à jour par Hibernate.
Il faut cependant toujours vérifier le schéma généré et le faire valider par un DBA (junior, dilettante, senior, guru, ... au choix)
Si c'est à l'application de mettre à jour le modèle de données, des produits plus évolués comme Liquibase sont préférables au DDL hibernate pur.

Préconisation : Modèle physique non géré par Hibernate.

  • les liens dans les JPA doivent-il représenter tous les liens/contraintes de la base de données ?

Quel problème à mettre toutes les relations de la base physique dans les enttités JPA ? Aucun a priori, sauf avec de jeunes développeurs qui vont se restreindre aux relations JPA plutôt que d'inventer des requêtes SQL efficaces qui ne passent pas par les relations JPA.

Exemple : Si A -> B -> C et que C peut-être relier à A par une concaténation de chaine par exemple, le développeur "de base", va faire un A join B join C alors qu'il serait possible de faire un A, C where A.toto = concat(C.titi + truc).

Préconisation : seulement les liens métiers forts. (assez indéfinissable en soit, c'est tout l'apport d'un architecte à ce niveau - et de se remettre en cause pour faire évoluer ces choix :))

  • quel Flushmode par défaut utiliser ?

Le flushmode.AUTO, s'il est pratique, fait qu'Hibernate réalise beaucoup d'opération

Préconisation : Ici c'est Monsieur performance qui parle : Flushmode.COMMIT par défaut. Les autres Flushmode à la demande en fonction des cas.

  • quel pool de connexion ?

Surtout le principe est de connaitre son pool de connexion et de le configurer (nb maximum de connexions, timeout, idle, requête de validation, etc...)

Préconisation : n'importe du moment qu'on puisse configurer les paramètres précédents

  • quel cache de niveau 1 ?

De la même façon que le pool de connexion, il faut savoir quel est celui utilisé et comment le configurer.

Préconisation : idem, n'importe mais le maitriser

  • utiliser ou non le cache de niveau 2 ?

Le cache de niveau 2 est partagé par toutes les sessions, en général seulement au sein de la JVM. Il est possible de partager un cache de niveau 2 au travers de plusieurs JVM via des caches distribués.

Préconisation : si 1 seule JVM, vous pouvez l'activer. Idem que les autres, maitriser le contenu du cache, sa taille, etc... Si plusieurs JVM, soit pas de cache niveau 2, soit cache distribué ou cache de niveau 2 pour des données en lecture seule.

  • spring data ou non ?

Permet de s'abstraire de pas mal de code technique pour la couche DAO.

Préconisation : Oui si vous avez Spring. Si vous n'avez pas Spring pensez-y...

  • écrire des requêtes avec les critérias, en HQL

Comment écrire les requêtes pour accéder à la base de données.

  1. en criteria : ça permet des refactors assez facile
  2. en HQL écrit à la main : très particulier pour des requêtes très flexibles
  3. en namedQuery : ça permet à la JVM de valider les requêtes au lancement

Préconisation : NamedQuery sur SpringData, Criteria pour les plus compliquées/flexibles

Quelque soit le mode d'écriture, on n'utilise QUE des paramètres bindés.

  • comment tester ? Derby / H2 ? base mémoire / base physique ?

L'avantage des bases mémoire c'est leur rapidité (de mise en oeuvre et d'exécution). Leur inconvénient est qu'il peut y avoir des écarts avec la base physique vraiment utilisé.

Par contre dans les deux cas, le problème est la création des données pour les tests, d'où l'utilisation préconisée des mocks qui simulent les accès base de données :)

Préconisation : des mocks pour les services métiers, une base réelle pour la validation des requêtes écrites par le développeur.

  • Transaction

Les transactions sont utilisées pour deux choses :

  1. garantir que plusieurs requêtes SQL sont validées en même temps
  2. conserver une connexion pour charger les objets et leurs enfants (et éviter les lazy-loading)

Les transactions en lecture seule existe et se termine quand même par un COMMIT et non pas un rollback... 

Préconisation : Déterminer les services qui ont besoin d'une transaction, leur cadre (commit globale ou optimisation de connexion). Utiliser un framework de transaction (Spring, EJB 3.1) et les tags @Transactional.

  • Monitoring

Comme pour les caches et les pools, il convient de savoir ce qui se passe dans la JVM. Des outils existent, mais l'important est d'avoir des informations sur :

- les caches (taille, nombre d'éléments, nombre de hits)
- les pools (nombre de connexions en cours /  nombre max de connexions)
- c'est pratique d'avoir un accès en lecture seule à la base de production pour consulter les informations indexs, query_plan, etc...

 

H2 base mémoire et client WEB intégré

Rédigé par gorki Aucun commentaire

Le problème :

La base H2 intègre un mode SERVEUR comme Hsqldb ou Derby, mais aussi un mode mixe qui permet au premier client connecté à la base de démarrer un serveur.

Très pratique, en utilisant un client quelconque , on peut se connecter au serveur !

Deux problèmes :

  • quel client ?
  • le mode serveur, OK, mais il ne fonctionne pas avec la base mémoire embarquée !

Solution : quel client ?

Tombé un peu par hasard dessus : ici sur stackoverflow

Il y a une liste ici : http://h2database.com/html/links.html#tools

La console WEB n'est pas intégrée au driver H2, même si dans la librairie H2 il y a la console H2 ; au départ je pensais qu'on aurais pu y accéder en tapant l'URL de la base de données + /console par exemple :)

Pour la console H2 :

  • soit vous avez le raccourci si vous avez installé H2, cf la doc
  • soit via le jar : java org.h2.tools.Console -web -browser
  • sinon, on peut la démarrer tout simplement :
import java.sql.SQLException;
import org.h2.tools.Console;


public class H2Client {

    public static void main(String[] args) {
        try {
            new Console().runTool();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}

Entrer l'url indiquée dans la configuration ou affichée lors du lancement du serveur pour la base mémoire.

Solution : serveur et base mémoire ?

Idem, dans le même post : ici sur stackoverflow

Sur disque

Ajouter AUTOSERVER=TRUE à la fin de la déclaration de la base de données :

Exemple :

jdbc:h2:~/my-database/db2;AUTO_SERVER=TRUE

En base mémoire

Il faut démarrer le serveur dans la JVM qui utilise la base mémoire embarquée :

Pour la déclaration base mémoire classique :

  • jdbc:h2:mem:test
            Server server = Server.createTcpServer().start();
            System.out.println("URL du serveur H2 : jdbc:h2:" + server.getURL() + "/mem:test");

Notez le "mem:test" à la fin de l'URL, à adapter si vous modifier la votre.

En fin de démarrage de Spring Boot, ça donne :

    @Bean
    public Server initH2Server() {
        try {
            Server server = Server.createTcpServer().start();
            System.out.println("URL: jdbc:h2:" + server.getURL() + "/mem:test");
            return server;
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return null;
    }
Fil RSS des articles de cette catégorie