/** * 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 d�pendances 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 d�pendances 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 rencontr�es 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 d�faut. * * @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 lanc�e 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'it�rateur poss�de des �l�ments */ if ( null != it && it.hasNext() ) { /* tant qu'il en poss�de */ while ( it.hasNext() ) { /* * on affecte le projet courant en variable de classe */ JWSADProject project = (JWSADProject) it.next(); /* V�rification de la pr�sence 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 consid�re que le projet WSAD a d�j� �t� compil� */ LOGGER.debug( CompilingMessages.getString( "java.logs.task.dropped" ) + project.getName() ); project.setCompiled( true ); } } executeParsingEntries(); } else { /* on affecte le bool�en */ isNull = true; } it = null; } else { /* on affecte le bool�en */ isNull = true; } /* si le bool�en 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 r�sultats */ printParsingResults(); } /** * Traite le parsing des entr�es r�cup�r�e 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 entr�es 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 entr�es du classpath for ( Iterator keysIt = project.getClasspathEntries().keySet().iterator(); keysIt.hasNext(); ) { String key = (String) keysIt.next(); // On va it�rer sur la liste des valeurs identifi�es 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 r�cup�re le manifest File manifest = getManifest( pProject ); if ( null != manifest ) { // On r�cup�re les packages export�s parseManifestForExportedPackages( pProject, manifest ); } } /** * La partie concern�e se pr�sente de cette mani�re : 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 export�s par r�flexion * * @param pProject le projet * @param pPackage la package � ajouter */ public void addExportedPackage( JWSADProject pProject, String pPackage ) { pProject.addExportedPackage( pPackage.trim() ); } /** * Indique la pr�sence 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 succ�s, <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 r�cup�re 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 r�cup�re 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 r�cup�re les attributs du noeud */ attrMap = myNode.getAttributes(); /* on r�cup�re la valeur de l'attribut KIND */ attrName = ( attrMap.getNamedItem( mConfiguration.getKind() ) ).getNodeValue().trim(); /* on r�cup�re la valeur de l'attribut PATH */ attrValue = ( attrMap.getNamedItem( mConfiguration.getPath() ) ).getNodeValue().trim(); /* on r�cup�re la valeur de l'attribut EXPORTED */ // Par d�faut 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 it�re sur les noeuds */ myNode = myNode.getNextSibling(); } /* on fait le m�nage */ 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 cr�e un buffer pour d�finir le chemin du dossier contenant les ressources n�cessaires � 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 cr�e le descripteur de fichier et on appelle la m�thode addCompilingRessourcesToClasspath(File) */ File f = new File( path.toString().replace( '.', '_' ) ); addCompilingRessourcesToClasspath( pProject, f ); f = null; return isParsed; } /** * Cette m�thode n'a �t� cr��e que dans le but de faire chuter la complexit� cyclomatique de la m�thode * <code>parse()</code>. * * @param pProject projet WSAD * @param pKeyName nom de la cl�. * @param pKeyValue valeur de la cl�. * @param pExported si pKeyName est export�e * @throws Exception exception : lanc�e uniquement si elle provient des m�thodes <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 trait�s */ 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 d�pendances vers des plugins. // Il faut donc parser le manifest pour trouver toutes les d�pendances // 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 n�cessaires � la compilation La partie concern�e se pr�sente de cette * mani�re : 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 d�pendances 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 m�me 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 m�thode � appeler pour chaque ligne trouv�e * @throws ConfigurationException si erreur */ private void parseManifest( JWSADProject pProject, File pManifest, String pBlock, Method pMethod ) throws ConfigurationException { try { // On r�cup�re 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 int�resse line = reader.readLine(); } if ( null != line ) { boolean stop = !line.endsWith( "," ); // On r�cup�re 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 d�pendance 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 r�cup�re 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 export�s boolean reexport = false; for ( int i = 1; i < options.length && !reexport; i++ ) { if ( options[i].matches( ".*" + PLUGIN_VISIBILITY + ".*" ) ) { reexport = true; } } // On recherche une d�pendance boolean found = findDependency( pProject, plugin, reexport, true ); // Si la d�pendance n'a pas �t� trouv�e, 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 r�pertoire 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� d�fini 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><classpathentry kind="lib" * path="/TonusIntranetEAR/my_jars/my.jar"/></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 d�pendance n'a �t� trouv�e 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 v�rifie 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 s�parateur 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 export�es du projet addToExportedLib( pProject, path.toString() ); } path = null; } /** * Ajoute <code>pPath</code> aux librairies export�es 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 d�pendance * @param pPath le chemin a remplir * @return le projet d�pendant si une d�pendance de projet a �t� trouv�e, null sinon */ protected JWSADProject findProjectDependency( String pLibPath, StringBuffer pPath ) { // Initialisation du retour de la m�thode JWSADProject result = null; /* on cr�e un it�rateur de la liste des projets */ Iterator it = mProjectList.iterator(); /* * bool�en utilis� pour signifier la d�couverte d'une d�pendance, i.e. d'un projet WSAD */ boolean found = false; /* si l'it�rateur n'est pas nul */ if ( null != it ) { /* * on r�cup�re la cha�ne comprise entre les 2 premiers s�parateurs UNIX */ String nomProjet = pLibPath.substring( 1, pLibPath.indexOf( JCompilingConfiguration.UNIX_SEPARATOR, 1 ) ); JWSADProject pTemp = null; /* * tant que l'it�rateur a des �l�ments ou qu'aucune d�pendance n'est trouv�e */ 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 d�pendance */ if ( ( pTemp.getName() ).equals( nomProjet ) ) { /* on construit le path en cons�quence */ 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 d�pendance, inutile d'it�rer plus longtemps. */ result = pTemp; } } } return result; } /** * Cette m�thode parcourt le r�pertoire (et ses sous-r�pertoires) 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 r�pertoire � parcourir. * @throws Exception exception lors du parcours du r�pertoire. */ private void addCompilingRessourcesToClasspath( JWSADProject pProject, final File pFile ) throws Exception { /* Liste des extensions autoris�es */ 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 r�pertoire. */ 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 r�cup�re l'extension */ fileExt = fileList[i].getName(); fileExt = fileExt.substring( fileExt.lastIndexOf( JWSADParser.DOT ) + 1, fileExt.length() ); /* si l'extension est autoris�e */ 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 r�pertoire */ } else { /* on appelle r�cursivement la m�thode */ addCompilingRessourcesToClasspath( pProject, fileList[i] ); } } /* m�nage */ fileList = null; fileExt = null; /* on ajoute le buffer au classpath */ addToClasspath( pProject, path.toString() ); } /* m�nage */ 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 r�cup�re le morceau de cha�ne apr�s 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 r�pertoire contenant des fichiers sources du * projet courant */ doPath = !found; /* * sinon il s'agit d'un r�pertoire contenant des fichiers sources du projet courant */ } /* * on affecte le r�pertoire comme �tant le r�pertoire contenant les sources */ if ( doPath ) { // Il faut pour tous les r�pertoires exclus supprimer le pPath // du pattern si il y est car le pattern doit �tre relatif au r�pertoire // source. String replacePath = ( pProject.getPath() + "/" + pPath ).replaceAll( "//", "/" ); for ( int i = 0; null != pProject.getExcludedDirs() && i < pProject.getExcludedDirs().size(); i++ ) { // On r�cup�re le r�pertoire exclu et on lui rajoute un "/" en bout de nom pour sp�cifier la fin // du nom String currentEx = ( (String) pProject.getExcludedDirs().get( i ) + "/" ).replaceAll( "//", "/" ); currentEx = currentEx.replaceFirst( replacePath + "/+", "" ); // Si il s'agit d'un r�pertoire fils du r�pertoire source, on l'ajoute dans les exclusions // on v�rifie donc si il ne s'ahit pas du r�pertoire source lui-m�me (currentEx.length() > 0) // et que ce r�pertoire 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 r�pertoire 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 d�pendances * @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 �l�ments et qu'aucune d�pendance n'a �t� trouv�e */ while ( false == found && it.hasNext() ) { /* * on appelle la m�thode processSrcDir(JWSADProject, String) qui ajoute le cas �ch�ant des d�pendances * au projet courant (pProject). Si une d�pendance est ajout�e, alors found est mis � true. */ found = processSrcDir( pProject, (JWSADProject) it.next(), pProjectName, pExported, pIsPlugin ); } } return found; } /** * Cette m�thode a �t� impl�ment�e afin de faire chuter la complexit� cyclomatique de la m�thode * <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 d�pendance 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 cha�ne est �gale au nom du projet WSAD */ if ( pNomProject.equals( pProject.getName() ) ) { /* alors il y a d�pendance : on l'ajoute. */ addProjectDependency( pMainProject, pProject, pExported, pIsPlugin ); if ( !pIsPlugin ) { /* * on ajoute le r�pertoire contenant les classes compil�es de pProject au classpath de pMainProject */ addToClasspath( pMainProject, pProject.getDestPath() ); /* Ainsi que ses libraries export�es si il s'agit d'un projet */ LOGGER.debug( "Traitement des librairies export�es de " + pProject.getName() + " pour " + pMainProject.getName() ); addToClasspath( pMainProject, pProject.getExportedLib() ); } else { /* * On d�zippe les librairies export�es de pProject dans le r�pertoire d�fini dans la configuration et * ajoute les .class au classpath n�cessaires lors de la compilation */ if ( pProject.getExportedLib().length() > 0 ) { addExportedLibs( pMainProject, pProject ); } // Il faut aussi ajouter aussi les .classes compil�es du plugin au classpath // en fonction des packages export�s mais dans ce cas il faut attendre que le projet // soit compil� donc on ex�cute la m�thode lors de la compilation des projets // @see JWSADCompiler.java } found = true; } return found; } /** * Ajoute les .class des packages export�s pour toutes les libraries export�es * * @param pMainPlugin le plugin courant * @param pPlugin le plugin d�pendant * @throws Exception si erreur */ private void addExportedLibs( JWSADProject pMainPlugin, JWSADProject pPlugin ) throws Exception { LOGGER.debug( "Traitement des librairies export�es de " + pPlugin.getName() + " pour " + pMainPlugin.getName() ); // Pour chaque librairie export�e, on d�zippe String[] libs = pPlugin.getExportedLib().split( mConfiguration.getClasspathSeparator() ); // On parcours si il y a des librairies export�es. 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 export�s des librairies extraites au classpath addExportedPackagesToClasspath( pMainPlugin, pPlugin, mConfiguration.getExportedLibsDir() ); } /** * Permet d'ajouter le r�pertoire contenant les .class des packages export�s 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 d�pend <code>pMainPlugin</code> * @param pRoot le r�pertoire de recherche des packages export�s * @throws IOException si erreur lors de la copie */ public void addExportedPackagesToClasspath( JWSADProject pMainPlugin, JWSADProject pPlugin, File pRoot ) throws IOException { File packageDir = null; // On cr�e le r�pertoire racine qui contiendra les .class (chemin_pRoot/nomProjet) File copyRoot = new File( pRoot, pMainPlugin.getName() ); if ( !copyRoot.exists() ) { // On cr�e le r�pertoire 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 cr�e le r�pertoire � 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 cr�e le r�pertoire 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 r�pertoire dans le r�pertoire sp�cifique // au projet // Cette copie est faite car il faut ajouter au -classpath de javac un r�pertoire contenant le chemin // des packages car on ne peut pas rajouter le chemin absolu du .classpath sinon les imports // ne seront pas r�solus. copyClassesTo( packageDir, copyDest ); } // On ajoute le r�pertoire 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 r�pertoire <code>pDir</code> dans <code>pDest</code> * * @param pDir le r�pertoire dans lequel il faut chercher les .class * @param pDest le r�pertoire de destination des .class copi�s * @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 cr�er le chemin des r�pertoires pour pr�parer 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 cha�ne dans le format "classpath" (i.e. s�par�e 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 cha�ne 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 d�pendant, il faut ajouter des d�pendances r�cursivement pour tous // les plugins ayant un visibility=reexport if ( pIsAPlugin ) { addPluginDependencies( pProject, pProj ); } else { // Il faut ajouter au classpath toutes les librairies export�es de tous les projets export�s // par le projet dont project d�pend et ce r�cursivement. // Ex : A d�pend 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 d�pendances des plugins export�s * * @param pMainPlugin le plugin courant * @param pDependencyPlugin le plugin d�pendant * @throws Exception si erreur dans la recherche du plugin */ private void addPluginDependencies( JWSADProject pMainPlugin, JWSADProject pDependencyPlugin ) throws Exception { // On ajoute au projets d�pendants de pMainProject les plugins export�es par // le plugin d�pendant pDependencyPlugin for ( int i = 0; i < pDependencyPlugin.getExportedProjects().size(); i++ ) { JWSADProject curExportedPlugin = (JWSADProject) pDependencyPlugin.getExportedProjects().get( i ); // On ajoute la d�pendance findDependency( pMainPlugin, curExportedPlugin.getName(), false, true ); } } /** * Ajoute toutes les librairies export�es par les projets d�pendants eux-m�me export�s * * @param pMainProject le projet courant * @param pDependencyProject le projet d�pendant */ private void addExportedLibToClasspath( JWSADProject pMainProject, JWSADProject pDependencyProject ) { // On ajoute au classpath de pMainProject les librairies export�es par // les projets export�s par pDependencyProject for ( int i = 0; i < pDependencyProject.getExportedProjects().size(); i++ ) { JWSADProject curExportedProject = (JWSADProject) pDependencyProject.getExportedProjects().get( i ); // On ajoute ses librairies export�es au classpath addToClasspath( pMainProject, curExportedProject.getExportedLib() ); // On rapelle r�cursivement la m�thode pour les projets export�s de curExportedProject addExportedLibToClasspath( pMainProject, curExportedProject ); } } /** * M�thode permettant d'afficher les r�sultats du parsing. */ private void printParsingResults() { LOGGER.debug( "WSAD PARSING RESULTS" ); Iterator it = mProjectList.iterator(); /* si l'it�rateur poss�de des �l�ments */ if ( null != it && it.hasNext() ) { JWSADProject affP = null; Iterator tmpIt = null; /* tant qu'il y a des �l�ments */ 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 d�pendances */ 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 r�pertoire */ class OnlyClassesFilter implements FileFilter { /** Extension d'une classe java compil�e */ 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 r�cup�re que les fichiers .class au premier niveau du r�pertoire if ( pathname.isFile() && pathname.getAbsolutePath().endsWith( CLASS_EXTENSION ) ) { accept = true; } return accept; } } }