P3 A new story begins

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

mardi 4 janvier 2011

Configuration Option Java pour Tomcat

Un petit billet sous forme de memento:

Voici les paramètres essentiels pour la machine virtuelle Java d'un Tomcat de dévelopement ou d'intégration : (avec une JVM SUN)

///

Arguments to pass to the Java virtual machine (JVM).

JAVA_OPTS="-Xms64m -Xmx512m -XX:PermSize=32m -XX:MaxPermSize=256m -XX:+CMSClassUnloadingEnabled -Djava.awt.headless=true -Xdebug -Xrunjdwp:transport=dt_socket, address=8000,server=y,suspend=n -Dcom.sun.management.jmxremote"

///

  1. -Xms64m
  2. -Xmx512m : application quelque peu gourmande en mémoire.
  3. -XX:PermSize=32m
  4. -XX:MaxPermSize=256m : Utilisation massive de spring-hibernate avec des proxies donc le perm gen est bien utilisé
  5. -XX:+CMSClassUnloadingEnabled : essaye de décharger les classes de l'espace permanent generation
  6. -Djava.awt.headless=true (gestion sans IHM pour permettre les impression des graphiques pe: pour lambdaprobe)
  7. -Xdebug -Xrunjdwp:transport=dt_socket,address=8000,server=y,suspend=n
  8. -Dcom.sun.management.jmxremote : utilisation du débugger d'eclipse à distance

mardi 30 novembre 2010

About Logging !

Un petit billet au sujet de la gestion des logs avec Java :

Si on se réfère au règles diverses (Checkstyle, PMD ...), voici la bonne façon de déclarer un logger en Java

  1. // Pour Log4J avec commons-logging
  2. private static final Log logger = LogFactory.getLog(MyClass.class);
  3.  
  4. // Pour logback avec slf4j
  5. private static final Logger logger = LoggerFactory.getLogger(MyClass.class);

...Hein.. c'est quoi logback ???

Logback est le digne hériter de log4j, il a été conçu en même que les api slf4j par le créateur lui même de log4j: Ceki Gülcü

Il y a de nombreuses raisons d'utiliser logback, et elles sont toutes expliquées sur le site http://logback.qos.ch/reasonsToSwitch.html

Le seul défaut est que vous perdrez le niveau fatal, mais bon toutes les erreurs ne devraient-elles pas êtres évitées, et un niveau fatal devraient entrainer l'arrêt de l'application ??

Donc switchons tous ensemble :D

Revenons à nos moutons si on veut logger des évènements qui ont lieu dans une classe abstraite commune la bonne solution est de déclarer le logger protégé et de l'initialiser de manière statique.

  1. protected transient final Logger logger = LoggerFactory.getLogger(this.getClass());

Toutefois cette déclaration n'est pas compatible avec une règle (qui à dit 'à la con') de PMD à savoir LoggerIsNotStaticFinal

Certains puristes veulent que la classe Abstraite et la classe fille ai chacune leur propre logger pour permettre de les filtrés différemment avec le fichier de configuration du gestionnaire de log. (cf ce billet )

Personnellement j'ai jamais voulu séparer les logs des méthodes abstraites hérités de celles déclarées dans la classe fille, surtout quand la pile d'appel est imbriqué et que plusieurs classes filles peuvent être appelés.

On pourrait ajouter l'information getClass() dans chaque log de la classe abstraite, mais c'est quand même relativement pénible

Donc comment faire ??

Une des solutions peut-être d'utiliser AOP => en bon français la Programmation par aspect (soit en bon anglais Aspect Oriented Programmation à opposer à la OOP)

Avec Spring AOP par exemple on peut ajouter des logs sur des points de coupe définissant des endroits où logger.

Voici la déclaration via le conteneur léger de spring (spring-beans):

  1. <bean id="loggingAdvice" class="fr.webeo.rapidoo.aop.LoggingAdvice" />
  2.  
  3. <bean id="loggingAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
  4. <property name="advice" ref="loggingAdvice" />
  5. <property name="pattern" value="fr.webeo.rapidoo.services" />
  6. <property name="order" value="50" />
  7. </bean>

A vous de spécialiser votre point de coupe si vous voulez plus de précision, ici toutes les méthodes de toutes les classes du package fr.webeo.rapidoo.services seront traitées à la même enseigne !

Et l'advice qui va logger tout seul les classes filles

  1. public class LoggingAdvice implements MethodBeforeAdvice, AfterReturningAdvice, ThrowsAdvice {
  2.  
  3. /**
  4.   * Default Constructor.
  5.   */
  6. public LoggingAdvice() {
  7. // Nothing to do
  8. }
  9.  
  10. /**
  11.   * {@inheritDoc}
  12.   */
  13. @Override
  14. public void before(final Method method, final Object[] args, final Object target) throws Throwable {
  15. final Logger logger = LoggerFactory.getLogger(target.getClass());
  16. if (logger.isInfoEnabled()) {
  17. logger.info("Calling : " + method.getName() + " " + target.getClass().getName());
  18. }
  19. if (logger.isDebugEnabled()) {
  20. final StringBuilder sb = new StringBuilder();
  21. sb.append("Parameters : ");
  22. if (method.getParameterTypes().length == args.length) {
  23. for (int i = 0; i < args.length; i++) {
  24. sb.append("\r\nParam : ").append(method.getParameterTypes()[i]).append(" - ").append(args[i] == null ? "null" : args[i].toString());
  25. }
  26. }
  27. if (sb.length() > 1000) {
  28. logger.debug(sb.substring(0, 1000));
  29. } else {
  30. logger.debug(sb.toString());
  31. }
  32. }
  33. }
  34.  
  35. /**
  36.   * {@inheritDoc}
  37.   */
  38. @Override
  39. public void afterReturning(final Object returnValue, final Method method, final Object[] args, final Object target) throws Throwable {
  40. final Logger logger = LoggerFactory.getLogger(target.getClass());
  41.  
  42. if (logger.isInfoEnabled()) {
  43. logger.info("Returning : " + method.getName());
  44. }
  45. if (logger.isDebugEnabled() && returnValue != null) {
  46. if (returnValue instanceof List) {
  47. logger.debug("Return value is list of " + ((List<?>) returnValue).size() + " elements.");
  48. } else {
  49. logger.debug("Return Value = " + returnValue.toString());
  50. }
  51. }
  52. }
  53.  
  54. /**
  55.   * Call after an exception thrown.
  56.   *
  57.   * @param method the method called
  58.   * @param args the method arguments
  59.   * @param target the object who call the method
  60.   * @param exception the exception thrown
  61.   */
  62. public void afterThrowing(final Method method, final Object[] args, final Object target, final Throwable exception) {
  63. final Logger logger = LoggerFactory.getLogger(target.getClass());
  64. if (logger.isErrorEnabled()) {
  65. logger.error("Throwing : " + method.getName() + " \r\n=> " + exception.getMessage(), exception);
  66. }
  67. }
  68. }

Pour conclure il existe 3 possibilités pour logger des classes filles héritant d'une même classe abstraite :

  • Un logger par classe

Avantages : Chaque ligne de la log renvoi vers la bonne classe physique

Défauts : les log contiendront des log par enfant et pour la classe mère, donc si quelque chose se passe mal dans la classe abstraite il faut espérer trouver à proximité une log indiquant quel est la classe fille concernée (ou bien la rajouter explicitement dans la ligne loggée)

  • Déclaration du logger de la classe abstraite en protected non static

Avantages : Toutes les logs seront générés au nom de la classe fille

Défauts : les numéros de lignes des méthodes héritées concerneront la classe abstraite

  • Déclaration des loggers via AOP :

Avantages : Déclaration très rapide, bonne personnalisation

Defauts : Seulement utile pour les log génériques, induit donc une bonne conception objet avec des méthodes courtes et atomiques
Et vous comment faîtes-vous ??

lundi 29 novembre 2010

De l'utilité des Expressions Régulières dans Eclipse

Récemment j'ai pour la première fois trouvé une utilité à la case à cocher Regular Expressions de la boîte de dialogue Find/Replace d'Eclipse (ctrl+F)

en effet le plus souvent une bonne orgie au clavier prendra moins de temps que de réfléchir à écrire la bonne regexp pour faire un petit refactor.

Mon problème était le suivant, j'avais plusieurs énumération (enum) dont les champs étaient écrit ainsi :

  1. ...
  2. field1, // Field1 comment
  3. ...

Or CheckStyle nous tape sur les doigts car il faut un élément de javadoc par champs

Donc ctrl+F

Find_Replace_With_Regex.png

en version texte pour faire un copier-coller

([a-zA-Z_]*)([,|;] // )([a-zA-Z_-éè' .\[\]#]*)
/** $3. */\r\n\t$1,

Ce qui nous donnera :

  1. ...
  2. /** Field1 comment. */
  3. field1,
  4. ...

Vous pouvez rajouter vos caractères spéciaux par exemple les parenthèses si vous en avez dans vos commentaires ce qui donnerait :

([a-zA-Z_]*)([,|;] // )([a-zA-Z_-éè' .\[\]#\(\)]*)

De quoi devenir le Leader de la Board :D

mercredi 22 septembre 2010

Bouchon JNDI

Tout récemment j'ai été confronté à un problème comment lancer des tests se services java effectuant des requêtes en base de données avec une datasource JNDI !!!

Une des solution aurait été de se connecter directement à la base de données avec une URL standard, mais je ne souhaitait pas modifier le code existant.

Donc voici l'astuce :

  1. System.setProperty(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.fscontext.RefFSContextFactory");
  2.  
  3. Reference reference = new Reference("javax.sql.DataSource", "org.apache.commons.dbcp.BasicDataSourceFactory", null);
  4. reference.add(new StringRefAddr("driverClassName", "oracle.jdbc.OracleDriver")); //Le driver de la base utilisée
  5. reference.add(new StringRefAddr("url", "url_de_la_base"));
  6. reference.add(new StringRefAddr("username", "username"));
  7. reference.add(new StringRefAddr("password", "password"));
  8. context.rebind("jdbc/myappl", reference);

Nous n'avez plus qu'à renseigner le user/mot de passe et l'url de la base, bien sur si vous n'utilisez pas une base oracle changez le driver et n'oubliez pas le driver jdbc

Pour pouvoir utiliser ce code vous aurez besoin de rajouter les jars suivant dans votre classpath :

  • fscontext.jar
  • providerutil.jar
  • commons-dbcp-1.4.jar (pour la factory de Datasource)

Les deux premiers jars sont récupérable chez Sun/Oracle

POur vous faire gagner du temps les voici réunit dans une archive : Jars pour utiliser une datasource via JNDI

mercredi 10 février 2010

Gestion des Map en EMF dans un ecore

Voici le contenu du code source d'un fichier exemple ou une Map est déclaré :

Voici une petite capture de l'éditeur ecore d'Eclipse pour plus de clarté :

Visualisation du fichier ecore avec gestion de map dans l'éditeur d'Eclipse

Et le code du fichier ecore pour plus d'exhaustivité...

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <ecore:EPackage xmi:version="2.0"
  3. xmlns:xmi="http://www.omg.org/XMI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xmlns:ecore="http://www.eclipse.org/emf/2002/Ecore" name="fr">
  5. <eSubpackages name="webeo">
  6. <eSubpackages name="blog">
  7. <eClassifiers xsi:type="ecore:EClass" name="CarOwner">
  8. <eStructuralFeatures xsi:type="ecore:EReference" name="carMap" upperBound="-1"
  9. eType="#//webeo/blog/CarMapEntry" containment="true"/>
  10. </eClassifiers>
  11. <eClassifiers xsi:type="ecore:EClass" name="Car"/>
  12. <eClassifiers xsi:type="ecore:EClass" name="CarMapEntry" instanceClassName="java.util.Map$Entry">
  13. <eStructuralFeatures xsi:type="ecore:EAttribute" name="key" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
  14. <eStructuralFeatures xsi:type="ecore:EReference" name="value" lowerBound="1"
  15. eType="#//webeo/blog/Car" containment="true"/>
  16. </eClassifiers>
  17. </eSubpackages>
  18. </eSubpackages>
  19. </ecore:EPackage>

Et pour terminer le fichier ecore :D

Fichier Ecore avec Gestion de Map