/** * 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/>. */ package org.squale.squalix.tools.compiling.jsp; import java.io.File; import java.io.FileInputStream; import java.util.ArrayList; import java.util.List; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.tools.ant.BuildEvent; import org.apache.tools.ant.BuildListener; import org.apache.tools.ant.Project; import org.squale.squalecommon.enterpriselayer.businessobject.component.parameters.ListParameterBO; import org.squale.squalecommon.enterpriselayer.businessobject.component.parameters.ParametersConstants; import org.squale.squalecommon.enterpriselayer.businessobject.component.parameters.StringParameterBO; import org.squale.squalecommon.enterpriselayer.businessobject.result.ErrorBO; import org.squale.squalix.core.AbstractTask; import org.squale.squalix.core.TaskData; import org.squale.squalix.core.TaskException; 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.compiler.wsad.JWSADAntCompiler; import org.squale.squalix.tools.compiling.jsp.bean.J2eeWSADProject; import org.squale.squalix.tools.compiling.jsp.configuration.JspCompilingConfiguration; import org.squale.squalix.tools.compiling.jsp.wsad.AbstractTomcatCompiler; import org.squale.squalix.tools.compiling.jsp.wsad.TomcatCompilerFactory; import org.squale.squalix.util.buildpath.BuildProjectPath; import org.squale.squalix.util.file.FileUtility; /** * T�che de compilation des JSPs. La t�che de compilation Java doit avoir �t� effectu�e au pr�alable afin d'avoir le * classpath correctement form� et accessible via le param�tre temporaire <code>CLASSPATH</code> */ public class JspCompilingTask extends AbstractTask implements BuildListener { /** * Logger */ private static final Log LOGGER = LogFactory.getLog( JspCompilingTask.class ); /** Le message des erreurs de compilation */ private String compileErrorMessage; /** pour savoir si on compile les .java */ private boolean isJavaComplation; /** * Constructeur par d�faut. */ public JspCompilingTask() { mName = "JspCompilingTask"; compileErrorMessage = ""; isJavaComplation = false; } /** * {@inheritDoc} * * @see org.squale.squalix.core.AbstractTask#execute() */ public void execute() throws TaskException { // On r�cup�re le classpath dans les param�tres temporaires String classpath = (String) mData.getData( TaskData.CLASSPATH ); if ( null == classpath ) { // On lance une exception de configuration car cette variable // doit exister String message = CompilingMessages.getString( "jsp.exception.classpath_not_found" ); throw new TaskException( message ); } // On cr�e le projet J2eeWSADProject associ� J2eeWSADProject j2eeProject = new J2eeWSADProject(); j2eeProject.setName( mProject.getName() ); j2eeProject.setClasspath( classpath ); j2eeProject.setListener( this ); String viewPath = (String) mData.getData( TaskData.VIEW_PATH ); if ( null == viewPath ) { // On lance une exception de configuration car cette variable // doit exister String message = CompilingMessages.getString( "jsp.exception.view_path_not_found" ); throw new TaskException( message ); } if ( !viewPath.endsWith( "/" ) ) { viewPath += "/"; } try { setConfiguration(); String servletVersion = setJ2eeWSADProject( j2eeProject, viewPath ); // On lance le compilateur AbstractTomcatCompiler compiler = new TomcatCompilerFactory().createCompiler( j2eeProject, servletVersion ); compiler.compileJsp(); // On ajoute les liens entres les.java g�n�r�s et les .jsp dans les param�tres temporaires mData.putData( TaskData.JSP_MAP_NAMES, j2eeProject.getGeneratedClassesName() ); } catch ( Exception be ) { throw new TaskException( be ); } // on modifie les param�tres temporaires pour ajouter le r�pertoire // des .java des JSPs qui viennent d'�tre compil�es mData.putData( TaskData.JSP_TO_JAVA_DIR, j2eeProject.getJspDestPath() ); compileJava( viewPath, j2eeProject ); } /** * 1. V�rifie que les sources vers les JSPs existent et sont bien des r�pertoires racines de pages JSPs (ie. a des * .jsp � la racine ou � la racine de ses r�pertoires) 2. Construit la liste des jsps � compiler sous forme de map. * La map est de la taille de la liste donn�e dans les param�tres du projet et chaque entr�e correspond contient la * liste des fichiers JSPs que le r�pertoire de m�me index contient. Ex : ParametersConstants.JSP = {path1, path2} * alors le r�sultat sera {{*.jsp dans path1}, {*.jsp dans path2}} PRE-CONDITION : le param�tre du projet * <code>ParametersConstants.JSP</code> n'est pas nul. * * @param viewPath le chemin de la vue * @param absoluteJspPaths la liste des chemins absolus vers les r�pertoires sources JSP * @return la liste de liste des jsps � compiler de chaque r�pertoire source JSP */ private Object[][] verifyAndBuildJspSrc( String viewPath, List absoluteJspPaths ) { ListParameterBO excludedDirs = (ListParameterBO) mProject.getParameter( ParametersConstants.JSP_EXCLUDED_DIRS ); Object[][] result = new Object[absoluteJspPaths.size()][J2eeWSADProject.NB_ID]; File curJspDir; File[] jspsList; List path = new ArrayList( 1 ); for ( int i = 0; i < absoluteJspPaths.size(); i++ ) { curJspDir = new File( (String) absoluteJspPaths.get( i ) ); if ( curJspDir.exists() ) { // On regarde si le r�pertoire contient des .jsp ou des r�pertoires contenant des .jsps if ( !isJspRoot( curJspDir ) ) { // Il ne s"agit pas d'un r�pertoire racine de JSP String message = CompilingMessages.getString( "jsp.exception.no_jsp_root", curJspDir.getAbsolutePath().replace( '\\', '/' ).replaceFirst( viewPath, "" ) ); // On affiche un warning sans lancer d'exception car la t�che va quand m�me �tre ex�cut�e initError( message ); LOGGER.warn( message ); } // On ajoute les fichiers de ce r�pertoire � traiter sans prendre en compte les r�pertoires // exclus path.clear(); path.add( curJspDir.getAbsolutePath().replace( '\\', '/' ) ); result[i][J2eeWSADProject.DIR_ID] = curJspDir.getAbsolutePath(); result[i][J2eeWSADProject.JSP_LIST_ID] = FileUtility.getIncludedFiles( viewPath, path, null, null, excludedDirs, new String[] { ".jsp" } ); } else { String message = CompilingMessages.getString( "jsp.exception.src_not_found", curJspDir.getAbsolutePath().replace( '\\', '/' ).replaceFirst( viewPath, "" ) ); // On affiche un warning sans lancer d'exception car la t�che peut quand m�me �tre ex�cut�e initError( message ); LOGGER.warn( message ); // On ajoute une liste vide dans la liste des sources pour respecter l'ordre des indexes result[i][J2eeWSADProject.DIR_ID] = curJspDir.getAbsolutePath(); result[i][J2eeWSADProject.JSP_LIST_ID] = new ArrayList( 0 ); } } return result; } /** * @param curJspDir le r�pertoire courant des Jsps � v�rifier * @return true si le r�pertoire contient des .jsp � la racine ou � la racine de ses r�pertoires. */ private boolean isJspRoot( File curJspDir ) { boolean result = false; if ( curJspDir.isDirectory() ) { // On liste les fichiers et r�pertoires de premier niveau File[] files = curJspDir.listFiles(); for ( int i = 0; i < files.length && !result; i++ ) { result = files[i].isFile() && files[i].getName().endsWith( ".jsp" ); } } else if ( curJspDir.getName().endsWith( ".jsp" ) ) { result = true; } return result; } /** * Set task configuration * * @throws ConfigurationException if task is not set */ private void setConfiguration() throws ConfigurationException { // On r�cup�re la version servlet utilis�e StringParameterBO webapp = (StringParameterBO) mProject.getParameter( ParametersConstants.WEB_APP ); if ( webapp == null ) { // erreur de configuration throw new ConfigurationException( CompilingMessages.getString( "jsp.exception.webb_app_not_set" ) ); } // On r�cup�re la version j2ee utilis�e StringParameterBO j2eeScr = (StringParameterBO) mProject.getParameter( ParametersConstants.J2EE_VERSION ); if ( j2eeScr == null ) { // erreur de configuration throw new ConfigurationException( CompilingMessages.getString( "jsp.exception.servlet_version_not_set" ) ); } // On r�cup�re la liste des chemins vers les jsps du projet ListParameterBO jspsList = (ListParameterBO) mProject.getParameter( ParametersConstants.JSP ); if ( null == jspsList ) { // erreur de configuration throw new ConfigurationException( CompilingMessages.getString( "jsp.exception.sources_not_found" ) ); } } /** * Modifie les param�tres du projet wsad PRECONDITION : Les param�tres du projet ont �t� v�rifi�s et ne sont pas * nuls. * * @param j2eeProject le projet wsad * @param viewPath le viewpath * @return les sp�cifications servlet * @throws TaskException si erreur */ private String setJ2eeWSADProject( J2eeWSADProject j2eeProject, String viewPath ) throws TaskException { // Version des sources java j2eeProject.setJavaVersion( ( (StringParameterBO) mProject.getParameter( ParametersConstants.DIALECT ) ).getValue() ); // On r�cup�re la version j2ee utilis�e StringParameterBO j2eeScr = (StringParameterBO) mProject.getParameter( ParametersConstants.J2EE_VERSION ); String j2eeVersion = j2eeScr.getValue(); // On r�cup�re la liste des chemins vers les jsps du projet ListParameterBO jspsList = (ListParameterBO) mProject.getParameter( ParametersConstants.JSP ); // On construit le chemin vers les jsps en ne r�cup�rant que les fichiers � compiler // (on prend en compte les r�pertoires exclus de la compilation) List jsps = BuildProjectPath.buildProjectPath( viewPath, jspsList.getParameters() ); j2eeProject.setJspPaths( verifyAndBuildJspSrc( viewPath, jsps ) ); // On r�cup�re le r�pertoire racine de l'application dans les param�tres du projet String webAppPath = ( (StringParameterBO) mProject.getParameter( ParametersConstants.WEB_APP ) ).getValue(); File webApp = FileUtility.getAbsoluteFile( viewPath, new File( webAppPath ) ); if ( !webApp.exists() ) { // On lance une erreur de configuration LOGGER.warn( "Web application directory not found for project " + mProject.getName() ); throw new TaskException( "Web application directory not found : " + webAppPath ); } j2eeProject.setPath( webApp.getAbsolutePath() ); j2eeProject.setJspDestPath( J2eeWSADProject.JAVA_DEST ); // On affecte le r�pertoire de destination File destDir = new File( viewPath + j2eeProject.getJspDestPath() ); if ( !destDir.exists() ) { // On le cr�e destDir.mkdirs(); } j2eeProject.setJspDestPath( destDir.getAbsolutePath() ); // On r�cup�re le r�pertoire contenant les jars n�cessaires � la compilation // des jsps pour l'ajouter au classpath JspCompilingConfiguration conf = new JspCompilingConfiguration(); try { conf.parse( new FileInputStream( "config/jspcompiling-config.xml" ) ); // La version des servlets est de type 2.4, le nom du r�pertoire contenant les jars // et de la forme 2_4 donc on remplace le '.' par '_' File dir = new File( conf.getJarDirectory() + "/" + j2eeVersion.replace( '.', '_' ) ); if ( !dir.exists() && !dir.isDirectory() ) { String message = CompilingMessages.getString( "jsp.exception.jar_dir_not_found", new Object[] { conf.getJarDirectory() } ); throw new TaskException( new ConfigurationException( message ) ); } j2eeProject.addJarDirToClasspath( dir ); // On supprime tous les fichiers nomm�es "log4j.properties" dans le projet // pour �viter de g�n�rer des conflits avec le log4j de Squalix FileUtility.deleteFilesinPath( new File ( viewPath ) , "log4j.properties" ); FileUtility.deleteFilesinPath( new File ( viewPath ) , "commons-logging.properties" ); // On copie notre log4j.properties dans le WEB-INF/classes pour avoir une bonne configuration // des logs File log4j = new File( "config/log4j.properties" ); if ( log4j.exists() ) { FileUtility.copyIntoDir( log4j, new File( j2eeProject.getPath(), "WEB-INF/classes" ) ); } LOGGER.debug( "Classpath pour la compilation des JSPs : " + j2eeProject.getClasspath() ); } catch ( Exception be ) { throw new TaskException( be ); } return j2eeVersion; } /** * Compile les .java des JSPs * * @param viewPath le chemin de la vue * @param j2eeProject le projet J2EE * @throws TaskException si erreur de compilation */ private void compileJava( String viewPath, J2eeWSADProject j2eeProject ) throws TaskException { try { JWSADProject jwsadProject = new JWSADProject(); // l'�couteur est celui de la compilation Java jwsadProject.setListener( j2eeProject.getListener() ); jwsadProject.setRequiredMemory( "1024m" ); // On indique le r�pertoire qui va recevoir les .class File dest = new File( viewPath + J2eeWSADProject.CLASSES_DEST ); // On le cr�e dest.mkdirs(); jwsadProject.setDestPath( dest.getAbsolutePath() ); jwsadProject.setClasspath( j2eeProject.getClasspath() ); // On r�cup�re les r�pertoires des .class (hors jsp) du projet pour l'ajouter au classpath List classesDirs = (List) mData.getData( TaskData.CLASSES_DIRS ); for ( int i = 0; i < classesDirs.size(); i++ ) { jwsadProject.setClasspath( jwsadProject.getClasspath() + ";" + (String) classesDirs.get( i ) ); } // On modifie le classpath des param�tres temporaires jwsadProject.setSrcPath( j2eeProject.getJspDestPath() ); jwsadProject.setJavaVersion( ( (StringParameterBO) mProject.getParameter( ParametersConstants.DIALECT ) ).getValue() ); JWSADAntCompiler compiler = new JWSADAntCompiler( jwsadProject ); isJavaComplation = true; compiler.doCompilation(); mData.putData( TaskData.JSP_CLASSES_DIR, jwsadProject.getDestPath() ); StringBuffer classpath = new StringBuffer( jwsadProject.getClasspath() ); // On ajoute le r�pertoire des .class jsp au classpath pour mccabe if ( classpath.length() > 0 && !classpath.toString().endsWith( ";" ) ) { classpath.append( ";" ); } classpath.append( jwsadProject.getDestPath() ); mData.putData( TaskData.CLASSPATH, classpath.toString() ); affectFileSystemSize( mData.getData( TaskData.JSP_CLASSES_DIR ), true ); } catch ( Exception e ) { throw new TaskException( e ); } } /** * (non-Javadoc) * * @see org.apache.tools.ant.BuildListener#buildStarted(org.apache.tools.ant.BuildEvent) */ public void buildStarted( BuildEvent pEvent ) { log( pEvent ); } /** * (non-Javadoc) * * @see org.apache.tools.ant.BuildListener#buildFinished(org.apache.tools.ant.BuildEvent) */ public void buildFinished( BuildEvent pEvent ) { log( pEvent ); } /** * (non-Javadoc) * * @see org.apache.tools.ant.BuildListener#targetStarted(org.apache.tools.ant.BuildEvent) */ public void targetStarted( BuildEvent pEvent ) { log( pEvent ); } /** * (non-Javadoc) * * @see org.apache.tools.ant.BuildListener#targetFinished(org.apache.tools.ant.BuildEvent) */ public void targetFinished( BuildEvent pEvent ) { log( pEvent ); } /** * (non-Javadoc) * * @see org.apache.tools.ant.BuildListener#taskStarted(org.apache.tools.ant.BuildEvent) */ public void taskStarted( BuildEvent pEvent ) { log( pEvent ); } /** * (non-Javadoc) * * @see org.apache.tools.ant.BuildListener#taskFinished(org.apache.tools.ant.BuildEvent) */ public void taskFinished( BuildEvent pEvent ) { log( pEvent ); } /** * (non-Javadoc) * * @see org.apache.tools.ant.BuildListener#messageLogged(org.apache.tools.ant.BuildEvent) */ public void messageLogged( BuildEvent pEvent ) { log( pEvent ); } /** * Log JRAF L'�v�nement ANT est redirig� vers le log JRAF * * @param pEvent �v�nement ANT */ private void log( BuildEvent pEvent ) { // TODO : Trouver comment configurer Tomcat // en attendant on filtre les logs log4j // On adapte les logs en fonction de la gravit� du log initial String message = pEvent.getMessage(); if ( message != null && !message.startsWith( "log4j" ) ) { Throwable exception = pEvent.getException(); // Utilisation d'un switch car on ne peut pas // se passer du mapping entre en entier et une m�thode // � appeler : on pourrait m�moriser dans une map // la m�thode et l'entier mais cel� est un peu lourd switch ( pEvent.getPriority() ) { case Project.MSG_ERR: LOGGER.error( message, exception ); manageCompilError( message, ErrorBO.CRITICITY_FATAL ); break; case Project.MSG_WARN: LOGGER.warn( message, exception ); manageCompilError( message, ErrorBO.CRITICITY_WARNING ); break; case Project.MSG_INFO: LOGGER.info( message, exception ); break; case Project.MSG_VERBOSE: LOGGER.trace( message, exception ); break; case Project.MSG_DEBUG: LOGGER.debug( message, exception ); break; default: // Par d�faut on log sur le flux de warning LOGGER.warn( message, exception ); // par d�faut manageCompilError( message, ErrorBO.CRITICITY_WARNING ); break; } } } /** * g�re la cr�ation des erreurs de compilation * * @param pMessage le message d'erreur * @param pLevel le niveau d'erreur */ private void manageCompilError( String pMessage, String pLevel ) { if ( isJavaComplation ) { // TODO : sortir le code de JavaCompilingTask pour le factoriser avec celui-ci // Filtrage Java if ( pMessage.indexOf( "see the compiler error output" ) == -1 ) { // rajoute "\n" pour formater l'affichage de la jsp compileErrorMessage += pMessage + "\n"; } // on ne stocke que les erreurs de compil,pas les infos if ( pMessage.indexOf( "^" ) != -1 ) { // on enl�ve le chemin de la vue qui n'est pas une information n�cessaire compileErrorMessage = compileErrorMessage.replaceAll( (String) mData.getData( TaskData.VIEW_PATH ), "" ); // d�termine le niveau de criticit� if ( compileErrorMessage.toLowerCase().indexOf( "warning" ) == -1 ) { initError( compileErrorMessage, ErrorBO.CRITICITY_FATAL ); } else { initError( compileErrorMessage, ErrorBO.CRITICITY_WARNING ); } // reset compileErrorMessage = ""; } else { // pb de classpath sur les chargements de jar if ( pMessage.indexOf( ".jar" ) != -1 ) { // on enl�ve le chemin de la vue qui n'est pas une information n�cessaire compileErrorMessage = compileErrorMessage.replaceAll( (String) mData.getData( TaskData.VIEW_PATH ), "" ); // envoie du message niveau warning initError( compileErrorMessage, ErrorBO.CRITICITY_WARNING ); // reset compileErrorMessage = ""; } } } else { // Filtrage JSP // on enl�ve le chemin de la vue qui n'est pas une information n�cessaire compileErrorMessage = pMessage.replaceAll( (String) mData.getData( TaskData.VIEW_PATH ), "" ); // Il s'agit d'une exception Jasper String errorLevel = pLevel; if ( compileErrorMessage.matches( ".*JasperException.*" ) ) { errorLevel = ErrorBO.CRITICITY_FATAL; } initError( compileErrorMessage, errorLevel ); compileErrorMessage = ""; } } }