Recherche sur le blog

lundi 18 avril 2011

[Utilitaires] ZXing "Zebra Crossing"

ZXing, ou "Zebra Crossing", est un ensemble de librairies open-source pour traiter et convertir des codes-barres en texte, ou inversement. Le but premier est de permettre le décodage par les appareils photos de téléphone sans communiquer avec un service web quelconque. Les librairies sont actuellement sous licence Apache (Apache License v2.0) et le projet est actuellement hébergé sur Google Code. Outre le fait qu'il est possible de décoder, il existe des classes permettant l'encodage. Ainsi on peut s'essayer à la création de codes QR ou même de codes 128, UPC-A, etc. Intéressés ? Rendez-vous sur la page du projet pour télécharger les librairies ou bien l'un des portages réalisé... Bon amusement à tous !

[WinDev] Exécuter du Java dans WinDev

Étant donné l'absence de QRCode dans WinDev 15, il a fallu développer une petite application Java permettant d'encoder des caractères dans ce fameux code. Le code QR est un type spécifique de code-barres qui peut contenir jusqu'à un peu plus de 4200 caractères alphanumériques, voire plus de 7000 caractères uniquement numériques. "QR" est en fait un acronyme qui signifie "Quick Response" car le contenu du code est récupéré quasi instantanément, quel que soit la taille de celui-ci. Le code-barres est en 2D et est représenté par un ensemble de modules noirs sur fond blanc. Il peut être décodé par les smartphones actuels grâce à une application gratuite ou grâce aux lecteurs adéquats. Bref, ceci est une digression car ce n'est pas le but premier de l'article.

En effet, dans WinDev 15 il est possible d'exécuter du code Java qui a été écrit et compilé sous forme de classe. Deux fonctions permettent en effet de réaliser cette opération : la première a pour but de charger toutes les classes nécessaires, tandis que la seconde permet de lancer la fonction "main" de la classe que l'on spécifie en paramètre. Voyons ces deux fonctions un peu plus en détail...

Chargement des classes

La fonction suivante définit la localisation des classes pour le classloader. Les différents répertoires/dossiers (ou archives) seront séparées par des ";". Comme renseigné dans la documentation, cette méthode ne peut être appelée qu'une seule fois. Un double appel génèrera une erreur et l'application sera fermée.

JavaCharge("c:\my_classes\applic.jar")

Exécution de la classe désirée

Pour qu'une classe puisse être exécutée, elle doit implémenter la fonction statique "void main" avec comme paramètre un tableau de chaînes (arguments) qui sont les paramètres passés à l'application (String args[]). Contrairement à une exécution en ligne de commandes (par exemple, via l'interpréteur Windows), les paramètres séparés par un espace seront considérés comme un seul et unique paramètre! 

JavaExecute("Application", "MaChaîne")

Le premier paramètre est le nom de la classe dont on veut appeler la méthode "main" (qui est le point d'entrée de l'application Java). Si la classe se trouve dans un package, il faut indiquer le nom complet avec le nom de chacun des packages, le tout séparé par "/". Ensuite, le deuxième paramètre de la fonction JavaExecute sera le paramètre envoyé et stocké dans le tableau d'arguments.

En ligne de commandes (en supposant que notre classe soit stockée dans une archive JAR), lorsque l'on exécute la commande... : 

java -jar x.jar param1 param2

Les paramètres sont respectivement stockés dans :

args[0] et args[1], soit args[0] == "param1" et args[1] == "param2"

Cependant, si "MaChaine" (dans JavaExecute) vaut aussi "param1 param2", le tout sera stocké dans args[0] tel que args[0] == "param1 param2". Une solution peut-être d'envoyer une chaîne contenant un caractère de séparation, qui sera traitée dans l'application Java grâce à la classe StringTokenizer.

Voilà qui peut être utile à tout le monde! Bon développement...

vendredi 15 avril 2011

[Java] Se connecter à un système AS/400

Comme nous travaillons régulièrement sur le système AS/400 d'IBM, plus précisément sur une machine iSeries 520 en version V5R3 sur laquelle on retrouve une base de données SQL de type DB2 UDB, il m'est venu l'idée de tester les fameuses librairies ("IBM Toolbox for Java") fournies par IBM lui-même afin d'exécuter une simple requête de sélection pour interroger un fichier en particulier (ou une table, pour les puristes). Voici donc une liste de pré-requis pour faire fonctionner le code qui va suivre :
  • Posséder une machine AS/400 iSeries, mise en réseau bien entendu.
  • Télécharger IBM Toolbox for Java. Pour ma part, j'ai pris la version estampillée "jtopen_7_3.zip". Il faut ensuite décompresser ces libraires dans un endroit particulier.
  • Avoir intégré les librairies via la configuration du projet (par exemple, si vous utilisez NetBeans, ce qui est mon cas, ou un autre IDE en particulier comme Eclipse).

Créer le projet, intégrer les librairies...

 
Après avoir créé un nouveau projet avec NetBeans dans lequel on y intègre les archives ".jar" téléchargées (voir aperçu écran ci-dessus), il faut créer une nouvelle fenêtre de type JFrame. On y insérera une table qu'on appellera simplement "jTableSt" et dont on va personnaliser le modèle avec une classe héritant de AbstractTableModel.  On aura aussi besoin d'établir la connexion à l'AS/400. Toutes ces étapes vont être détaillées dans la suite.
          
Créer une table dynamique grâce à un modèle

Ici l'effet attendu est que la table ait un nombre de colonnes différent selon la requête exécutée. Pour cela il faut créer un nouveau modèle qui sera utilisé par la table (on pourra le définir dans le code de la fonction principale). On l'appellera DynamicTableModel et il devra hériter de la classe AbstractTableModel, grâce au mot-clé "extends".

public class DynamicTableModel extends AbstractTableModel
{
    ArrayList cache;
    int colCount;
    String[] headers;
    Connection db;
    Statement statement;
    ...
}
    
  • La variable cache contiendra les valeurs pour chacune des colonnes. On aurait pu utiliser une variable vecteur mais cela pose un problème de synchronisation et son utilisation est déconseillée (deprecated).
  • L'entier sert à stocker le nombre de colonnes et pourra être renvoyé grâce à un getter.
  • Le tableau de chaînes "headers" contiendra les titres des colonnes.
  • Les deux dernières variables sont utilisées pour la connexion à la base de données et l'exécution de la requête. On initialisera ces variables grâce à un setter de la classe.
  • Toutes les méthodes seront publiques.
Voici quelques méthodes de la classe, dont la méthode (execute) qui exécute la requête SQL sur la base de données. Dans celle-ci, on crée les titres des colonnes grâce aux métadonnées et ont crée les lignes avec toutes les valeurs. Ensuite, on signale à tous que la table a été modifiée (fire*), et on ferme les variables "ResultSet" et "Statement". Remarque : le setter qui initialise les variables pour la connexion n'a pas été repris car il est simple à écrire. Les fonctions qui doivent être implémentées sont décrites dans la documentation Java. A vous de découvrir ce qu'il faut indiquer...

    public DynamicTableModel() {cache = new ArrayList();} 
    ...

    public void execute(String query)
    {
        cache = new ArrayList();
        try
        {
            ResultSet rs = statement.executeQuery(query);
            ResultSetMetaData meta = rs.getMetaData();
            colCount = meta.getColumnCount();
            headers = new String[colCount];

            for (int h = 1; h <= colCount; h++) {
            headers[h - 1] = meta.getColumnName(h);
            }

            while (rs.next()) {
              String[] rsRow= new String[colCount];
              for (int i = 0; i < colCount; i++) {
                  rsRow[i] = rs.getString(i + 1);
                }
              cache.add(rsRow);
            }

            fireTableChanged(null);
            rs.close();
            statement.close();
        }
        catch (Exception e)
        {
            cache = new ArrayList();
            System.err.println(e.getMessage());
        }
    }

Créer la connexion

        Connection conn;
        DriverManager.registerDriver(new com.ibm.as400.access.AS400JDBCDriver());
        conn = DriverManager.getConnection("jdbc:as400://ip/LIB");

On va indiquer et enregistrer la classe du driver JDBC fournie par IBM afin de pouvoir récupérer un objet connexion. Les informations à donner lors de la connexion sont l'adresse IP de l'AS/400 (ou le nom de l'hôte) et la librairie dans laquelle on veut travailler. On pourrait aussi spécifier les informations d'identification ou les librairies de la *LIBL dans une variable Properties, mais cela fera l'objet d'un nouvel article. Dans notre cas, une fenêtre apparaitra pour demander les informations de connexion de l'utilisateur, avant d'exécuter le reste du code.

Créer la table et exécuter la requête

        DynamicTableModel qtm = new DynamicTableModel();
        jTableSt.setModel(qtm);
        qtm.setConnection(conn);
        qtm.execute("select * from pegecl");

Dans la fonction ci-dessus, on crée une nouvelle instance du modèle précédemment écrit. Ensuite, on le définit pour la table grâce à la fonction setModel().  Ensuite, on utilise le setter du modèle pour définir la connexion utilisée et on appelle la fonction "execute" pour que la requête soit exécutée. La table sera alors générée, il ne reste plus qu'à fermer la connexion. Et voilà le résultat que nous avons obtenu après une ou deux secondes :


Alors, qui a dit que Java n'était pas adapté à tous les problèmes ? Bon développement.

    lundi 4 avril 2011

    [Info] Article sur Google Maps dans PROgrammez! n° 140

    J'ai l'immense joie de découvrir que mon article sur Google Maps est apparu dans le numéro 140 du magazine "PROgrammez!", vendu en Belgique pour la modique somme de 6,45 €uros. Au sommaire, l'instrumentation sous Linux, le programmation asynchrone en .NET, la programmation par contraintes en Java, l'avenir du développement multiplateforme,...