org.squale.squalix.tools.compiling.java.parser.wsad.JWSADParser.java Source code

Java tutorial

Introduction

Here is the source code for org.squale.squalix.tools.compiling.java.parser.wsad.JWSADParser.java

Source

/**
 * 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\\tools\\compiling\\java\\parser\\wsad\\WSADParser.java

package org.squale.squalix.tools.compiling.java.parser.wsad;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileFilter;
import java.io.FileReader;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;

import org.squale.squalecommon.enterpriselayer.businessobject.result.ErrorBO;
import org.squale.squalix.core.exception.ConfigurationException;
import org.squale.squalix.tools.compiling.CompilingMessages;
import org.squale.squalix.tools.compiling.java.beans.JWSADProject;
import org.squale.squalix.tools.compiling.java.configuration.JCompilingConfiguration;
import org.squale.squalix.tools.compiling.java.parser.configuration.JParserConfiguration;
import org.squale.squalix.tools.compiling.java.parser.configuration.JParserUtility;
import org.squale.squalix.util.file.FileUtility;

/**
 * Parser de fichier <code>.classpath</code> pour WSAD 5.x.
 * 
 * @author m400832 (by rose)
 * @version 1.0
 */
public class JWSADParser {

    /**
     * Logger.
     */
    private static final Log LOGGER = LogFactory.getLog(JWSADParser.class);

    /** Container indiquant des dpendances de plugins */
    public static final String PLUGIN_CON = "org.eclipse.pde.core.requiredPlugins";

    /** Option d'export d'un plugin */
    public static final String PLUGIN_VISIBILITY = "visibility:=reexport";

    /** Le chemin minimum du manifest d'un projet */
    public static final String MANIFEST_PATHNAME = "META-INF/MANIFEST.MF";

    /** Indique les dpendances des plugins dans le manifest */
    public static final String REQUIRE_BUNDLE = "Require-Bundle";

    /** Indique les exports de packages dans le manifest */
    public static final String EXPORT_PACKAGE = "Export-Package";

    /**
     * Constante ".".
     */
    protected static final String DOT = ".";

    /** La liste des erreurs rencontres durant le traitement du composant */
    private List mErrors = new ArrayList();

    /**
     * Instance de configuration.
     */
    protected JWSADParserConfiguration mConfiguration = null;

    /**
     * Liste de projets WSAD  parser.
     */
    protected List mProjectList = null;

    /**
     * Construteur par dfaut.
     * 
     * @param pProjectList liste de projets WSAD  parser.
     * @throws Exception exception.
     */
    public JWSADParser(List pProjectList) throws Exception {
        mProjectList = pProjectList;
        mConfiguration = new JWSADParserConfiguration();
    }

    /**
     * This method runs the parsing process (if the project list isn't null or empty). <br />
     * If the <code>parse()</code> method returns <code>false</code>, then the <code>Project</code> boolean
     * <code>mIsCompiled</code> is set to <code>true</code> : this is to say that this project will not be compiled
     * by the Compile class. Actually, the goal is to avoid trying to compile a project in which no classpath file was
     * found.
     * 
     * @see JWSADProject
     * @see JWSADParser#parse()
     * @throws Exception exception lance en cas d'erreur.
     */
    public void execute() throws Exception {
        boolean isNull = false;

        /* si la liste des projets n'est pas nulle */
        if (null != mProjectList) {
            Iterator it = mProjectList.iterator();

            /* si l'itrateur possde des lments */
            if (null != it && it.hasNext()) {
                /* tant qu'il en possde */
                while (it.hasNext()) {
                    /*
                     * on affecte le projet courant en variable de classe
                     */
                    JWSADProject project = (JWSADProject) it.next();
                    /* Vrification de la prsence du .classpath indiquant un projet WSAD */
                    if (needsParsing(project)) {
                        // On parse le manifest dans le cas de la compilation RCP
                        parseManifest(project);
                        parse(project);
                    } else {
                        /*
                         * alors on considre que le projet WSAD a dj t compil
                         */
                        LOGGER.debug(CompilingMessages.getString("java.logs.task.dropped") + project.getName());
                        project.setCompiled(true);
                    }
                }
                executeParsingEntries();
            } else {
                /* on affecte le boolen */
                isNull = true;
            }
            it = null;
        } else {
            /* on affecte le boolen */
            isNull = true;
        }

        /* si le boolen est nul */
        if (isNull) {
            /* alors on lance une nouvelle exception */
            throw new Exception(CompilingMessages.getString("java.exception.parsing.wsad_project_list_is_null"));
        }

        /* en mode debug, on affiche les rsultats */
        printParsingResults();
    }

    /**
     * Traite le parsing des entres rcupre lor du parsing du .classpath autre que "lib" pour chaque projet pars
     * 
     * @throws Exception si une erreur survient dans un traitement
     */
    private void executeParsingEntries() throws Exception {
        // Pour chaque projet on traite les entres du parsing autre que "lib"
        Iterator it = mProjectList.iterator();
        Iterator valueIt;
        while (it.hasNext()) {
            /*
             * on affecte le projet courant en variable de classe
             */
            JWSADProject project = (JWSADProject) it.next();
            // On a trait les librairies, on traite les autres entres du classpath
            for (Iterator keysIt = project.getClasspathEntries().keySet().iterator(); keysIt.hasNext();) {
                String key = (String) keysIt.next();
                // On va itrer sur la liste des valeurs identifies par la cl
                valueIt = ((Collection) project.getClasspathEntries().get(key)).iterator();
                if (mConfiguration.getSrc().equals(key)) {
                    while (valueIt.hasNext()) {
                        processSrc(project, (String) valueIt.next(), false, false);
                    }
                } else if (mConfiguration.getCon().equals(key)) {
                    while (valueIt.hasNext()) {
                        processCon(project, (String) valueIt.next());
                    }
                } else {
                    while (valueIt.hasNext()) {
                        processSrc(project, (String) valueIt.next(), true, false);
                    }
                }
            }
        }
    }

    /**
     * Parse le manifest
     * 
     * @param pProject le projet
     * @throws Exception si erreur
     */
    private void parseManifest(JWSADProject pProject) throws Exception {
        // On rcupre le manifest
        File manifest = getManifest(pProject);
        if (null != manifest) {
            // On rcupre les packages exports
            parseManifestForExportedPackages(pProject, manifest);
        }
    }

    /**
     * La partie concerne se prsente de cette manire : Export-Package: p1, p2, p4
     * 
     * @param pProject le projet
     * @param pManifest le manifest
     * @throws Exception si erreur
     */
    private void parseManifestForExportedPackages(JWSADProject pProject, File pManifest) throws Exception {
        parseManifest(pProject, pManifest, EXPORT_PACKAGE,
                this.getClass().getMethod("addExportedPackage", new Class[] { JWSADProject.class, String.class }));
    }

    /**
     * Ajoute les packages exports par rflexion
     * 
     * @param pProject le projet
     * @param pPackage la package  ajouter
     */
    public void addExportedPackage(JWSADProject pProject, String pPackage) {
        pProject.addExportedPackage(pPackage.trim());
    }

    /**
     * Indique la prsence du fichier .classpath
     * 
     * @param pProject projet WSAD
     * @return false si aucun fichier .classpath n'est trouv
     */
    private boolean needsParsing(JWSADProject pProject) {
        String path = pProject.getPath();
        File classPathFile = new File(path + mConfiguration.getFilename());

        return classPathFile.exists();
    }

    /**
     * Lance le parsing.
     * 
     * @param pProject projet WSAD
     * @return <code>true</code> en cas de succs, <code>false</code> sinon.
     * @throws Exception lorque le fichier est mal format
     */
    private boolean parse(JWSADProject pProject) throws Exception {
        /* on part du principe que le parsing fonctionnera */
        boolean isParsed = true;
        /*
         * on rcupre le noeud "<classpath>" du fichier ".classpath" du projet WSAD
         */
        Node myNode = JParserUtility.getRootNode(pProject.getPath() + mConfiguration.getFilename(),
                mConfiguration.getClasspathAnchor());

        /*
         * si le noeud n'est pas nul, et qu'il s'agit d'un noeud de type ELEMENT_NODE
         */
        if (null != myNode && Node.ELEMENT_NODE == myNode.getNodeType()) {
            /* on rcupre le noeud "<classpathentry>" */
            myNode = JParserUtility.getNodeByTagName(myNode, mConfiguration.getClasspathentry());

            /* on initialise les variables pour la bouche  suivre */
            NamedNodeMap attrMap = null;
            Node exported = null;
            String attrValue = null, attrName = null, exportedAttr = "false";

            /* si le noeud n'est pas nul */
            while (null != myNode) {
                /* si le noeud est de type ELEMENT_NODE */
                if (Node.ELEMENT_NODE == myNode.getNodeType()) {
                    /* on rcupre les attributs du noeud */
                    attrMap = myNode.getAttributes();

                    /* on rcupre la valeur de l'attribut KIND */
                    attrName = (attrMap.getNamedItem(mConfiguration.getKind())).getNodeValue().trim();

                    /* on rcupre la valeur de l'attribut PATH */
                    attrValue = (attrMap.getNamedItem(mConfiguration.getPath())).getNodeValue().trim();

                    /* on rcupre la valeur de l'attribut EXPORTED */
                    // Par dfaut exported = false;
                    exportedAttr = "false";
                    exported = attrMap.getNamedItem(mConfiguration.getExported());
                    if (null != exported) {
                        exportedAttr = exported.getNodeValue().trim();
                    }

                    /*
                     * on mappe les couples cl / valeur car il faut traiter les lib en premier
                     */
                    mapKeyValues(pProject, attrName, attrValue, Boolean.valueOf(exportedAttr).booleanValue());
                }
                /* on itre sur les noeuds */
                myNode = myNode.getNextSibling();
            }
            /* on fait le mnage */
            attrMap = null;
            attrName = null;
            attrValue = null;

            /* si le noeud est nul ou du mauvais type */
        } else {
            /* alors on lance une exception */
            throw new Exception(CompilingMessages.getString("exception.xml.node_not_found"));
        }

        myNode = null;

        /*
         * on cre un buffer pour dfinir le chemin du dossier contenant les ressources ncessaires  la compilation
         */
        StringBuffer path = new StringBuffer(CompilingMessages.getString("dir.root.java"));
        path.append(JCompilingConfiguration.UNIX_SEPARATOR);
        path.append(pProject.getJavaVersion());
        path.append(JCompilingConfiguration.UNIX_SEPARATOR);

        /*
         * on cre le descripteur de fichier et on appelle la mthode addCompilingRessourcesToClasspath(File)
         */
        File f = new File(path.toString().replace('.', '_'));
        addCompilingRessourcesToClasspath(pProject, f);
        f = null;

        return isParsed;
    }

    /**
     * Cette mthode n'a t cre que dans le but de faire chuter la complexit cyclomatique de la mthode
     * <code>parse()</code>.
     * 
     * @param pProject projet WSAD
     * @param pKeyName nom de la cl.
     * @param pKeyValue valeur de la cl.
     * @param pExported si pKeyName est exporte
     * @throws Exception exception : lance uniquement si elle provient des mthodes <code>processLib(String)</code>,
     *             <code>processVar(String)</code> ou <code>processSrc(String)</code>.
     */
    protected void mapKeyValues(JWSADProject pProject, String pKeyName, String pKeyValue, boolean pExported)
            throws Exception {

        /* si pKeyName="lib" */
        if (mConfiguration.getLib().equals(pKeyName)) {
            processLib(pProject, pKeyValue, pExported);
            /* si pKeyName="src" ou pKeyName="con" */
        } else if (mConfiguration.getSrc().equals(pKeyName)) {
            if (pExported) {
                pProject.addClasspathEntrie(pKeyName + "Exported", pKeyValue);
            } else {
                pProject.addClasspathEntrie(pKeyName, pKeyValue);
            }
        } else if (mConfiguration.getCon().equals(pKeyName)) {
            pProject.addClasspathEntrie(pKeyName, pKeyValue);
        } else {
            /* les autres cas ne sont pas traits */
            LOGGER.debug(CompilingMessages.getString("java.exception.parsing.tag_non_used") + " : " + pKeyName);
        }
    }

    /**
     * Dans le cas o des plugins sont requis (ex: Projets RCP)
     * 
     * @param pProject le projet
     * @param pKeyValue la valeur
     * @throws Exception si erreur
     */
    private void processCon(JWSADProject pProject, String pKeyValue) throws Exception {
        if (PLUGIN_CON.equals(pKeyValue)) {
            // Il y a des dpendances vers des plugins.
            // Il faut donc parser le manifest pour trouver toutes les dpendances
            // On ajoute les plugins eclipse directement au classpath
            addCompilingRessourcesToClasspath(pProject, pProject.getBundleDir());
            File manifest = getManifest(pProject);
            if (null == manifest) {
                // On affiche un warning sans lancer d'exception car le projet peut compiler sans ce fichier
                String message = CompilingMessages.getString("java.warning.manifest_not_found", pProject.getName());
                LOGGER.warn(message);
            } else {
                // On parse le manifest
                parseManifestForPluginDependencies(pProject, manifest);
            }
        }
    }

    /**
     * Parse le manifest pour trouver les plugins ncessaires  la compilation La partie concerne se prsente de cette
     * manire : Require-Bundle: plugin1, plugin2;option1=v1;visibility:=reexport, plugin3, plugin4
     * 
     * @param pProject le projet
     * @param pManifest le manifest
     * @throws Exception si erreur
     */
    private void parseManifestForPluginDependencies(JWSADProject pProject, File pManifest) throws Exception {
        LOGGER.debug("On parse le manifest de " + pProject.getName() + " pour trouver les dpendances de plugins");
        parseManifest(pProject, pManifest, REQUIRE_BUNDLE,
                this.getClass().getMethod("processPlugin", new Class[] { JWSADProject.class, String.class }));
    }

    /**
     * Sert  parser des block du manifest qui ont la mme DTD pBlock: string1, string2, string3 (par exemple les
     * parties Bundle-Required et Export-Package)
     * 
     * @param pProject le projet
     * @param pManifest le manifest
     * @param pBlock le block  trouver
     * @param pMethod la mthode  appeler pour chaque ligne trouve
     * @throws ConfigurationException si erreur
     */
    private void parseManifest(JWSADProject pProject, File pManifest, String pBlock, Method pMethod)
            throws ConfigurationException {
        try {
            // On rcupre toutes les valeurs (commence par un espace et se termine par un espace)
            BufferedReader reader = new BufferedReader(new FileReader(pManifest));
            String line = reader.readLine();
            String plugin = "";

            while (null != line && !line.startsWith(pBlock)) {
                // on parse jusqu' trouver la partie qui nous intresse
                line = reader.readLine();
            }
            if (null != line) {
                boolean stop = !line.endsWith(",");
                // On rcupre chaque plugin du Require-Bundle
                line = line.replaceFirst(pBlock + ": ", "");
                String[] plugins = line.split(",");
                for (int i = 0; i < plugins.length; i++) {
                    pMethod.invoke(this, new Object[] { pProject, plugins[i].trim() });
                }
                line = reader.readLine();
                while (null != line && !stop) {
                    if (line.endsWith(",")) {
                        plugins = line.split(",");
                        for (int i = 0; i < plugins.length; i++) {
                            pMethod.invoke(this, new Object[] { pProject, plugins[i].trim() });
                        }
                    } else {
                        stop = true;
                        pMethod.invoke(this, new Object[] { pProject, line.trim() });
                    }
                    line = reader.readLine();
                }
            }
        } catch (IOException ioe) {
            throw new ConfigurationException(ioe.getMessage());
        } catch (InvocationTargetException ite) {
            throw new ConfigurationException(ite.getTargetException().getMessage());
        } catch (IllegalAccessException iae) {
            throw new ConfigurationException(iae.getMessage());
        }

    }

    /**
     * Traite la dpendance d'un plugin
     * 
     * @param pProject le projet
     * @param pPlugin le nom du plugin
     * @throws Exception si erreur
     */
    public void processPlugin(JWSADProject pProject, String pPlugin) throws Exception {
        String[] options = pPlugin.split(";");

        // On rcupre le nom du plugin
        String plugin = options[0].trim();

        // On regarde si l'option "visibility" est en reexport
        // car dans ce cas il faudra ajouter ce plugin  la liste des plugins exports
        boolean reexport = false;
        for (int i = 1; i < options.length && !reexport; i++) {
            if (options[i].matches(".*" + PLUGIN_VISIBILITY + ".*")) {
                reexport = true;
            }
        }

        // On recherche une dpendance
        boolean found = findDependency(pProject, plugin, reexport, true);
        // Si la dpendance n'a pas t trouve, c'est peut-tre un plugin eclipse
        if (!found && !isEclipsePlugin(pProject.getBundleDir(), plugin)) {
            // si le plugin est introuvable, on lance une exception de configuration
            throw new ConfigurationException(
                    "Required plugin (" + plugin + ") not found in project's compilation rules!");
        }
    }

    /**
     * @param pBundle le rpertoire du bundle eclipse
     * @param pPlugin le nom du plugin
     * @return true si il appartient au bundle
     */
    private boolean isEclipsePlugin(File pBundle, String pPlugin) {
        boolean result = false;
        File[] files = pBundle.listFiles();
        // Si le fichier existe, il s'agit bien d'un plugin eclipse
        for (int i = 0; null != files && i < files.length && !result; i++) {
            if (files[i].getName().matches(pPlugin + ".*")) {
                return true;
            } else if (files[i].isDirectory()) {
                result = isEclipsePlugin(files[i], pPlugin);
            }
        }
        return result;
    }

    /**
     * @param pProject le projet
     * @return le fichier manifest si il existe, null sinon
     */
    protected File getManifest(JWSADProject pProject) {
        File manifest = null;
        // Le manifest a pu tre donn par l'utilisateur
        if (null != pProject.getManifestPath() && pProject.getManifestPath().length() > 0) {
            manifest = FileUtility.getAbsoluteFile(pProject.getPath(), new File(pProject.getManifestPath()));
        }
        if (null == manifest || !manifest.exists()) {
            // Si il n'existe pas ou qu'il n'a pas t dfini dans la configuration, on le recherche
            manifest = FileUtility.findFileWithPathSuffix(new File(pProject.getPath()), MANIFEST_PATHNAME);
            if (null != manifest) {
                LOGGER.info("Chemin du Manifest : " + manifest.getAbsolutePath());
            }
        }
        return manifest;
    }

    /**
     * If the <code>lib</code> value is encountered in a <code>kind</code> tag, this method is called by the
     * <code>parse()</code> method. <br />
     * <br />
     * Two cases exist : <br/>
     * <ul>
     * <li>the path value begins with a "/",</li>
     * <li>or not !</li>
     * </ul>
     * <br />
     * In the first case, two possibilities : <br />
     * <ul>
     * <li> the string between the first and second "/" is the name of a project contained in the workspace. For
     * example, one has three projects inside his workspace : <b>TonusIntranetWeb</b>, <b>TonusIntranetCommons</b> and
     * <b>TonusIntranetEAR</b>.<br />
     * In the <b>TonusIntranetWeb</b> classpath file, one founds the following line :
     * <code>&lt;classpathentry kind="lib" 
     * path="/TonusIntranetEAR/my_jars/my.jar"/&gt;</code>.<br />
     * The path to <code>my.jar</code> is thus :
     * <code>workspace_path/TonusIntranetWeb/../TonusIntranetEAR/my_jars/my.jar</code>, which is equal to
     * <code>workspace_path/TonusIntranetEAR/my_jars/my.jar</code>. </li>
     * <li> the string between the first and second "/" is not a project name contained in the workspace. It's an
     * absolute UNIX filepath. It is therefore directly added to the classpath. </li>
     * </ul>
     * <br />
     * In the second case, the following path is added to the classpath : <code>
     * workspace_path/current_project_name/pPath</code>.
     * 
     * @param pProject project WSAD
     * @param pPath value of the <code>path</code> tag linked with.
     * @param pExported value of the <code>exported</code> tag linked with
     * @throws Exception exception.
     * @since 1.0
     */
    protected void processLib(JWSADProject pProject, final String pPath, final boolean pExported) throws Exception {
        StringBuffer path = new StringBuffer();

        /* si pPath commence par un "/" */
        if (0 == pPath.indexOf(JCompilingConfiguration.UNIX_SEPARATOR)) {
            JWSADProject project = findProjectDependency(pPath, path);
            /*
             * aucune dpendance n'a t trouve ou il n'y a pas de projets WSAD, il s'agit d'un chemin UNIX absolu
             */
            if (null == project) {
                path.append(pPath);
                path.append(mConfiguration.getClasspathSeparator());
            }

            /*
             * pPath ne commence pas par un "/" il s'agit d'une ressource du projet WSAD  ajouter au classpath
             */
        } else {
            path.append(pProject.getPath());
            path.append(pPath);
            // On vrifie l'existence du fichier sur le filesystem
            File file = new File(path.toString());
            if (!file.exists()) {
                String warning = CompilingMessages.getString("logs.task.classpath.filenotfound")
                        + path.toString().replaceFirst(pProject.getPath(), "");
                LOGGER.warn(warning);
                // On ajoute un warning  la liste des erreurs
                ErrorBO warningDB = new ErrorBO();
                warningDB.setLevel(ErrorBO.CRITICITY_WARNING);
                warningDB.setInitialMessage(warning);
                addError(warningDB);
            }
            // On ajoute le sparateur de classpath
            path.append(mConfiguration.getClasspathSeparator());
        }

        /* on ajoute le chemin construit au classpath */
        addToClasspath(pProject, path.toString());
        if (pExported) {
            // On l'ajoute  la liste des librairies exportes du projet
            addToExportedLib(pProject, path.toString());
        }
        path = null;
    }

    /**
     * Ajoute <code>pPath</code> aux librairies exportes de <code>pProject</code>
     * 
     * @param pProject le projet courant
     * @param pPath le chemin  ajouter
     */
    private void addToExportedLib(JWSADProject pProject, String pPath) {
        pProject.setExportedLib(getClasspathFormatAfterAdd(pProject.getExportedLib(), pPath));
    }

    /**
     * @param pLibPath le chemin de la dpendance
     * @param pPath le chemin a remplir
     * @return le projet dpendant si une dpendance de projet a t trouve, null sinon
     */
    protected JWSADProject findProjectDependency(String pLibPath, StringBuffer pPath) {
        // Initialisation du retour de la mthode
        JWSADProject result = null;
        /* on cre un itrateur de la liste des projets */
        Iterator it = mProjectList.iterator();

        /*
         * boolen utilis pour signifier la dcouverte d'une dpendance, i.e. d'un projet WSAD
         */
        boolean found = false;

        /* si l'itrateur n'est pas nul */
        if (null != it) {
            /*
             * on rcupre la chane comprise entre les 2 premiers sparateurs UNIX
             */
            String nomProjet = pLibPath.substring(1, pLibPath.indexOf(JCompilingConfiguration.UNIX_SEPARATOR, 1));
            JWSADProject pTemp = null;

            /*
             * tant que l'itrateur a des lments ou qu'aucune dpendance n'est trouve
             */
            while (null == result && it.hasNext()) {
                /* on stocke le projet WSAD courant de la liste */
                pTemp = (JWSADProject) it.next();

                /*
                 * si nomProject est gale au nom du projet, alors il y a dpendance
                 */
                if ((pTemp.getName()).equals(nomProjet)) {
                    /* on construit le path en consquence */
                    pPath.append(pTemp.getPath());
                    pPath.append(pLibPath.substring(pLibPath.indexOf(JCompilingConfiguration.UNIX_SEPARATOR, 1) + 1,
                            pLibPath.length()));
                    pPath.append(mConfiguration.getClasspathSeparator());

                    /*
                     * on a trouv la dpendance, inutile d'itrer plus longtemps.
                     */
                    result = pTemp;
                }
            }
        }
        return result;
    }

    /**
     * Cette mthode parcourt le rpertoire (et ses sous-rpertoires) contenant les ressources de compilation et les
     * ajoute au classpath, i.e. ajoute tous les jars / zips / classes communes  toutes les compilations (typiquement
     * <code>j2ee.jar</code>). <br />
     * 
     * @param pProject projet WSAD
     * @param pFile rpertoire  parcourir.
     * @throws Exception exception lors du parcours du rpertoire.
     */
    private void addCompilingRessourcesToClasspath(JWSADProject pProject, final File pFile) throws Exception {
        /* Liste des extensions autorises */
        ArrayList allowedExtensions = new ArrayList();
        allowedExtensions.add(JParserConfiguration.EXT_JAR);
        allowedExtensions.add(JParserConfiguration.EXT_CLASS);
        allowedExtensions.add(JParserConfiguration.EXT_ZIP);

        /* Buffer qui contiendra le classpath */
        StringBuffer path = null;

        /* Parcours du rpertoire. */
        if (pFile.isDirectory()) {
            String s;
            path = new StringBuffer();
            File[] fileList = pFile.listFiles();
            String fileExt;

            for (int i = 0; i < fileList.length; i++) {
                /* s'il s'agit d'un fichier */
                if (fileList[i].isFile()) {
                    /* on rcupre l'extension */
                    fileExt = fileList[i].getName();
                    fileExt = fileExt.substring(fileExt.lastIndexOf(JWSADParser.DOT) + 1, fileExt.length());

                    /* si l'extension est autorise */
                    if (allowedExtensions.contains(fileExt)) {
                        /* on ajoute le fichier au buffer */
                        path.append(fileList[i].getAbsolutePath().replaceAll(
                                JCompilingConfiguration.WINDOWS_SEPARATOR
                                        + JCompilingConfiguration.WINDOWS_SEPARATOR,
                                JCompilingConfiguration.UNIX_SEPARATOR));
                        path.append(mConfiguration.getClasspathSeparator());
                    }
                    /* s'il s'agit d'un rpertoire */
                } else {
                    /* on appelle rcursivement la mthode */
                    addCompilingRessourcesToClasspath(pProject, fileList[i]);
                }
            }
            /* mnage */
            fileList = null;
            fileExt = null;
            /* on ajoute le buffer au classpath */
            addToClasspath(pProject, path.toString());

        }

        /* mnage */
        path = null;
        allowedExtensions = null;
    }

    /**
     * If the <code>src</code> value is encountered in a <code>kind</code> tag, this method is called by the
     * <code>parse()</code> method. <br />
     * <br />
     * Two cases exist : <br/>
     * <ul>
     * <li>the path value begins with a "/",</li>
     * <li>or not !</li>
     * </ul>
     * <br />
     * In the first case, two sub-cases :
     * <ul>
     * <li>it's a linked project,</li>
     * <li>it's an unix path.</li>
     * </ul>
     * If it's a known project, then the dependency is added, by calling the
     * <code>processSrcDir(JWSADProject, String)</code> method. <br />
     * If an unix file path is encoutered, then it is directly added to the classpath, such as in the case in which the
     * file path does not begin by a "/".
     * 
     * @param pProject project WSAD
     * @param pPath value of the <code>path</code> tag linked with.
     * @param pExported value of the <code>exported</code> tag linked with.
     * @param pIsPlugin si pProject est un plugin
     * @throws Exception exception.
     * @since 1.0
     * @see JWSADProject#setSrcPath(String)
     * @see #processSrcDir(JWSADProject, String)
     */
    private void processSrc(JWSADProject pProject, final String pPath, final boolean pExported,
            final boolean pIsPlugin) throws Exception {
        boolean appendPath = true;
        boolean doPath = true;
        StringBuffer path = new StringBuffer();

        /* si pPath commence par un "/" */
        if (pPath.startsWith(JCompilingConfiguration.UNIX_SEPARATOR)) {
            /* on rcupre le morceau de chane aprs le 1er "/" */
            String nomProjet = pPath.substring(1, pPath.length());
            boolean found = findDependency(pProject, nomProjet, pExported, pIsPlugin);

            /*
             * alors il s'agit d'un chemin UNIX absolu : il s'agit d'un rpertoire contenant des fichiers sources du
             * projet courant
             */
            doPath = !found;

            /*
             * sinon il s'agit d'un rpertoire contenant des fichiers sources du projet courant
             */
        }
        /*
         * on affecte le rpertoire comme tant le rpertoire contenant les sources
         */
        if (doPath) {
            // Il faut pour tous les rpertoires exclus supprimer le pPath
            // du pattern si il y est car le pattern doit tre relatif au rpertoire
            // source.
            String replacePath = (pProject.getPath() + "/" + pPath).replaceAll("//", "/");
            for (int i = 0; null != pProject.getExcludedDirs() && i < pProject.getExcludedDirs().size(); i++) {
                // On rcupre le rpertoire exclu et on lui rajoute un "/" en bout de nom pour spcifier la fin
                // du nom
                String currentEx = ((String) pProject.getExcludedDirs().get(i) + "/").replaceAll("//", "/");
                currentEx = currentEx.replaceFirst(replacePath + "/+", "");
                // Si il s'agit d'un rpertoire fils du rpertoire source, on l'ajoute dans les exclusions
                // on vrifie donc si il ne s'ahit pas du rpertoire source lui-mme (currentEx.length() > 0)
                // et que ce rpertoire exclu n'est pas un parent (!replacePath.startsWith(currentEx))
                if (currentEx.length() > 0 && !replacePath.startsWith(currentEx)) {
                    // On remplace l'exclusion
                    pProject.getExcludedDirs().remove(i);
                    pProject.getExcludedDirs().add(i, currentEx);
                } else {
                    // On n'ajoutera pas le rpertoire source puisqu'il est exclu
                    appendPath = false;
                }
            }
            if (appendPath) {
                if (pProject.getSrcPath().length() > 0) {
                    path.append(pProject.getSrcPath());
                }
                path.append(pProject.getPath());
                path.append(pPath);
                path.append(JCompilingConfiguration.UNIX_SEPARATOR);
                path.append(mConfiguration.getClasspathSeparator());
                pProject.setSrcPath(path.toString());
            }
        }

        path = null;
    }

    /**
     * @param pProject le projet
     * @param pProjectName le nom du projet  chercher
     * @param pExported true si le projet de nom <code>pProjectName</code> est export
     * @return true si le projet a t trouv parmis les dpendances
     * @param pIsPlugin si pProject est un plugin
     * @throws Exception si erreur
     */
    private boolean findDependency(JWSADProject pProject, String pProjectName, boolean pExported, boolean pIsPlugin)
            throws Exception {
        Iterator it = mProjectList.iterator();
        boolean found = false;
        if (null != it) {
            /*
             * tant qu'il y a des lments et qu'aucune dpendance n'a t trouve
             */
            while (false == found && it.hasNext()) {
                /*
                 * on appelle la mthode processSrcDir(JWSADProject, String) qui ajoute le cas chant des dpendances
                 * au projet courant (pProject). Si une dpendance est ajoute, alors found est mis  true.
                 */
                found = processSrcDir(pProject, (JWSADProject) it.next(), pProjectName, pExported, pIsPlugin);
            }
        }
        return found;
    }

    /**
     * Cette mthode a t implmente afin de faire chuter la complexit cyclomatique de la mthode
     * <code>processSrc(String)</code>.
     * 
     * @param pMainProject JWSADProject.
     * @param pProject JWSADProject.
     * @param pNomProject Nom du projet : issu du tag <code>path</code> du fichier XML de classpath.
     * @param pExported true si le <code>pMainProject</code> exporte <code>pProject</code>
     * @param pIsPlugin si pProject est un plugin
     * @return <code>true</code> s'il existe une dpendance entre projets, <code>false</code> sinon.
     * @throws Exception exception en cas d'erreur.
     * @see #processSrc(String)
     * @see #processSrcDir(JWSADProject, String)
     * @see #addProjectDependency(JWSADProject)
     */
    private boolean processSrcDir(JWSADProject pMainProject, JWSADProject pProject, String pNomProject,
            boolean pExported, boolean pIsPlugin) throws Exception {
        boolean found = false;
        /* si la chane est gale au nom du projet WSAD */
        if (pNomProject.equals(pProject.getName())) {
            /* alors il y a dpendance : on l'ajoute. */
            addProjectDependency(pMainProject, pProject, pExported, pIsPlugin);
            if (!pIsPlugin) {
                /*
                 * on ajoute le rpertoire contenant les classes compiles de pProject au classpath de pMainProject
                 */
                addToClasspath(pMainProject, pProject.getDestPath());
                /* Ainsi que ses libraries exportes si il s'agit d'un projet */
                LOGGER.debug("Traitement des librairies exportes de " + pProject.getName() + " pour "
                        + pMainProject.getName());
                addToClasspath(pMainProject, pProject.getExportedLib());
            } else {
                /*
                 * On dzippe les librairies exportes de pProject dans le rpertoire dfini dans la configuration et
                 * ajoute les .class au classpath ncessaires lors de la compilation
                 */
                if (pProject.getExportedLib().length() > 0) {
                    addExportedLibs(pMainProject, pProject);
                }
                // Il faut aussi ajouter aussi les .classes compiles du plugin au classpath
                // en fonction des packages exports mais dans ce cas il faut attendre que le projet
                // soit compil donc on excute la mthode lors de la compilation des projets
                // @see JWSADCompiler.java
            }
            found = true;
        }
        return found;
    }

    /**
     * Ajoute les .class des packages exports pour toutes les libraries exportes
     * 
     * @param pMainPlugin le plugin courant
     * @param pPlugin le plugin dpendant
     * @throws Exception si erreur
     */
    private void addExportedLibs(JWSADProject pMainPlugin, JWSADProject pPlugin) throws Exception {
        LOGGER.debug(
                "Traitement des librairies exportes de " + pPlugin.getName() + " pour " + pMainPlugin.getName());
        // Pour chaque librairie exporte, on dzippe
        String[] libs = pPlugin.getExportedLib().split(mConfiguration.getClasspathSeparator());
        // On parcours si il y a des librairies exportes.
        for (int i = 0; i < libs.length && !(libs.length == 1 && libs[0].length() == 0); i++) {
            FileUtility.copyOrExtractInto(new File(libs[i]), mConfiguration.getExportedLibsDir());
        }
        // On ajoute les packages exports des librairies extraites au classpath
        addExportedPackagesToClasspath(pMainPlugin, pPlugin, mConfiguration.getExportedLibsDir());
    }

    /**
     * Permet d'ajouter le rpertoire contenant les .class des packages exports par <code>pPlugin</code> au classpath
     * de <code>pMainPlugin</code>
     * 
     * @param pMainPlugin le plugin dont il faut modifier le classpath
     * @param pPlugin le plugin dont dpend <code>pMainPlugin</code>
     * @param pRoot le rpertoire de recherche des packages exports
     * @throws IOException si erreur lors de la copie
     */
    public void addExportedPackagesToClasspath(JWSADProject pMainPlugin, JWSADProject pPlugin, File pRoot)
            throws IOException {
        File packageDir = null;
        // On cre le rpertoire racine qui contiendra les .class (chemin_pRoot/nomProjet)
        File copyRoot = new File(pRoot, pMainPlugin.getName());
        if (!copyRoot.exists()) {
            // On cre le rpertoire si il n'existe pas pour pouvoir faire la copie
            copyRoot.mkdir();
        }
        File copyDest = null;
        for (int i = 0; i < pPlugin.getExportedPackages().size(); i++) {
            // On cre le rpertoire  partir du nom du package
            // Ex : org.squale.jraf --> chemin_pRoot/org/squale/jraf
            packageDir = new File(pRoot,
                    ((String) pPlugin.getExportedPackages().get(i)).replaceAll("\\.", File.separator));
            // On cre le rpertoire de destination des .class
            // Ex : chemin_pRoot/nomProjet/org/squale/jraf
            copyDest = new File(copyRoot,
                    ((String) pPlugin.getExportedPackages().get(i)).replaceAll("\\.", File.separator));
            // On copie les .class qui sont  la racine du rpertoire dans le rpertoire spcifique
            // au projet
            // Cette copie est faite car il faut ajouter au -classpath de javac un rpertoire contenant le chemin
            // des packages car on ne peut pas rajouter le chemin absolu du .classpath sinon les imports
            // ne seront pas rsolus.
            copyClassesTo(packageDir, copyDest);
        }
        // On ajoute le rpertoire si il n'a pas encore t rajout
        if (!pMainPlugin.getClasspath().matches(".*" + copyRoot.getAbsolutePath() + ";.*")) {
            addToClasspath(pMainPlugin, copyRoot.getAbsolutePath());
        }
    }

    /**
     * Copie tous les .class  la racine du rpertoire <code>pDir</code> dans <code>pDest</code>
     * 
     * @param pDir le rpertoire dans lequel il faut chercher les .class
     * @param pDest le rpertoire de destination des .class copis
     * @throws IOException si erreur lors de la copie
     */
    private void copyClassesTo(File pDir, File pDest) throws IOException {
        // On liste les fichiers  la racine de pDir
        File[] classes = pDir.listFiles();
        if (null != classes) {
            File currentFile = null;
            // On crer le chemin des rpertoires pour prparer la copie
            pDest.mkdirs();
            // On copie tous les fichiers ayant l'extension .class
            for (int i = 0; i < classes.length; i++) {
                currentFile = classes[i];
                if (currentFile.isFile()
                        && currentFile.getName().endsWith(JWSADParser.DOT + JParserConfiguration.EXT_CLASS)) {
                    FileUtility.copyIntoDir(currentFile, pDest);
                }
            }
        }
    }

    /**
     * This method adds a string (i.e. a directory that should be added to the project classpath) to the
     * <code>mClasspath</code> JWSADProject attribute.
     * 
     * @param pProject JWSADProject.
     * @param pCp String to be added to the <code>mClasspath</code> WSAD attribute.
     * @since 1.0
     * @see JWSADProject#setClasspath(String)
     */
    public void addToClasspath(JWSADProject pProject, String pCp) {
        pProject.setClasspath(getClasspathFormatAfterAdd(pProject.getClasspath(), pCp));
    }

    /**
     * @param pClasspathFormat une chane dans le format "classpath" (i.e. spare par ";")
     * @param pPathToAdd le chemin  ajouter
     * @return pClasspathFormat  laquelle on a ajout pPath
     */
    private String getClasspathFormatAfterAdd(String pClasspathFormat, String pPathToAdd) {
        StringBuffer s = new StringBuffer(pClasspathFormat);
        s.append(pPathToAdd);
        /* si la chane ne se termine pas un ";" */
        if (s.lastIndexOf(mConfiguration.getClasspathSeparator()) != (s.length() - 1)) {
            s.append(mConfiguration.getClasspathSeparator());
        }
        return s.toString();
    }

    /**
     * This method adds a dependency for the current project. <br />
     * <br />
     * For example : <br />
     * <br />
     * <code>project1.addProjectDependency(project2)</code><br />
     * <br />
     * means that <code>project1</code> depends on <code>project2</code> to be successfully compiled. <br />
     * <br />
     * 
     * @param pProject JWSADProject.
     * @param pProj JWSADProject on which depends the current project.
     * @param pExported if <code>pProj</code> is exported by <code>pProject</code>
     * @param pIsAPlugin true si pProj est un plugin
     * @throws Exception si erreur
     * @see JWSADProject#addProjectDependency(JWSADProject)
     */
    private void addProjectDependency(JWSADProject pProject, JWSADProject pProj, boolean pExported,
            boolean pIsAPlugin) throws Exception {
        if (pExported) {
            pProject.addExportedProject(pProj);
        } else {
            pProject.addProjectDependency(pProj);
        }
        // Si on il s'agit d'un plugin dpendant, il faut ajouter des dpendances rcursivement pour tous
        // les plugins ayant un visibility=reexport
        if (pIsAPlugin) {
            addPluginDependencies(pProject, pProj);
        } else {
            // Il faut ajouter au classpath toutes les librairies exportes de tous les projets exports
            // par le projet dont project dpend et ce rcursivement.
            // Ex : A dpend de B qui exporte C qui exporte D qui exporte la librairie L
            // Alors L doit tre dans le classpath de A,B,C et D!
            addExportedLibToClasspath(pProject, pProj);
        }
    }

    /**
     * Ajoute toutes les dpendances des plugins exports
     * 
     * @param pMainPlugin le plugin courant
     * @param pDependencyPlugin le plugin dpendant
     * @throws Exception si erreur dans la recherche du plugin
     */
    private void addPluginDependencies(JWSADProject pMainPlugin, JWSADProject pDependencyPlugin) throws Exception {
        // On ajoute au projets dpendants de pMainProject les plugins exportes par
        // le plugin dpendant pDependencyPlugin
        for (int i = 0; i < pDependencyPlugin.getExportedProjects().size(); i++) {
            JWSADProject curExportedPlugin = (JWSADProject) pDependencyPlugin.getExportedProjects().get(i);
            // On ajoute la dpendance
            findDependency(pMainPlugin, curExportedPlugin.getName(), false, true);
        }
    }

    /**
     * Ajoute toutes les librairies exportes par les projets dpendants eux-mme exports
     * 
     * @param pMainProject le projet courant
     * @param pDependencyProject le projet dpendant
     */
    private void addExportedLibToClasspath(JWSADProject pMainProject, JWSADProject pDependencyProject) {
        // On ajoute au classpath de pMainProject les librairies exportes par
        // les projets exports par pDependencyProject
        for (int i = 0; i < pDependencyProject.getExportedProjects().size(); i++) {
            JWSADProject curExportedProject = (JWSADProject) pDependencyProject.getExportedProjects().get(i);
            // On ajoute ses librairies exportes au classpath
            addToClasspath(pMainProject, curExportedProject.getExportedLib());
            // On rapelle rcursivement la mthode pour les projets exports de curExportedProject
            addExportedLibToClasspath(pMainProject, curExportedProject);
        }
    }

    /**
     * Mthode permettant d'afficher les rsultats du parsing.
     */
    private void printParsingResults() {
        LOGGER.debug("WSAD PARSING RESULTS");
        Iterator it = mProjectList.iterator();
        /* si l'itrateur possde des lments */
        if (null != it && it.hasNext()) {
            JWSADProject affP = null;
            Iterator tmpIt = null;
            /* tant qu'il y a des lments */
            while (it.hasNext()) {
                affP = (JWSADProject) it.next();
                /* on ajoute les variables "simples" */
                LOGGER.debug("Project: " + affP.getName());
                LOGGER.debug("SourcePath: " + affP.getSrcPath());
                LOGGER.debug("DestinationPath: " + affP.getDestPath());
                LOGGER.debug("NeedsToBeCompiled " + !(affP.isCompiled()));
                String dependencies = "";
                if (affP.getDependsOnProjects() != null) {
                    tmpIt = affP.getDependsOnProjects().iterator();
                    /* tant qu'il y a des dpendances */
                    while (tmpIt.hasNext()) {
                        dependencies += ((JWSADProject) (tmpIt.next())).getName();
                    }
                }
                LOGGER.debug("Dependencies " + dependencies);
                LOGGER.debug("Classpath: " + affP.getClasspath());
            }
        }
    }

    /**
     * Getter.
     * 
     * @return la liste des projets WSAD.
     */
    public List getProjectList() {
        return mProjectList;
    }

    /**
     * @return la liste des erreurs
     */
    public List getErrors() {
        return mErrors;
    }

    /**
     * Ajoute une erreur de traitement
     * 
     * @param pError l'erreur
     */
    public void addError(ErrorBO pError) {
        mErrors.add(pError);
    }

    /**
     * Filtre sur les fichiers .class d'un rpertoire
     */
    class OnlyClassesFilter implements FileFilter {

        /** Extension d'une classe java compile */
        public static final String CLASS_EXTENSION = ".class";

        /**
         * {@inheritDoc}
         * 
         * @see java.io.FileFilter#accept(java.io.File)
         */
        public boolean accept(File pathname) {
            boolean accept = false;
            // On ne rcupre que les fichiers .class au premier niveau du rpertoire
            if (pathname.isFile() && pathname.getAbsolutePath().endsWith(CLASS_EXTENSION)) {
                accept = true;
            }
            return accept;
        }
    }
}