mardi 26 février 2013

PayPal Instant Payment Notification (IPN) simulator

Je suis en train de mettre en oeuvre une solution de payement PayPal pour le site de calcul d'ensoleillement heliorama.com.
L'idée est de faire deux types de comptes utilisateurs : un gratuit et un payant.

Le payement se fait par des boutons PayPal et j'utilise l'Instant Payment Notification (IPN) pour activer le compte une fois le payement effectué.

IPN est un service asynchrone qui nous envoie des messages sur un listener pour notifier des évènements PayPal (payement en cours, payement effectué, remboursement etc.). Une bonne source d'information est l'IPN Guide de PayPal.

Donc, après avoir implémenté une servlet comme listener, j'utilise l'IPN Simulator de PayPal Sandbox pour vérifier son fonctionnement.

L'objectif est donc que le service PayPal accède en HTTP à mon poste de développement.
Il a fallu pour cela effectuer un translation de port NAT sur la box de mon FAI.
port externe 8080 --> @IPposteDev port interne 8080

Sauf que, malgré ce paramétrage, l'IPN Simulator donne l'erreur :

IPN delivery failed. Unable to connect to the specified URL. Please verify the URL and try again.

La solution, non documentée à ma connaissance, est que l'IPN Simulator ne fonctionne qu'avec le port HTTP par défaut : 80. La translation NAT est donc :
       port externe 80 --> @IPposteDev port interne 8080


lundi 25 février 2013

Génération Schéma Hibernate Annotation avec JNDI

Hiers, je suis tombé sur un os :
Pour le site de calcul d'ensoleillement sur www.heliorama.com, la gestion de la persistance objet est faite par Hibernate, avec une configuration par Annotation et la définition de la datasource en JNDI.

La méthode classique pour générer un schéma DDL à partir de la config annotation est d'utiliser la tâche ant hibernatetool, de cette façon (QUI NE FONCTIONNE PAS SI LA DATASOURCE EST EN JNDI):


<hibernatetool destdir="./generated">
 <classpath>
  <path location="." />
  <path location="../build/classes" />
 </classpath>
 <annotationconfiguration configurationfile="../WebContent/WEB-INF/hibernate.cfg.xml"/>
 <hbm2ddl export="false" outputfilename="sql.ddl"/>
</hibernatetool>

A ce propos, il assez sioux de faire fonctionner cette tâche, étant donné qu'il faut récupérer tout les jar nécessaires. Pour ma part, j'ai décidé d'allez assez vite en ajoutant tout les jar du plug-in hibenate-tool eclipse (plugins/org.jboss.tools.hibernate4_0_3.5.1.v20130102-1835-H100-Final) et tous les jar de ma webapp.

On défini un classpath de cette façon :


<path id="toolslib">
<fileset dir="lib" includes="**/*.jar"/> <!-- copie du plug-in hibernate-tool dans un répertoire lib au même niveau que le build.xml -->
<fileset dir="../WebContent/WEB-INF/lib" includes="**/*.jar"/> <!-- webapp -->
</path>

Puis on l'utilise dans une taskdef :

<taskdef name="hibernatetool"
         classname="org.hibernate.tool.ant.HibernateToolTask"
         classpathref="toolslib" />

Ce qui donne le fichier de build ant :

<project name="MyProject" basedir="." default="default">
<path id="toolslib">
<fileset dir="lib" includes="**/*.jar"/>
<fileset dir="../WebContent/WEB-INF/lib" includes="**/*.jar"/>
</path>

<taskdef name="hibernatetool"
         classname="org.hibernate.tool.ant.HibernateToolTask"
         classpathref="toolslib" />

<target name="default">
<hibernatetool destdir="./generated">
 <classpath>
  <path location="." />
  <path location="../build/classes" />
 </classpath>
 <annotationconfiguration configurationfile="../WebContent/WEB-INF/hibernate.cfg.xml"/>
 <hbm2ddl export="false" outputfilename="sql.ddl"/>
</hibernatetool>
</target>
</project>

JNDI 

Lorsque la configuration de la connexion à la base de donnée est définie par JNDI, il est évident que cela ne peut pas fonctionner. Pourquoi ? Car un build ant n'a pas de context JNDI défini et encore moins celui de tomcat (ou autre) où est définie notre datasource.

La solution est de faire la génération de manière programatique :


// Get de MySQL Dialect
Properties props = new Properties();
props.put(Environment.DIALECT , "org.hibernate.dialect.MySQLDialect");
props.put(Environment.DEFAULT_SCHEMA, "heliorama");
Dialect dialect = Dialect.getDialect(props);

// Configure Hibernate
File configFile = new File("WebContent/WEB-INF/hibernate.cfg.xml");
Configuration configure = new Configuration().configure(configFile).setProperties(props);

// Generate Drop
String[] sqls  = configure.generateDropSchemaScript(dialect);
for(String s : sqls){
System.out.println(s + ";");
}

// Generate schema
sqls  = configure.generateSchemaCreationScript(dialect);
for(String s : sqls){
System.out.println(s + ";");
}












lundi 18 février 2013

Changer de version Java sous Windows 7

En tant que développeur Java, il est souvent nécessaire de changer de version Java pour différents projets : Certaines applications ne supportant que Java  7, d'autre étant encore strictement Java 6 ou 5.

La méthode classique est d'avoir plusieurs répertoires d'installation de Java pour chaque version et de changer soit :

  • les paramètres d'appel de l'application. Par exemple préciser dans eclipse.ini le chemin du jdk à utiliser,
  • la variable d'environnement %Path% pour pointer vers la bonne version.
Cependant, j'ai eu quelques difficultés avec mon nouveau PC sous Windows 7 : En effet, après avoir installé Java 7, même en changeant la variable %Path%, java -version continuait à me fournir Java 7.

La raison est la suivante : L'installateur Java 7 créé une copie de java.exe et javaw.exe sous C:\Windows\System32, or ce répertoire est avant celui de Java 6 dans mon Path.

C'est, à mon avis, une très mauvaise pratique de la part d'Orcale de fournir un installateur de JDK, dédié au développement, qui se comporte de cette façon !

Les solutions sont donc :
  • Supprimer ou renommer java.exe et javaw.exe de System32 (ce que j'ai fait)
  • Mettre le répertoire de Java avant System32 dans le Path
Noter qu'il existe aussi dans le "Panneau de configuration" Windows un "Java Control Panel" qui donne accès à des clé dans la base de registre, notamment pour les applets et pour Java Web Start. Je n'ai pas réussi à la faire fonctionner correctement... Encore une pollution Oracle lors de l'installation ! Grrrrrr...

EDIT :
Le problème de Java Control Panel qui ne sauve pas la configuration semble être un problème de droit : Il doit est exécuté avec le droit Admin, voir : Can't seem to disable Java Automatic Update
L’astuce est d'exécuter javacpl.exe en administrateur (chercher javacpl.exe dans /jre/bin de l'installation du jdk/jre, clic-droit exécuter en tant qu'administrateur).


mardi 5 février 2013

Ignorer les erreurs javascript pour les fichier javascript minifier dans Eclipse (Ignore Minify js Validation in Eclipse)

Eclipse ne gère pas correctement les fichiers minifier en javascript (minified javascript). La validation échoue est on est pollué avec des erreurs dans la vue "Problems" qui n'en sont pas.


Pour résoudre ce problème, il suffit de contrôler la validation javascript dans Eclipse :
Window > Preferences > Validation

Cliquer sur "settings" de "Client-side Javascript Validator".

Nous allons ajouter une règle pour exclure les fichiers javascript terminant par .min.js :

  1. "Add Exclude Group", 
  2. Sélectionner le nouveau "Exclude Group" 
  3. Puis cliquer "Add Rule".
  4. Choisir "File extension"
  5. Saisir "min.js" dans File extension.
  6. Finish


J'effectue l'opération en même temps que j'écris se message et après validation et rebuild, j'ai toujours les messages d'erreurs....

En fait, il y a deux types dans la vue Problems : "Javascript Problem" et "Client-side Javascript Problem".
En activant "Client-side Javascript Problem" j'ai eu un nouveau "problem".

Je pense qu'il y a deux validations différente entre "Javascript Problem" et "Client-side Javascript Problem".
Je vais creuser cela un peu plus tard.

Un peu plus tard :
Ok, si vous supprimez les markers problem suivi d'un clean, ça devrait marcher !

Autre solution : Commentaire 15 de https://bugs.eclipse.org/bugs/show_bug.cgi?id=349020#c11.

Pour aller plus loin :

Différence entre "Javascript Problem" et "Client-side Javascript Problem" :
The Client-side JavaScript Validator only validates JavaScript in web pages, as its name implies.