Publié le 31 Mars 2010

Il arrive qu'on est besoin de rediriger la sortie standard d'un script vers un fichier. Cela se fait facilement avec la redirection des flux (en ajoutant "> monfichier" à la fin de la ligne de commande).

Le problème est que parfois on aimerait bien aussi suivre l'éxecution simultanément à l'écran.

Et bien c'est possible avec la commande "tee" qui s'utilise de la façon suivante:

./monscript.sh | tee monfichier

 

ou

 

./monscript.sh 2>&1 | tee monfichier

 

si on veut aussi récupérer le flux d'erreurs.


Une autre solution consiste à faire un tail depuis un autre terminal:

tail -f monfichier

Voir les commentaires

Rédigé par Bliz

Publié dans #Script

Repost 0

Publié le 30 Mars 2010

Lorsqu'on rencontre des problèmes dans une application Java, il peut être utile de générer un Thread dump.

 

Cette technique peut s'avérer utile lorsqu'on ne parvient pas à déterminer la cause d'un problème à travers les traces et logs de l'application, particulièrement pour diagnostiquer des problèmes de performances.

 

Le thread dump permet de récupérer la stack trace de la JVM c'est à dire toutes les méthodes actuellement en exécution dans la JVM ainsi que les threads qui y tournent.

 

Pour générer un thread dump il faut envoyer le signal SIGQUIT à la JVM. Ceci s'effectue au moyen de la commande kill:

 

kill -3 <process_id>

 

ou

 

kill -QUIT <process_id>

 

où <process_id> est le process Id de la JVM (process Java)

Voir les commentaires

Rédigé par Bliz

Publié dans #Java

Repost 0

Publié le 29 Mars 2010

Le chargement d'un fichier .properties contenant des propriétés du type:

clé=valeur

s'effectue très simplement en Java au moyen de la classe java.util.Properties.

Il suffit en effet d'appeler la méthode load de l'objet Properties pour charger toutes les propriété du fichier.

Voilà le code pour charger un fichier de propriété:

package com.over-blog.patatos.example;

import java.util.Properties;
import java.io.IOException;
import java.io.FileNotFoundException;
import java.io.FileInputStream;

public class PropertyLoader{

   /**
    * Charge la liste des propriétés contenu dans le fichier spécifié
    *
    * @param filename le fichier contenant les propriétés
    * @return un objet Properties contenant les propriétés du fichier
    */

   public static Properties load(String filename) throws IOException, FileNotFoundException{
      Properties properties = new Properties();

      FileInputStream input = new FileInputStream(filename);
      try{

         properties.load(input);
         return properties;

      }

              finally{

         input.close();

      }

   }

   public static void main(String[] args){
      try{
         // chargement des propriétés
         Properties prop = PropertyLoader.load("monFichier.properties");

         // Affichage des propriétés
         // Récupère la propriété ma.cle
         // Si la propriété n'existe pas, retourne la valeur par défaut "vide"
        
System.out.println("ma.cle: "+ prop.getProperty("ma.cle", "vide"));
      }
      catch(Exception e){
         e.printStackTrace();
      }
   }
}

Voir les commentaires

Rédigé par Bliz

Publié dans #Java

Repost 0

Publié le 26 Mars 2010

Log4j est une bibliothèque de log en Java qui est très connue et très utilisé actuellement.

Elle permet entre autres de gérer plusieurs niveaux de log (debug, info, warn, error, ...) et plusieurs sorties (console, fichier, etc).

Bref c'est un outil très performant et très utile qui permet d'éviter le recours à des System.out.println() qui n'offre pas autant de souplesse.

De plus son utilisation est assez simple:

Tout d'abord il faut récupérer le jar log4j sur le site d'Apache: http://logging.apache.org/log4j/ et l'inclure dans le classpath Java.

Ensuite son utilisation au niveau du code se fait de la manière suivante:

package com.over-blog.patatos.example;

/**
 * importation de la classe Logger
 * qui est celle qu'on va utiliser pour générer les logs
 */

import org.apache.log4j.Logger;

public class App {

   /**
    * Déclaration du logger que nous allons utilisé
    * On utilise la classe App pour générer un nom de logger
    * unique dans notre application ici:
    * com.over-blog.patatos.example.App
    */

   private static Logger logger = Logger.getLogger(App.class);

   /**
    * Une méthode main où on va juste effectuer un log
    * Un Hello World Log4j en somme
    */

   public static void main(String[] args){
      logger.info("Hello World!");
   }

}


La notre programme est presque prêt! Il compile sans erreur mais il reste encore une étape : la configuration de log4j.

La configuration s'effectue au travers d'un fichier de configuration: log4j.properties ou log4j.xml (les 2 formats sont possibles).
Ici nous allons utilisé un fichier properties assez simple:

# Set root category priority to DEBUG and its only appender to CONSOLE.
log4j.rootCategory=DEBUG, CONSOLE
# CONSOLE is set to be a ConsoleAppender using a PatternLayout.
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
log4j.appender.CONSOLE.Threshold=INFO
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
log4j.appender.CONSOLE.layout.ConversionPattern=[%p] %c{1} %x - %m%n


La dernière ligne spécifie le format de log à générer. On peut donc facilement changer le format ou le niveau de log en modifiant le fichier de propriétés. Il n'y a donc pas besoin de recompiler notre programme à chaque changement de configuration.

Il reste cependant une fonctionalité à ajouter dans notre programme : le chargement de la configuration log4j.

Cela s'effectue grâce à la classe PropertyConfigurator de log4j.
Donc il faut ajouter l'import suivant à notre classe java:

import org.apache.log4j.PropertyConfigurator;

Ensuite dans la méthode main nous allons configurer log4j à l'aide de la méthode configure:

PropertyConfigurator.configure(
          App.class.getClassLoader().getResource("log4j.properties"));


Il faut ensuite placer le fichier log4j.properties dans le classpath java et le tour est joué.

Voir les commentaires

Rédigé par Bliz

Publié dans #Java

Repost 0

Publié le 25 Mars 2010

Pour charger le contenu d'un fichier texte dans une String on va utiliser la classe IOUtils qui permet de mettre facilement le contenu d'une InputStream dans une String.

La class IOUtils fait partie du package org.apache.commons.io.
Le jar commons-io-<version>.jar est disponible sur le site d'Apache: http://commons.apache.org/io/

L'utilisation est très simple on crée une FileInputStream avec le fichier à charger.
Puis on donne cette InputStream à la méthode toString() de IOUtils.

Ce qui donne le code suivant:

// Penser à faire l'import de IOUtils avant avec:
// import org.apache.commons.io.IOUtils;

InputStream myStream = new FileInputStream("monFichier.txt");
String myString = IOUtils.toString(myStream).trim();
// trim() permet de supprimer les éventuels espaces blancs en début et fin de fichier
// ce qui peut être utile pour effectuer une comparaison par la suite

Voir les commentaires

Rédigé par Bliz

Publié dans #Java

Repost 0

Publié le 24 Mars 2010

la commande est la suivante:

echo "Ma chaine avec des MAJUSCULES et des miniscules" | tr 'A-Z' 'a-z'

pour transformer les majuscules en minuscules.

Et pour le contraire minuscules vers majuscules il faut inverser les arguments du tr

echo "Ma chaine avec des MAJUSCULES et des miniscules" | tr 'a-z' 'A-Z'

Voir les commentaires

Rédigé par Bliz

Publié dans #Script

Repost 0

Publié le 23 Mars 2010

SAX signifie Simple API XML, c'est donc une API très simple qui permet de lire des flux (donc des fichiers) XML.

Son utilisation en Java est assez simple:

SAX se charge de lire le flux XML et à chaque fois qu'il rencontre un élément particulier, il appelle une méthode correspondante. Par exemple à chaque nouvelle balise XML qu'il rencontre il va appeler la méthode "startElement".

Pour l'utiliser il faut donc définir une classe qui va implémenter ces méthodes particulières qui sont:

startElement appelé lorsque le parser rencontre une nouvelle balise XML  les balises d'ouverture <maBalise>
endElement appelé lorsque le parser rencontre une balise fermante XML  les balises de fermeture </maBalise>



C'est essentiellement ces 2 méthodes qui vont nous intéresser ici mais il y en a d'autres qui permettent de traiter d'autres évènement:

startDocument appelé lorsque le parser débute la lecture du document XML  
endDocument appelé lorsque le parser termine la lecture du document XML  
startPrefixMapping appelé lorsque le parser rencontre le début d'un espace de nommage (namespace)  
endPrefixMapping appelé lorsque le parser rencontre la fin d'un espace de nommage (namespace)  
characters appelé lorsque le parser rencontre des caractères à l'intérieur d'un élément pour les charactères "mes caractères" dans <maBalise>mes caractères</maBalise>
ignorableWhitespace appelé lorsque le parser rencontre des caractères blancs (espaces) qui peuvent être ignorés les espaces utilisés pour indenter le XML
processingInstruction appelé lorsque le parser rencontre une instruction dans le flux XML  
skippedEntity appelé lorsque le parser saute une entité  


Il existe également des méthodes pour la gestion des erreurs:

warning appelé lorsque le parser rencontre un warning
error appelé lorsque le parser rencontre une erreur non bloquante
fatalError appelé lorsque le parser rencontre une erreur de parsing fatale


Donc voilà pour le principe maintenant pour utiliser le parser il faut définir son propre handler, c'est à dire une classe qui va implémenter les méthodes dont nous avons besoin.

Cette classe étend la classe org.xml.sax.helpers.DefaultHandler qui propose une implémentation par défaut de toutes ces méthodes. (Il n'y a aucune action effectuée dans ces méthodes, mais ceci permet de ne définir que les méthodes qui nous intéressent).

Donc voilà le code pour définir notre handler:

package com.over-blog.patatos.sax;

import java.util.ArrayList;
import java.util.List;

import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;

import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

public class MySaxHandler extends DefaultHandler {

   /**
    * Un tableau qui contient la hierarchie courante des balises
    * Permet de gérer les balises imbriquées
    **/

   private List<String> blocks;

   public void parse(InputStream input) throws
           ParserConfigurationException,
           SAXException,
           IOException{
        // creation du parser SAX
        SAXParserFactory factory = SAXParserFactory.newInstance();
        factory.setValidating(true);
        factory.setNamespaceAware(true);
        SAXParser parser = factory.newSAXParser();
        // lancement du parsing en précisant le flux et le "handler"
        // l'instance qui implémente les méthodes appelées par le parser
        // dans notre cas: this

        parser.parse(input, this);
    }

   public void parse(String filename) throws
           FileNotFoundException,
           ParserConfigurationException,
           SAXException,
           IOException{
        parse(new FileInputStream(filename));
    }

   public void startDocument() throws SAXException{
      // initialisation
      blocks = new ArrayList<String>();
   }

   public void startElement(
            String uri,
            String localName,
            String qName,
            Attributes attributes) throws SAXException {
        if (localName.equals("maBaliseSimple")) {
            System.out.println(localName+"-"+attributes.getValue("id"));
        }
        if (localName.equals("maBaliseImbrique")) {
           
System.out.println(
               indent(
                   blocks.size(),
                   localName+"-"+attributes.getValue("id"));
            // balise imbriquée: ajoute un niveau de profondeur
            blocks.add(
localName+"-"+attributes.getValue("id"));
        }
   }

   public void endElement(
            String uri,
            String localName,
            String qName) throws SAXException {
        if (localName.equals("
maBaliseImbrique")) {
            // fermeture d'une balise imbriquée
            // -> remonte d'un niveau de profondeur

            blocks.remove(blocks.size()-1);
        }
    }

   private String indent(int spaces, String text){
      String tabs = "";
      for(int i = 0; i < spaces; i++){
         tabs += "\t"; //tabulation
      }
      return tabs+text;
   }
}

Voilà un parser assez simple qui ne fait qu'afficher les élements qu'il rencontre avec une indentation en fonction de l'imbrication des balises.
Pour ceci il faut garder une trace de la profondeur actuelle. C'est le tableau blocks qui permet de gérer ceci. On aurait pu utiliser un simple int ici, mais utiliser un tableau avec des objets (au lieu des String qui ne serve pas vraiment ici) aurait permis un traitement plus complexe, notamment en construisant une arborescence reflétant la structure du xml.

Enfin les méthode parse permettent de parser un fichier xml soit à partir d'un nom de fichier ou directement depuis un flux (InputStream).

Le document XML que nous allons parser ressemble à ceci:

<?xml version="1.0" encoding="UTF-8"?>
<monDoc>
   <maBalise id="1" />
  
<maBalise id="2" />
       <maBaliseImbriquee id="3">
          <maBaliseImbriquee id="4">
               <maBalise id="5" />
          </maBaliseImbriquee>
       </maBaliseImbriquee>         
</monDoc>

Pour lancer le programme il faut ajouter une méthode main:

public static void main( String[] args ) throws FileNotFoundException, ParserConfigurationException, SAXException, IOException {
       
MySaxHandler handler = new MySaxHandler();
        handler.parse("monFichier.xml");
}

Une fois compilé et lancé le résultat est le suivant:

maBalise-1
maBalise-2
maBaliseImbriquee-3
   maBaliseImbriquee-4
maBalise-5

Voir les commentaires

Rédigé par Bliz

Publié dans #Java

Repost 0

Publié le 22 Mars 2010

Après avoir extrait des données depuis des fichiers textes sous formes de colonnes, j'ai du transposer une colonne sur 1 ligne pour pouvoir faire un graphique.

Cette opération s'effectue très simplement dans Excel car il est possible de coller les données d'une colonne sur 1 ligne et vice versa.

Ce collage particulier s'effectue, après avoir copié les données, en sélectionnant :

Edition / Collage spécial ...

puis un cachant la case Transposé.

Voir les commentaires

Rédigé par Bliz

Publié dans #Office

Repost 0

Publié le 19 Mars 2010

Pour compléter l'article sur "comment exécuter un fichier SQL depuis un script avec SQL*Plus", voici comment passer une variable au fichier SQL.

Il faut rajouter les paramètres à la fin de la ligne de commande après avoir spécifié le fichier sql :

sqlplus -L <username>/<password>@<database> @<fichier_sql> <param1> <param2> <etc>

Ensuite on récupère les paramètres dans le sql en utilisant la syntaxe suivante :

ma_variable_numerique := &1;
ma_variable_string := '&2';


Attention à ne pas oublier les guillements simples si le paramètre passée est une string (VARCHAR).

Voici par exemple un fichier SQL qui effectue un simple select :

SET SERVEROUTPUT ON
SET VERIFY OFF
DECLARE
   mycond1  VARCHAR2(255);
   mycond2  NUMBER;
   myresult VARCHAR2(255);
BEGIN
   mycond1 := '&1';
   mycond2 := &2;
   SELECT name INTO myresult FROM films WHERE realisateur=mycond1 AND annee=mycond2;
   DBMS_OUTPUT.PUT_LINE('Titre : ' || myresult);
END;
/

Puis pour l'appeler on utilise sqlplus:

sqlplus -L <username>/<password>@<database> @mon_fichier.sql cameron 2009



Voir les commentaires

Rédigé par Bliz

Publié dans #Oracle

Repost 0

Publié le 17 Mars 2010

Voilà un tutoriel bien utile expliquant comment générer un graphique à partir d'une liste de données brutes.

Donc pour commencer voilà les données:

VOITURE DATE KM
Renault Clio 01/03/2010 53
Renault Clio 01/03/2010 26
Peugeot 206 01/03/2010 15
Peugeot 206 01/03/2010 104
Volkswagen Polo 01/03/2010 87
Citroen C3 01/03/2010 39
Renault Clio 02/03/2010 12
Peugeot 206 02/03/2010 63
Peugeot 206 02/03/2010 78
etc ...
... ...

Ici il s'agit de l'utilisation de voitures avec leur kilométrages mais on peut aussi imaginer des ventes effectuées par des vendeurs, etc ...

Donc le gros du problème est de transformer les données en un tableau un peu plus exploitable.
Pour l'instant il y a une ligne pour chaque utilisation, ce qui donne parfois lieu à plusieurs lignes par jour pour la même voiture.

L'idéal serait dont d'arriver à un tableau comme ceci


Renault Clio Peugeot 206 Volkswagen Polo Citroen C3
01/03/2010 79 119 87 39
02/03/2010 12 141 88 43
03/03/2010 0 65 113 215
04/03/2010 397 0 81 9
05/03/2010 0 332 174 26

Où on retrouve le nombre de kilomètre total effectué par voiture et par jour.

Et bien cette transformation est possible et ce n'est même pas trop compliqué puisqu'il suffit d'utiliser la fonction SOMMEPROD. Mais procédons par étape:

1/ On commence par mettre en place notre tableau avec les voitures en haut et les dates à droite:

Renault Clio Peugeot 206 Volkswagen Polo Citroen C3
01/03/2010



02/03/2010



03/03/2010



04/03/2010



05/03/2010




2/ Nous allons passer au remplissage du tableau. Il s'effectue avec la fonction SOMMEPROD grâce à laquelle nous allons pouvoir préciser un certains nombres de critères pour additionner les kilomètres. Dans notre cas nous avons 2 critères:
 - un premier sur la voiture (on ne veut que les kilomètres d'une voiture donnée)
 - un deuxième sur la date (on ne veut que les kilomètres d'un jour donné)
et cela s'écrit de la manière suivante:

=SOMMEPROD((A2:A31=F1)*(B2:B31=E2)*(C2:C31))

ou :
A2:131 correspond à la colonne contenant les noms des voitures
F1 correspond à l'entête de la colonne de notre tableau: "Renault Clio"
Cette première parenthèse (matrice) correspond au premier critère de sélection
B2:B31 correspond à la colonne des dates
E2 est la première date de la colonne des date de notre tableau: "01/03/2010"
Cette deuxième matrice correspond au deuxième critère
C2:C31 est la colonne des kilomètres. Ce sont les valeurs qu'on veut ajouter.

voilà c'est peut être plus clair avec une capture d'écran:

excel-synthese.JPG

3/ Pour compléter le tableau il suffit de faire varier les critères:
 - F1: varie de F1 à I1 en fonction de la colonne où on se trouve (c'est le nom des voitures)
 - E2: varie de E2 à E6 en fonction de la ligne où on se trouve (c'est la date courante)

4/ On peut éventuellement tracer un graphique pour synthétiser toutes ces données.

Voir les commentaires

Rédigé par Bliz

Publié dans #Office

Repost 0