/** * Copyright (C) 2008-2010, Squale Project - http://www.squale.org * * This file is part of Squale. * * Squale is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation, either version 3 of the * License, or any later version. * * Squale is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with Squale. If not, see <http://www.gnu.org/licenses/>. */ //Source file: D:\\cc_views\\squale_v0_0_act\\squale\\src\\squalix\\src\\org\\squale\\squalix\\util\\csv\\CSVParser.java package org.squale.squalix.util.csv; import java.io.BufferedReader; import java.io.FileReader; import java.io.IOException; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.apache.commons.logging.Log; import org.apache.commons.logging.impl.LogFactoryImpl; /** * Permet de parser un fichier CSV (comma separated values) et de le mapper avec un Bean selon un configuration.<br> * Les beans � mapper doivent impl�menter l'interface <code>CSVBean</code> et poss�der les setters publics ad�quats.<br> * <br> * Les d�pendances avec le logger JRAF et la classe org.squale.squalix.configurationmanager.ConfigUtility doivent * �tre r�solues. <br> * Le fichier de mapping (ici csv-mapping.xml) :<br> * <code> *   <templates><br> *     <template name="method"><br> *       <csvbean>test.MonBean</csvbean><br> *       <header size="2" /><br> *       <footer size="3" /><br> *       <field name="name" type="java.lang.String" column="0"></field><br> *       <field name="misc" type="java.lang.String" column="1"></field><br> *       <field name="val1" type="java.lang.Integer" column="2"></field><br> *       <field name="val2" type="java.lang.Double" column="3"></field><br> *     </template><br> *   </templates><br> * </code> Pour chaque template, sp�cifier :<br> * <ul> * <li>son nom avec l'attribut name</li> * <li>le nom de la classe correspondante avec l'�lement csvbean</li> * <li>le nombre de lignes de l'en-t�te</li> * <li>le nombre de lignes du pied de page</li> * <li>chaque attribut avec pour chacun : * <ul> * <li>son nom (attribut name) (si la valeur de cet attribut est monNom, le setter recherch� est alors setMonNom)</li> * <li>son type objet (pas de type simple) qui accepte un constructeur avec une <code>String</code> en param�tre</li> * <li>le num�ro de la colonne correspondante dans le fichier CSV (� partir de 0)</li> * </ul> * </li> * </ul> * <br> * <br> * Les classes mapp�es doivent poss�der les setters associ�s aux attributs mapp�s sur le CSV.<br> * Exemple : si la classe poss�de un attribut nomm� <code>name</code>, elle devra impl�menter une m�thode publique * nomm�e <code>setName</code>.<br> * D'autre part les param�tres des setters ne peuvent �tre des types simples. Ils doivent �tre des objets qui poss�dent * un constructeur prenant un seul param�tre <code>String</code>. * * @author m400842 * @version 1.0 */ public class CSVParser { /** * Configuration du framework */ private CSVConfiguration mConfiguration; /** * Logger. */ private static final Log LOGGER = LogFactoryImpl.getLog( CSVParser.class ); /** * Buffer de lecture du fichier CSV */ private BufferedReader mBuffreader = null; /** * Chaine contenant l'expression r�guli�re permettant de r�cup�rer les champs du fichier CSV s�par�ment. */ private String mREGEXPCSV = "\"([^\"]|\"\")*\"(,|$)|[^,]+(?=,|$)"; /** * Instance du r�cup�rateur de configuration */ private CSVConfigurationGetter mConfigGetter = null; /** * Cr�e une nouvelle instance de CSVParser avec la configuration donn�e. * * @param pConfigFile Chemin du fichier de configuration * @throws CSVException si un probl�me appara�t * @roseuid 429431A903D2 */ public CSVParser( final String pConfigFile ) { mConfigGetter = new CSVConfigurationGetter( pConfigFile ); } /** * Cr�e une nouvelle instance de CSVParser * * @throws CSVException si un probl�me appara�t * @roseuid 429431C201AF */ public CSVParser() throws CSVException { mConfigGetter = new CSVConfigurationGetter(); } /** * Retourne les valeurs ordonn�es de la ligne sous la forme d'un vecteur * * @return les �l�ments de la ligne * @roseuid 4294384A01A5 */ private ArrayList readNextLine() { ArrayList results = null; String line = null; Matcher m; Pattern p; try { // On cr�e le pattern de partage des valeurs p = Pattern.compile( mREGEXPCSV ); // On r�cup�re la nouvelle ligne line = mBuffreader.readLine(); if ( line != null ) { results = new ArrayList(); // On ajoute dans le tableau chacune des valeurs issues // du parsing de la ligne m = p.matcher( line ); while ( m.find() ) { results.add( m.group() ); } } } catch ( Exception e ) { // Si un probl�me de lecture apparait LOGGER.error( e ); } return results; } /** * Charge le fichier, cr�e la collection de CSVBean correspondant, puis renvoie cette collection * * @param pTemplateName le nom du mod�le de parsing � appliquer. * @param pFilename le nom du fichier � parser. * @return la collection d'objets issus du fichier. * @throws CSVException si un probl�me de parsing appara�t. * @roseuid 4294287000A6 */ public Collection parse( final String pTemplateName, final String pFilename ) throws CSVException { Collection beans = new ArrayList(); CSVBeanInstanciator instanciator = new CSVBeanInstanciator(); BeanCSVHandler handler = new BeanCSVHandler( beans, instanciator ); parseLines( pTemplateName, pFilename, handler ); return beans; } /** * Instanciation de bean par lecture de CSV */ class BeanCSVHandler implements CSVHandler { /** beans */ private Collection mBeans; /** instanciateur */ private CSVBeanInstanciator mInstanciator; /** * Constructeur * * @param pBeans beans * @param pInstanciator instanciateur */ public BeanCSVHandler( Collection pBeans, CSVBeanInstanciator pInstanciator ) { mBeans = pBeans; mInstanciator = pInstanciator; } /** * {@inheritDoc} * * @see org.squale.squalix.util.csv.CSVParser.CSVHandler#processLine(java.util.ArrayList) */ public void processLine( List pLine ) { mBeans.add( fullfillBean( pLine, mInstanciator ) ); } } /** * Parsing des lignes du fichier * * @param pTemplateName template de d�finition * @param pFilename fichier � parser * @param pHandler handler de parsing * @throws CSVException si erreur */ public void parseLines( final String pTemplateName, final String pFilename, CSVHandler pHandler ) throws CSVException { // r�cup�re la configuration mConfiguration = mConfigGetter.getConfiguration( pTemplateName ); try { instanciateBufferedReader( pFilename ); ArrayList values = readNextLine(); // On compte le nombre de lignes � lire int fileSize = getLineCount( pFilename ) - mConfiguration.getFooterSize(); // analyse chaque ligne du fichier qui a �t� mise sous forme d'une // liste d'objets for ( int i = mConfiguration.getHeaderSize(); i < fileSize && null != values; i++ ) { pHandler.processLine( values ); values = readNextLine(); } } catch ( Exception e ) { // Si un probl�me de lecture du fichier appara�t. throw new CSVException( e ); } finally { // on essaye de fermer le buffer dans tous les cas try { if ( mBuffreader != null ) { mBuffreader.close(); } } catch ( IOException e1 ) { LOGGER.error( e1, e1 ); } } } /** * Remplit un bean avec les valeurs pass�es en param�tre. * * @param pValues la liste des valeurs ordonn�es. * @param pInstanciator l'instance d'instanciateur utilis�e. * @return un objet rempli. */ private Object fullfillBean( final List pValues, final CSVBeanInstanciator pInstanciator ) { Object bean = null; String value = null; try { // On instancie un bean par ligne bean = pInstanciator.instanciate( mConfiguration.getCSVBean() ); for ( int j = 0; j < pValues.size(); j++ ) { // Pour chaque valeur de la ligne, on attribue la valeur au // bean, en r�cup�rant le nom de l'attribut de la configuration. Method setter = mConfiguration.getMappingData( j ); if ( null != setter ) { value = String.valueOf( pValues.get( j ) ); pInstanciator.setValue( bean, setter, value ); } } } catch ( Exception e ) { LOGGER.error( e, e ); bean = null; } return bean; } /** * Retourne le nombre de lignes du fichier * * @param pFileName Le nom du fichier * @return Le nombre de ligne du fichier * @throws Exception si un probl�me de lecture apparait. * @roseuid 42DFB3500158 */ private int getLineCount( String pFileName ) throws Exception { int count = 0; FileReader fr = null; BufferedReader br = null; fr = new FileReader( pFileName ); br = new BufferedReader( fr ); while ( null != br.readLine() ) { count++; } br.close(); fr.close(); return count; } /** * Instancie un BufferedReader li� au fichier * * @param pFileName le nom du fichier * @throws Exception si un probl�me de lecture apparait. * @roseuid 42DFB3500168 */ private void instanciateBufferedReader( String pFileName ) throws Exception { FileReader fr; mBuffreader = null; fr = new FileReader( pFileName ); mBuffreader = new BufferedReader( fr ); if ( mConfiguration.getHeaderSize() > 0 ) { // S'il y a des lignes d'en-t�te dont il ne faut pas tenir compte, // elles sont lues pour placer le lecteur de buffer � la premi�re ligne utile. for ( int i = 0; i < mConfiguration.getHeaderSize(); i++ ) { mBuffreader.readLine(); } } } /** * Traitement des donn�es d'un fichier CSV */ public interface CSVHandler { /** * Traitement d'une ligne * * @param pLine ligne � lire, les donn�es sont contenues dans une liste */ public void processLine( List pLine ); } }